root/trunk/twisted/python/reflect.py

Revision 33661, 25.8 KB (checked in by thijs, 2 months ago)

Merge reflect-macro-5035: Removed twisted.python.reflect.macro, deprecated since Twisted 8.2.

Author: thijs
Reviewer: itamar
Fixes: #5035

Line 
1# -*- test-case-name: twisted.test.test_reflect -*-
2# Copyright (c) Twisted Matrix Laboratories.
3# See LICENSE for details.
4
5"""
6Standardized versions of various cool and/or strange things that you can do
7with Python's reflection capabilities.
8"""
9
10import sys
11import os
12import types
13import pickle
14import traceback
15import weakref
16import re
17import warnings
18
19try:
20    from collections import deque
21except ImportError:
22    deque = list
23
24RegexType = type(re.compile(""))
25
26
27try:
28    from cStringIO import StringIO
29except ImportError:
30    from StringIO import StringIO
31
32from twisted.python.util import unsignedID
33from twisted.python.deprecate import deprecated, deprecatedModuleAttribute
34from twisted.python.deprecate import _fullyQualifiedName as fullyQualifiedName
35from twisted.python.versions import Version
36
37
38
39class 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
62class 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
126class 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
169class 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
225OriginalAccessor = Accessor
226deprecatedModuleAttribute(
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
232class 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
280class 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
291def 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
319ISNT=0
320WAS=1
321IS=2
322
323
324def 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
331def qual(clazz):
332    """
333    Return full import path of a class.
334    """
335    return clazz.__module__ + '.' + clazz.__name__
336
337
338def 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
347def 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...
360def 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
376def 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
388def 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
396namedClass = namedObject # backwards compat
397
398
399
400class _NoModuleFound(Exception):
401    """
402    No module was found because none exists.
403    """
404
405
406class InvalidName(ValueError):
407    """
408    The given name is not a dot-separated list of Python objects.
409    """
410
411
412class ModuleNotFound(InvalidName):
413    """
414    The module associated with the given name doesn't exist and it can't be
415    imported.
416    """
417
418
419class ObjectNotFound(InvalidName):
420    """
421    The object associated with the given name doesn't exist and it can't be
422    imported.
423    """
424
425
426def _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
459def 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
523def _determineClass(x):
524    try:
525        return x.__class__
526    except:
527        return type(x)
528
529
530
531def _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
543def _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
559def 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
570def 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")
584def 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")
596def accumulateBases(classObj, l, baseClass=None):
597    _accumulateBases(classObj, l, baseClass)
598
599
600def _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
607def 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
616def 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
639def 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
648def 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
668def 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
705def 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
717def isSame(a, b):
718    return (a is b)
719
720
721def isLike(a, b):
722    return (a == b)
723
724
725def modgrep(goal):
726    return objgrep(sys.modules, goal, isLike, 'sys.modules')
727
728
729def isOfType(start, goal):
730    return ((type(start) is goal) or
731            (isinstance(start, types.InstanceType) and
732             start.__class__ is goal))
733
734
735def findInstances(start, t):
736    return objgrep(start, t, isOfType)
737
738
739def 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
787def 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']
Note: See TracBrowser for help on using the browser.