Imported Upstream version 12.1.0
[contrib/python-twisted.git] / twisted / python / reflect.py
1 # -*- test-case-name: twisted.test.test_reflect -*-
2 # Copyright (c) Twisted Matrix Laboratories.
3 # See LICENSE for details.
4
5 """
6 Standardized versions of various cool and/or strange things that you can do
7 with Python's reflection capabilities.
8 """
9
10 import sys
11 import os
12 import types
13 import pickle
14 import traceback
15 import weakref
16 import re
17 import warnings
18
19 try:
20     from collections import deque
21 except ImportError:
22     deque = list
23
24 RegexType = type(re.compile(""))
25
26
27 try:
28     from cStringIO import StringIO
29 except ImportError:
30     from StringIO import StringIO
31
32 from twisted.python.util import unsignedID
33 from twisted.python.deprecate import deprecated, deprecatedModuleAttribute
34 from twisted.python.deprecate import _fullyQualifiedName as fullyQualifiedName
35 from twisted.python.versions import Version
36
37
38
39 class Settable:
40     """
41     A mixin class for syntactic sugar.  Lets you assign attributes by
42     calling with keyword arguments; for example, C{x(a=b,c=d,y=z)} is the
43     same as C{x.a=b;x.c=d;x.y=z}.  The most useful place for this is
44     where you don't want to name a variable, but you do want to set
45     some attributes; for example, C{X()(y=z,a=b)}.
46     """
47
48     deprecatedModuleAttribute(
49         Version("Twisted", 12, 1, 0),
50         "Settable is old and untested. Please write your own version of this "
51         "functionality if you need it.", "twisted.python.reflect", "Settable")
52
53     def __init__(self, **kw):
54         self(**kw)
55
56     def __call__(self,**kw):
57         for key,val in kw.items():
58             setattr(self,key,val)
59         return self
60
61
62 class AccessorType(type):
63     """
64     Metaclass that generates properties automatically.
65
66     This is for Python 2.2 and up.
67
68     Using this metaclass for your class will give you explicit accessor
69     methods; a method called set_foo, will automatically create a property
70     'foo' that uses set_foo as a setter method. Same for get_foo and del_foo.
71
72     Note that this will only work on methods that are present on class
73     creation. If you add methods after the class is defined they will not
74     automatically become properties. Likewise, class attributes will only
75     be used if they are present upon class creation, and no getter function
76     was set - if a getter is present, the class attribute will be ignored.
77
78     This is a 2.2-only alternative to the Accessor mixin - just set in your
79     class definition::
80
81         __metaclass__ = AccessorType
82
83     """
84
85     deprecatedModuleAttribute(
86         Version("Twisted", 12, 1, 0),
87         "AccessorType is old and untested. Please write your own version of "
88         "this functionality if you need it.", "twisted.python.reflect",
89         "AccessorType")
90
91     def __init__(self, name, bases, d):
92         type.__init__(self, name, bases, d)
93         accessors = {}
94         prefixs = ["get_", "set_", "del_"]
95         for k in d.keys():
96             v = getattr(self, k)
97             for i in range(3):
98                 if k.startswith(prefixs[i]):
99                     accessors.setdefault(k[4:], [None, None, None])[i] = v
100         for name, (getter, setter, deler) in accessors.items():
101             # create default behaviours for the property - if we leave
102             # the getter as None we won't be able to getattr, etc..
103             if getter is None:
104                 if hasattr(self, name):
105                     value = getattr(self, name)
106                     def getter(this, value=value, name=name):
107                         if name in this.__dict__:
108                             return this.__dict__[name]
109                         else:
110                             return value
111                 else:
112                     def getter(this, name=name):
113                         if name in this.__dict__:
114                             return this.__dict__[name]
115                         else:
116                             raise AttributeError("no such attribute %r" % name)
117             if setter is None:
118                 def setter(this, value, name=name):
119                     this.__dict__[name] = value
120             if deler is None:
121                 def deler(this, name=name):
122                     del this.__dict__[name]
123             setattr(self, name, property(getter, setter, deler, ""))
124
125
126 class PropertyAccessor(object):
127     """
128     A mixin class for Python 2.2 that uses AccessorType.
129
130     This provides compatability with the pre-2.2 Accessor mixin, up
131     to a point.
132
133     Extending this class will give you explicit accessor methods; a
134     method called set_foo, for example, is the same as an if statement
135     in __setattr__ looking for 'foo'.  Same for get_foo and del_foo.
136
137     There are also reallyDel and reallySet methods, so you can
138     override specifics in subclasses without clobbering __setattr__
139     and __getattr__, or using non-2.1 compatible code.
140
141     There is are incompatibilities with Accessor - accessor
142     methods added after class creation will *not* be detected. OTOH,
143     this method is probably way faster.
144
145     In addition, class attributes will only be used if no getter
146     was defined, and instance attributes will not override getter methods
147     whereas in original Accessor the class attribute or instance attribute
148     would override the getter method.
149     """
150     # addendum to above:
151     # The behaviour of Accessor is wrong IMHO, and I've found bugs
152     # caused by it.
153     #  -- itamar
154
155     deprecatedModuleAttribute(
156         Version("Twisted", 12, 1, 0),
157         "PropertyAccessor is old and untested. Please write your own version "
158         "of this functionality if you need it.", "twisted.python.reflect",
159         "PropertyAccessor")
160     __metaclass__ = AccessorType
161
162     def reallySet(self, k, v):
163         self.__dict__[k] = v
164
165     def reallyDel(self, k):
166         del self.__dict__[k]
167
168
169 class Accessor:
170     """
171     Extending this class will give you explicit accessor methods; a
172     method called C{set_foo}, for example, is the same as an if statement
173     in L{__setattr__} looking for C{'foo'}.  Same for C{get_foo} and
174     C{del_foo}.  There are also L{reallyDel} and L{reallySet} methods,
175     so you can override specifics in subclasses without clobbering
176     L{__setattr__} and L{__getattr__}.
177
178     This implementation is for Python 2.1.
179     """
180
181     deprecatedModuleAttribute(
182         Version("Twisted", 12, 1, 0),
183         "Accessor is an implementation for Python 2.1 which is no longer "
184         "supported by Twisted.", "twisted.python.reflect", "Accessor")
185
186     def __setattr__(self, k,v):
187         kstring='set_%s'%k
188         if hasattr(self.__class__,kstring):
189             return getattr(self,kstring)(v)
190         else:
191             self.reallySet(k,v)
192
193     def __getattr__(self, k):
194         kstring='get_%s'%k
195         if hasattr(self.__class__,kstring):
196             return getattr(self,kstring)()
197         raise AttributeError("%s instance has no accessor for: %s" % (qual(self.__class__),k))
198
199     def __delattr__(self, k):
200         kstring='del_%s'%k
201         if hasattr(self.__class__,kstring):
202             getattr(self,kstring)()
203             return
204         self.reallyDel(k)
205
206     def reallySet(self, k,v):
207         """
208         *actually* set self.k to v without incurring side-effects.
209         This is a hook to be overridden by subclasses.
210         """
211         if k == "__dict__":
212             self.__dict__.clear()
213             self.__dict__.update(v)
214         else:
215             self.__dict__[k]=v
216
217     def reallyDel(self, k):
218         """
219         *actually* del self.k without incurring side-effects.  This is a
220         hook to be overridden by subclasses.
221         """
222         del self.__dict__[k]
223
224 # just in case
225 OriginalAccessor = Accessor
226 deprecatedModuleAttribute(
227     Version("Twisted", 12, 1, 0),
228     "OriginalAccessor is a reference to class twisted.python.reflect.Accessor "
229     "which is deprecated.", "twisted.python.reflect", "OriginalAccessor")
230
231
232 class Summer(Accessor):
233     """
234     Extend from this class to get the capability to maintain 'related
235     sums'.  Have a tuple in your class like the following::
236
237         sums=(('amount','credit','credit_total'),
238               ('amount','debit','debit_total'))
239
240     and the 'credit_total' member of the 'credit' member of self will
241     always be incremented when the 'amount' member of self is
242     incremented, similiarly for the debit versions.
243     """
244
245     deprecatedModuleAttribute(
246         Version("Twisted", 12, 1, 0),
247         "Summer is a child class of twisted.python.reflect.Accessor which is " 
248         "deprecated.", "twisted.python.reflect", "Summer")
249
250     def reallySet(self, k,v):
251         "This method does the work."
252         for sum in self.sums:
253             attr=sum[0]
254             obj=sum[1]
255             objattr=sum[2]
256             if k == attr:
257                 try:
258                     oldval=getattr(self, attr)
259                 except:
260                     oldval=0
261                 diff=v-oldval
262                 if hasattr(self, obj):
263                     ob=getattr(self,obj)
264                     if ob is not None:
265                         try:oldobjval=getattr(ob, objattr)
266                         except:oldobjval=0.0
267                         setattr(ob,objattr,oldobjval+diff)
268
269             elif k == obj:
270                 if hasattr(self, attr):
271                     x=getattr(self,attr)
272                     setattr(self,attr,0)
273                     y=getattr(self,k)
274                     Accessor.reallySet(self,k,v)
275                     setattr(self,attr,x)
276                     Accessor.reallySet(self,y,v)
277         Accessor.reallySet(self,k,v)
278
279
280 class QueueMethod:
281     """
282     I represent a method that doesn't exist yet.
283     """
284     def __init__(self, name, calls):
285         self.name = name
286         self.calls = calls
287     def __call__(self, *args):
288         self.calls.append((self.name, args))
289
290
291 def funcinfo(function):
292     """
293     this is more documentation for myself than useful code.
294     """
295     warnings.warn(
296         "[v2.5] Use inspect.getargspec instead of twisted.python.reflect.funcinfo",
297         DeprecationWarning,
298         stacklevel=2)
299     code=function.func_code
300     name=function.func_name
301     argc=code.co_argcount
302     argv=code.co_varnames[:argc]
303     defaults=function.func_defaults
304
305     out = []
306
307     out.append('The function %s accepts %s arguments' % (name ,argc))
308     if defaults:
309         required=argc-len(defaults)
310         out.append('It requires %s arguments' % required)
311         out.append('The arguments required are: %s' % argv[:required])
312         out.append('additional arguments are:')
313         for i in range(argc-required):
314             j=i+required
315             out.append('%s which has a default of' % (argv[j], defaults[i]))
316     return out
317
318
319 ISNT=0
320 WAS=1
321 IS=2
322
323
324 def fullFuncName(func):
325     qualName = (str(pickle.whichmodule(func, func.__name__)) + '.' + func.__name__)
326     if namedObject(qualName) is not func:
327         raise Exception("Couldn't find %s as %s." % (func, qualName))
328     return qualName
329
330
331 def qual(clazz):
332     """
333     Return full import path of a class.
334     """
335     return clazz.__module__ + '.' + clazz.__name__
336
337
338 def getcurrent(clazz):
339     assert type(clazz) == types.ClassType, 'must be a class...'
340     module = namedModule(clazz.__module__)
341     currclass = getattr(module, clazz.__name__, None)
342     if currclass is None:
343         return clazz
344     return currclass
345
346
347 def getClass(obj):
348     """
349     Return the class or type of object 'obj'.
350     Returns sensible result for oldstyle and newstyle instances and types.
351     """
352     if hasattr(obj, '__class__'):
353         return obj.__class__
354     else:
355         return type(obj)
356
357 # class graph nonsense
358
359 # I should really have a better name for this...
360 def isinst(inst,clazz):
361     if type(inst) != types.InstanceType or type(clazz)!= types.ClassType:
362         return isinstance(inst,clazz)
363     cl = inst.__class__
364     cl2 = getcurrent(cl)
365     clazz = getcurrent(clazz)
366     if issubclass(cl2,clazz):
367         if cl == cl2:
368             return WAS
369         else:
370             inst.__class__ = cl2
371             return IS
372     else:
373         return ISNT
374
375
376 def namedModule(name):
377     """
378     Return a module given its name.
379     """
380     topLevel = __import__(name)
381     packages = name.split(".")[1:]
382     m = topLevel
383     for p in packages:
384         m = getattr(m, p)
385     return m
386
387
388 def namedObject(name):
389     """
390     Get a fully named module-global object.
391     """
392     classSplit = name.split('.')
393     module = namedModule('.'.join(classSplit[:-1]))
394     return getattr(module, classSplit[-1])
395
396 namedClass = namedObject # backwards compat
397
398
399
400 class _NoModuleFound(Exception):
401     """
402     No module was found because none exists.
403     """
404
405
406 class InvalidName(ValueError):
407     """
408     The given name is not a dot-separated list of Python objects.
409     """
410
411
412 class ModuleNotFound(InvalidName):
413     """
414     The module associated with the given name doesn't exist and it can't be
415     imported.
416     """
417
418
419 class ObjectNotFound(InvalidName):
420     """
421     The object associated with the given name doesn't exist and it can't be
422     imported.
423     """
424
425
426 def _importAndCheckStack(importName):
427     """
428     Import the given name as a module, then walk the stack to determine whether
429     the failure was the module not existing, or some code in the module (for
430     example a dependent import) failing.  This can be helpful to determine
431     whether any actual application code was run.  For example, to distiguish
432     administrative error (entering the wrong module name), from programmer
433     error (writing buggy code in a module that fails to import).
434
435     @raise Exception: if something bad happens.  This can be any type of
436     exception, since nobody knows what loading some arbitrary code might do.
437
438     @raise _NoModuleFound: if no module was found.
439     """
440     try:
441         try:
442             return __import__(importName)
443         except ImportError:
444             excType, excValue, excTraceback = sys.exc_info()
445             while excTraceback:
446                 execName = excTraceback.tb_frame.f_globals["__name__"]
447                 if (execName is None or # python 2.4+, post-cleanup
448                     execName == importName): # python 2.3, no cleanup
449                     raise excType, excValue, excTraceback
450                 excTraceback = excTraceback.tb_next
451             raise _NoModuleFound()
452     except:
453         # Necessary for cleaning up modules in 2.3.
454         sys.modules.pop(importName, None)
455         raise
456
457
458
459 def namedAny(name):
460     """
461     Retrieve a Python object by its fully qualified name from the global Python
462     module namespace.  The first part of the name, that describes a module,
463     will be discovered and imported.  Each subsequent part of the name is
464     treated as the name of an attribute of the object specified by all of the
465     name which came before it.  For example, the fully-qualified name of this
466     object is 'twisted.python.reflect.namedAny'.
467
468     @type name: L{str}
469     @param name: The name of the object to return.
470
471     @raise InvalidName: If the name is an empty string, starts or ends with
472         a '.', or is otherwise syntactically incorrect.
473
474     @raise ModuleNotFound: If the name is syntactically correct but the
475         module it specifies cannot be imported because it does not appear to
476         exist.
477
478     @raise ObjectNotFound: If the name is syntactically correct, includes at
479         least one '.', but the module it specifies cannot be imported because
480         it does not appear to exist.
481
482     @raise AttributeError: If an attribute of an object along the way cannot be
483         accessed, or a module along the way is not found.
484
485     @return: the Python object identified by 'name'.
486     """
487     if not name:
488         raise InvalidName('Empty module name')
489
490     names = name.split('.')
491
492     # if the name starts or ends with a '.' or contains '..', the __import__
493     # will raise an 'Empty module name' error. This will provide a better error
494     # message.
495     if '' in names:
496         raise InvalidName(
497             "name must be a string giving a '.'-separated list of Python "
498             "identifiers, not %r" % (name,))
499
500     topLevelPackage = None
501     moduleNames = names[:]
502     while not topLevelPackage:
503         if moduleNames:
504             trialname = '.'.join(moduleNames)
505             try:
506                 topLevelPackage = _importAndCheckStack(trialname)
507             except _NoModuleFound:
508                 moduleNames.pop()
509         else:
510             if len(names) == 1:
511                 raise ModuleNotFound("No module named %r" % (name,))
512             else:
513                 raise ObjectNotFound('%r does not name an object' % (name,))
514
515     obj = topLevelPackage
516     for n in names[1:]:
517         obj = getattr(obj, n)
518
519     return obj
520
521
522
523 def _determineClass(x):
524     try:
525         return x.__class__
526     except:
527         return type(x)
528
529
530
531 def _determineClassName(x):
532     c = _determineClass(x)
533     try:
534         return c.__name__
535     except:
536         try:
537             return str(c)
538         except:
539             return '<BROKEN CLASS AT 0x%x>' % unsignedID(c)
540
541
542
543 def _safeFormat(formatter, o):
544     """
545     Helper function for L{safe_repr} and L{safe_str}.
546     """
547     try:
548         return formatter(o)
549     except:
550         io = StringIO()
551         traceback.print_exc(file=io)
552         className = _determineClassName(o)
553         tbValue = io.getvalue()
554         return "<%s instance at 0x%x with %s error:\n %s>" % (
555             className, unsignedID(o), formatter.__name__, tbValue)
556
557
558
559 def safe_repr(o):
560     """
561     safe_repr(anything) -> string
562
563     Returns a string representation of an object, or a string containing a
564     traceback, if that object's __repr__ raised an exception.
565     """
566     return _safeFormat(repr, o)
567
568
569
570 def safe_str(o):
571     """
572     safe_str(anything) -> string
573
574     Returns a string representation of an object, or a string containing a
575     traceback, if that object's __str__ raised an exception.
576     """
577     return _safeFormat(str, o)
578
579
580
581 ## the following were factored out of usage
582
583 @deprecated(Version("Twisted", 11, 0, 0), "inspect.getmro")
584 def allYourBase(classObj, baseClass=None):
585     """
586     allYourBase(classObj, baseClass=None) -> list of all base
587     classes that are subclasses of baseClass, unless it is None,
588     in which case all bases will be added.
589     """
590     l = []
591     _accumulateBases(classObj, l, baseClass)
592     return l
593
594
595 @deprecated(Version("Twisted", 11, 0, 0), "inspect.getmro")
596 def accumulateBases(classObj, l, baseClass=None):
597     _accumulateBases(classObj, l, baseClass)
598
599
600 def _accumulateBases(classObj, l, baseClass=None):
601     for base in classObj.__bases__:
602         if baseClass is None or issubclass(base, baseClass):
603             l.append(base)
604         _accumulateBases(base, l, baseClass)
605
606
607 def prefixedMethodNames(classObj, prefix):
608     """
609     A list of method names with a given prefix in a given class.
610     """
611     dct = {}
612     addMethodNamesToDict(classObj, dct, prefix)
613     return dct.keys()
614
615
616 def addMethodNamesToDict(classObj, dict, prefix, baseClass=None):
617     """
618     addMethodNamesToDict(classObj, dict, prefix, baseClass=None) -> dict
619     this goes through 'classObj' (and its bases) and puts method names
620     starting with 'prefix' in 'dict' with a value of 1. if baseClass isn't
621     None, methods will only be added if classObj is-a baseClass
622
623     If the class in question has the methods 'prefix_methodname' and
624     'prefix_methodname2', the resulting dict should look something like:
625     {"methodname": 1, "methodname2": 1}.
626     """
627     for base in classObj.__bases__:
628         addMethodNamesToDict(base, dict, prefix, baseClass)
629
630     if baseClass is None or baseClass in classObj.__bases__:
631         for name, method in classObj.__dict__.items():
632             optName = name[len(prefix):]
633             if ((type(method) is types.FunctionType)
634                 and (name[:len(prefix)] == prefix)
635                 and (len(optName))):
636                 dict[optName] = 1
637
638
639 def prefixedMethods(obj, prefix=''):
640     """
641     A list of methods with a given prefix on a given instance.
642     """
643     dct = {}
644     accumulateMethods(obj, dct, prefix)
645     return dct.values()
646
647
648 def accumulateMethods(obj, dict, prefix='', curClass=None):
649     """
650     accumulateMethods(instance, dict, prefix)
651     I recurse through the bases of instance.__class__, and add methods
652     beginning with 'prefix' to 'dict', in the form of
653     {'methodname':*instance*method_object}.
654     """
655     if not curClass:
656         curClass = obj.__class__
657     for base in curClass.__bases__:
658         accumulateMethods(obj, dict, prefix, base)
659
660     for name, method in curClass.__dict__.items():
661         optName = name[len(prefix):]
662         if ((type(method) is types.FunctionType)
663             and (name[:len(prefix)] == prefix)
664             and (len(optName))):
665             dict[optName] = getattr(obj, name)
666
667
668 def accumulateClassDict(classObj, attr, adict, baseClass=None):
669     """
670     Accumulate all attributes of a given name in a class hierarchy into a single dictionary.
671
672     Assuming all class attributes of this name are dictionaries.
673     If any of the dictionaries being accumulated have the same key, the
674     one highest in the class heirarchy wins.
675     (XXX: If \"higest\" means \"closest to the starting class\".)
676
677     Ex::
678
679       class Soy:
680         properties = {\"taste\": \"bland\"}
681     
682       class Plant:
683         properties = {\"colour\": \"green\"}
684     
685       class Seaweed(Plant):
686         pass
687     
688       class Lunch(Soy, Seaweed):
689         properties = {\"vegan\": 1 }
690     
691       dct = {}
692     
693       accumulateClassDict(Lunch, \"properties\", dct)
694     
695       print dct
696
697     {\"taste\": \"bland\", \"colour\": \"green\", \"vegan\": 1}
698     """
699     for base in classObj.__bases__:
700         accumulateClassDict(base, attr, adict)
701     if baseClass is None or baseClass in classObj.__bases__:
702         adict.update(classObj.__dict__.get(attr, {}))
703
704
705 def accumulateClassList(classObj, attr, listObj, baseClass=None):
706     """
707     Accumulate all attributes of a given name in a class heirarchy into a single list.
708
709     Assuming all class attributes of this name are lists.
710     """
711     for base in classObj.__bases__:
712         accumulateClassList(base, attr, listObj)
713     if baseClass is None or baseClass in classObj.__bases__:
714         listObj.extend(classObj.__dict__.get(attr, []))
715
716
717 def isSame(a, b):
718     return (a is b)
719
720
721 def isLike(a, b):
722     return (a == b)
723
724
725 def modgrep(goal):
726     return objgrep(sys.modules, goal, isLike, 'sys.modules')
727
728
729 def isOfType(start, goal):
730     return ((type(start) is goal) or
731             (isinstance(start, types.InstanceType) and
732              start.__class__ is goal))
733
734
735 def findInstances(start, t):
736     return objgrep(start, t, isOfType)
737
738
739 def objgrep(start, goal, eq=isLike, path='', paths=None, seen=None, showUnknowns=0, maxDepth=None):
740     """
741     An insanely CPU-intensive process for finding stuff.
742     """
743     if paths is None:
744         paths = []
745     if seen is None:
746         seen = {}
747     if eq(start, goal):
748         paths.append(path)
749     if id(start) in seen:
750         if seen[id(start)] is start:
751             return
752     if maxDepth is not None:
753         if maxDepth == 0:
754             return
755         maxDepth -= 1
756     seen[id(start)] = start
757     if isinstance(start, types.DictionaryType):
758         for k, v in start.items():
759             objgrep(k, goal, eq, path+'{'+repr(v)+'}', paths, seen, showUnknowns, maxDepth)
760             objgrep(v, goal, eq, path+'['+repr(k)+']', paths, seen, showUnknowns, maxDepth)
761     elif isinstance(start, (list, tuple, deque)):
762         for idx in xrange(len(start)):
763             objgrep(start[idx], goal, eq, path+'['+str(idx)+']', paths, seen, showUnknowns, maxDepth)
764     elif isinstance(start, types.MethodType):
765         objgrep(start.im_self, goal, eq, path+'.im_self', paths, seen, showUnknowns, maxDepth)
766         objgrep(start.im_func, goal, eq, path+'.im_func', paths, seen, showUnknowns, maxDepth)
767         objgrep(start.im_class, goal, eq, path+'.im_class', paths, seen, showUnknowns, maxDepth)
768     elif hasattr(start, '__dict__'):
769         for k, v in start.__dict__.items():
770             objgrep(v, goal, eq, path+'.'+k, paths, seen, showUnknowns, maxDepth)
771         if isinstance(start, types.InstanceType):
772             objgrep(start.__class__, goal, eq, path+'.__class__', paths, seen, showUnknowns, maxDepth)
773     elif isinstance(start, weakref.ReferenceType):
774         objgrep(start(), goal, eq, path+'()', paths, seen, showUnknowns, maxDepth)
775     elif (isinstance(start, types.StringTypes+
776                     (types.IntType, types.FunctionType,
777                      types.BuiltinMethodType, RegexType, types.FloatType,
778                      types.NoneType, types.FileType)) or
779           type(start).__name__ in ('wrapper_descriptor', 'method_descriptor',
780                                    'member_descriptor', 'getset_descriptor')):
781         pass
782     elif showUnknowns:
783         print 'unknown type', type(start), start
784     return paths
785
786
787 def filenameToModuleName(fn):
788     """
789     Convert a name in the filesystem to the name of the Python module it is.
790
791     This is agressive about getting a module name back from a file; it will
792     always return a string.  Agressive means 'sometimes wrong'; it won't look
793     at the Python path or try to do any error checking: don't use this method
794     unless you already know that the filename you're talking about is a Python
795     module.
796     """
797     fullName = os.path.abspath(fn)
798     base = os.path.basename(fn)
799     if not base:
800         # this happens when fn ends with a path separator, just skit it
801         base = os.path.basename(fn[:-1])
802     modName = os.path.splitext(base)[0]
803     while 1:
804         fullName = os.path.dirname(fullName)
805         if os.path.exists(os.path.join(fullName, "__init__.py")):
806             modName = "%s.%s" % (os.path.basename(fullName), modName)
807         else:
808             break
809     return modName
810
811
812
813 __all__ = [
814     'InvalidName', 'ModuleNotFound', 'ObjectNotFound',
815
816     'ISNT', 'WAS', 'IS',
817
818     'Settable', 'AccessorType', 'PropertyAccessor', 'Accessor', 'Summer',
819     'QueueMethod', 'OriginalAccessor',
820
821     'funcinfo', 'fullFuncName', 'qual', 'getcurrent', 'getClass', 'isinst',
822     'namedModule', 'namedObject', 'namedClass', 'namedAny',
823     'safe_repr', 'safe_str', 'allYourBase', 'accumulateBases',
824     'prefixedMethodNames', 'addMethodNamesToDict', 'prefixedMethods',
825     'accumulateClassDict', 'accumulateClassList', 'isSame', 'isLike',
826     'modgrep', 'isOfType', 'findInstances', 'objgrep', 'filenameToModuleName',
827     'fullyQualifiedName']