Source code for sourceinfo.objectinfo

# -*- coding: utf-8 -*-
"""PySourceInfo - runtime type and source information on Python.

Based on the stack-frames of **inspect**, main parameter is **spos** 
- stack position. 

* *spos=1* is caller, *spos=2* is caller-of-caller, etc.. 

* 'r' is a regular expression for 'search()'.

Details see @local-manuals or @[https://pythonhosted.org/pysourceinfo/]
"""
from __future__ import absolute_import

import os
import sys
import re
from inspect import stack, getmodule, ismodule

from imp import is_builtin, is_frozen, find_module
from types import ModuleType, BuiltinFunctionType, BuiltinMethodType

from pythonids import PYV35Plus, PYVxyz, PYV34
from sourceinfo import SourceInfoError, \
    MT_UNKNOWN, MT_SOURCE, MT_COMPILED, MT_EXTENSION, MT_DIRECTORY, MT_BUILTIN, MT_FROZEN, \
    MT_COMPILED_OPT, MT_COMPILED_OPT1, MT_COMPILED_OPT2, MT_COMPILED_DEBUG

if PYV35Plus:
    if PYVxyz > PYV34:
        from importlib.util import find_spec  # @UnresolvedImport
    else:
        from importlib import find_loader  # @UnresolvedImport
    


__author__ = 'Arno-Can Uestuensoez'
__license__ = "Artistic-License-2.0 + Forced-Fairplay-Constraints"
__copyright__ = "Copyright (C) 2010-2017 Arno-Can Uestuensoez" \
    " @Ingenieurbuero Arno-Can Uestuensoez"
__version__ = '0.1.34'
__uuid__ = '9de52399-7752-4633-9fdc-66c87a9200b8'

__docformat__ = "restructuredtext en"

def _ismodule(mod):
    """Checks imported modules and sys.builtin_module_names.
    Returns True is either is true.
    """
    return (ismodule(mod) or mod.__name__ in sys.builtin_module_names)

[docs]def getcaller_module(spos=1): """Caller module. Args: spos: Caller position on the stack. Returns: Returns the caller module. Raises: pass-through """ _sf = stack() if spos >= len(_sf): return None return getmodule(_sf[spos][0])
[docs]def getcaller_module_name(spos=1): """Name of caller module, else *None*. Both approaches for evaluation the actual relative module name seem to have their own challenges, *module.__name__* and *getmodule_name()*. Args: spos: Caller position on the stack. Returns: Returns the name of caller module. The dotted object path is relative to the actual used sys.path item. Raises: pass-through """ _sf = stack() if len(_sf) <= spos: return None module = getmodule(_sf[spos][0]) if module: # seems to be more accurate than getmodule_name if module.__name__ == '__main__': return os.path.basename(os.path.splitext(_sf[spos][1])[0]) return module.__name__
[docs]def getcaller_module_name_sub(spos=1): """Name from package to module. Args: spos: Caller position on the stack. Returns: Returns the sub-name as the portion from package to module. Raises: pass-through """ # TODO: _sf = stack() if len(_sf) <= spos: return None module = getmodule(_sf[spos][0]) if module: return module.__name__ # seems to be more accurate than getmodule_name
[docs]def getcaller_module_oid(spos=1): """OID of caller module. Args: spos: Caller position on the stack. Returns: Returns the OID of the module. Raises: pass-through """ return getmodule_oid(getcaller_module(spos + 1))
[docs]def getcaller_module_oid_sub(spos=1): """OID of caller module. Args: spos: Caller position on the stack. Returns: Returns the sub-OID of the module. Raises: pass-through """ return getmodule_oid_sub(getcaller_module_oid(spos))
[docs]def getcaller_name(spos=1): """Name of caller. Args: spos: Caller position on the stack. Returns: Returns the name. Raises: pass-through """ return stack()[spos][3]
[docs]def getcaller_package_name(spos=1): """Name of first matching package containing the caller. The package is defined as the the first part of the module name. Relies on 'inspect'. Args: spos: Caller position on the stack. Returns: Returns the package name when defined, else None. Raises: pass-through """ _sf = stack() if len(_sf) < spos: return None module = getmodule(_sf[spos][0]) try: return re.sub("^([^.]+).*", r'\1', module.__package__) except: return re.sub("^([^.]+).*", r'\1', getcaller_module_name(spos + 1))
[docs]def getmodule_by_id(i): """Loaded module by ID. Args: n: ID of loaded module. Returns: Returns the loaded module. Raises: passed through exceptions """ if i: return [x for x in sys.modules.values() if id(x) == i][0]
[docs]def getmodule_by_name(n): """Loaded module by given name. Args: n: Name of the loaded module. Returns: Returns the loaded module. Raises: pass-through """ if n and sys.modules.get(n): return sys.modules[n]
_gmn = re.compile(r'^.*[.]')
[docs]def getmodule_name(mod): """Name similar to basename of loaded module, same as getmodule_oid. Args: mod: Module. Returns: Returns the name of the loaded module. Raises: pass-through """ if mod and _ismodule(mod) and hasattr(mod, '__name__'): return _gmn.sub('', mod.__name__)
[docs]def getmodule_name_sub(mod): """Name relative to PYTHONPATH/sys.path of loaded module, same as getmodule_oid_sub. Args: mod: Module. Returns: Returns the sub-name of the loaded module. Raises: passed through exceptions """ if mod and _ismodule(mod) and hasattr(mod, '__name__'): return re.sub(r'^[^.]*[.]', r'', mod.__name__)
[docs]def getmodule_oid(mod): """Name relative to PYTHONPATH/sys.path of loaded module. Args: mod: Module. Returns: Returns the package name. Raises: pass-through """ if mod and _ismodule(mod) and hasattr(mod, '__name__'): return mod.__name__
[docs]def getmodule_oid_sub(mod): """Name relative to PYTHONPATH/sys.path of loaded module. Args: mod: Module. Returns: Returns the package name. Raises: pass-through """ if mod and _ismodule(mod): if hasattr(mod, '__name__'): return re.sub(r'^[^.]*[.]', r'', mod.__name__)
[docs]def getmodule_package_name(mod): """Name of package for loaded module. Args: mod: Reference to a loaded module. Returns: Returns the package name of the loaded module. Raises: pass-through """ mn = getmodule_name(mod) if mn: if hasattr(mod, '__name__'): return mod.__name__
[docs]def getmodule_type(mod): """Type for loaded module as defined by module 'imp.*' Args: mod: Reference to a loaded module. Returns: Returns the module type as defined by imp, else None. :: ret:=( C_BUILTIN | C_EXTENSION | PKG_DIRECTORY | PY_COMPILED | PY_FROZEN | PY_SOURCE | None ) Raises: passed through exceptions """ if not PYV35Plus: try: ret = find_module(getmodule_oid(mod)) if ret and ret[2]: if type(ret[2]) is int: # MT_SOURCE,MT_COMPILED,MT_EXTENSION return ret[2] elif type(ret[2]) is tuple: # MT_DIRECTORY,MT_BUILTIN return ret[2][2] # TODO: PY_FROZEN except: if _ismodule(mod) or type(mod) is ModuleType: try: _n = getmodule_oid(mod) if _n in sys.builtin_module_names or is_builtin(_n): return MT_BUILTIN else: bn = sys.modules[_n].__file__ if bn: bn = os.path.basename(bn) if bn.startswith('__init__'): return MT_DIRECTORY elif bn[-2:] == 'py': return MT_SOURCE elif bn.endswith('$py.class'): return MT_COMPILED elif bn[-3:] in ('pyc',): return MT_COMPILED_DEBUG elif bn[-3:] in ('pyo'): return MT_COMPILED_OPT # either O1 or O2 elif bn[-3:] in ('so',): return MT_EXTENSION elif is_frozen(_n): return MT_FROZEN except ImportError: pass except: raise return MT_UNKNOWN else: # PEP 3147 -- PYC Repository Directories if PYVxyz > PYV34: ret = find_spec(getmodule_oid(mod)) else: # deprecated with 3.4 ret = find_loader(getmodule_oid(mod)) if ret and hasattr(ret, 'path'): # check python native cdir = os.path.dirname(ret.path) + os.path.sep + '__pycache__' if os.path.exists(cdir): mname = re.sub(r"^.*[.]", '', ret.name) + '.' + sys.implementation.cache_tag # @UndefinedVariable for xf in os.walk(cdir): for xi in xf[2]: if xi.startswith(mname): # # for now supports: Python3, Pypy3 # if xi[-3:]== "pyc": return MT_COMPILED_DEBUG elif xi[-3:]== "pyo": if xi[-9:-4]== "opt-1": return MT_COMPILED_OPT1 if xi[-9:-4]== "opt-2": return MT_COMPILED_OPT2 else: raise SourceInfoError("Extension unknown:" + str(xi)) else: return MT_SOURCE elif type(ret) in (BuiltinFunctionType, BuiltinMethodType,): return MT_BUILTIN else: _n = None if ret: if not hasattr(ret, 'name'): if type(ret) == type: return MT_BUILTIN else: return MT_UNKNOWN else: _n = ret.name else: try: _n = getmodule_oid(mod) except ImportError: pass except: raise if _n in sys.builtin_module_names or is_builtin(_n): return MT_BUILTIN elif is_frozen(_n): return MT_FROZEN else: bn = sys.modules[_n].__file__ if bn: bn = os.path.basename(bn) if bn.startswith('__init__'): return MT_DIRECTORY elif bn[-2:] == 'py': return MT_SOURCE elif bn[-3:] in ('pyc', 'pyo'): return MT_COMPILED elif bn[-3:] in ('so',): return MT_EXTENSION return MT_UNKNOWN