Simplify pywin32_bootstrap, avoid importing site#1651
Simplify pywin32_bootstrap, avoid importing site#1651mhammond merged 6 commits intomhammond:masterfrom
Conversation
Since pywin32 has dropped support for Python 2.7 since version 300 and support for Python 3.0 through 3.4 since version 223, we can now rely on [PEP-420] semantics when importing names of directories available on `sys.path` and not containing an `__init__.py`. This applies to to `pywin32_system32`. The previous version of `win32.lib.pywin32_boostrap` manually searched site-packages directories, stopping at the first one found. Now we pass this responsibility off to Python's import machinery. When we `import pywin32_system32`, if successful, `pywin32_system32` will likely be a `_frozen_importlib_external._NamespacePath` object. We obtain its first entry, being careful that it didn't support sequence indexing until Python 3.7 or so (and in any case, that's all undocumented; the [documentation promises] only that `__path__: Iterable[str]`). This first entry is the path to the directory containing the DLLs, just as before, so the remainder of the code is unchanged. The only semantic differences between this implementation and the previous one is that 1. we no longer import `site` (always better to import less!), and 2. `pywin32_system32` is no longer _required_ to be in a site-packages directory Just as with the previous implementation, this one does not raise an exception if `pywin32_system32` cannot be found. I did one annoying thing in this patch to minimize the diff, which is that I redefine the variable `pywin32_system32`: first it refers to a namespace package module object, and then later it refers to the `str` directory name. It might be reasonable after initial review of the patch to rename the latter instance of the variable to something like `path`. Finally, I added no tests and no change log entry, but can if necessary. [PEP-420]: https://www.python.org/dev/peps/pep-0420/#specification [documentation promises]: https://docs.python.org/3/reference/import.html#__path__
mhammond
left a comment
There was a problem hiding this comment.
Thanks, I don't see a problem with this approach. I think renaming the var makes sense, and I'd also like a changelog entry just to help people should this have unintended consequences.
win32/Lib/pywin32_bootstrap.py
Outdated
| # It needs to be searched when installed in virtual environments. | ||
| level3_up_dir = dirname(dirname(dirname(__file__))) | ||
| try: | ||
| Exc = ModuleNotFoundError # Introduced in Python 3.6 |
There was a problem hiding this comment.
Is this strictly necessary? IIUC, ModuleNotFoundError derives from ImportError and I don't see a good reason to differentiate.
There was a problem hiding this comment.
My instinct is generally to pick the most specific possible exception for except to match. This avoids hiding errors unrelated to the absence of pywin32_system32. There would be some bizarre circumstances that would lead to such hiding, but the cost of being specific here seems low to me. Anyway, I won't die on this hill. If you insist, I'll just use ImportError.
There was a problem hiding this comment.
I don't feel too strongly about it, and in general I'd agree, but in this case I feel the added complexity from changing behaviors based on the version, when in practice it's exactly the same behavior regardless, swings the argument to just catching ImportError.
win32/Lib/pywin32_bootstrap.py
Outdated
|
|
||
| for site_packages_dir in site_packages_dirs: | ||
| pywin32_system32 = os.path.join(site_packages_dir, "pywin32_system32") | ||
| try: |
There was a problem hiding this comment.
We can probably simplify this by putting the rest of the body under this else - ie, just have a pass on the import error and everything else in the else?
mhammond#1651 (comment) This very slightly changes semantics: if `pywin32_system32` is found to have multiple entries in `__path__` and the first one is not an existing directory, now the search will continue whereas before it would give up.
Per review comment: mhammond#1651 (comment)
Normally I wouldn't push the line on PEP 8 for importing `os`, but `win32.lib.pywin32_bootstrap` is imported by `site` at Python startup via pywin32.pth. Programs that care a lot about startup time might appreciate our caution here.
|
I believe I've responded to everything. 74c96dc is not strictly necessary, just seemed like a good idea. See the commit message. I can revert it if you'd prefer. |
|
There is still one small behavior change. Previously it is possible to use the system python to manually call Now However, this is no big deal as
Nice work @wkschwartz @mhammond! Really appreciate what you have been doing. |
Since pywin32 has dropped support for Python 2.7 since version 300 and support for Python 3.0 through 3.4 since version 223, we can now rely on PEP-420 semantics when importing names of directories available on
sys.pathand not containing an__init__.py. This applies to topywin32_system32. The previous version ofwin32.lib.pywin32_boostrapmanually searched site-packages directories, stopping at the first one found. Now we pass this responsibility off to Python's import machinery. When weimport pywin32_system32, if successful,pywin32_system32will likely be a_frozen_importlib_external._NamespacePathobject. We obtain its first entry, being careful that it didn't support sequence indexing until Python 3.7 or so (and in any case, that's all undocumented; the documentation promises only that__path__: Iterable[str]). This first entry is the path to the directory containing the DLLs, just as before, so the remainder of the code is unchanged.The only semantic differences between this implementation and the previous one is that
site(always better to import less!), andpywin32_system32is no longer required to be in a site-packages directoryJust as with the previous implementation, this one does not raise an exception if
pywin32_system32cannot be found.I did one annoying thing in this patch to minimize the diff, which is that I redefine the variable
pywin32_system32: first it refers to a namespace package module object, and then later it refers to thestrdirectory name. It might be reasonable after initial review of the patch to rename the latter instance of the variable to something likepath.Finally, I added no tests and no change log entry, but can if necessary.