0

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.

shadowtalker
  • 12,529
  • 3
  • 53
  • 96
  • Does this answer your question? [Get name of current script in Python](https://stackoverflow.com/questions/4152963/get-name-of-current-script-in-python) – mkrieger1 Mar 24 '22 at 22:03
  • Not quite, see my edit @mkrieger1. I'm not sure if it's universally correct to assume that the module name is just the script name with `.py` removed. – shadowtalker Mar 24 '22 at 22:04
  • Do you mean which interpreter was used? In that case sys.executable is probably what you are after. – miksus Mar 24 '22 at 22:04
  • 4
    What are you trying to accomplish here? I suspect an [XY problem](https://meta.stackexchange.com/q/66377/248627). – ChrisGPT was on strike Mar 24 '22 at 22:05
  • @Chris I am writing an application that needs to behave a certain way depending on how it was invoked. Regardless, I think this is a perfectly legitimate Python question as it stands. – shadowtalker Mar 24 '22 at 22:06
  • 2
    A generic "I need it" isn't terribly helpful in explaining your actual requirements. What's the difference between `python foo.py` and `python -m foo` that you are trying to get at? Context is always helpful. – ChrisGPT was on strike Mar 24 '22 at 22:07
  • `__name__` will be `"__main__"` in a directly-run script, but I assume it's the module name if you use `python -m`. – jasonharper Mar 24 '22 at 22:07
  • @Chris suffice it to say that I want to know the difference between `python a/b/c.py` and `python -m a.b.c`. I also want to know the difference between `python -m a.b.c` and `python -m unittest`; I'd rather not resort to heuristics about the filename. – shadowtalker Mar 24 '22 at 22:08
  • I appreciate your desire to help me solve my real-world problem, but I insist that this is a valid question on its own. I can figure out other ways to achieve "Y" if I need to. I am asking about "X" with the intention to learn about "X". – shadowtalker Mar 24 '22 at 22:11
  • @Chris moreover, my hope was also that an answer to this question might be useful to _other_ people in the future; that's part of the purpose of SO, after all. – shadowtalker Mar 24 '22 at 22:14

2 Answers2

4

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.

mkrieger1
  • 19,194
  • 5
  • 54
  • 65
  • 1
    Very interesting observation about `__package__`. Even if the official answer is "no you can't", that might be useful for some cases, e.g. warning users if they invoke your program incorrectly. – shadowtalker Mar 24 '22 at 23:38
  • @shadowtalker, strange that you accepted my answer when mkrieger1 provides a way to do the thing I said was not possible. If I were you, I'd accept this answer instead. – ChrisGPT was on strike Mar 25 '22 at 01:33
  • @Chris the last case is actually the case I am most interested in, distinguishing between `python -m a` and `python -m unittest a`. So unfortunately the answer really is "no, it's not possible" for the most general case. I appreciate both of your answers. – shadowtalker Mar 25 '22 at 13:36
3

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.

ChrisGPT was on strike
  • 127,765
  • 105
  • 273
  • 257