Skip to content

Commit

Permalink
The win32com.gen_py directory now defaults to under site.getusersitep…
Browse files Browse the repository at this point in the history
…ackages (fixes #1666)
  • Loading branch information
mhammond committed Mar 27, 2021
1 parent 256e043 commit b7b46f1
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 38 deletions.
6 changes: 6 additions & 0 deletions CHANGES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
71 changes: 42 additions & 29 deletions com/win32com/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
1 change: 0 additions & 1 deletion com/win32com/client/gencache.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
8 changes: 0 additions & 8 deletions pywin32_postinstall.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit b7b46f1

Please sign in to comment.