238 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			Python
		
	
	
	
			
		
		
	
	
			238 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			Python
		
	
	
	
| """
 | |
| A path to python objects located in filesystems.
 | |
| 
 | |
| Note: this is still experimental and may be removed
 | |
|       for the first stable release!
 | |
| """
 | |
| from __future__ import generators
 | |
| import py
 | |
| from py.__.path import common
 | |
| import sys
 | |
| import inspect
 | |
| moduletype = type(py)
 | |
| 
 | |
| class Extpy(common.PathBase):
 | |
|     """ path object for addressing python objects. """
 | |
|     sep = '.'
 | |
|     def __new__(cls, root, modpath=''):
 | |
|         if not isinstance(modpath, str):
 | |
|             raise TypeError("second 'modpath' argument must be a dotted name.")
 | |
|         if isinstance(root, str):
 | |
|             root = py.path.local(root)
 | |
| 
 | |
|         self = object.__new__(cls)
 | |
|         if isinstance(root, Extpy): 
 | |
|             # we don't want it nested, do we? 
 | |
|             assert not modpath 
 | |
|             root = root.root 
 | |
|         self.modpath = modpath
 | |
|         self.root = root
 | |
|         return self
 | |
| 
 | |
|     def __hash__(self):
 | |
|         return hash((self.root, self.modpath))
 | |
| 
 | |
|     def __repr__(self):
 | |
|         return 'extpy(%r, %r)' % (self.root, self.modpath)
 | |
| 
 | |
|     def __str__(self):
 | |
|         return "%s%s.%s" %(self.root, self.root.sep, self.modpath) 
 | |
| 
 | |
|     def join(self, *args):
 | |
|         for arg in args:
 | |
|             if not isinstance(arg, str):
 | |
|                 raise TypeError, "non-strings not allowed in %r" % args
 | |
|         modpath = [x.strip('.') for x in ((self.modpath,)+args) if x]
 | |
|         modpath = self.sep.join(modpath)
 | |
|         return self.__class__(self.root, modpath)
 | |
| 
 | |
|     def relto(self, other):
 | |
|         if self.root != other.root: 
 | |
|             return '' 
 | |
|         return super(Extpy, self).relto(other) 
 | |
| 
 | |
|     def dirpath(self, *args):
 | |
|         modpath = self.modpath.split(self.sep) [:-1]
 | |
|         modpath = self.sep.join(modpath+list(args))
 | |
|         return self.__class__(self.root, modpath)
 | |
| 
 | |
|     def new(self, **kw):
 | |
|         """ create a modified version of this path.
 | |
|             the following keyword arguments modify various path parts:
 | |
|             modpath    substitute module path
 | |
|         """
 | |
|         cls = self.__class__
 | |
|         if 'modpath' in kw:
 | |
|             return cls(self.root, kw['modpath'])
 | |
|         if 'basename' in kw:
 | |
|             i = self.modpath.rfind('.')
 | |
|             if i != -1:
 | |
|                 return cls(self.root, self.modpath[i+1:] + kw['basename'])
 | |
|             else:
 | |
|                 return cls(self.root, kw['basename'])
 | |
|         return cls(self.root, self.modpath)
 | |
| 
 | |
|     def _getbyspec(self, spec):
 | |
|         l = []
 | |
|         modparts = self.modpath.split(self.sep)
 | |
|         for name in spec.split(','):
 | |
|             if name == 'basename':
 | |
|                 l.append(modparts[-1])
 | |
|         return l
 | |
| 
 | |
|     def resolve(self):
 | |
|         """return the python object, obtained from traversing from
 | |
|            the root along the modpath.
 | |
|         """
 | |
|         rest = filter(None, self.modpath.split('.'))
 | |
|         target = self.getpymodule()
 | |
|         for name in rest:
 | |
|             try:
 | |
|                 target = getattr(target, name)
 | |
|             except AttributeError:
 | |
|                 raise py.error.ENOENT(target, name)
 | |
|         return target
 | |
| 
 | |
|     def getpymodule(self):
 | |
|         if hasattr(self.root, 'resolve'):
 | |
|             return self.root.resolve()
 | |
|         else:
 | |
|             return self.root.getpymodule()
 | |
| 
 | |
|     def listobj(self, fil=None, **kw):
 | |
|         l = []
 | |
|         for x in self.listdir(fil, **kw):
 | |
|             l.append(x.resolve())
 | |
|         return l
 | |
| 
 | |
|     def listdir(self, fil=None, sort=True, **kw):
 | |
|         if kw:
 | |
|             if fil is None:
 | |
|                 fil = lambda x: x.check(**kw) 
 | |
|             else:
 | |
|                 raise TypeError, "cannot take filter and keyword arguments"
 | |
|         elif isinstance(fil, str):
 | |
|             fil = common.fnmatch(fil)
 | |
|         obj = self.resolve()
 | |
|         l = []
 | |
|         #print "listdir on", self
 | |
|         if not hasattr(obj, '__dict__'):
 | |
|             raise py.error.ENOTDIR(self, "does not have a __dict__ attribute")
 | |
|         for name in dir(obj):
 | |
|             sub = self.join(name)
 | |
|             if not fil or fil(sub):
 | |
|                 l.append(sub)
 | |
| 
 | |
|         #print "listdir(%r) -> %r" %(self, l)
 | |
|         #print "listdir on", repr(self)
 | |
|         return l
 | |
| 
 | |
|     def getfilelineno(self, scrapinit=0):
 | |
|         x = obj = self.resolve()
 | |
|         if inspect.ismodule(obj):
 | |
|             return obj.__file__, 0
 | |
|         if inspect.ismethod(obj):
 | |
|             obj = obj.im_func
 | |
|         if inspect.isfunction(obj):
 | |
|             obj = obj.func_code
 | |
|         if inspect.iscode(obj):
 | |
|             return py.path.local(obj.co_filename), obj.co_firstlineno - 1
 | |
|         else:
 | |
|             source, lineno = inspect.findsource(obj)
 | |
|             return x.getfile(), lineno - 1
 | |
| 
 | |
|     def visit(self, fil=None, rec=None, ignore=None, seen=None):
 | |
|         def myrec(p, seen={id(self): True}):
 | |
|             if id(p) in seen:
 | |
|                 return False
 | |
|             seen[id(p)] = True
 | |
|             if self.samefile(p):
 | |
|                 return True
 | |
| 
 | |
|         for x in super(Extpy, self).visit(fil=fil, rec=rec, ignore=ignore):
 | |
|             yield x
 | |
|         return
 | |
| 
 | |
|         if seen is None:
 | |
|             seen = {id(self): True}
 | |
| 
 | |
|         if isinstance(fil, str):
 | |
|             fil = common.fnmatch(fil)
 | |
|         if isinstance(rec, str):
 | |
|             rec = common.fnmatch(fil)
 | |
| 
 | |
|         if ignore:
 | |
|             try:
 | |
|                 l = self.listdir()
 | |
|             except ignore:
 | |
|                 return
 | |
|         else:
 | |
|             l = self.listdir()
 | |
|         reclist = []
 | |
|         for p in l:
 | |
|             if fil is None or fil(p):
 | |
|                 yield p
 | |
|             if id(p) not in seen:
 | |
|                 try:
 | |
|                     obj = p.resolve()
 | |
|                     if inspect.isclass(obj) or inspect.ismodule(obj):
 | |
|                         reclist.append(p)
 | |
|                 finally:
 | |
|                     seen[id(p)] = p
 | |
|         for p in reclist:
 | |
|             for i in p.visit(fil, rec, seen):
 | |
|                 yield i
 | |
| 
 | |
|     def samefile(self, other):
 | |
|         otherobj = other.resolve()
 | |
|         try:
 | |
|             x = inspect.getfile(otherobj)
 | |
|         except TypeError:
 | |
|             return False
 | |
|         if x.endswith('.pyc'):
 | |
|             x = x[:-1]
 | |
|         if str(self.root) == x:
 | |
|             return True
 | |
| 
 | |
|     def read(self, mode='ignored'):
 | |
|         """ return a bytestring from looking at our underlying object. 
 | |
|         
 | |
|         mode parmeter exists for consistency, but is ignored."""
 | |
|         return str(self.resolve())
 | |
| 
 | |
|     class Checkers(common.Checkers):
 | |
|         _depend_on_existence = (common.Checkers._depend_on_existence +
 | |
|                                 ('func', 'class_', 'exists', 'dir'))
 | |
| 
 | |
|         def _obj(self):
 | |
|             self._obj = self.path.resolve()
 | |
|             return self._obj
 | |
| 
 | |
|         def exists(self):
 | |
|             obj = self._obj()
 | |
|             return True
 | |
| 
 | |
|         def func(self):
 | |
|             ob = self._obj()
 | |
|             return inspect.isfunction(ob) or inspect.ismethod(ob)
 | |
| 
 | |
|         def class_(self):
 | |
|             ob = self._obj()
 | |
|             return inspect.isclass(ob)
 | |
| 
 | |
|         def isinstance(self, args):
 | |
|             return isinstance(self._obj(), args)
 | |
| 
 | |
|         def dir(self):
 | |
|             obj = self._obj()
 | |
|             return inspect.isclass(obj) or inspect.ismodule(obj)
 | |
| 
 | |
|         def file(self):
 | |
|             return not self.dir()
 | |
| 
 | |
|         def genfunc(self):
 | |
|             try:
 | |
|                 return self._obj().func_code.co_flags & 32
 | |
|             except AttributeError:
 | |
|                 return False
 |