I have a python script that uses the __file__
variable to take some action. This was working fine before I used zipapp since __file__
matched the actual running file.
Now I am starting to use zipapp and the logic doesn't work anymore, because __file__
is "loinc.pyz"
and not "loinc.py"
.
Is there a way that, within my Python code, I can tell if the file is actually loinc.pyz, say, rather than loinc.py?
The only way I can see to do it now is to just try to see if __file__ + "z"
exists, and if it does, assume we're using zipapp. But I'd like something more elegant.
I looked at the specifications from zipapp https://docs.python.org/3/library/zipapp.html but couldn't find anything. Looked at the 8 pages of zipapp-referenced questions in Stack Overflow and nothing either.
Use sys.argv[0]
.
(Note: this example was created on a UNIX system. Command invocations on a ms-windows system will differ.)
Create a file __main__.py
:
import sys
print(f"__file__ = {__file__}")
print(f"sys.argv[0] = {sys.argv[0]}")
(Zipped Python executables depend on the name __main__.py
being present in the zipfile.)
Next, create a file named hdr
:
#!/usr/bin/env python
Compress __main__.py
:
zip -q foo __main__.py
This will create foo.zip
.
Concatenate the header and the zipfile, and make the resulting file executable:
cat hdr foo.zip >foo.pyz
chmod u+x foo.pyz
Now, call __main__.py
:
> python __main__.py
__file__ = /zstorage/home/rsmith/tmp/src/__main__.py
sys.argv[0] = __main__.py
Then call foo.pyz
:
> ./foo.pyz
__file__ = /zstorage/home/rsmith/tmp/src/./foo.pyz/__main__.py
sys.argv[0] = ./foo.pyz
Note how __file__
ends with __main__.py
in both cases!