classification
Title: Support embedding the standard library in an executable
Type: enhancement Stage: test needed
Components: Interpreter Core Versions: Python 3.6, Python 3.5
process
Status: open Resolution:
Dependencies: Superseder:
Assigned To: Nosy List: lemburg, paul.moore, philthompson10
Priority: normal Keywords:

Created on 2016-01-04 16:13 by philthompson10, last changed 2020-09-11 23:15 by brett.cannon.

Messages (12)
msg257464 - (view) Author: Phil Thompson (philthompson10) Date: 2016-01-04 16:13
The use case is a packaging tool that can create a single executable for a Python application. Like similar tools it embeds frozen Python code (including the standard library) and is linked (often statically) against the interpreter library.

Executables are usually configured so that they cannot import packages from the filesystem. They can only import packages embedded in the executable. This is done directly, ie. the package is not written out to the filesystem and imported from there. This is done by a specially written importer.

The importer is installed by adding it to sys.path_hooks. However this must be done early on in the bootstrap process so that the parts of the standard library that are implemented as Python packages can be found by the installer. For example, the point at which the zipimport importer is added to sys.path_hooks is too late.

Currently a modified version of bootstrap_external.py is embedded in the executable which updates sys.path_hooks at the end of the _install() function.

What I would like is some way to avoid having to modify bootstrap_external.py to install a new importer sufficiently early in the bootstrap process to allow it to import the standard library.
msg257465 - (view) Author: Paul Moore (paul.moore) * (Python committer) Date: 2016-01-04 16:23
Why is it too late to install a new importer to sys.path_hooks when zipimport is installed? As far as I am aware, running the stdlib from a zipfile works fine, which seems to be equivalent to your use case.
msg257466 - (view) Author: Phil Thompson (philthompson10) Date: 2016-01-04 16:50
The problem is the import of the encodings module in _PyCodecRegistry_Init().
msg257469 - (view) Author: Marc-Andre Lemburg (lemburg) * (Python committer) Date: 2016-01-04 17:07
So the use case is that you want to explicitly prevent the file system from being used for imports ?

You might want to look at how eGenix PyRun works, since this does embed the Python stdlib into the executable (including the encodings package). While it does allow imports from the file system, it only looks there for things it cannot find embedded in the binary.

PS: I'd suggest to make the issue title more specific to what you are actually after, which seems to be a way to install importers from C at a very early stage during initialization.
msg257470 - (view) Author: Phil Thompson (philthompson10) Date: 2016-01-04 17:17
Yes, preventing the filesystem being used for imports would be another way of expressing the issue.

Regarding the title I specifically didn't want to suggest a solution as I'm not expert enough to know what the best solution might be.

If, as Paul implies, it should be possible to run the standard library from a zipfile then it suggests that this should actually be a bug report.
msg257477 - (view) Author: Brett Cannon (brett.cannon) * (Python committer) Date: 2016-01-04 18:06
What Phil is after is a hook at the C level that will allow him to modify the sys module to add something to sys.meta_path to remove PathEntryFinder and put in his own importer (assuming he isn't simply freezing everything).

And yes, you should be able to run the stdlib from a zipfile, but the issue here is all the stuff Python imports as part of startup before the first bit of user Python code is executed, e.g. the encodings module. Since zipimport is added by importlib it gets special treatment  to be usable ASAP. Since Phil wants to completely skew standard import mechanisms this does require a C hook.

What this all means is that Phil really needs https://www.python.org/dev/peps/pep-0432/ to happen so that he can easily get his hook point added into the startup sequence.
msg257480 - (view) Author: Phil Thompson (philthompson10) Date: 2016-01-04 19:18
At the moment my importer does the same as zipimport and gets added to sys.path_hooks rather than sys.meta_path.

While waiting for the PEP, how about a table of (externally modifiable) importer installers that is worked through where _PyImportZip_Init() is currently called? By default _PyImportZip_Init() will be the only entry.
msg257493 - (view) Author: Brett Cannon (brett.cannon) * (Python committer) Date: 2016-01-04 21:08
I personally would rather wait until PEP 432 happens before adding any such hook. This sort of thing is extremely hard to test and the startup sequence for Python is already quite complicated and honestly too tightly bound to the magical sequence of steps it current has.
msg257495 - (view) Author: Phil Thompson (philthompson10) Date: 2016-01-04 21:32
I don't see why it would be hard to test. The change suggested wouldn't alter the default behaviour at all.
msg257496 - (view) Author: Brett Cannon (brett.cannon) * (Python committer) Date: 2016-01-04 21:38
It might not change the default behaviour, but we still have to make sure it works and doesn't accidentally break. If we add official support for a C API to specify callbacks to execute during interpreter startup before any stdlib Python code then we are making a promise that it will work and so we have to worry about it even if the vast majority of users will never use it.
msg257503 - (view) Author: Phil Thompson (philthompson10) Date: 2016-01-04 23:14
Understood, but the only promise here is to call a function (with no arguments, and returning no result).
msg376748 - (view) Author: Brett Cannon (brett.cannon) * (Python committer) Date: 2020-09-11 23:15
Update: PEP 432 was withdrawn, so this issue is now languishing and not blocked on something else.
History
Date User Action Args
2020-09-11 23:15:20brett.cannonsetnosy: - brett.cannon
2020-09-11 23:15:15brett.cannonsetmessages: + msg376748
2016-01-08 18:24:00terry.reedysettitle: Request for Support for Embedding the Standard Library in an Executable -> Support embedding the standard library in an executable
stage: test needed
versions: + Python 3.6
2016-01-04 23:14:29philthompson10setmessages: + msg257503
2016-01-04 21:38:55brett.cannonsetmessages: + msg257496
2016-01-04 21:32:15philthompson10setmessages: + msg257495
2016-01-04 21:08:16brett.cannonsetmessages: + msg257493
2016-01-04 19:18:24philthompson10setmessages: + msg257480
2016-01-04 18:06:06brett.cannonsetnosy: + brett.cannon
messages: + msg257477
2016-01-04 17:17:26philthompson10setmessages: + msg257470
2016-01-04 17:07:47lemburgsetnosy: + lemburg
messages: + msg257469
2016-01-04 16:50:52philthompson10setmessages: + msg257466
2016-01-04 16:23:06paul.mooresetnosy: + paul.moore
messages: + msg257465
2016-01-04 16:13:13philthompson10create