There are two files:
# the_imported.py
import inspect
imported_by_fname = inspect.currentframe().f_back.f_code.co_filename
print('{} was imported by {}'.format(__name__, imported_by_fname))
And:
# the_importer.py
import the_imported
When executed with Python 2.7:
$ python the_importer.py
the_imported was imported by the_importer.py
When executed with Python 3.5:
$ python3 the_importer.py
the_imported was imported by <frozen importlib._bootstrap>
What is that weird thing <frozen importlib._bootstrap>
all about? What happened with import
and/or inspect
that changed this behaviour? How can we get that Python 2 filename introspection working again on Python 3?
In Python, you use the import keyword to make code in one module available in another. Imports in Python are important for structuring your code effectively. Using imports properly will make you more productive, allowing you to reuse code while keeping your projects maintainable.
Running "python -v"from the command line tells you what is being imported and from where. This is useful if you want to know the location of built in modules.
Import in python is similar to #include header_file in C/C++. Python modules can get access to code from another module by importing the file/function using import. The import statement is the most common way of invoking the import machinery, but it is not the only way. import module_name.
There's just more on the stack in Python 3. importlib
is now responsible for importing:
# the_imported.py
from inspect import getframeinfo, getouterframes, currentframe
frame = currentframe()
while frame:
print(frame.f_code.co_filename)
frame = frame.f_back
Output:
C:\Users\user\Desktop\the_imported.py
<frozen importlib._bootstrap>
<frozen importlib._bootstrap>
<frozen importlib._bootstrap>
<frozen importlib._bootstrap>
<frozen importlib._bootstrap>
<frozen importlib._bootstrap>
<frozen importlib._bootstrap>
<frozen importlib._bootstrap>
C:\Users\user\Desktop\the_importer.py
You could do something like:
# the_imported.py
from inspect import getframeinfo, getouterframes, currentframe
frame = currentframe().f_back
while frame.f_code.co_filename.startswith('<frozen'):
frame = frame.f_back
print(frame.f_code.co_filename)
Output:
C:\Users\user\Desktop\the_importer.py
In Python 3.1 and newer the import machinery is implemented in Python, which makes it possible to access its call stack. To illustrate this, I'll put the following code
from traceback import print_stack
print_stack()
to the_imported.py and import it.
On Python 2 that code prints
File "the_importer.py", line 2, in <module>
import the_imported
File ".../the_imported.py", line 3, in <module>
print_stack()
But on Python 3 the output is much more verbose:
File "the_importer.py", line 2, in <module>
import the_imported
File "<frozen importlib._bootstrap>", line 961, in _find_and_load
File "<frozen importlib._bootstrap>", line 950, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 655, in _load_unlocked
File "<frozen importlib._bootstrap_external>", line 677, in exec_module
File "<frozen importlib._bootstrap>", line 205, in _call_with_frames_removed
File ".../the_imported.py", line 2, in <module>
print_stack()
Before Python 3.3, these lines were also included in tracebacks.
To achieve the desired result you could walk up the call stack to find the first frame, the file name of which doesn't start with <frozen importlib
.
from traceback import extract_stack
for x in extract_stack():
if not x[0].startswith('<frozen importlib'):
print('{} was imported by {}'.format(__name__, x[0]))
break
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With