Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add comments to metaclasses. #635

Merged
merged 6 commits into from
Oct 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion comtypes/_meta.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,17 @@ class _coclass_meta(type):
def __new__(cls, name, bases, namespace):
self = type.__new__(cls, name, bases, namespace)
if bases == (object,):
# HACK: Could this conditional branch be removed since it is never reached?
# Since definition is `class CoClass(COMObject, metaclass=_coclass_meta)`,
# the `bases` parameter passed to the `_coclass_meta.__new__` would be
# `(COMObject,)`.
# Moreover, since the `COMObject` derives from `object` and does not specify
# a metaclass, `(object,)` will not be passed as the `bases` parameter
# to the `_coclass_meta.__new__`.
# The reason for this implementation might be a remnant of the differences
# in how metaclasses work between Python 3.x and Python 2.x.
# If there are no problems with the versions of Python that `comtypes`
# supports, this removal could make the process flow easier to understand.
return self
# XXX We should insist that a _reg_clsid_ is present.
if "_reg_clsid_" in namespace:
Expand All @@ -67,4 +78,6 @@ def __new__(cls, name, bases, namespace):

# will not work if we change the order of the two base classes!
class _coclass_pointer_meta(type(c_void_p), _coclass_meta):
pass
# metaclass for CoClass pointer

pass # no functionality, but needed to avoid a metaclass conflict
15 changes: 13 additions & 2 deletions comtypes/_post_coinit/unknwn.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,11 +85,21 @@ def __new__(cls, name, bases, namespace):
# subclass of POINTER(IUnknown) because of the way ctypes
# typechecks work.
if bases == (object,):
# `self` is the `IUnknown` type.
_ptr_bases = (self, _compointer_base)
else:
# `self` is an interface type derived from `IUnknown`.
_ptr_bases = (self, POINTER(bases[0]))

# The interface 'self' is used as a mixin.
# HACK: Could `type(_compointer_base)` be replaced with `_compointer_meta`?
# `type(klass)` returns its metaclass.
# Since this specification, `type(_compointer_base)` will return the
# `_compointer_meta` type as per the class definition.
# The reason for this implementation might be a remnant of the differences in
# how metaclasses work between Python 3.x and Python 2.x.
# If there are no problems with the versions of Python that `comtypes`
# supports, this replacement could make the process flow easier to understand.
p = type(_compointer_base)(
f"POINTER({self.__name__})",
_ptr_bases,
Expand Down Expand Up @@ -369,10 +379,11 @@ def _make_methods(self, methods: List[_ComMemberSpec]) -> None:
################################################################


# will not work if we change the order of the two base classes!
class _compointer_meta(type(c_void_p), _cominterface_meta):
"metaclass for COM interface pointer classes"
"""metaclass for COM interface pointer classes"""

# no functionality, but needed to avoid a metaclass conflict
pass # no functionality, but needed to avoid a metaclass conflict


class _compointer_base(c_void_p, metaclass=_compointer_meta):
Expand Down