I expected both prints to output “…/test_script.py” because the second one is equivalent to g = dcor(g). So the first one does, but the second one prints “…/mylib.py”.
What I want to do is to get the “correct” filename from g.
Is it possible?
Thank you in advance!
The function g is actually the function _f from inside dcor, so it’s quite correct to say that that comes from mylib. But if you want to inspect the wrapped function, look at g.__wrapped__, which functools.wraps() adds as an attribute.
The inspect module seems to use f.__code__.co_filename.
Using __import__(g.__module__).__file__ looked cool … except one case I found:
# test_script.py
from mylib import dcor
@dcor
def g(): pass
if __name__ == "__main__":
print(__import__(g.__module__))
print(__import__(g.__module__).__file__)
If you launch this script,
>py -i test_script.py
<module '__main__' from 'C:\\usr\\home\\lib\\python\\test-py\\test_script.py'>
C:\usr\home\lib\python\test-py\test_script.py
>>>
So far, so good. However, it fails when I continue with interactive input!
>>> __import__(g.__module__)
<module '__main__' (<_frozen_importlib_external.SourceFileLoader object at 0x00000208D3B08D60>)>
>>> __import__(g.__module__).__file__
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: module '__main__' has no attribute '__file__'. Did you mean: '__name__'?
>>>
I guess “frozen” has something to do with it…, but I don’t know why.
Not all imported modules have a __file__ attribute, because not all modules come from a file.
You must always be prepared to deal with built in modules which are part of the interpreter, and module objects that were created dynamically.
>>> import sys
>>> sys.__file__
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: module 'sys' has no attribute '__file__'. Did you mean: '__name__'?
>>> from types import ModuleType
>>> mod = ModuleType('mymod', {})
>>> mod
<module 'mymod'>
>>> mod.__file__
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: module 'mymod' has no attribute '__file__'. Did you mean: '__name__'?
I’m not sure what happens to modules loaded from a zip file. Something exciting, probably.
“frozen” is, I think, an implementation detail of how modules are currently loaded. That may or may not exist in alternate Python interpreters, or the future.
More important is that you are running in the interactive interpreter.
Normally, in the interactive interpreter, the __main__ module object has no __file__ attribute because there is no file being executed!
But when you use -i, you get both behaviours! While the script is running, the __file__ is set to the actual file; then when the script is over and you enter the interative interpreter, the attribute is removed.
I can’t tell if that makes perfect sense or is the weirdest gotcha I’ve ever seen. I genuinely don’t know what to make of that.