# -*- coding: utf-8 -*-
"""pysourceinfo.bininfo - runtime information on compiled Python binaries.
Details see manuals.
"""
from __future__ import absolute_import
from __future__ import print_function
import os
import sys
import re
from inspect import stack, getmodule, isbuiltin, ismodule
from pythonids import PYV3
__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"
#---
#
# redundant for autonomous load-independence by reduction of dependencies
#
def __getpythonpath_rel(fpname, plist=None):
"""Relative path name for first match on plist."""
if not plist:
plist = sys.path
# for now dirs with terminating os.sep
_fp = os.path.normpath(os.path.abspath(fpname))
_fp = re.escape(_fp)
for _sp in plist:
_sp = os.path.normpath(os.path.abspath(_sp))
_sp = re.escape(_sp)
if _fp and _fp.startswith(_sp):
_r = _fp.replace(_sp, "")
if _r and _r[0:2] == re.escape(os.sep):
return re.sub(r'\\(.)', r'\1', _r[2:])
elif _r and _r[0] == os.sep:
return re.sub(r'\\(.)', r'\1', _r[1:])
if not _r:
return '.'
return re.sub(r'\\(.)', r'\1', _r)
#---
[docs]def getcaller_bin_filename(spos=1):
"""Filename of binary caller module.
Args:
spos:
Caller position on the stack.
Returns:
Returns the filename.
Raises:
pass-through
"""
return os.path.basename(getcaller_bin_filepathname(spos))
[docs]def getcaller_bin_filepathname(spos=1):
"""File pathname of caller module.
Args:
spos:
Caller position on the stack.
Returns:
Returns the file pathname.
Raises:
pass-through
"""
_sf = stack()
if spos >= len(_sf):
return None
module = getmodule(_sf[spos][0])
if not PYV3:
if module:
return os.path.abspath(module.__file__) # source
else:
# PEP 3147 -- PYC Repository Directories
ret = find_loader(module.__name__) #@UndefinedVariable
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)
for xf in os.walk(cdir):
res = None
for xi in xf[2]:
if vers == re.sub( #@UndefinedVariable
mname + r".cpython-(3[0-9]).py[co]$", r'\1', xi):
res = cdir + os.path.sep + xi
if res[-1] == 'o': # prio over '.pyc' on '.pyo'
break
return res
else:
return ret.path
else:
if ret:
if hasattr(ret, 'name'):
fn = ret.get_filename(module.__name__)
# fd = ret.get_data(fn)
return fn
# FIXME: module.__name__ => 'baseOID'
if module.__name__ in sys.builtin_module_names:
return None
else:
bn = sys.modules[module.__name__].__file__
if bn and os.path.exists(bn):
return bn
[docs]def getcaller_bin_pathname(spos=1):
"""pathname of caller source file.
Args:
spos:
Caller position on the stack.
Returns:
Returns the filename.
Raises:
passed through exceptions
"""
if not PYV3:
return os.path.dirname(getcaller_bin_filepathname(spos + 1))
else:
_sf = stack()
module = getmodule(_sf[spos][0])
if hasattr(module, '__file__'):
f = module.__file__
return os.path.dirname(f)
# PEP 3147 -- PYC Repository Directories
[docs]def getcaller_bin_pathname_rel(spos=1):
"""Relative pathname to first matching package directory of caller.
Evaluates 'sys.path' first, else switches to 'inspect'.
Args:
spos:
Caller position on the stack.
Returns:
Returns the path name to the package.
Raises:
pass-through
"""
ax = os.path.normpath(getcaller_bin_filepathname(
spos + 1)) # TODO: check for normpath
for si in sys.path:
si = os.path.normpath(si)
if ax.startswith(si):
return re.sub(si + r"[/\\\\]*(.+?)[/\\\\]*[^/\\\\]+.py[oc]*$", r"\1", ax)
[docs]def getcaller_bin_pathname_sub(spos=1):
"""sub-pathname to first matching module directory of caller.
Evaluates 'sys.path' first, else switches to 'inspect'.
Args:
spos:
Caller position on the stack.
Returns:
Returns the path name to the package.
Raises:
passed through exceptions
"""
ax = getcaller_bin_pathname_rel(spos + 1)
return re.sub(r"[^/\\\\]*[/\\\\](.*)", r"\1", ax)
[docs]def getmodule_bin_filename(mod):
"""Basename of file for loaded module *mod*.
Args:
mod:
Reference to a loaded module.
Returns:
Returns the basename of the loaded module.
Raises:
passed through exceptions
"""
if mod and ismodule(mod) and not isbuiltin(mod):
if hasattr(mod, '__file__') and os.path.exists(mod.__file__):
return os.path.basename(mod.__file__)
[docs]def getmodule_bin_filepathname(mod):
"""File pathname of loaded module *mod*.
Args:
mod:
Reference to a loaded module.
Returns:
Returns the file pathname of the loaded module.
Raises:
pass-through
"""
if mod and ismodule(mod) and not isbuiltin(mod):
if hasattr(mod, '__file__') and os.path.exists(mod.__file__):
return os.path.abspath(os.path.normpath(mod.__file__))
[docs]def getmodule_bin_pathname(mod):
"""Path name of loaded module.
Args:
mod:
Reference to a loaded module.
Returns:
Returns the pathname of the loaded module.
Raises:
pass-through
"""
if mod and ismodule(mod) and not isbuiltin(mod):
if hasattr(mod, '__file__'):
return os.path.normpath(os.path.dirname(mod.__file__))
[docs]def getmodule_bin_pathname_rel(mod, plist=None):
"""Relative path name to PYTHONPATH for loaded module.
Args:
mod:
Reference to a loaded module.
Returns:
Returns the relative pathname of the loaded module.
Raises:
pass-through
"""
if mod and ismodule(mod) and not isbuiltin(mod):
if hasattr(mod, '__file__'):
return __getpythonpath_rel(mod.__file__, plist)
[docs]def getmodule_bin_pathname_sub(mod, plist=None):
"""Path name for loaded module, relative to package path.
Args:
mod:
Reference to a loaded module.
Returns:
Returns the sub pathname of the loaded module.
Raises:
passed through exceptions
"""
ax = getmodule_bin_pathname_rel(mod, plist)
if not PYV3:
return re.sub(r"[^/\\\\]*[/\\\\]", r"\1", ax)
else:
return re.sub(r"[^/\\\\]*[/\\\\]".encode('utf-8'), r"\1".encode('utf-8'), ax)