Skip to content

argparse reports python -m for programmatic module-as-main execution #155009

Description

@itamaro

Bug report

Bug description:

Python 3.14 changed argparse's default prog in gh-66436.
A non-__main__ __main__.__spec__.name is now rendered as a python -m invocation.

Our PAR executable bootstrap uses:

runpy._run_module_as_main(main_module, alter_argv=False)

This intentionally executes an importable module as __main__, while preserving the user-facing executable filename in sys.argv[0].
Python 3.14 instead reports a synthetic python -m module command that the user did not invoke.

This is an uncommon setup, but other executable loaders or embedded runtimes may use the same pattern.

Reproducer

# reproducer.py
import argparse
import os
import runpy
import sys

if os.environ.pop("_ARGPARSE_REPRO_MAIN", None):
    print(argparse.ArgumentParser().prog)
else:
    sys.argv[0] = "/tmp/my_tool.par"
    os.environ["_ARGPARSE_REPRO_MAIN"] = "1"
    runpy._run_module_as_main("reproduce", alter_argv=False)

With 3.14-3.16:

$ python3.1{4,5,6} reproduce.py
python3.1{4,5,6} -m reproduce

With 3.12:

my_tool.par

The module is deliberately executed as __main__, so its populated __main__.__spec__ is expected.
The issue is that this alone does not prove the interpreter was invoked with -m.

A potential solution that preserves the intent of the original change is consulting sys.orig_argv to confirm an actual -m <module> invocation.

CPython versions tested on:

3.14, 3.15, CPython main branch

Operating systems tested on:

Linux

Metadata

Metadata

Labels

stdlibStandard Library Python modules in the Lib/ directorytype-bugAn unexpected behavior, bug, or error

Projects

Status
No status

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions