2015-08-08 00:43:09 -04:00
|
|
|
|
PEP: 499
|
2016-07-11 11:14:08 -04:00
|
|
|
|
Title: ``python -m foo`` should bind ``sys.modules['foo']`` in addition to ``sys.modules['__main__']``
|
2015-08-08 00:43:09 -04:00
|
|
|
|
Version: $Revision$
|
|
|
|
|
Last-Modified: $Date$
|
|
|
|
|
Author: Cameron Simpson <cs@zip.com.au>
|
|
|
|
|
Status: Draft
|
|
|
|
|
Type: Standards Track
|
|
|
|
|
Content-Type: text/x-rst
|
|
|
|
|
Created: 07-Aug-2015
|
|
|
|
|
Python-Version: 3.6
|
|
|
|
|
|
|
|
|
|
Abstract
|
|
|
|
|
========
|
|
|
|
|
|
|
|
|
|
When a module is used as a main program on the Python command line,
|
|
|
|
|
such as by:
|
|
|
|
|
|
|
|
|
|
python -m module.name ...
|
|
|
|
|
|
|
|
|
|
it is easy to accidentally end up with two independent instances
|
|
|
|
|
of the module if that module is again imported within the program.
|
|
|
|
|
This PEP proposes a way to fix this problem.
|
|
|
|
|
|
|
|
|
|
When a module is invoked via Python's -m option the module is bound
|
|
|
|
|
to ``sys.modules['__main__']`` and its ``.__name__`` attribute is set to
|
|
|
|
|
``'__main__'``.
|
|
|
|
|
This enables the standard "main program" boilerplate code at the
|
|
|
|
|
bottom of many modules, such as::
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
|
sys.exit(main(sys.argv))
|
|
|
|
|
|
|
|
|
|
However, when the above command line invocation is used it is a
|
|
|
|
|
natural inference to presume that the module is actually imported
|
|
|
|
|
under its official name ``module.name``,
|
|
|
|
|
and therefore that if the program again imports that name
|
|
|
|
|
then it will obtain the same module instance.
|
|
|
|
|
|
|
|
|
|
That actuality is that the module was imported only as ``'__main__'``.
|
|
|
|
|
Another import will obtain a distinct module instance, which can
|
|
|
|
|
lead to confusing bugs.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Proposal
|
|
|
|
|
========
|
|
|
|
|
|
|
|
|
|
It is suggested that to fix this situation all that is needed is a
|
|
|
|
|
simple change to the way the ``-m`` option is implemented: in addition
|
|
|
|
|
to binding the module object to ``sys.modules['__main__']``, it is also
|
|
|
|
|
bound to ``sys.modules['module.name']``.
|
|
|
|
|
|
|
|
|
|
Nick Coghlan has suggested that this is as simple as modifying the
|
|
|
|
|
``runpy`` module's ``_run_module_as_main`` function as follows::
|
|
|
|
|
|
|
|
|
|
main_globals = sys.modules["__main__"].__dict__
|
|
|
|
|
|
|
|
|
|
to instead be::
|
|
|
|
|
|
|
|
|
|
main_module = sys.modules["__main__"]
|
|
|
|
|
sys.modules[mod_spec.name] = main_module
|
|
|
|
|
main_globals = main_module.__dict__
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Considerations and Prerequisites
|
|
|
|
|
================================
|
|
|
|
|
|
|
|
|
|
Pickling Modules
|
|
|
|
|
----------------
|
|
|
|
|
|
|
|
|
|
Nick has mentioned `issue 19702`_ which proposes (quoted from the issue):
|
|
|
|
|
|
|
|
|
|
- runpy will ensure that when __main__ is executed via the import
|
|
|
|
|
system, it will also be aliased in sys.modules as __spec__.name
|
|
|
|
|
- if __main__.__spec__ is set, pickle will use __spec__.name rather
|
|
|
|
|
than __name__ to pickle classes, functions and methods defined in
|
|
|
|
|
__main__
|
|
|
|
|
- multiprocessing is updated appropriately to skip creating __mp_main__
|
|
|
|
|
in child processes when __main__.__spec__ is set in the parent
|
|
|
|
|
process
|
|
|
|
|
|
|
|
|
|
The first point above covers this PEP's specific proposal.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Background
|
|
|
|
|
==========
|
|
|
|
|
|
|
|
|
|
`I tripped over this issue`_ while debugging a main program via a
|
|
|
|
|
module which tried to monkey patch a named module, that being the
|
|
|
|
|
main program module. Naturally, the monkey patching was ineffective
|
|
|
|
|
as it imported the main module by name and thus patched the second
|
|
|
|
|
module instance, not the running module instance.
|
|
|
|
|
|
|
|
|
|
However, the problem has been around as long as the ``-m`` command
|
|
|
|
|
line option and is encountered regularly, if infrequently, by others.
|
|
|
|
|
|
|
|
|
|
In addition to `issue 19702`_, the discrepancy around `__main__`
|
|
|
|
|
is alluded to in PEP 451 and a similar proposal (predating PEP 451)
|
|
|
|
|
is described in PEP 395 under `Fixing dual imports of the main module`_.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
References
|
|
|
|
|
==========
|
|
|
|
|
|
|
|
|
|
.. _issue 19702: http://bugs.python.org/issue19702
|
|
|
|
|
|
|
|
|
|
.. _I tripped over this issue: https://mail.python.org/pipermail/python-list/2015-August/694905.html
|
|
|
|
|
|
|
|
|
|
.. _Fixing dual imports of the main module: https://www.python.org/dev/peps/pep-0395/#fixing-dual-imports-of-the-main-module
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Copyright
|
|
|
|
|
=========
|
|
|
|
|
|
|
|
|
|
This document has been placed in the public domain.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
..
|
|
|
|
|
Local Variables:
|
|
|
|
|
mode: indented-text
|
|
|
|
|
indent-tabs-mode: nil
|
|
|
|
|
sentence-end-double-space: t
|
|
|
|
|
fill-column: 70
|
|
|
|
|
coding: utf-8
|
|
|
|
|
End:
|