How to get a reference to current module's attributes in Python
As previously mentioned, globals gives you a dictionary as opposed to dir() which gives you a list of the names defined in the module. The way I typically see this done is like this:
import sys
dir(sys.modules[__name__])
Just use globals()
globals() — Return a dictionary representing the current global symbol table. This is always the dictionary of the current module (inside a function or method, this is the module where it is defined, not the module from which it is called).
http://docs.python.org/library/functions.html#globals
It might be late to answer, but I didn't found the correct answer for myself.
The most closest and precise solution (faster than inspect.stack()
) in the python 3.7.x
:
# search for first module in the stack
stack_frame = inspect.currentframe()
while stack_frame:
print('***', stack_frame.f_code.co_name, stack_frame.f_code.co_filename, stack_frame.f_lineno)
if stack_frame.f_code.co_name == '<module>':
if stack_frame.f_code.co_filename != '<stdin>':
caller_module = inspect.getmodule(stack_frame)
else:
# piped or interactive import
caller_module = sys.modules['__main__']
if not caller_module is None:
#... do something here ...
break
stack_frame = stack_frame.f_back
Pros:
- Preciser than
globals()
method. - Does not depend on the stack intermediate frames, which can be added for example, via hooking or by the 3dparty tools like
pytest
:
*** foo ... ..
*** boo ... ..
*** runtest c:\python\x86\37\lib\site-packages\xonsh\pytest_plugin.py 58
*** pytest_runtest_call c:\python\x86\37\lib\site-packages\_pytest\runner.py 125
*** _multicall c:\python\x86\37\lib\site-packages\pluggy\callers.py 187
*** <lambda> c:\python\x86\37\lib\site-packages\pluggy\manager.py 86
*** _hookexec c:\python\x86\37\lib\site-packages\pluggy\manager.py 92
*** __call__ c:\python\x86\37\lib\site-packages\pluggy\hooks.py 286
*** <lambda> c:\python\x86\37\lib\site-packages\_pytest\runner.py 201
*** from_call c:\python\x86\37\lib\site-packages\_pytest\runner.py 229
*** call_runtest_hook c:\python\x86\37\lib\site-packages\_pytest\runner.py 201
*** call_and_report c:\python\x86\37\lib\site-packages\_pytest\runner.py 176
*** runtestprotocol c:\python\x86\37\lib\site-packages\_pytest\runner.py 95
*** pytest_runtest_protocol c:\python\x86\37\lib\site-packages\_pytest\runner.py 80
*** _multicall c:\python\x86\37\lib\site-packages\pluggy\callers.py 187
*** <lambda> c:\python\x86\37\lib\site-packages\pluggy\manager.py 86
*** _hookexec c:\python\x86\37\lib\site-packages\pluggy\manager.py 92
*** __call__ c:\python\x86\37\lib\site-packages\pluggy\hooks.py 286
*** pytest_runtestloop c:\python\x86\37\lib\site-packages\_pytest\main.py 258
*** _multicall c:\python\x86\37\lib\site-packages\pluggy\callers.py 187
*** <lambda> c:\python\x86\37\lib\site-packages\pluggy\manager.py 86
*** _hookexec c:\python\x86\37\lib\site-packages\pluggy\manager.py 92
*** __call__ c:\python\x86\37\lib\site-packages\pluggy\hooks.py 286
*** _main c:\python\x86\37\lib\site-packages\_pytest\main.py 237
*** wrap_session c:\python\x86\37\lib\site-packages\_pytest\main.py 193
*** pytest_cmdline_main c:\python\x86\37\lib\site-packages\_pytest\main.py 230
*** _multicall c:\python\x86\37\lib\site-packages\pluggy\callers.py 187
*** <lambda> c:\python\x86\37\lib\site-packages\pluggy\manager.py 86
*** _hookexec c:\python\x86\37\lib\site-packages\pluggy\manager.py 92
*** __call__ c:\python\x86\37\lib\site-packages\pluggy\hooks.py 286
*** main c:\python\x86\37\lib\site-packages\_pytest\config\__init__.py 90
*** <module> c:\Python\x86\37\Scripts\pytest.exe\__main__.py 7
- Can handle python piped or interactive session.
Cons:
- A kind of much precise and can return modules registered in an executable like for the
pytest.exe
which might not what you want. -
inspect.getmodule
still may return None on valid modules depending on hooking
I have an extension to the python: How to import a module given the full path?
The extension having wrapper functions for that case:
def tkl_get_stack_frame_module_by_offset(skip_stack_frames = 0, use_last_frame_on_out_of_stack = False):
...
def tkl_get_stack_frame_module_by_name(name = '<module>'):
...
You have to just initialize the extension properly:
# portable import to the global space
sys.path.append(<path-to-tacklelib-module-directory>)
import tacklelib as tkl
tkl.tkl_init(tkl, global_config = {'log_import_module':os.environ.get('TACKLELIB_LOG_IMPORT_MODULE')})
# cleanup
del tkl # must be instead of `tkl = None`, otherwise the variable would be still persist
sys.path.pop()
# use `tkl_*` functions directly from here ...