'Check the name of the module (not necessarily the file) that was used to run Python

If you invoke python foo.py or python -m foo, is there a way to detect, from inside Python, that the file foo.py / the module foo was used to run the program?

The docs for sys.argv suggest that sys.argv[0] can be used for this purpose, but it only works part-way. In my testing, invoking python -m foo still populates sys.argv[0] with the full filename of foo.py, not the module name foo, so it doesn't do what I would want it to do in all cases. I believe that this is also equivalent to __file__. It is very error-prone to try and extract a fully qualified module name from a filename.

I want to be able to distinguish between cases like python a/b/c.py and python -m a.b.c, as well as invoking Python with a "wrapper" like python -m unittest a.b.c. I do not want to rely on heuristics on sys.argv[0], if at all possible.

In reply to the comments and close votes: I am not interested in workarounds; I have some already. I am asking this question because it want to know if this very specific thing is possible, not because I want help with my work in general.



Solution 1:[1]

I don't believe this is possible.

The documentation says:

When called with -m module-name, the given module is located on the Python module path and executed as a script

and:

Search sys.path for the named module and execute its contents as the __main__ module.

I understand that to mean that -m module-name is simply shorthand for python module_name.py, where module_name.py is the file in sys.path where Python is able to locate a module named module-name.


As an interesting side note, the documentation also says

The module name should be a valid absolute Python module name, but the implementation may not always enforce this (e.g. it may allow you to use a name that includes a hyphen).

but it uses module-name as its example module.

Solution 2:[2]

It is fairly easy to distinguish between python a.py and python -m a by looking at the __package__ variable:

a.py:

print(repr(__package__))
$ python a.py
None

$ python -m a
''

In order to distinguish python -m a from python -m unittest a we can use __name__.

a.py:

print(__name__)
$ python -m a
__main__

$ python -m unittest a
a

I don't know how to get "unittest" from the last invocation without using sys.argv heuristics.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Chris
Solution 2 mkrieger1