Skip to content

Commit 8954f61

Browse files
bennyrowlandBen Rowlandjunkmd
authored
477 Move clear_comtypes_cache to be a callable module (#478)
* move clear_comtypes_cache to be a callable module This commit modifies the clear_comtypes_cache.py script so that it is inside the main comtypes module (renamed as just clear_cache) so that is can be called more easily as "py -m comtypes.clear_cache". The main function of the script is also exported using the "console_scripts" entry point so that the script also goes into the standard Python "Scripts" folder as before, but now as a .exe instead of a .py script, which makes it easier to run if systems are set to open .py files instead of running them. This version also includes a test case using the 3rd party package pyfakefs. Currently, this is not desired to avoid the requirement of 3rd party packages in comtypes, but is included here for potential use if the position changes. A subsequent commit will modify the tests to use unittest.patch instead, which is an inferior technical solution but avoids a 3rd party package. * modify clear_cache tests to not use pyfakefs This commit updates the test for comtypes.clear_cache to not use any 3rd party packages, instead relying on mocking the shutil.rmtree function which is used to do the actual cache deletion. * change quotes in print string * style changes based on review by @junkmd * Apply suggestions from code review Co-authored-by: Jun Komoda <[email protected]> --------- Co-authored-by: Ben Rowland <[email protected]> Co-authored-by: Jun Komoda <[email protected]>
1 parent 62ce303 commit 8954f61

File tree

5 files changed

+84
-65
lines changed

5 files changed

+84
-65
lines changed

CONTRIBUTING.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ Those `.py` files act like ”caches”.
9191

9292
If there are some problems with the developing code base, partial or non-executable modules might be created in `.../comtypes/gen/...`.
9393
Importing them will cause some error.
94-
If that happens, you should run `python -m clear_comtypes_cache` to clear those caches.
94+
If that happens, you should run `python -m comtypes.clear_cache` to clear those caches.
9595
The command will delete the entire `.../comtypes/gen` directory.
9696
Importing `comtypes.gen.client` will restore the directory and `__init__.py` file.
9797

clear_comtypes_cache.py

Lines changed: 0 additions & 57 deletions
This file was deleted.

comtypes/clear_cache.py

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import argparse
2+
import contextlib
3+
import os
4+
import sys
5+
from shutil import rmtree # TESTS ASSUME USE OF RMTREE
6+
7+
8+
# if supporting Py>=3.11 only, this might be `contextlib.chdir`.
9+
# https://docs.python.org/3/library/contextlib.html#contextlib.chdir
10+
@contextlib.contextmanager
11+
def chdir(path):
12+
"""Context manager to change the current working directory."""
13+
work_dir = os.getcwd()
14+
os.chdir(path)
15+
yield
16+
os.chdir(work_dir)
17+
18+
19+
def main():
20+
parser = argparse.ArgumentParser(
21+
prog="py -m comtypes.clear_cache", description="Removes comtypes cache folders."
22+
)
23+
parser.add_argument(
24+
"-y", help="Pre-approve deleting all folders", action="store_true"
25+
)
26+
args = parser.parse_args()
27+
28+
if not args.y:
29+
confirm = input("Remove comtypes cache directories? (y/n): ")
30+
if confirm.lower() != "y":
31+
print("Cache directories NOT removed")
32+
return
33+
34+
# change cwd to avoid import from local folder during installation process
35+
with chdir(os.path.dirname(sys.executable)):
36+
try:
37+
import comtypes.client
38+
except ImportError:
39+
print("Could not import comtypes", file=sys.stderr)
40+
sys.exit(1)
41+
42+
# there are two possible locations for the cache folder (in the comtypes
43+
# folder in site-packages if that is writable, otherwise in APPDATA)
44+
# fortunately, by deleting the first location returned by _find_gen_dir()
45+
# we make it un-writable, so calling it again gives us the APPDATA location
46+
for _ in range(2):
47+
dir_path = comtypes.client._find_gen_dir()
48+
rmtree(dir_path)
49+
print(f'Removed directory "{dir_path}"')
50+
51+
52+
if __name__ == "__main__":
53+
main()

comtypes/test/test_clear_cache.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
"""
2+
Test for the ``comtypes.clear_cache`` module.
3+
"""
4+
import contextlib
5+
import runpy
6+
from unittest.mock import patch, call
7+
from unittest import TestCase
8+
9+
from comtypes.client import _find_gen_dir
10+
11+
12+
class ClearCacheTestCase(TestCase):
13+
# we patch sys.stdout so unittest doesn't show the print statements
14+
15+
@patch("sys.argv", ["clear_cache.py", "-y"])
16+
@patch("shutil.rmtree")
17+
def test_clear_cache(self, mock_rmtree):
18+
with contextlib.redirect_stdout(None):
19+
runpy.run_module("comtypes.clear_cache", {}, "__main__")
20+
21+
# because we don't actually delete anything, _find_gen_dir() will
22+
# give the same answer every time we call it
23+
self.assertEqual(
24+
mock_rmtree.call_args_list, [call(_find_gen_dir()) for _ in range(2)]
25+
)

setup.py

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -110,14 +110,10 @@ def run(self):
110110
install.run(self)
111111
# Custom script we run at the end of installing
112112
if not self.dry_run and not self.root:
113-
filename = os.path.join(
114-
self.install_scripts, "clear_comtypes_cache.py")
115-
if not os.path.isfile(filename):
116-
raise RuntimeError("Can't find '%s'" % (filename,))
117113
print("Executing post install script...")
118-
print('"' + sys.executable + '" "' + filename + '" -y')
114+
print(f'"{sys.executable}" -m comtypes.clear_cache -y')
119115
try:
120-
subprocess.check_call([sys.executable, filename, '-y'])
116+
subprocess.check_call([sys.executable, "-m", "comtypes.clear_cache", '-y'])
121117
except subprocess.CalledProcessError:
122118
print("Failed to run post install script!")
123119

@@ -145,7 +141,9 @@ def run(self):
145141
]},
146142
classifiers=classifiers,
147143

148-
scripts=["clear_comtypes_cache.py"],
144+
entry_points={
145+
"console_scripts": ["clear_comtypes_cache=comtypes.clear_cache:main"]
146+
},
149147

150148
cmdclass={
151149
'test': test,

0 commit comments

Comments
 (0)