"""
Path and module resolution utilities.
This module provides utilities for determining the calling package,
used internally by Tet's configuration system.
"""
import sys
from itertools import count
from pyramid.path import caller_module
[docs]
def caller_package(ignored_modules=(), caller_module=caller_module):
"""
Determine the package of the calling code.
Walks up the call stack to find the first module not in ignored_modules,
then returns its package.
:param ignored_modules: Module names to skip when walking the stack
:param caller_module: Function to get caller module (for testing)
:return: The caller's package module
"""
ignored_modules = set(ignored_modules)
ignored_modules.add(__name__)
for i in count(3):
# caller_module in arglist for tests
module = caller_module(i)
if getattr(module, '__name__', '__main__') in ignored_modules:
continue
f = getattr(module, '__file__', '')
if f.endswith(('__init__.py', '__init__$py')): # empty at >>>
# Module is a package
return module
# Go up one level to get package
package_name = module.__name__.rsplit('.', 1)[0]
return sys.modules[package_name]