comtypes 1.4.1__zip → 1.4.3__zip
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {comtypes-1.4.1 → comtypes-1.4.3}/CHANGES.txt +24 -1
- {comtypes-1.4.1/comtypes.egg-info → comtypes-1.4.3}/PKG-INFO +29 -1
- {comtypes-1.4.1 → comtypes-1.4.3}/README.md +28 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/__init__.py +6 -8
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/automation.py +26 -2
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/client/_generate.py +105 -80
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/hints.pyi +29 -2
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_GUID.py +23 -2
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_client.py +14 -4
- comtypes-1.4.3/comtypes/test/test_client_regenerate_modules.py +158 -0
- comtypes-1.4.3/comtypes/test/test_dispifc_records.py +90 -0
- comtypes-1.4.3/comtypes/test/test_findgendir.py +87 -0
- comtypes-1.4.3/comtypes/tools/codegenerator/__init__.py +5 -0
- {comtypes-1.4.1/comtypes/tools → comtypes-1.4.3/comtypes/tools/codegenerator}/codegenerator.py +140 -716
- comtypes-1.4.3/comtypes/tools/codegenerator/helpers.py +357 -0
- comtypes-1.4.3/comtypes/tools/codegenerator/modulenamer.py +24 -0
- comtypes-1.4.3/comtypes/tools/codegenerator/namespaces.py +212 -0
- comtypes-1.4.3/comtypes/tools/codegenerator/packing.py +81 -0
- {comtypes-1.4.1/comtypes/tools → comtypes-1.4.3/comtypes/tools/codegenerator}/typeannotator.py +32 -15
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/tools/tlbparser.py +19 -49
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/tools/typedesc.py +58 -10
- {comtypes-1.4.1 → comtypes-1.4.3/comtypes.egg-info}/PKG-INFO +29 -1
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes.egg-info/SOURCES.txt +10 -3
- {comtypes-1.4.1 → comtypes-1.4.3}/setup.py +1 -0
- comtypes-1.4.1/comtypes/test/test_findgendir.py +0 -94
- {comtypes-1.4.1 → comtypes-1.4.3}/LICENSE.txt +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/MANIFEST.in +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/GUID.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/_comobject.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/_memberspec.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/_meta.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/_npsupport.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/_safearray.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/clear_cache.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/client/__init__.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/client/_code_cache.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/client/_constants.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/client/_events.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/client/dynamic.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/client/lazybind.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/connectionpoints.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/errorinfo.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/git.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/hresult.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/logutil.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/messageloop.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/patcher.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/persist.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/safearray.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/server/__init__.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/server/automation.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/server/connectionpoints.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/server/inprocserver.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/server/localserver.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/server/register.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/server/w_getopt.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/shelllink.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/TestComServer.idl +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/TestComServer.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/TestComServer.tlb +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/TestDispServer.idl +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/TestDispServer.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/TestDispServer.tlb +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/__init__.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/find_memleak.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/mylib.idl +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/mytypelib.idl +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/runtests.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/setup.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_BSTR.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_DISPPARAMS.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_QueryService.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_agilent.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_avmc.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_basic.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_casesensitivity.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_clear_cache.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_client_dynamic.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_collections.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_comserver.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_createwrappers.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_dict.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_dispinterface.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_dyndispatch.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_excel.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_getactiveobj.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_ie.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_ienum.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_imfattributes.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_inout_args.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_jscript.js +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_msscript.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_npsupport.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_outparam.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_propputref.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_pump_events.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_safearray.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_sapi.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_server.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_showevents.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_subinterface.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_typeinfo.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_urlhistory.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_variant.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_win32com_interop.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_wmi.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_word.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/tools/__init__.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/tools/typedesc_base.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/typeinfo.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/util.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/viewobject.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes.egg-info/dependency_links.txt +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes.egg-info/entry_points.txt +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes.egg-info/top_level.txt +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/setup.cfg +0 -0
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import contextlib
|
|
2
|
+
import importlib
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
import shutil
|
|
5
|
+
import sys
|
|
6
|
+
import tempfile
|
|
7
|
+
import types
|
|
8
|
+
from typing import Iterator
|
|
9
|
+
import unittest as ut
|
|
10
|
+
from unittest import mock
|
|
11
|
+
|
|
12
|
+
import comtypes
|
|
13
|
+
import comtypes.client
|
|
14
|
+
import comtypes.gen
|
|
15
|
+
|
|
16
|
+
comtypes.client.GetModule("scrrun.dll")
|
|
17
|
+
from comtypes.gen import Scripting # noqa
|
|
18
|
+
from comtypes.gen import stdole # noqa
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
SCRRUN_FRIENDLY = Path(Scripting.__file__)
|
|
22
|
+
SCRRUN_WRAPPER = Path(Scripting.__wrapper_module__.__file__)
|
|
23
|
+
STDOLE_FRIENDLY = Path(stdole.__file__)
|
|
24
|
+
STDOLE_WRAPPER = Path(stdole.__wrapper_module__.__file__)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@contextlib.contextmanager
|
|
28
|
+
def _mkdtmp_gen_dir() -> Iterator[Path]:
|
|
29
|
+
with tempfile.TemporaryDirectory() as t:
|
|
30
|
+
tmp_dir = Path(t)
|
|
31
|
+
tmp_comtypes_dir = tmp_dir / "comtypes"
|
|
32
|
+
tmp_comtypes_dir.mkdir()
|
|
33
|
+
(tmp_comtypes_dir / "__init__.py").touch()
|
|
34
|
+
tmp_comtypes_gen_dir = tmp_comtypes_dir / "gen"
|
|
35
|
+
tmp_comtypes_gen_dir.mkdir()
|
|
36
|
+
(tmp_comtypes_gen_dir / "__init__.py").touch()
|
|
37
|
+
yield tmp_comtypes_gen_dir
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@contextlib.contextmanager
|
|
41
|
+
def _patch_gen_pkg(new_path: Path) -> Iterator[types.ModuleType]:
|
|
42
|
+
new_comtypes_init = (new_path / "comtypes" / "__init__.py").resolve()
|
|
43
|
+
assert new_comtypes_init.exists()
|
|
44
|
+
new_comtypes_gen_init = (new_path / "comtypes" / "gen" / "__init__.py").resolve()
|
|
45
|
+
assert new_comtypes_gen_init.exists()
|
|
46
|
+
orig_comtypes = sys.modules["comtypes"]
|
|
47
|
+
orig_gen_names = list(filter(lambda k: k.startswith("comtypes.gen"), sys.modules))
|
|
48
|
+
tmp_sys_path = list(sys.path) # copy
|
|
49
|
+
with mock.patch.object(sys, "path", tmp_sys_path):
|
|
50
|
+
sys.path.insert(0, str(new_path))
|
|
51
|
+
with mock.patch.dict(sys.modules):
|
|
52
|
+
# The reason for removing the parent module (in this case, `comtypes`)
|
|
53
|
+
# from `sys.modules` is because the child module (in this case,
|
|
54
|
+
# `comtypes.gen`) refers to the namespace of the parent module.
|
|
55
|
+
# If the parent module exists in `sys.modules`, Python uses that cache
|
|
56
|
+
# to import the child module. Therefore, in order to import a new version
|
|
57
|
+
# of the child module, it is necessary to temporarily remove the parent
|
|
58
|
+
# module from `sys.modules`.
|
|
59
|
+
del sys.modules["comtypes"]
|
|
60
|
+
for k in orig_gen_names:
|
|
61
|
+
del sys.modules[k]
|
|
62
|
+
# The module that is imported here is not the one cached in `sys.modules`
|
|
63
|
+
# before the patch, but the module that is newly loaded from
|
|
64
|
+
# `new_path / 'comtypes' / 'gen' / '__init__.py'`.
|
|
65
|
+
new_comtypes_gen = importlib.import_module("comtypes.gen")
|
|
66
|
+
assert new_comtypes_gen.__file__ is not None
|
|
67
|
+
assert Path(new_comtypes_gen.__file__).resolve() == new_comtypes_gen_init
|
|
68
|
+
# The `comtypes` module cached in `sys.modules` as a side effect of
|
|
69
|
+
# executing the above line is empty because it is the one loaded from
|
|
70
|
+
# `new_path / 'comtypes' / '__init__.py'`.
|
|
71
|
+
# If we call the test target as it is, an error will occur due to
|
|
72
|
+
# referencing an empty module, so we restore the original `comtypes`
|
|
73
|
+
# to `sys.modules`.
|
|
74
|
+
sys.modules["comtypes"] = orig_comtypes
|
|
75
|
+
assert sys.modules["comtypes.gen"] is new_comtypes_gen
|
|
76
|
+
# By making the empty `comtypes.gen` package we created earlier to be
|
|
77
|
+
# referenced as the `gen` attribute of `comtypes`, the original
|
|
78
|
+
# `comtypes.gen` will not be referenced within the context.
|
|
79
|
+
with mock.patch.object(orig_comtypes, "gen", new_comtypes_gen):
|
|
80
|
+
yield new_comtypes_gen
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
@contextlib.contextmanager
|
|
84
|
+
def patch_gen_dir() -> Iterator[Path]:
|
|
85
|
+
with _mkdtmp_gen_dir() as tmp_gen_dir:
|
|
86
|
+
with mock.patch.object(comtypes.client, "gen_dir", str(tmp_gen_dir)):
|
|
87
|
+
try:
|
|
88
|
+
with _patch_gen_pkg(tmp_gen_dir.parent.parent):
|
|
89
|
+
yield tmp_gen_dir
|
|
90
|
+
finally:
|
|
91
|
+
importlib.invalidate_caches()
|
|
92
|
+
importlib.reload(comtypes.gen)
|
|
93
|
+
importlib.reload(stdole)
|
|
94
|
+
importlib.reload(Scripting)
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
class Test(ut.TestCase):
|
|
98
|
+
def test_all_modules_are_missing(self):
|
|
99
|
+
with patch_gen_dir() as gen_dir:
|
|
100
|
+
# ensure `gen_dir` and `sys.modules` are patched.
|
|
101
|
+
with self.assertRaises(ImportError):
|
|
102
|
+
from comtypes.gen import Scripting as _ # noqa
|
|
103
|
+
self.assertFalse((gen_dir / SCRRUN_FRIENDLY.name).exists())
|
|
104
|
+
self.assertFalse((gen_dir / SCRRUN_WRAPPER.name).exists())
|
|
105
|
+
self.assertFalse((gen_dir / STDOLE_FRIENDLY.name).exists())
|
|
106
|
+
self.assertFalse((gen_dir / STDOLE_WRAPPER.name).exists())
|
|
107
|
+
# generate new files and modules.
|
|
108
|
+
comtypes.client.GetModule("scrrun.dll")
|
|
109
|
+
self.assertTrue((gen_dir / SCRRUN_FRIENDLY.name).exists())
|
|
110
|
+
self.assertTrue((gen_dir / SCRRUN_WRAPPER.name).exists())
|
|
111
|
+
self.assertTrue((gen_dir / STDOLE_FRIENDLY.name).exists())
|
|
112
|
+
self.assertTrue((gen_dir / STDOLE_WRAPPER.name).exists())
|
|
113
|
+
|
|
114
|
+
def test_friendly_module_is_missing(self):
|
|
115
|
+
with patch_gen_dir() as gen_dir:
|
|
116
|
+
shutil.copy2(SCRRUN_WRAPPER, gen_dir / SCRRUN_WRAPPER.name)
|
|
117
|
+
wrp_mtime = (gen_dir / SCRRUN_WRAPPER.name).stat().st_mtime_ns
|
|
118
|
+
shutil.copy2(STDOLE_FRIENDLY, gen_dir / STDOLE_FRIENDLY.name)
|
|
119
|
+
shutil.copy2(STDOLE_WRAPPER, gen_dir / STDOLE_WRAPPER.name)
|
|
120
|
+
comtypes.client.GetModule("scrrun.dll")
|
|
121
|
+
self.assertTrue((gen_dir / SCRRUN_FRIENDLY.name).exists())
|
|
122
|
+
# Check the most recent content modification time to confirm whether
|
|
123
|
+
# the module file has been regenerated.
|
|
124
|
+
self.assertGreater(
|
|
125
|
+
(gen_dir / SCRRUN_WRAPPER.name).stat().st_mtime_ns, wrp_mtime
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
def test_wrapper_module_is_missing(self):
|
|
129
|
+
with patch_gen_dir() as gen_dir:
|
|
130
|
+
shutil.copy2(SCRRUN_WRAPPER, gen_dir / SCRRUN_FRIENDLY.name)
|
|
131
|
+
frd_mtime = (gen_dir / SCRRUN_FRIENDLY.name).stat().st_mtime_ns
|
|
132
|
+
shutil.copy2(STDOLE_FRIENDLY, gen_dir / STDOLE_FRIENDLY.name)
|
|
133
|
+
shutil.copy2(STDOLE_WRAPPER, gen_dir / STDOLE_WRAPPER.name)
|
|
134
|
+
comtypes.client.GetModule("scrrun.dll")
|
|
135
|
+
self.assertTrue((gen_dir / SCRRUN_WRAPPER.name).exists())
|
|
136
|
+
self.assertGreater(
|
|
137
|
+
(gen_dir / SCRRUN_FRIENDLY.name).stat().st_mtime_ns, frd_mtime
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
def test_dependency_modules_are_missing(self):
|
|
141
|
+
with patch_gen_dir() as gen_dir:
|
|
142
|
+
shutil.copy2(SCRRUN_WRAPPER, gen_dir / SCRRUN_FRIENDLY.name)
|
|
143
|
+
frd_mtime = (gen_dir / SCRRUN_FRIENDLY.name).stat().st_mtime_ns
|
|
144
|
+
shutil.copy2(SCRRUN_WRAPPER, gen_dir / SCRRUN_WRAPPER.name)
|
|
145
|
+
wrp_mtime = (gen_dir / SCRRUN_WRAPPER.name).stat().st_mtime_ns
|
|
146
|
+
comtypes.client.GetModule("scrrun.dll")
|
|
147
|
+
self.assertTrue((gen_dir / STDOLE_FRIENDLY.name).exists())
|
|
148
|
+
self.assertTrue((gen_dir / STDOLE_WRAPPER.name).exists())
|
|
149
|
+
self.assertGreater(
|
|
150
|
+
(gen_dir / SCRRUN_FRIENDLY.name).stat().st_mtime_ns, frd_mtime
|
|
151
|
+
)
|
|
152
|
+
self.assertGreater(
|
|
153
|
+
(gen_dir / SCRRUN_WRAPPER.name).stat().st_mtime_ns, wrp_mtime
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
if __name__ == "__main__":
|
|
158
|
+
ut.main()
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
|
|
3
|
+
import unittest
|
|
4
|
+
|
|
5
|
+
from comtypes import CLSCTX_LOCAL_SERVER
|
|
6
|
+
from comtypes.client import CreateObject, GetModule
|
|
7
|
+
from ctypes import byref, pointer
|
|
8
|
+
|
|
9
|
+
ComtypesCppTestSrvLib_GUID = "{07D2AEE5-1DF8-4D2C-953A-554ADFD25F99}"
|
|
10
|
+
|
|
11
|
+
try:
|
|
12
|
+
GetModule((ComtypesCppTestSrvLib_GUID, 1, 0, 0))
|
|
13
|
+
import comtypes.gen.ComtypesCppTestSrvLib as ComtypesCppTestSrvLib
|
|
14
|
+
|
|
15
|
+
IMPORT_FAILED = False
|
|
16
|
+
except (ImportError, OSError):
|
|
17
|
+
IMPORT_FAILED = True
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@unittest.skipIf(IMPORT_FAILED, "This depends on the out of process COM-server.")
|
|
21
|
+
class Test_DispMethods(unittest.TestCase):
|
|
22
|
+
"""Test dispmethods with record and record pointer parameters."""
|
|
23
|
+
|
|
24
|
+
EXPECTED_INITED_QUESTIONS = "The meaning of life, the universe and everything?"
|
|
25
|
+
|
|
26
|
+
def _create_dispifc(self) -> "ComtypesCppTestSrvLib.IDispRecordParamTest":
|
|
27
|
+
# Explicitely ask for the dispinterface of the component.
|
|
28
|
+
return CreateObject(
|
|
29
|
+
"Comtypes.DispIfcParamTests",
|
|
30
|
+
clsctx=CLSCTX_LOCAL_SERVER,
|
|
31
|
+
interface=ComtypesCppTestSrvLib.IDispRecordParamTest,
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
def test_inout_byref(self):
|
|
35
|
+
dispifc = self._create_dispifc()
|
|
36
|
+
# Passing a record by reference to a method that has declared the parameter
|
|
37
|
+
# as [in, out] we expect modifications of the record on the server side to
|
|
38
|
+
# also change the record on the client side.
|
|
39
|
+
test_record = ComtypesCppTestSrvLib.StructRecordParamTest()
|
|
40
|
+
self.assertEqual(test_record.question, None)
|
|
41
|
+
self.assertEqual(test_record.answer, 0)
|
|
42
|
+
self.assertEqual(test_record.needs_clarification, False)
|
|
43
|
+
dispifc.InitRecord(byref(test_record))
|
|
44
|
+
self.assertEqual(test_record.question, self.EXPECTED_INITED_QUESTIONS)
|
|
45
|
+
self.assertEqual(test_record.answer, 42)
|
|
46
|
+
self.assertEqual(test_record.needs_clarification, True)
|
|
47
|
+
|
|
48
|
+
def test_inout_pointer(self):
|
|
49
|
+
dispifc = self._create_dispifc()
|
|
50
|
+
# Passing a record pointer to a method that has declared the parameter
|
|
51
|
+
# as [in, out] we expect modifications of the record on the server side to
|
|
52
|
+
# also change the record on the client side.
|
|
53
|
+
test_record = ComtypesCppTestSrvLib.StructRecordParamTest()
|
|
54
|
+
self.assertEqual(test_record.question, None)
|
|
55
|
+
self.assertEqual(test_record.answer, 0)
|
|
56
|
+
self.assertEqual(test_record.needs_clarification, False)
|
|
57
|
+
dispifc.InitRecord(pointer(test_record))
|
|
58
|
+
self.assertEqual(test_record.question, self.EXPECTED_INITED_QUESTIONS)
|
|
59
|
+
self.assertEqual(test_record.answer, 42)
|
|
60
|
+
self.assertEqual(test_record.needs_clarification, True)
|
|
61
|
+
|
|
62
|
+
def test_in_record(self):
|
|
63
|
+
# Passing a record to a method that has declared the parameter just as [in]
|
|
64
|
+
# we expect modifications of the record on the server side NOT to change
|
|
65
|
+
# the record on the client side.
|
|
66
|
+
# We also need to test if the record gets properly passed to the method on
|
|
67
|
+
# the server side. For this, the 'VerifyRecord' method returns 'True' if
|
|
68
|
+
# all record fields have values equivalent to the initialization values
|
|
69
|
+
# provided by 'InitRecord'.
|
|
70
|
+
inited_record = ComtypesCppTestSrvLib.StructRecordParamTest()
|
|
71
|
+
inited_record.question = self.EXPECTED_INITED_QUESTIONS
|
|
72
|
+
inited_record.answer = 42
|
|
73
|
+
inited_record.needs_clarification = True
|
|
74
|
+
for rec, expected, (q, a, nc) in [
|
|
75
|
+
(inited_record, True, (self.EXPECTED_INITED_QUESTIONS, 42, True)),
|
|
76
|
+
# Also perform the inverted test. For this, create a blank record.
|
|
77
|
+
(ComtypesCppTestSrvLib.StructRecordParamTest(), False, (None, 0, False)),
|
|
78
|
+
]:
|
|
79
|
+
with self.subTest(expected=expected, q=q, a=a, nc=nc):
|
|
80
|
+
# Perform the check on initialization values.
|
|
81
|
+
self.assertEqual(self._create_dispifc().VerifyRecord(rec), expected)
|
|
82
|
+
self.assertEqual(rec.question, q)
|
|
83
|
+
# Check if the 'answer' field is unchanged although the method
|
|
84
|
+
# modifies this field on the server side.
|
|
85
|
+
self.assertEqual(rec.answer, a)
|
|
86
|
+
self.assertEqual(rec.needs_clarification, nc)
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
if __name__ == "__main__":
|
|
90
|
+
unittest.main()
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import contextlib
|
|
2
|
+
import importlib
|
|
3
|
+
import os
|
|
4
|
+
import sys
|
|
5
|
+
import tempfile
|
|
6
|
+
import types
|
|
7
|
+
from typing import Iterator
|
|
8
|
+
import unittest
|
|
9
|
+
from unittest import mock
|
|
10
|
+
|
|
11
|
+
import comtypes
|
|
12
|
+
import comtypes.client
|
|
13
|
+
import comtypes.gen
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
IMGBASE = os.path.splitext(os.path.basename(sys.executable))[0]
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@contextlib.contextmanager
|
|
20
|
+
def patch_empty_module_to_comtypes_gen() -> Iterator[types.ModuleType]:
|
|
21
|
+
with mock.patch.dict(sys.modules):
|
|
22
|
+
del sys.modules["comtypes.gen"]
|
|
23
|
+
mod = sys.modules["comtypes.gen"] = types.ModuleType("comtypes.gen")
|
|
24
|
+
mod.__path__ = []
|
|
25
|
+
with mock.patch.object(comtypes, "gen", mod):
|
|
26
|
+
try:
|
|
27
|
+
yield mod
|
|
28
|
+
finally:
|
|
29
|
+
importlib.reload(comtypes.gen)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class Test(unittest.TestCase):
|
|
33
|
+
"""Test the comtypes.client._find_gen_dir() function in several
|
|
34
|
+
simulated environments.
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
def test_script(self):
|
|
38
|
+
# %APPDATA%\Python\Python25\comtypes_cache
|
|
39
|
+
ma, mi = sys.version_info[:2]
|
|
40
|
+
cache = rf"$APPDATA\Python\Python{ma:d}{mi:d}\comtypes_cache"
|
|
41
|
+
path = os.path.expandvars(cache)
|
|
42
|
+
with patch_empty_module_to_comtypes_gen():
|
|
43
|
+
gen_dir = comtypes.client._find_gen_dir()
|
|
44
|
+
self.assertEqual(path, gen_dir)
|
|
45
|
+
|
|
46
|
+
# patch py2exe-attributes to `sys` modules
|
|
47
|
+
@mock.patch.object(sys, "frozen", "dll", create=True)
|
|
48
|
+
@mock.patch.object(sys, "frozendllhandle", sys.dllhandle, create=True)
|
|
49
|
+
def test_frozen_dll(self):
|
|
50
|
+
# %TEMP%\comtypes_cache\<imagebasename>25-25
|
|
51
|
+
# the image is python25.dll
|
|
52
|
+
ma, mi = sys.version_info[:2]
|
|
53
|
+
cache = rf"comtypes_cache\{IMGBASE}{ma:d}{mi:d}-{ma:d}{mi:d}"
|
|
54
|
+
path = os.path.join(tempfile.gettempdir(), cache)
|
|
55
|
+
with patch_empty_module_to_comtypes_gen():
|
|
56
|
+
gen_dir = comtypes.client._find_gen_dir()
|
|
57
|
+
self.assertEqual(path, gen_dir)
|
|
58
|
+
|
|
59
|
+
# patch py2exe-attributes to `sys` modules
|
|
60
|
+
@mock.patch.object(sys, "frozen", "console_exe", create=True)
|
|
61
|
+
def test_frozen_console_exe(self):
|
|
62
|
+
# %TEMP%\comtypes_cache\<imagebasename>-25
|
|
63
|
+
ma, mi = sys.version_info[:2]
|
|
64
|
+
cache = rf"comtypes_cache\{IMGBASE}-{ma:d}{mi:d}"
|
|
65
|
+
path = os.path.join(tempfile.gettempdir(), cache)
|
|
66
|
+
with patch_empty_module_to_comtypes_gen():
|
|
67
|
+
gen_dir = comtypes.client._find_gen_dir()
|
|
68
|
+
self.assertEqual(path, gen_dir)
|
|
69
|
+
|
|
70
|
+
# patch py2exe-attributes to `sys` modules
|
|
71
|
+
@mock.patch.object(sys, "frozen", "windows_exe", create=True)
|
|
72
|
+
def test_frozen_windows_exe(self):
|
|
73
|
+
# %TEMP%\comtypes_cache\<imagebasename>-25
|
|
74
|
+
ma, mi = sys.version_info[:2]
|
|
75
|
+
cache = rf"comtypes_cache\{IMGBASE}-{ma:d}{mi:d}"
|
|
76
|
+
path = os.path.join(tempfile.gettempdir(), cache)
|
|
77
|
+
with patch_empty_module_to_comtypes_gen():
|
|
78
|
+
gen_dir = comtypes.client._find_gen_dir()
|
|
79
|
+
self.assertEqual(path, gen_dir)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def main():
|
|
83
|
+
unittest.main()
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
if __name__ == "__main__":
|
|
87
|
+
main()
|