Source code for tangled.util.path

import importlib
import inspect
import os


__all__ = [
    'abs_path',
    'asset_path',
    'fully_qualified_name',
    'is_asset_path',
    'is_module_path',
    'is_object_path',
]


[docs]def abs_path(path): """Get abs. path for ``path``. ``path`` may be a relative or absolute file system path or an asset path. If ``path`` is already an abs. path, it will be returned as is. Otherwise, it will be converted into a normalized abs. path. """ if not os.path.isabs(path): if is_asset_path(path): path = asset_path(path) else: path = os.path.expanduser(path) path = os.path.normpath(os.path.abspath(path)) return path
[docs]def asset_path(path, *rel_path): """Get absolute path to asset in package. ``path`` can be just a package name like 'tangled.web' or it can be a package name and a relative file system path like 'tangled.web:some/path'. If ``rel_path`` is passed, it will be appended to the base rel. path in ``path``. Examples:: >>> asset_path('tangled.util') '.../tangled/tangled' >>> asset_path('tangled.util:') '.../tangled/tangled' >>> asset_path('tangled.util:x') '.../tangled/tangled/x' >>> asset_path('tangled.util', 'x') '.../tangled/tangled/x' >>> asset_path('tangled.util:x', 'y') '.../tangled/tangled/x/y' """ if not (is_asset_path(path) or is_module_path(path)): raise ValueError('Path is not an asset path: %s' % path) if ':' in path: package_name, base_rel_path = path.split(':') rel_path = (base_rel_path,) + rel_path else: package_name = path package = importlib.import_module(package_name) if not hasattr(package, '__file__'): raise ValueError("Can't compute path relative to namespace package") package_path = os.path.dirname(package.__file__) path = os.path.join(package_path, *rel_path) path = os.path.normpath(os.path.abspath(path)) return path
[docs]def fully_qualified_name(obj): """Get the fully qualified name for an object. Returns the object's module name joined with its qualified name. If the object is a module, its name is returned. >>> fully_qualified_name(object) 'builtins.object' >>> import tangled.util >>> fully_qualified_name(tangled.util) 'tangled.util' """ if inspect.ismodule(obj): return obj.__name__ return '{}.{}'.format(obj.__module__, obj.__qualname__)
[docs]def is_asset_path(path) -> bool: """Is ``path`` an asset path like ``package.module:path``? If ``path`` is absolute, it will not be considered an asset path. Otherwise, it will be considered an asset path if it contains a colon *and* the module path contains only valid Python identifiers. The file system path to the right of the colon can be empty or any string (it's ignored here). Examples:: >>> is_asset_path('/some/abs/path') False >>> is_asset_path('rel/path') False >>> is_asset_path('package') False >>> is_asset_path('package:') True >>> is_asset_path('package.subpackage:rel/path') True >>> is_asset_path('package.subpackage:') True >>> is_asset_path('package.subpackage:rel/path') True >>> is_asset_path('base.ini') False """ if os.path.isabs(path) or ':' not in path: return False module_path, _ = path.split(':', 1) return is_module_path(module_path)
[docs]def is_module_path(path) -> bool: """Is ``path`` a module path like ``package.module``? Examples:: >>> is_module_path('package') True >>> is_module_path('package.module') True >>> is_module_path('.module') True >>> is_module_path('package.module:obj') False >>> is_module_path('a/b') False >>> is_module_path('/a/b') False """ return all(p.isidentifier() for p in path.lstrip('.').split('.'))
[docs]def is_object_path(path) -> bool: """Is ``path`` an object path like ``package.module:obj.path``? Examples:: >>> is_object_path('package.module:obj') True >>> is_object_path('.module:obj') True >>> is_object_path('package') False >>> is_object_path('package:') False >>> is_object_path('a/b') False >>> is_object_path('/a/b') False """ if ':' not in path: return False pkg_path, *object_path = path.split(':', 1) if object_path: object_path = object_path[0] return is_module_path(pkg_path) and is_module_path(object_path) return False