8000 no longer inherit from collections.abc · pywinrt/pywinrt@6997690 · GitHub 8000
[go: up one dir, main page]

Skip to content

Commit 6997690

Browse files
committed
no longer inherit from collections.abc
In Python 3.12, it is no longer possible for C types to inherit from abc.ABC since it has a custom tp_new. So we must find an alternate solution to implement collections.abc protocols. This attempts to do that by still using the methods from collection.abc but mixing in the methods manually and registering the type. Idea from: python/cpython#103968 (comment)
1 parent 0edd77c commit 6997690

File tree

4 files changed

+158
-154
lines changed

4 files changed

+158
-154
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
### Added
88
- Added positional-only parameters indication to type hints.
99

10+
### Changed
11+
- Changed how `collections.abc` protocols are implemented.
12+
1013
### Fixed
1114
- Fixed structs should not inherit from `_winrt.Object`.
1215

src/code_writers.h

Lines changed: 28 additions & 130 deletions
< F438 tr class="diff-line-row">
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,33 @@ namespace pywinrt
124124
}
125125

126126
w.write("@ = _ns_module.@\n", type.TypeName(), type.TypeName());
127+
128+
if (implements_imap(type))
129+
{
130+
w.write(
131+
"%.system._mixin_mutable_mapping(@)\n",
132+
settings.module,
133+
type.TypeName());
134+
}
135+
else if (implements_imapview(type))
136+
{
137+
w.write(
138+
"%.system._mixin_mapping(@)\n",
139+
settings.module,
140+
type.TypeName());
141+
}
142+
else if (implements_ivector(type)) {
143+
w.write(
144+
"%.system._mixin_mutable_sequence(@)\n",
145+
settings.module,
146+
type.TypeName());
147+
}
148+
else if (implements_ivectorview(type)) {
149+
w.write(
150+
"%.system._mixin_sequence(@)\n",
151+
settings.module,
152+
type.TypeName());
153+
}
127154
}
128155

129156
/**
@@ -469,26 +496,7 @@ PyTypeObject* py::winrt_type<%>::get_python_type() noexcept {
469496

470497
if (category == category::interface_type || category == category::class_type)
471498
{
472-
if (implements_imap(type))
473-
{
474-
w.write("mutable_mapping_bases.get()");
475-
}
476-
else if (implements_imapview(type))
477-
{
478-
w.write("mapping_bases.get()");
479-
}
480-
else if (implements_ivector(type))
481-
{
482-
w.write("mutable_sequence_bases.get()");
483-
}
484-
else if (implements_ivectorview(type))
485-
{
486-
w.write("sequence_bases.get()");
487-
}
488-
else
489-
{
490-
w.write("object_bases.get()");
491-
}
499+
w.write("object_bases.get()");
492500
}
493501
else
494502
{
@@ -837,100 +845,6 @@ static PyModuleDef module_def
837845
}
838846
w.write("}\n\n");
839847

840-
w.write(
841-
"py::pyobj_handle collections_abc_module{PyImport_ImportModule(\"collections.abc\")};\n\n");
842-
w.write("if (!collections_abc_module)\n{\n");
843-
{
844-
writer::indent_guard gg{w};
845-
846-
w.write("return nullptr;\n");
847-
}
848-
w.write("}\n\n");
849-
850-
w.write(
851-
"py::pyobj_handle sequence_type{PyObject_GetAttrString(collections_abc_module.get(), \"Sequence\")};\n\n");
852-
w.write("if (!sequence_type)\n{\n");
853-
{
854-
writer::indent_guard gg{w};
855-
856-
w.write("return nullptr;\n");
857-
}
858-
w.write("}\n\n");
859-
860-
w.write(
861-
"py::pyobj_handle sequence_bases{PyTuple_Pack(2, object_type, sequence_type.get())};\n\n");
862-
863-
w.write("if (!sequence_bases)\n{\n");
864-
{
865-
writer::indent_guard gg{w};
866-
867-
w.write("return nullptr;\n");
868-
}
869-
w.write("}\n\n");
870-
871-
w.write(
872-
"py::pyobj_handle mutable_sequence_type{PyObject_GetAttrString(collections_abc_module.get(), \"MutableSequence\")};\n\n");
873-
w.write("if (!mutable_sequence_type)\n{\n");
874-
{
875-
writer::indent_guard gg{w};
876-
877-
w.write("return nullptr;\n");
878-
}
879-
w.write("}\n\n");
880-
881-
w.write(
882-
"py::pyobj_handle mutable_sequence_bases{PyTuple_Pack(2, object_type, mutable_sequence_type.get())};\n\n");
883-
884-
w.write("if (!mutable_sequence_bases)\n{\n");
885-
{
886-
writer::indent_guard gg{w};
887-
888-
w.write("return nullptr;\n");
889-
}
890-
w.write("}\n\n");
891-
892-
w.write(
893-
"py::pyobj_handle mapping_type{PyObject_GetAttrString(collections_abc_module.get(), \"Mapping\")};\n\n");
894-
w.write("if (!mapping_type)\n{\n");
895-
{
896-
writer::indent_guard gg{w};
897-
898-
w.write("return nullptr;\n");
899-
}
900-
w.write("}\n\n");
901-
902-
w.write(
903-
"py::pyobj_handle mapping_bases{PyTuple_Pack(2, object_type, mapping_type.get())};\n\n");
904-
905-
w.write("if (!mapping_bases)\n{\n");
906-
{
907-
writer::indent_guard gg{w};
908-
909-
w.write("return nullptr;\n");
910-
}
911-
w.write("}\n\n");
912-
913-
w.write(
914-
"py::pyobj_handle mutable_mapping_type{PyObject_GetAttrString(collections_abc_module.get(), \"MutableMapping\")};\n\n");
915-
w.write("if (!mutable_mapping_type)\n{\n");
916-
{
917-
writer::indent_guard gg{w};
918-
919-
w.write("return nullptr;\n");
920-
}
921-
w.write("}\n\n");
922-
923-
w.write(
924-
"py::pyobj_handle mutable_mapping_bases{PyTuple_Pack(2, object_type, mutable_mapping_type.get())};\n\n");
925-
926-
w.write("if (!mutable_mapping_bases)\n{\n");
927-
{
928-
writer::indent_guard gg{w};
929-
930-
w.write("return nullptr;\n");
931-
}
932-
w.write("}\n\n");
933-
934848
w.write(
935849
"auto state = reinterpret_cast<module_state*>(PyModule_GetState(module.get()));\n");
936850
w.write("assert(state);\n\n");
@@ -2280,17 +2194,6 @@ return 0;
22802194
});
22812195
}
22822196
w.write("}\n");
2283-
2284-
// alias InsertAt to insert for Python sequence protocol
2285-
w.write(
2286-
"\nstatic PyObject* @_get_insert(PyObject* self) noexcept\n{\n",
2287-
type.TypeName());
2288-
{
2289-
writer::indent_guard g{w};
2290-
2291-
w.write("return PyObject_GetAttrString(self, \"insert_at\");\n");
2292-
}
2293-
w.write("}\n");
22942197
}
22952198
}
22962199

@@ -2513,11 +2416,6 @@ return 0;
25132416
});
25142417
}
25152418

2516-
if (implements_ivector(type))
2517-
{
2518-
write_row("insert", "get_insert", "");
2519-
}
2520-
25212419
w.write("{ }\n");
25222420
}
25232421
w.write("};\n");

src/strings/system_init.py

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import sys
44
from types import ModuleType
55
import uuid
6+
from collections.abc import Sequence, MutableSequence, Mapping, MutableMapping
67

78
from .._winrt import __file__ as _winrt_file, Array as Array, Object as Object
89

@@ -16,6 +17,129 @@ def _import_ns_module(ns: str) -> ModuleType:
1617
loader.exec_module(module)
1718
return module
1819

20+
# NB: The types implemented in C cannot inherit from abc.ABC since Python 3.12
21+
# so we have to implement the protocols like this instead.
22+
# https://github.com/python/cpython/issues/103968#issuecomment-1589928055
23+
24+
def _mixin_sequence(typ) -> None:
25+
"""
26+
Adds missing Python mapping methods to types that implement IVectorView and
27+
registers the type as a Sequence.
28+
"""
29+
# mixin methods
30+
if not hasattr(typ, "index"):
31+
typ.index = Sequence.index
32+
33+
if not hasattr(typ, "count"):
34+
typ.count = Sequence.count
35+
36+
if not hasattr(typ, "__contains__"):
37+
typ.__contains__ = Sequence.__contains__
38+
39+
if not hasattr(typ, "__iter__"):
40+
typ.__iter__ = Sequence.__iter__
41+
42+
if not hasattr(typ, "__reversed__"):
43+
typ.__reversed__ = Sequence.__reversed__
44+
45+
Sequence.register(typ)
46+
47+
def _mixin_mutable_sequence(typ) -> None:
48+
"""
49+
Adds missing Python mapping methods to types that implement IVector and
50+
registers the type as a MutableSequence.
51+
"""
52+
_mixin_sequence(typ)
53+
54+
if not hasattr(typ, "insert") and hasattr(typ, "insert_at"):
55+
def insert(self, index: int, value: object) -> None:
56+
"""
57+
Alias for ``insert_at`` for compatibility with Python Sequence protocol.
58+
"""
59+
self.insert_at(index, value)
60+
61+
typ.insert = insert
62+
63+
# mixin methods
64+
if not hasattr(typ, "append"):
65+
typ.append = MutableSequence.append
66+
67+
if not hasattr(typ, "clear"):
68+
typ.clear = MutableSequence.clear
69+
70+
if not hasattr(typ, "extend"):
71+
typ.extend = MutableSequence.extend
72+
73+
if not hasattr(typ, "reverse"):
74+
typ.reverse = MutableSequence.reverse
75+
76+
if not hasattr(typ, "pop"):
77+
typ.pop = MutableSequence.pop
78+
79+
if not hasattr(typ, "remove"):
80+
typ.remove = MutableSequence.remove
81+
82+
if not hasattr(typ, "__iadd__"):
83+
typ.__iadd__ = MutableSequence.__iadd__
84+
85+
MutableSequence.register(typ)
86+
87+
def _mixin_mapping(typ) -> None:
88+
"""
89+
Adds missing Python mapping methods to types that implement IMapView and
90+
registers the type as a Mapping.
91+
"""
92+
# mixin methods
93+
if not hasattr(typ, "keys"):
94+
typ.keys = Mapping.keys
95+
96+
if not hasattr(typ, "items"):
97+
typ.items = Mapping.items
98+
99+
if not hasattr(typ, "values"):
100+
typ.values = Mapping.values
101+
102+
if not hasattr(typ, "get"):
103+
typ.get = Mapping.get
104+
105+
if not hasattr(typ, "__contains__"):
106+
typ.__contains__ = Mapping.__contains__
107+
108+
if not hasattr(typ, "__eq__"):
109+
typ.__eq__ = Mapping.__eq__
110+
111+
if not hasattr(typ, "__ne__"):
112+
typ.__ne__ = Mapping.__ne__
113+
114+
Mapping.register(typ)
115+
116+
def _mixin_mutable_mapping(typ) -> None:
117+
"""
118+
Adds missing Python mapping methods to types that implement IMap and
119+
registers the type as a MutableMapping.
120+
"""
121+
_mixin_mapping(typ)
122+
123+
# mixin methods
124+
if not hasattr(typ, "clear"):
125+
typ.clear = MutableMapping.clear
126+
127+
if not hasattr(typ, "pop"):
128+
typ.pop = MutableMapping.pop
129+
# private-name-mangled attribute :-(
130+
typ._MutableMapping__marker = MutableMapping._MutableMapping__marker # type: ignore
131+
132+
if not hasattr(typ, "popitem"):
133+
typ.popitem = MutableMapping.popitem
134+
135+
if not hasattr(typ, "setdefault"):
136+
typ.setdefault = MutableMapping.setdefault
137+
138+
if not hasattr(typ, "update"):
139+
typ.update = MutableMapping.update
140+
141+
142+
MutableMapping.register(typ)
19143

20144
if sys.version_info >= (3, 9):
21145
from typing import Annotated
@@ -48,3 +172,5 @@ def _import_ns_module(ns: str) -> ModuleType:
48172
Double = float
49173
Char16 = str
50174
Guid = uuid.UUID
175+
176+
_mixin_mutable_sequence(Array)

src/strings/winrt_module.cpp

Lines changed: 1 addition & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -290,29 +290,6 @@ namespace py::cpp::_winrt
290290
static const auto kSTA
291291
= static_cast<long>(winrt::apartment_type::single_threaded);
292292

293-
py::pyobj_handle collections_abc_module{
294-
PyImport_ImportModule("collections.abc")};
295-
296-
if (!collections_abc_module)
297-
{
298-
return nullptr;
299-
}
300-
301-
py::pyobj_handle mutable_sequence_type{
302-
PyObject_GetAttrString(collections_abc_module.get(), "MutableSequence")};
303-
304-
if (!mutable_sequence_type)
305-
{
306-
return nullptr;
307-
}
308-
309-
py::pyobj_handle array_bases{PyTuple_Pack(1, mutable_sequence_type.get())};
310-
311-
if (!array_bases)
312-
{
313-
return nullptr;
314-
}
315-
316293
py::pyobj_handle module{PyModule_Create(&module_def)};
317294

318295
if (!module)
@@ -332,7 +309,7 @@ namespace py::cpp::_winrt
332309
}
333310

334311
state->Array_type = py::register_python_type(
335-
module.get(), "Array", &Array_type_spec, array_bases.get(), nullptr);
312+
module.get(), "Array", &Array_type_spec, nullptr, nullptr);
336313

337314
if (!state->Array_type)
338315
{

0 commit comments

Comments
 (0)
0