classification
Title: python -m and runpy.run_module set different __name__ by default
Type: Stage: resolved
Components: Versions:
process
Status: closed Resolution: not a bug
Dependencies: Superseder:
Assigned To: Nosy List: Julian, ncoghlan
Priority: normal Keywords:

Created on 2019-08-24 17:59 by Julian, last changed 2019-09-12 14:19 by Julian. This issue is now closed.

Messages (5)
msg350387 - (view) Author: Julian Berman (Julian) * Date: 2019-08-24 17:59
This seems brutally simple, to the point where I'm concerned I'm missing something (or have seen this issue filed elsewhere but can't find it), but `python -m` and `runpy.run_module` don't set the same __name__ -- specifically `runpy.run_module`, when given a non-package, defaults to setting __name__ to `mod_name`.

So, given package/foo.py, with the "common"

`if __name__ == "__main__":` check at the bottom, `python -m package.foo` successfully executes, but `runpy.run_module("package.foo")` exits silently, unless explicitly passed `runpy.run_module("package.foo", run_name="__main__").

[n.b. pep517.{build,check} is a specific example of such a module that advertises itself as wanting to be executed via `python -m`]

issue16737 seems related but not exactly the same from what I can tell.
msg351069 - (view) Author: Nick Coghlan (ncoghlan) * (Python committer) Date: 2019-09-03 07:41
Yes, this is deliberate. From the run_module documentation: "__name__ is set to run_name if this optional argument is not None, to mod_name + '.__main__' if the named module is a package and to the mod_name argument otherwise."

This allows arbitrary code to be executed to populate a namespace, but you have to explicitly opt-in to having a second pseudo-__main__ module run in the same process (with all the potential pickle compatibility issues that doing so creates).
msg351075 - (view) Author: Julian Berman (Julian) * Date: 2019-09-03 08:26
Is there no desire to have an API that works like -m (entirely. In this and
any other way)?

On Tue, Sep 3, 2019, 09:41 Nick Coghlan <report@bugs.python.org> wrote:

>
> Change by Nick Coghlan <ncoghlan@gmail.com>:
>
>
> ----------
> stage:  -> resolved
> status: open -> closed
>
> _______________________________________
> Python tracker <report@bugs.python.org>
> <https://bugs.python.org/issue37941>
> _______________________________________
>
msg352030 - (view) Author: Nick Coghlan (ncoghlan) * (Python committer) Date: 2019-09-11 23:03
There is one, it just isn't public: runpy._run_module_as_main.

It's a private API that the -m switch implementation calls, and was introduced after the original runpy.run_module was found not to offer everything the switch needed.

It isn't possible to fully emulate -m from Python code though, as the lifecycle of the real main module is intertwined with the lifecycle of the underlying interpreter.

So if folks really want to try to do this, the source code is there to look at, but we're not giving the false impression that it's easy to do correctly with no unintended consequences.
msg352175 - (view) Author: Julian Berman (Julian) * Date: 2019-09-12 14:19
That all makes sense, I understand that in the general case you can't
really promise someone that if you mutate global state in-process that the
runpy module has any way of preventing that. Except IMO, the module gives
exactly the impression you're saying is bad (that you want to use it if you
need to do what -m does from Python, assuming you are OK with the
constraints there). And then runpy.run_module is a footgun, because it does
not in fact do what -m does, so it's hard to imagine the kind of person who
*does* want to use runpy -- it's basically "try it on your specific -m, and
possibly it works, and then possibly it will continue to work" (to be
slightly but hopefully not overwhelmingly facetious).

Quoting the docs for it themselves:

See also

The -m <https://docs.python.org/3/using/cmdline.html#cmdoption-m> option
offering equivalent functionality from the command line.
From an external developer's perspective, if some other thing would be
necessary tomorrow that would only be for -m, could one rely on it being
added to any or all of the functions in the runpy module? That sounds
unclear if there isn't a function that represents what -m does and promises
to stay that way.

It seems to me that either exposing a public API that promises to be -m as
much as possible (which means at least if an end-user knows they're just as
"clean" as the process that -m will run, you're probably good), or
otherwise deprecating the functions in here entirely as public, and just
making them all private, would be improvements to being able to understand
if someone wants to use this module or not, but I do appreciate you
explaining how things got here.

-J

On Wed, Sep 11, 2019 at 7:03 PM Nick Coghlan <report@bugs.python.org> wrote:

>
> Nick Coghlan <ncoghlan@gmail.com> added the comment:
>
> There is one, it just isn't public: runpy._run_module_as_main.
>
> It's a private API that the -m switch implementation calls, and was
> introduced after the original runpy.run_module was found not to offer
> everything the switch needed.
>
> It isn't possible to fully emulate -m from Python code though, as the
> lifecycle of the real main module is intertwined with the lifecycle of the
> underlying interpreter.
>
> So if folks really want to try to do this, the source code is there to
> look at, but we're not giving the false impression that it's easy to do
> correctly with no unintended consequences.
>
> ----------
>
> _______________________________________
> Python tracker <report@bugs.python.org>
> <https://bugs.python.org/issue37941>
> _______________________________________
>
History
Date User Action Args
2019-09-12 14:19:58Juliansetmessages: + msg352175
2019-09-11 23:03:31ncoghlansetmessages: + msg352030
2019-09-03 08:26:35Juliansetmessages: + msg351075
2019-09-03 07:41:37ncoghlansetstatus: open -> closed
stage: resolved
2019-09-03 07:41:26ncoghlansetresolution: not a bug
messages: + msg351069
2019-08-26 17:51:02brett.cannonsetnosy: + ncoghlan
2019-08-24 17:59:15Juliancreate