From b7b46f1155d1dfa7a21b30ee70a1613c1163e8e3 Mon Sep 17 00:00:00 2001 From: Mark Hammond Date: Sun, 14 Mar 2021 16:10:23 +1100 Subject: [PATCH] The win32com.gen_py directory now defaults to under site.getusersitepackages (fixes #1666) --- CHANGES.txt | 6 +++ com/win32com/__init__.py | 71 +++++++++++++++++++-------------- com/win32com/client/gencache.py | 1 - pywin32_postinstall.py | 8 ---- 4 files changed, 48 insertions(+), 38 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index 8651319d39..2442eef41d 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -10,6 +10,12 @@ Since build 300: ---------------- * Added win32com.shell.SHGetKnownFolderPath() and related constants. +* The directory for generated gen_py files is now under site.getusersitepackages() + (although for backwards compatibilty, the previously supported locations + remain preferred if they exist.) The post_install script no longer creates a + `win32com\gen_py` directory, so this new location will be used by default for + all new installs (#1666). + * Shifted work in win32.lib.pywin32_bootstrap to Python's import system from manual path manipulations (@wkschwartz in #1651) diff --git a/com/win32com/__init__.py b/com/win32com/__init__.py index c441eca33d..6f9700f745 100644 --- a/com/win32com/__init__.py +++ b/com/win32com/__init__.py @@ -81,40 +81,53 @@ def __PackageSupportBuildPath__(package_path): if not _frozen: SetupEnvironment() -# If we don't have a special __gen_path__, see if we have a gen_py as a -# normal module and use that (ie, "win32com.gen_py" may already exist as -# a package. -if not __gen_path__: - try: - import win32com.gen_py - # hrmph - 3.3 throws: TypeError: '_NamespacePath' object does not support indexing - # attempting to get __path__[0] - but I can't quickly repro this stand-alone. - # Work around it by using an iterator. - __gen_path__ = next(iter(sys.modules["win32com.gen_py"].__path__)) - except ImportError: - # If a win32com\gen_py directory already exists, then we use it - # (gencache doesn't insist it have an __init__, but our __import__ - # above does! +# Work out what directory we will use to save "makepy" generated sources. +# There's a bit of history here... +# * win32com often just uses `win32com.gen_py` as a normal package, and used +# to store the generated files directly in that path (ie, under the win32com +# directory in site-packages. This is problematic when the python install +# directory isn't writable, so: +# * We also supported a special directory under %TEMP% - but this isn't ideal +# either as that directory may be cleaned up periodically. +# * A slightly more deterministic location is now supported directly by Python, +# via `site.getusersitepackages()` - although according to google, this +# doesn't always exist in a virtualenv. +# * For reasons that probably made sense at the time, we even allowed a special +# registry key to exist to indicate what path should be used. +# We don't want to break existing installations, so what we now do is: +# * Still support the registry - but please don't do this - it will probably be +# removed. +# * Still support win32com/gen_py and the location under %TEMP%, but only if +# they already exist. +# * If all else fails and site.getusersitepackages() exists, use a directory +# under that. If it doesn't exist, use the location under %TEMP% +def setup_gen_py(): + global __gen_path__, gen_py + if not __gen_path__: __gen_path__ = os.path.abspath(os.path.join(__path__[0], "gen_py")) if not os.path.isdir(__gen_path__): - # We used to dynamically create a directory under win32com - - # but this sucks. If the dir doesn't already exist, we we - # create a version specific directory under the user temp - # directory. __gen_path__ = os.path.join( win32api.GetTempPath(), "gen_py", "%d.%d" % (sys.version_info[0], sys.version_info[1])) + # apparently `site.getusersitepackages()` doesn't exist in a virtualenv + import site + if not os.path.isdir(__gen_path__) and hasattr(site, "getusersitepackages"): + # getusersitepackages() is already different for different Python + # versions, so no need for our path name to discriminate on that. + # But we still use a descriptive name + __gen_path__ = os.path.join(site.getusersitepackages(), "win32com_gen_py") + + # we must have a __gen_path__, but may not have a gen_py module - + # set that up. + if "win32com.gen_py" not in sys.modules: + # Create a "win32com.gen_py", but with a custom __path__ + import types + gen_py = types.ModuleType("win32com.gen_py") + gen_py.__path__ = [ __gen_path__ ] + sys.modules[gen_py.__name__] = gen_py + gen_py = sys.modules["win32com.gen_py"] -# we must have a __gen_path__, but may not have a gen_py module - -# set that up. -if "win32com.gen_py" not in sys.modules: - # Create a "win32com.gen_py", but with a custom __path__ - import types - gen_py = types.ModuleType("win32com.gen_py") - gen_py.__path__ = [ __gen_path__ ] - sys.modules[gen_py.__name__] = gen_py - del types -gen_py = sys.modules["win32com.gen_py"] +setup_gen_py() # get rid of these for module users -del os, sys, win32api, pythoncom +del os, sys, win32api, pythoncom, setup_gen_py diff --git a/com/win32com/client/gencache.py b/com/win32com/client/gencache.py index 212d701539..cf64fba1c4 100644 --- a/com/win32com/client/gencache.py +++ b/com/win32com/client/gencache.py @@ -132,7 +132,6 @@ def GetGeneratePath(): assert not is_readonly, "Why do you want the genpath for a readonly store?" try: os.makedirs(win32com.__gen_path__) - #os.mkdir(win32com.__gen_path__) except os.error: pass try: diff --git a/pywin32_postinstall.py b/pywin32_postinstall.py index 906777dc9c..633956367f 100644 --- a/pywin32_postinstall.py +++ b/pywin32_postinstall.py @@ -422,14 +422,6 @@ def install(lib_dir): if verbose: print('Pythonwin has been registered in context menu') - # Create the win32com\gen_py directory. - make_dir = os.path.join(lib_dir, "win32com", "gen_py") - if not os.path.isdir(make_dir): - if verbose: - print("Creating directory %s" % (make_dir,)) - directory_created(make_dir) - os.mkdir(make_dir) - try: # create shortcuts # CSIDL_COMMON_PROGRAMS only available works on NT/2000/XP, and