Skip to content

Commit 90289eb

Browse files
geppiAvasam
andauthored
Integrate PyCOMTest server dll into CI workflow (#2493)
* Added Visual Studio 2022 solution/project files for PyCOMTest server dll. Also changed '.gitignore' to put the Visual Studio solution and pjoject files under revision control. * Added building and registering the PyCOMTest server dll to the CI workflow. * Retarget PyCOMTest solution for MSVC v142 and Win SDK 10.0.22000.0 * Moved PyCOMTest to 'Level 1' of the unit tests. This will include PyCOMTest in the tests of the github CI workflow. * Added registration of the PyCOMTest.dll with regsvr32 to the CI workflow. * Fixing the registred trademark symbol in'PyCOMTest.idl'. * Fix to generate a standalone PyCOMTestLib module and not a package. * Add bForDemand=False to testArrays.py * Fix formatting. * Fix to make special __dunder__ methods work with CoClass. This was initially implemented in commit 17fb589 to address #1699. The initial implementation had a problem with bool() (see #1753). The problem was caused by implementing __nonzero__ instead of __bool__, which was pointed out in the conclusion of #1870. The commit c072ff7 tried to fix #1753 but introduced another issue #1870. * Added a change entry for the #1870 fix. --------- Co-authored-by: Avasam <[email protected]>
1 parent 95ac01a commit 90289eb

File tree

10 files changed

+244
-46
lines changed

10 files changed

+244
-46
lines changed

.github/workflows/main.yml

+10
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,16 @@ jobs:
5858
python -m win32.scripts.pywin32_postinstall -install -destination "$UserSite"
5959
pywin32_postinstall -remove -destination "$UserSite"
6060
61+
# Compilation and registration of the PyCOMTest server dll
62+
- name: Set up MSVC
63+
uses: microsoft/setup-msbuild@v2
64+
- name: Build and register the PyCOMTest server dll
65+
run: |
66+
cd com/TestSources/PyCOMTest
67+
msbuild .\PyCOMTest.sln -property:Configuration=Release
68+
cd x64/Release
69+
regsvr32 .\PyCOMTest.dll
70+
6171
- name: Run tests
6272
# Run the tests directly from the source dir so support files (eg, .wav files etc)
6373
# can be found - they aren't installed into the Python tree.

.gitignore

+10-8
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,23 @@ arm64libs/
1818
pywin32.egg-info/
1919
PyWin32.kpf
2020

21+
# Visual Studio project files
22+
*.sln
23+
*.suo
24+
*.vc*proj*
25+
*.user
26+
2127
# COM test bits
2228
com/TestSources/Build
2329
com/TestSources/PyCOMTest/PyCOMTest.h
24-
com/TestSources/PyCOMTest/PyCOMTest.sln
2530
com/TestSources/PyCOMTest/PyCOMTest.suo
2631
com/TestSources/PyCOMTest/PyCOMTest.tlb
27-
com/TestSources/PyCOMTest/PyCOMTest.vc*proj*
2832
com/TestSources/PyCOMTest/PyCOMTest_i.c
2933
com/TestSources/PyCOMTest/.vs/
34+
com/TestSources/PyCOMTest/PyCOMTest/
35+
com/TestSources/PyCOMTest/x64/
36+
!com/TestSources/PyCOMTest/PyCOMTest.sln
37+
!com/TestSources/PyCOMTest/PyCOMTest.vcxproj
3038

3139
# SWIG generated files.
3240
com/win32comext/adsi/src/*.cpp
@@ -50,12 +58,6 @@ win32/src/win32service_messages.h
5058
win32/src/win32evtlog_messages.h
5159
isapi/src/pyISAPI_messages.h
5260

53-
# Visual Studio project files
54-
*.sln
55-
*.suo
56-
*.vcproj
57-
*.user
58-
5961
# Eclipse + PyDev
6062
.project
6163
.pydevproject

CHANGES.txt

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ https://mhammond.github.io/pywin32_installers.html .
1313

1414
Coming in build 311, as yet unreleased
1515
--------------------------------------
16+
* Fixed a regression that broke special __dunder__ methods with CoClass. (#1870, #2493, @Avasam, @geppi)
1617

1718
Build 310, released 2025/03/16
1819
------------------------------

com/TestSources/PyCOMTest/PyCOMTest.idl

+2-2
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ typedef enum // Missing EnumTestAttributes2
2626
uuid(6bcdcb60-5605-11d0-ae5f-cadd4c000000),
2727
version(1.1),
2828
// an extended character in the help string should stress things...
29-
helpstring("Python COM Test Harness 1.0 Type Library, � pywin32 contributors")
29+
helpstring("Python COM Test Harness 1.0 Type Library, � pywin32 contributors")
3030
]
3131
library PyCOMTestLib
3232
{
@@ -70,7 +70,7 @@ library PyCOMTestLib
7070
const long LongTest2 = 0x7FFFFFFFL;
7171
const unsigned char UCharTest = 255;
7272
const char CharTest = -1;
73-
const LPWSTR StringTest = L"Hello Wo�ld";
73+
const LPWSTR StringTest = L"Hello Wo�ld";
7474
};
7575

7676
enum TestAttributes3{ // Note missing the enum name.
+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
2+
Microsoft Visual Studio Solution File, Format Version 12.00
3+
# Visual Studio Version 17
4+
VisualStudioVersion = 17.10.35027.167
5+
MinimumVisualStudioVersion = 10.0.40219.1
6+
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PyCOMTest", "PyCOMTest.vcxproj", "{8EB3046C-6CE8-4537-9B58-6EDD46E6D632}"
7+
EndProject
8+
Global
9+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
10+
Debug|x64 = Debug|x64
11+
Debug|x86 = Debug|x86
12+
Release|x64 = Release|x64
13+
Release|x86 = Release|x86
14+
EndGlobalSection
15+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
16+
{8EB3046C-6CE8-4537-9B58-6EDD46E6D632}.Debug|x64.ActiveCfg = Debug|x64
17+
{8EB3046C-6CE8-4537-9B58-6EDD46E6D632}.Debug|x64.Build.0 = Debug|x64
18+
{8EB3046C-6CE8-4537-9B58-6EDD46E6D632}.Debug|x86.ActiveCfg = Debug|Win32
19+
{8EB3046C-6CE8-4537-9B58-6EDD46E6D632}.Debug|x86.Build.0 = Debug|Win32
20+
{8EB3046C-6CE8-4537-9B58-6EDD46E6D632}.Release|x64.ActiveCfg = Release|x64
21+
{8EB3046C-6CE8-4537-9B58-6EDD46E6D632}.Release|x64.Build.0 = Release|x64
22+
{8EB3046C-6CE8-4537-9B58-6EDD46E6D632}.Release|x86.ActiveCfg = Release|Win32
23+
{8EB3046C-6CE8-4537-9B58-6EDD46E6D632}.Release|x86.Build.0 = Release|Win32
24+
EndGlobalSection
25+
GlobalSection(SolutionProperties) = preSolution
26+
HideSolutionNode = FALSE
27+
EndGlobalSection
28+
GlobalSection(ExtensibilityGlobals) = postSolution
29+
SolutionGuid = {E15B431A-88C2-47F5-B809-AAC25279BD21}
30+
EndGlobalSection
31+
EndGlobal
+164
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3+
<ItemGroup Label="ProjectConfigurations">
4+
<ProjectConfiguration Include="Debug|Win32">
5+
<Configuration>Debug</Configuration>
6+
<Platform>Win32</Platform>
7+
</ProjectConfiguration>
8+
<ProjectConfiguration Include="Release|Win32">
9+
<Configuration>Release</Configuration>
10+
<Platform>Win32</Platform>
11+
</ProjectConfiguration>
12+
<ProjectConfiguration Include="Debug|x64">
13+
<Configuration>Debug</Configuration>
14+
<Platform>x64</Platform>
15+
</ProjectConfiguration>
16+
<ProjectConfiguration Include="Release|x64">
17+
<Configuration>Release</Configuration>
18+
<Platform>x64</Platform>
19+
</ProjectConfiguration>
20+
</ItemGroup>
21+
<PropertyGroup Label="Globals">
22+
<VCProjectVersion>17.0</VCProjectVersion>
23+
<ProjectGuid>{8EB3046C-6CE8-4537-9B58-6EDD46E6D632}</ProjectGuid>
24+
<Keyword>Win32Proj</Keyword>
25+
<WindowsTargetPlatformVersion>10.0.22000.0</WindowsTargetPlatformVersion>
26+
</PropertyGroup>
27+
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
28+
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
29+
<ConfigurationType>DynamicLibrary</ConfigurationType>
30+
<UseDebugLibraries>true</UseDebugLibraries>
31+
<PlatformToolset>v143</PlatformToolset>
32+
<CharacterSet>NotSet</CharacterSet>
33+
</PropertyGroup>
34+
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
35+
<ConfigurationType>DynamicLibrary</ConfigurationType>
36+
<UseDebugLibraries>false</UseDebugLibraries>
37+
<PlatformToolset>v143</PlatformToolset>
38+
<CharacterSet>NotSet</CharacterSet>
39+
</PropertyGroup>
40+
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
41+
<ConfigurationType>DynamicLibrary</ConfigurationType>
42+
<UseDebugLibraries>true</UseDebugLibraries>
43+
<PlatformToolset>v142</PlatformToolset>
44+
<CharacterSet>NotSet</CharacterSet>
45+
</PropertyGroup>
46+
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
47+
<ConfigurationType>DynamicLibrary</ConfigurationType>
48+
<UseDebugLibraries>false</UseDebugLibraries>
49+
<PlatformToolset>v142</PlatformToolset>
50+
<CharacterSet>NotSet</CharacterSet>
51+
</PropertyGroup>
52+
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
53+
<ImportGroup Label="ExtensionSettings">
54+
</ImportGroup>
55+
<ImportGroup Label="Shared">
56+
</ImportGroup>
57+
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
58+
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
59+
</ImportGroup>
60+
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
61+
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
62+
</ImportGroup>
63+
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
64+
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
65+
</ImportGroup>
66+
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
67+
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
68+
</ImportGroup>
69+
<PropertyGroup Label="UserMacros" />
70+
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
71+
<LinkIncremental>true</LinkIncremental>
72+
</PropertyGroup>
73+
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
74+
<LinkIncremental>true</LinkIncremental>
75+
</PropertyGroup>
76+
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
77+
<LinkIncremental>true</LinkIncremental>
78+
</PropertyGroup>
79+
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
80+
<LinkIncremental>true</LinkIncremental>
81+
</PropertyGroup>
82+
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
83+
<ClCompile>
84+
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;PYCOMTEST_EXPORTS;/nologo /MDd /W3 /Gm /GX /ZI /Od /D _DEBUG /D WIN32 /D _WINDOWS /D _USRDLL /D _UNICODE /D _WINDLL /D _AFXDLL /D _MBCS /Yupreconn.h /FD /c;%(PreprocessorDefinitions)</PreprocessorDefinitions>
85+
<WarningLevel>Level3</WarningLevel>
86+
</ClCompile>
87+
<Link>
88+
<GenerateDebugInformation>true</GenerateDebugInformation>
89+
<SubSystem>Windows</SubSystem>
90+
<ModuleDefinitionFile>Connect.def</ModuleDefinitionFile>
91+
</Link>
92+
</ItemDefinitionGroup>
93+
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
94+
<ClCompile>
95+
<PreprocessorDefinitions>_DEBUG;_WINDOWS;_USRDLL;PYCOMTEST_EXPORTS;/nologo /MDd /W3 /Gm /GX /ZI /Od /D _DEBUG /D WIN32 /D _WINDOWS /D _USRDLL /D _UNICODE /D _WINDLL /D _AFXDLL /D _MBCS /Yupreconn.h /FD /c;%(PreprocessorDefinitions)</PreprocessorDefinitions>
96+
<WarningLevel>Level3</WarningLevel>
97+
</ClCompile>
98+
<Link>
99+
<GenerateDebugInformation>true</GenerateDebugInformation>
100+
<SubSystem>Windows</SubSystem>
101+
<ModuleDefinitionFile>Connect.def</ModuleDefinitionFile>
102+
</Link>
103+
</ItemDefinitionGroup>
104+
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
105+
<ClCompile>
106+
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;PYCOMTEST_EXPORTS;/nologo /MD /W3 /GX /O2 /D NDEBUG /D WIN32 /D _WINDOWS /D _USRDLL /D _UNICODE /D _WINDLL /D _AFXDLL /D _MBCS /Yupreconn.h /FD /c;%(PreprocessorDefinitions)</PreprocessorDefinitions>
107+
<WarningLevel>Level3</WarningLevel>
108+
</ClCompile>
109+
<Link>
110+
<GenerateDebugInformation>true</GenerateDebugInformation>
111+
<SubSystem>Windows</SubSystem>
112+
<EnableCOMDATFolding>true</EnableCOMDATFolding>
113+
<OptimizeReferences>true</OptimizeReferences>
114+
<ModuleDefinitionFile>Connect.def</ModuleDefinitionFile>
115+
</Link>
116+
</ItemDefinitionGroup>
117+
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
118+
<ClCompile>
119+
<PreprocessorDefinitions>NDEBUG;_WINDOWS;_USRDLL;PYCOMTEST_EXPORTS;/nologo /MD /W3 /GX /O2 /D NDEBUG /D WIN32 /D _WINDOWS /D _USRDLL /D _UNICODE /D _WINDLL /D _AFXDLL /D _MBCS /Yupreconn.h /FD /c;%(PreprocessorDefinitions)</PreprocessorDefinitions>
120+
<WarningLevel>Level3</WarningLevel>
121+
</ClCompile>
122+
<Link>
123+
<GenerateDebugInformation>true</GenerateDebugInformation>
124+
<SubSystem>Windows</SubSystem>
125+
<EnableCOMDATFolding>true</EnableCOMDATFolding>
126+
<OptimizeReferences>false</OptimizeReferences>
127+
<RandomizedBaseAddress>false</RandomizedBaseAddress>
128+
<ModuleDefinitionFile>Connect.def</ModuleDefinitionFile>
129+
</Link>
130+
</ItemDefinitionGroup>
131+
<ItemGroup>
132+
<ClCompile Include="Connect.cpp" />
133+
<ClCompile Include="DSCArrayTest.cpp" />
134+
<ClCompile Include="preconn.cpp" />
135+
<ClCompile Include="PyCOMImpl.cpp" />
136+
<ClCompile Include="SimpleCounter.cpp" />
137+
</ItemGroup>
138+
<ItemGroup>
139+
<Midl Include="PyCOMTest.idl">
140+
<HeaderFileName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">%(Filename).h</HeaderFileName>
141+
<TypeLibraryName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">%(Filename).tlb</TypeLibraryName>
142+
<HeaderFileName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">%(Filename).h</HeaderFileName>
143+
<TypeLibraryName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">%(Filename).tlb</TypeLibraryName>
144+
</Midl>
145+
</ItemGroup>
146+
<ItemGroup>
147+
<None Include="ArrayTest.rgs" />
148+
<None Include="Connect.def" />
149+
<None Include="PyCOMTest.rgs" />
150+
</ItemGroup>
151+
<ItemGroup>
152+
<ClInclude Include="connres.h" />
153+
<ClInclude Include="DSCArrayTest.h" />
154+
<ClInclude Include="preconn.h" />
155+
<ClInclude Include="PyCOMImpl.h" />
156+
<ClInclude Include="SimpleCounter.h" />
157+
</ItemGroup>
158+
<ItemGroup>
159+
<ResourceCompile Include="Connect.rc" />
160+
</ItemGroup>
161+
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
162+
<ImportGroup Label="ExtensionTargets">
163+
</ImportGroup>
164+
</Project>

com/win32com/client/__init__.py

+19-32
Original file line numberDiff line numberDiff line change
@@ -628,18 +628,7 @@ class CoClassBaseClass:
628628
def __init__(self, oobj=None):
629629
if oobj is None:
630630
oobj = pythoncom.new(self.CLSID)
631-
dispobj = self.__dict__["_dispobj_"] = self.default_interface(oobj)
632-
# See comments below re the special methods.
633-
for maybe in [
634-
"__call__",
635-
"__str__",
636-
"__int__",
637-
"__iter__",
638-
"__len__",
639-
"__bool__",
640-
]:
641-
if hasattr(dispobj, maybe):
642-
setattr(self, maybe, getattr(self, "__maybe" + maybe))
631+
self.__dict__["_dispobj_"] = self.default_interface(oobj)
643632

644633
def __repr__(self):
645634
return f"<win32com.gen_py.{__doc__}.{self.__class__.__name__}>"
@@ -663,31 +652,29 @@ def __setattr__(self, attr, value):
663652
pass
664653
self.__dict__[attr] = value
665654

666-
# Special methods don't use __getattr__ etc, so explicitly delegate here.
667-
# Note however, that not all are safe to let bubble up - things like
668-
# `bool(ob)` will break if the object defines __int__ but then raises an
669-
# attribute error - eg, see #1753.
670-
# It depends on what the wrapped COM object actually defines whether these
671-
# will exist on the underlying object, so __init__ explicitly checks if they
672-
# do and if so, wires them up.
655+
# Special methods don't use __getattr__ etc, so explicitly delegate here.
656+
# Some wrapped objects might not have them, but that's OK - the attribute
657+
# error can just bubble up.
658+
# This was initially implemented to address #1699 which did cause a problem
659+
# with bool() in #1753 because the code initially implemented __nonzero__
660+
# instead of __bool__, which was pointed out in the conclusion of #1870.
661+
def __call__(self, *args, **kwargs):
662+
return self.__dict__["_dispobj_"](*args, **kwargs)
673663

674-
def __maybe__call__(self, *args, **kwargs):
675-
return self.__dict__["_dispobj_"].__call__(*args, **kwargs)
664+
def __str__(self, *args):
665+
return str(self.__dict__["_dispobj_"])
676666

677-
def __maybe__str__(self, *args):
678-
return self.__dict__["_dispobj_"].__str__(*args)
667+
def __int__(self, *args):
668+
return int(self.__dict__["_dispobj_"])
679669

680-
def __maybe__int__(self, *args):
681-
return self.__dict__["_dispobj_"].__int__(*args)
670+
def __iter__(self):
671+
return iter(self.__dict__["_dispobj_"])
682672

683-
def __maybe__iter__(self):
684-
return self.__dict__["_dispobj_"].__iter__()
673+
def __len__(self):
674+
return len(self.__dict__["_dispobj_"])
685675

686-
def __maybe__len__(self):
687-
return self.__dict__["_dispobj_"].__len__()
688-
689-
def __maybe__bool__(self):
690-
return self.__dict__["_dispobj_"].__bool__()
676+
def __bool__(self):
677+
return bool(self.__dict__["_dispobj_"])
691678

692679

693680
# A very simple VARIANT class. Only to be used with poorly-implemented COM

com/win32com/test/testArrays.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ def _normalize_array(a):
5151

5252
class ArrayTest(util.TestCase):
5353
def setUp(self):
54-
self.arr = gencache.EnsureDispatch("PyCOMTest.ArrayTest")
54+
self.arr = gencache.EnsureDispatch("PyCOMTest.ArrayTest", bForDemand=False)
5555

5656
def tearDown(self):
5757
self.arr = None

com/win32com/test/testPyComTest.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,9 @@
3636
from win32com.client import gencache
3737

3838
try:
39-
gencache.EnsureModule("{6BCDCB60-5605-11D0-AE5F-CADD4C000000}", 0, 1, 1)
39+
gencache.EnsureModule(
40+
"{6BCDCB60-5605-11D0-AE5F-CADD4C000000}", 0, 1, 1, bForDemand=False
41+
)
4042
except pythoncom.com_error:
4143
print("The PyCOMTest module can not be located or generated.")
4244
print(importMsg)

com/win32com/test/testall.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -178,10 +178,11 @@ def testit(self):
178178

179179
custom_test_cases = [
180180
# Level 1 tests.
181-
[],
182-
# Level 2 tests.
183181
[
184182
PyCOMTest,
183+
],
184+
# Level 2 tests.
185+
[
185186
PippoTest,
186187
],
187188
# Level 3 tests

0 commit comments

Comments
 (0)