Permalink
Cannot retrieve contributors at this time
233 lines (172 sloc)
8.65 KB
Name already in use
A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
peps/pep-0273.txt
Go to fileThis commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| PEP: 273 | |
| Title: Import Modules from Zip Archives | |
| Author: James C. Ahlstrom <jim@interet.com> | |
| Status: Final | |
| Type: Standards Track | |
| Content-Type: text/x-rst | |
| Created: 11-Oct-2001 | |
| Python-Version: 2.3 | |
| Post-History: 26-Oct-2001 | |
| Abstract | |
| ======== | |
| This PEP adds the ability to import Python modules | |
| ``*.py``, ``*.py[co]`` and packages from zip archives. The | |
| same code is used to speed up normal directory imports | |
| provided ``os.listdir`` is available. | |
| Note | |
| ==== | |
| Zip imports were added to Python 2.3, but the final implementation | |
| uses an approach different from the one described in this PEP. | |
| The 2.3 implementation is SourceForge patch #652586 [1]_, which adds | |
| new import hooks described in :pep:`302`. | |
| The rest of this PEP is therefore only of historical interest. | |
| Specification | |
| ============= | |
| Currently, ``sys.path`` is a list of directory names as strings. If | |
| this PEP is implemented, an item of ``sys.path`` can be a string | |
| naming a zip file archive. The zip archive can contain a | |
| subdirectory structure to support package imports. The zip | |
| archive satisfies imports exactly as a subdirectory would. | |
| The implementation is in C code in the Python core and works on | |
| all supported Python platforms. | |
| Any files may be present in the zip archive, but only files | |
| ``*.py`` and ``*.py[co]`` are available for import. Zip import of | |
| dynamic modules (``*.pyd``, ``*.so``) is disallowed. | |
| Just as ``sys.path`` currently has default directory names, a default | |
| zip archive name is added too. Otherwise there is no way to | |
| import all Python library files from an archive. | |
| Subdirectory Equivalence | |
| ======================== | |
| The zip archive must be treated exactly as a subdirectory tree so | |
| we can support package imports based on current and future rules. | |
| All zip data is taken from the Central Directory, the data must be | |
| correct, and brain dead zip files are not accommodated. | |
| Suppose ``sys.path`` contains "/A/B/SubDir" and "/C/D/E/Archive.zip", | |
| and we are trying to import ``modfoo`` from the ``Q`` package. Then | |
| ``import.c`` will generate a list of paths and extensions and will | |
| look for the file. The list of generated paths does not change | |
| for zip imports. Suppose ``import.c`` generates the path | |
| "/A/B/SubDir/Q/R/modfoo.pyc". Then it will also generate the path | |
| "/C/D/E/Archive.zip/Q/R/modfoo.pyc". Finding the SubDir path is | |
| exactly equivalent to finding "Q/R/modfoo.pyc" in the archive. | |
| Suppose you zip up /A/B/SubDir/* and all its subdirectories. Then | |
| your zip file will satisfy imports just as your subdirectory did. | |
| Well, not quite. You can't satisfy dynamic modules from a zip | |
| file. Dynamic modules have extensions like ``.dll``, ``.pyd``, and ``.so``. | |
| They are operating system dependent, and probably can't be loaded | |
| except from a file. It might be possible to extract the dynamic | |
| module from the zip file, write it to a plain file and load it. | |
| But that would mean creating temporary files, and dealing with all | |
| the ``dynload_*.c``, and that's probably not a good idea. | |
| When trying to import ``*.pyc``, if it is not available then | |
| ``*.pyo`` will be used instead. And vice versa when looking for ``*.pyo``. | |
| If neither ``*.pyc`` nor ``*.pyo`` is available, or if the magic numbers | |
| are invalid, then ``*.py`` will be compiled and used to satisfy the | |
| import, but the compiled file will not be saved. Python would | |
| normally write it to the same directory as ``*.py``, but surely we | |
| don't want to write to the zip file. We could write to the | |
| directory of the zip archive, but that would clutter it up, not | |
| good if it is ``/usr/bin`` for example. | |
| Failing to write the compiled files will make zip imports very slow, | |
| and the user will probably not figure out what is wrong. So it | |
| is best to put ``*.pyc`` and ``*.pyo`` in the archive with the ``*.py``. | |
| Efficiency | |
| ========== | |
| The only way to find files in a zip archive is linear search. So | |
| for each zip file in ``sys.path``, we search for its names once, and | |
| put the names plus other relevant data into a static Python | |
| dictionary. The key is the archive name from ``sys.path`` joined with | |
| the file name (including any subdirectories) within the archive. | |
| This is exactly the name generated by ``import.c``, and makes lookup | |
| easy. | |
| This same mechanism is used to speed up directory (non-zip) imports. | |
| See below. | |
| zlib | |
| ==== | |
| Compressed zip archives require ``zlib`` for decompression. Prior to | |
| any other imports, we attempt an import of ``zlib``. Import of | |
| compressed files will fail with a message "missing ``zlib``" unless | |
| ``zlib`` is available. | |
| Booting | |
| ======= | |
| Python imports ``site.py`` itself, and this imports ``os``, ``nt``, ``ntpath``, | |
| ``stat``, and ``UserDict``. It also imports ``sitecustomize.py`` which may | |
| import more modules. Zip imports must be available before ``site.py`` | |
| is imported. | |
| Just as there are default directories in ``sys.path``, there must be | |
| one or more default zip archives too. | |
| The problem is what the name should be. The name should be linked | |
| with the Python version, so the Python executable can correctly | |
| find its corresponding libraries even when there are multiple | |
| Python versions on the same machine. | |
| We add one name to ``sys.path``. On Unix, the directory is | |
| ``sys.prefix + "/lib"``, and the file name is | |
| ``"python%s%s.zip" % (sys.version[0], sys.version[2])``. | |
| So for Python 2.2 and prefix ``/usr/local``, the path | |
| ``/usr/local/lib/python2.2/`` is already on ``sys.path``, and | |
| ``/usr/local/lib/python22.zip`` would be added. | |
| On Windows, the file is the full path to ``python22.dll``, with | |
| "dll" replaced by "zip". The zip archive name is always inserted | |
| as the second item in ``sys.path``. The first is the directory of the | |
| ``main.py`` (thanks Tim). | |
| Directory Imports | |
| ================= | |
| The static Python dictionary used to speed up zip imports can be | |
| used to speed up normal directory imports too. For each item in | |
| ``sys.path`` that is not a zip archive, we call ``os.listdir``, and add | |
| the directory contents to the dictionary. Then instead of calling | |
| ``fopen()`` in a double loop, we just check the dictionary. This | |
| greatly speeds up imports. If ``os.listdir`` doesn't exist, the | |
| dictionary is not used. | |
| Benchmarks | |
| ========== | |
| ==== ================= ================= ========== ========== | |
| Case Original 2.2a3 Using os.listdir Zip Uncomp Zip Compr | |
| ==== ================= ================= ========== ========== | |
| 1 3.2 2.5 3.2->1.02 2.3 2.5 2.3->0.87 1.66->0.93 1.5->1.07 | |
| 2 2.8 3.9 3.0->1.32 Same as Case 1. | |
| 3 5.7 5.7 5.7->5.7 2.1 2.1 2.1->1.8 1.25->0.99 1.19->1.13 | |
| 4 9.4 9.4 9.3->9.35 Same as Case 3. | |
| ==== ================= ================= ========== ========== | |
| Case 1: Local drive C:, ``sys.path`` has its default value. | |
| Case 2: Local drive C:, directory with files is at the end of ``sys.path``. | |
| Case 3: Network drive, ``sys.path`` has its default value. | |
| Case 4: Network drive, directory with files is at the end of ``sys.path``. | |
| Benchmarks were performed on a Pentium 4 clone, 1.4 GHz, 256 Meg. | |
| The machine was running Windows 2000 with a Linux/Samba network server. | |
| Times are in seconds, and are the time to import about 100 Lib modules. | |
| Case 2 and 4 have the "correct" directory moved to the end of ``sys.path``. | |
| "Uncomp" means uncompressed zip archive, "Compr" means compressed. | |
| Initial times are after a re-boot of the system; the time after | |
| "->" is the time after repeated runs. Times to import from C: | |
| after a re-boot are rather highly variable for the "Original" case, | |
| but are more realistic. | |
| Custom Imports | |
| ============== | |
| The logic demonstrates the ability to import using default searching | |
| until a needed Python module (in this case, ``os``) becomes available. | |
| This can be used to bootstrap custom importers. For example, if | |
| "``importer()``" in ``__init__.py`` exists, then it could be used for imports. | |
| The "``importer()``" can freely import os and other modules, and these | |
| will be satisfied from the default mechanism. This PEP does not | |
| define any custom importers, and this note is for information only. | |
| Implementation | |
| ============== | |
| A C implementation is available as SourceForge patch 492105. | |
| Superseded by patch 652586 and current CVS. [2]_ | |
| A newer version (updated for recent CVS by Paul Moore) is 645650. | |
| Superseded by patch 652586 and current CVS. [3]_ | |
| A competing implementation by Just van Rossum is 652586, which is | |
| the basis for the final implementation of :pep:`302`. :pep:`273` has | |
| been implemented using :pep:`302`'s import hooks. [1]_ | |
| References | |
| ========== | |
| .. [1] Just van Rossum, New import hooks + Import from Zip files | |
| https://bugs.python.org/issue652586 | |
| .. [2] Import from Zip archive, James C. Ahlstrom | |
| https://bugs.python.org/issue492105 | |
| .. [3] Import from Zip Archive, Paul Moore | |
| https://bugs.python.org/issue645650 | |
| Copyright | |
| ========= | |
| This document has been placed in the public domain. |