Search code examples
pythonzipapp

How can I know if my python script is running within zipapp package?


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.


Solution

  • 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!