438 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			Python
		
	
	
	
			
		
		
	
	
			438 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			Python
		
	
	
	
"""
 | 
						|
module with base functionality for std.path package
 | 
						|
 | 
						|
"""
 | 
						|
from __future__ import generators
 | 
						|
import os, sys
 | 
						|
import py
 | 
						|
 | 
						|
def checktype(pathinstance, kw):
 | 
						|
    names = ('local', 'svnwc', 'svnurl', 'py', 'extpy')
 | 
						|
    for name,value in kw.items():
 | 
						|
        if name in names:
 | 
						|
            cls = getattr(py.path, name)
 | 
						|
            if bool(isinstance(pathinstance, cls)) ^ bool(value):
 | 
						|
                return False
 | 
						|
            del kw[name]
 | 
						|
    return True
 | 
						|
 | 
						|
class checker:
 | 
						|
    """ deprecated: return checker callable checking for the given 
 | 
						|
        kwargs-specified specification. 
 | 
						|
    """
 | 
						|
    def __init__(self, **kwargs):
 | 
						|
        py.std.warnings.warn("py.path.checker is deprecated, construct "
 | 
						|
                             "calls to pathobj.check() instead", 
 | 
						|
                             DeprecationWarning, stacklevel=2)
 | 
						|
        self.kwargs = kwargs
 | 
						|
    def __call__(self, p):
 | 
						|
        return p.check(**self.kwargs)
 | 
						|
 | 
						|
class Checkers:
 | 
						|
    _depend_on_existence = 'exists', 'link'
 | 
						|
 | 
						|
    def __init__(self, path):
 | 
						|
        self.path = path
 | 
						|
 | 
						|
    def exists(self):
 | 
						|
        raise NotImplementedError
 | 
						|
 | 
						|
    def basename(self, arg):
 | 
						|
        return self.path.basename == arg
 | 
						|
 | 
						|
    def basestarts(self, arg):
 | 
						|
        return self.path.basename.startswith(arg)
 | 
						|
 | 
						|
    def relto(self, arg):
 | 
						|
        return self.path.relto(arg)
 | 
						|
 | 
						|
    def fnmatch(self, arg):
 | 
						|
        return fnmatch(arg)(self.path)
 | 
						|
 | 
						|
    def endswith(self, arg):
 | 
						|
        return str(self.path).endswith(arg)
 | 
						|
 | 
						|
    def _evaluate(self, kw):
 | 
						|
        for name, value in kw.items():
 | 
						|
            invert = False
 | 
						|
            meth = None
 | 
						|
            try:
 | 
						|
                meth = getattr(self, name)
 | 
						|
            except AttributeError:
 | 
						|
                if name[:3] == 'not':
 | 
						|
                    invert = True
 | 
						|
                    try:
 | 
						|
                        meth = getattr(self, name[3:])
 | 
						|
                    except AttributeError:
 | 
						|
                        pass
 | 
						|
            if meth is None:
 | 
						|
                raise TypeError, "no %r checker available for %r" % (name, self.path)
 | 
						|
            try:
 | 
						|
                if meth.im_func.func_code.co_argcount > 1:
 | 
						|
                    if (not meth(value)) ^ invert:
 | 
						|
                        return False
 | 
						|
                else:
 | 
						|
                    if bool(value) ^ bool(meth()) ^ invert:
 | 
						|
                        return False
 | 
						|
            except (py.error.ENOENT, py.error.ENOTDIR):
 | 
						|
                for name in self._depend_on_existence:
 | 
						|
                    if name in kw:
 | 
						|
                        if kw.get(name):
 | 
						|
                            return False
 | 
						|
                    name = 'not' + name
 | 
						|
                    if name in kw:
 | 
						|
                        if not kw.get(name):
 | 
						|
                            return False
 | 
						|
        return True
 | 
						|
 | 
						|
class _dummyclass: 
 | 
						|
    pass
 | 
						|
 | 
						|
class PathBase(object):
 | 
						|
    """ shared implementation for filesystem path objects."""
 | 
						|
    Checkers = Checkers
 | 
						|
 | 
						|
    def check(self, **kw):
 | 
						|
        if kw:
 | 
						|
            kw = kw.copy()
 | 
						|
            if not checktype(self, kw):
 | 
						|
                return False
 | 
						|
        else:
 | 
						|
            kw = {'exists' : 1}
 | 
						|
        return self.Checkers(self)._evaluate(kw)
 | 
						|
 | 
						|
    def __iter__(self):
 | 
						|
        for i in self.listdir():
 | 
						|
            yield i
 | 
						|
 | 
						|
    def __contains__(self, other):
 | 
						|
        if isinstance(other, str):
 | 
						|
            return self.join(other).check()
 | 
						|
        else:
 | 
						|
            if other.dirpath() != self:
 | 
						|
                return False
 | 
						|
            p = self.join(other.basename)
 | 
						|
            return p.check()
 | 
						|
 | 
						|
    def basename(self):
 | 
						|
        return self._getbyspec('basename')[0]
 | 
						|
    basename = property(basename, None, None, 'basename part of path')
 | 
						|
 | 
						|
    def relto(self, relpath):
 | 
						|
        """ return a string which is the relative part of the path
 | 
						|
        to the given 'relpath'. 
 | 
						|
        """
 | 
						|
        if not isinstance(relpath, (str, PathBase)): 
 | 
						|
            raise TypeError("%r: not a string or path object" %(relpath,))
 | 
						|
        strrelpath = str(relpath)
 | 
						|
        if strrelpath and strrelpath[-1] != self.sep:
 | 
						|
            strrelpath += self.sep
 | 
						|
        #assert strrelpath[-1] == self.sep
 | 
						|
        #assert strrelpath[-2] != self.sep
 | 
						|
        strself = str(self)
 | 
						|
        if strself.startswith(strrelpath):
 | 
						|
            return strself[len(strrelpath):]
 | 
						|
        return ""
 | 
						|
 | 
						|
    def parts(self, reverse=False):
 | 
						|
        """ return a root-first list of all ancestor directories
 | 
						|
            plus the path itself.
 | 
						|
        """
 | 
						|
        current = self
 | 
						|
        l = [self]
 | 
						|
        while 1:
 | 
						|
            last = current
 | 
						|
            current = current.dirpath()
 | 
						|
            if last == current:
 | 
						|
                break
 | 
						|
            l.insert(0, current)
 | 
						|
        if reverse:
 | 
						|
            l.reverse()
 | 
						|
        return l
 | 
						|
 | 
						|
    def common(self, other):
 | 
						|
        """ return the common part shared with the other path
 | 
						|
            or None if there is no common part.
 | 
						|
        """
 | 
						|
        last = None
 | 
						|
        for x, y in zip(self.parts(), other.parts()):
 | 
						|
            if x != y:
 | 
						|
                return last
 | 
						|
            last = x
 | 
						|
        return last
 | 
						|
 | 
						|
    def __add__(self, other):
 | 
						|
        """ return new path object with 'other' added to the basename"""
 | 
						|
        return self.new(basename=self.basename+str(other))
 | 
						|
 | 
						|
    def __cmp__(self, other):
 | 
						|
        """ return sort value (-1, 0, +1). """
 | 
						|
        try:
 | 
						|
            return cmp(self.strpath, other.strpath)
 | 
						|
        except AttributeError:
 | 
						|
            return cmp(str(self), str(other)) # self.path, other.path)
 | 
						|
 | 
						|
    def __repr__(self):
 | 
						|
        """ return a string representation of this path. """
 | 
						|
        return repr(str(self))
 | 
						|
 | 
						|
    def visit(self, fil=None, rec=None, ignore=_dummyclass):
 | 
						|
        if isinstance(fil, str):
 | 
						|
            fil = fnmatch(fil)
 | 
						|
        if rec: 
 | 
						|
            if isinstance(rec, str):
 | 
						|
                rec = fnmatch(fil)
 | 
						|
            elif not callable(rec): 
 | 
						|
                rec = lambda x: True 
 | 
						|
        reclist = [self]
 | 
						|
        while reclist: 
 | 
						|
            current = reclist.pop(0)
 | 
						|
            try:
 | 
						|
                dirlist = current.listdir() 
 | 
						|
            except ignore:
 | 
						|
                return
 | 
						|
            for p in dirlist:
 | 
						|
                if fil is None or fil(p):
 | 
						|
                    yield p
 | 
						|
                if p.check(dir=1) and (rec is None or rec(p)):
 | 
						|
                    reclist.append(p)
 | 
						|
 | 
						|
    def _callex(self, func, *args):
 | 
						|
        """ call a function and raise errno-exception if applicable. """
 | 
						|
        __tracebackhide__ = True
 | 
						|
        try:
 | 
						|
            return func(*args)
 | 
						|
        except py.error.Error: 
 | 
						|
            raise
 | 
						|
        except EnvironmentError, e:
 | 
						|
            if not hasattr(e, 'errno'):
 | 
						|
                raise
 | 
						|
            __tracebackhide__ = False
 | 
						|
            cls, value, tb = sys.exc_info()
 | 
						|
            errno = e.errno 
 | 
						|
            try:
 | 
						|
                if not isinstance(e, WindowsError): 
 | 
						|
                    raise NameError
 | 
						|
            except NameError: 
 | 
						|
                # we are not on Windows, or we got a proper OSError
 | 
						|
                cls = py.error._geterrnoclass(errno)
 | 
						|
            else: 
 | 
						|
                try: 
 | 
						|
                    cls = py.error._getwinerrnoclass(errno)
 | 
						|
                except KeyError:    
 | 
						|
                    raise cls, value, tb
 | 
						|
            value = cls("%s%r" % (func.__name__, args))
 | 
						|
            __tracebackhide__ = True
 | 
						|
            raise cls, value
 | 
						|
 | 
						|
    def _gethashinstance(self, hashtype):
 | 
						|
        if hashtype == "md5": 
 | 
						|
            return py.std.md5.md5()
 | 
						|
        elif hashtype == "sha": 
 | 
						|
            return py.std.sha.sha()
 | 
						|
        else:
 | 
						|
            raise ValueError("unknown hash type: %r" %(hashtype,))
 | 
						|
 | 
						|
 | 
						|
class fnmatch:
 | 
						|
    def __init__(self, pattern):
 | 
						|
        self.pattern = pattern
 | 
						|
    def __call__(self, path):
 | 
						|
        """return true if the basename/fullname matches the glob-'pattern'.
 | 
						|
 | 
						|
        *       matches everything
 | 
						|
        ?       matches any single character
 | 
						|
        [seq]   matches any character in seq
 | 
						|
        [!seq]  matches any char not in seq
 | 
						|
 | 
						|
        if the pattern contains a path-separator then the full path
 | 
						|
        is used for pattern matching and a '*' is prepended to the
 | 
						|
        pattern.
 | 
						|
 | 
						|
        if the pattern doesn't contain a path-separator the pattern
 | 
						|
        is only matched against the basename.
 | 
						|
        """
 | 
						|
        pattern = self.pattern
 | 
						|
        if pattern.find(path.sep) == -1:
 | 
						|
            name = path.basename
 | 
						|
        else:
 | 
						|
            name = str(path) # path.strpath # XXX svn?
 | 
						|
            pattern = '*' + path.sep + pattern
 | 
						|
        from fnmatch import fnmatch
 | 
						|
        return fnmatch(name, pattern)
 | 
						|
 | 
						|
 | 
						|
class FSCheckers(Checkers):
 | 
						|
    _depend_on_existence = Checkers._depend_on_existence+('dir', 'file')
 | 
						|
 | 
						|
    def dir(self):
 | 
						|
        raise NotImplementedError
 | 
						|
 | 
						|
    def file(self):
 | 
						|
        raise NotImplementedError
 | 
						|
 | 
						|
    def dotfile(self):
 | 
						|
        return self.path.basename.startswith('.')
 | 
						|
 | 
						|
    def ext(self, arg):
 | 
						|
        if not arg.startswith('.'):
 | 
						|
            arg = '.' + arg
 | 
						|
        return self.path.ext == arg
 | 
						|
 | 
						|
class FSPathBase(PathBase):
 | 
						|
    """ shared implementation for filesystem path objects."""
 | 
						|
    Checkers = FSCheckers
 | 
						|
 | 
						|
    def __div__(self, other):
 | 
						|
        return self.join(str(other))
 | 
						|
 | 
						|
    def dirpath(self, *args, **kwargs):
 | 
						|
        """ return the directory Path of the current Path joined
 | 
						|
            with any given path arguments.
 | 
						|
        """
 | 
						|
        return self.new(basename='').join(*args, **kwargs)
 | 
						|
 | 
						|
    def ext(self):
 | 
						|
        """ extension of the path (including the '.')."""
 | 
						|
        return self._getbyspec('ext')[0]
 | 
						|
    ext = property(ext, None, None, 'extension part of path')
 | 
						|
 | 
						|
    def purebasename(self):
 | 
						|
        """ pure base name of the path."""
 | 
						|
        return self._getbyspec('purebasename')[0]
 | 
						|
    purebasename = property(purebasename, None, None, 'basename without extension')
 | 
						|
 | 
						|
    def read(self, mode='rb'):
 | 
						|
        """ read and return a bytestring from reading the path. """
 | 
						|
        if py.std.sys.version_info < (2,3):
 | 
						|
            for x in 'u', 'U':
 | 
						|
                if x in mode:
 | 
						|
                    mode = mode.replace(x, '')
 | 
						|
        f = self.open(mode)
 | 
						|
        try:
 | 
						|
            return f.read()
 | 
						|
        finally:
 | 
						|
            f.close()
 | 
						|
 | 
						|
    def readlines(self, cr=1):
 | 
						|
        """ read and return a list of lines from the path. if cr is False, the
 | 
						|
newline will be removed from the end of each line. """
 | 
						|
        if not cr:
 | 
						|
            content = self.read('rU')
 | 
						|
            return content.split('\n')
 | 
						|
        else:
 | 
						|
            f = self.open('rU')
 | 
						|
            try:
 | 
						|
                return f.readlines()
 | 
						|
            finally:
 | 
						|
                f.close()
 | 
						|
 | 
						|
    def load(self):
 | 
						|
        """ return object unpickled from self.read() """
 | 
						|
        f = self.open('rb')
 | 
						|
        try:
 | 
						|
            from cPickle import load
 | 
						|
            return self._callex(load, f)
 | 
						|
        finally:
 | 
						|
            f.close()
 | 
						|
 | 
						|
    def move(self, target):
 | 
						|
        """ move this path to target. """
 | 
						|
        if target.relto(self):
 | 
						|
            raise py.error.EINVAL(target, "cannot move path into a subdirectory of itself")
 | 
						|
        try:
 | 
						|
            self.rename(target)
 | 
						|
        except py.error.EXDEV:  # invalid cross-device link
 | 
						|
            self.copy(target)
 | 
						|
            self.remove()
 | 
						|
 | 
						|
    def getpymodule(self):
 | 
						|
        """resolve this path to a module python object. """
 | 
						|
        modname = str(self)
 | 
						|
        modname = modname.replace('.', self.sep)
 | 
						|
        try:
 | 
						|
            return sys.modules[modname]
 | 
						|
        except KeyError:
 | 
						|
            co = self.getpycodeobj()
 | 
						|
            mod = py.std.new.module(modname)
 | 
						|
            mod.__file__ = PathStr(self)
 | 
						|
            if self.basename == '__init__.py':
 | 
						|
                mod.__path__ = [str(self.dirpath())]
 | 
						|
            sys.modules[modname] = mod
 | 
						|
            try: 
 | 
						|
                exec co in mod.__dict__
 | 
						|
            except: 
 | 
						|
                del sys.modules[modname] 
 | 
						|
                raise 
 | 
						|
            return mod
 | 
						|
 | 
						|
    def getpycodeobj(self):
 | 
						|
        """ read the path and compile it to a py.code.Code object. """
 | 
						|
        s = self.read('rU')
 | 
						|
        # XXX str(self) should show up somewhere in the code's filename
 | 
						|
        return py.code.compile(s)
 | 
						|
 | 
						|
class PathStr(str):
 | 
						|
    def __init__(self, path):
 | 
						|
        global old_import_hook
 | 
						|
        self.__path__ = path
 | 
						|
        if old_import_hook is None:
 | 
						|
            import __builtin__
 | 
						|
            old_import_hook = __builtin__.__import__
 | 
						|
            __builtin__.__import__ = custom_import_hook
 | 
						|
 | 
						|
def relativeimport(p, name, parent=None):
 | 
						|
    names = name.split('.')
 | 
						|
    last_list = [False] * (len(names)-1) + [True]
 | 
						|
    modules = []
 | 
						|
    for name, is_last in zip(names, last_list):
 | 
						|
        if hasattr(parent, name):
 | 
						|
            # shortcut if there is already the correct name
 | 
						|
            # in the parent package
 | 
						|
            submodule = getattr(parent, name)
 | 
						|
        else:
 | 
						|
            if is_last and p.new(basename=name+'.py').check():
 | 
						|
                p = p.new(basename=name+'.py')
 | 
						|
            else:
 | 
						|
                p = p.new(basename=name).join('__init__.py')
 | 
						|
                if not p.check():
 | 
						|
                    return None   # not found
 | 
						|
            submodule = p.getpymodule()
 | 
						|
            if parent is not None:
 | 
						|
                setattr(parent, name, submodule)
 | 
						|
        modules.append(submodule)
 | 
						|
        parent = submodule
 | 
						|
    return modules   # success
 | 
						|
 | 
						|
 | 
						|
old_import_hook = None
 | 
						|
 | 
						|
def custom_import_hook(name, glob=None, loc=None, fromlist=None):
 | 
						|
    __tracebackhide__ = False 
 | 
						|
    __file__ = glob and glob.get('__file__')
 | 
						|
    if isinstance(__file__, PathStr):
 | 
						|
        # try to perform a relative import
 | 
						|
        # for cooperation with py.magic.autopath, first look in the pkgdir
 | 
						|
        modules = None
 | 
						|
        if hasattr(__file__.__path__, 'pkgdir'):
 | 
						|
            modules = relativeimport(__file__.__path__.pkgdir, name)
 | 
						|
        if not modules:
 | 
						|
            modules = relativeimport(__file__.__path__, name)
 | 
						|
        if modules:
 | 
						|
            if fromlist:
 | 
						|
                submodule = modules[-1]  # innermost submodule
 | 
						|
                # try to import submodules named in the 'fromlist' if the
 | 
						|
                # 'submodule' is a package
 | 
						|
                p = submodule.__file__.__path__
 | 
						|
                if p.check(basename='__init__.py'):
 | 
						|
                    for name in fromlist:
 | 
						|
                        relativeimport(p, name, parent=submodule)
 | 
						|
                        # failures are fine
 | 
						|
                return submodule
 | 
						|
            else:
 | 
						|
                return modules[0]   # outermost package
 | 
						|
    # fall-back
 | 
						|
    __tracebackhide__ = True 
 | 
						|
    return old_import_hook(name, glob, loc, fromlist)
 | 
						|
 |