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

change type hints from comment annotations to inline annotations in _memberspec #455

Merged
merged 2 commits into from
Jan 7, 2023
Merged
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
147 changes: 68 additions & 79 deletions comtypes/_memberspec.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@
import comtypes


PositionalParamFlagType = Tuple[int, Optional[str]]
OptionalParamFlagType = Tuple[int, Optional[str], Any]
ParamFlagType = _UnionT[PositionalParamFlagType, OptionalParamFlagType]
PositionalArgSpecElmType = Tuple[List[str], Type[_CData], str]
OptionalArgSpecElmType = Tuple[List[str], Type[_CData], str, Any]
ArgSpecElmType = _UnionT[PositionalArgSpecElmType, OptionalArgSpecElmType]
_PositionalParamFlagType = Tuple[int, Optional[str]]
_OptionalParamFlagType = Tuple[int, Optional[str], Any]
_ParamFlagType = _UnionT[_PositionalParamFlagType, _OptionalParamFlagType]
_PositionalArgSpecElmType = Tuple[List[str], Type[_CData], str]
_OptionalArgSpecElmType = Tuple[List[str], Type[_CData], str, Any]
_ArgSpecElmType = _UnionT[_PositionalArgSpecElmType, _OptionalArgSpecElmType]


_PARAMFLAGS = {
Expand All @@ -40,13 +40,18 @@ def _encode_idl(names):
_NOTHING = object()


def _unpack_argspec(idl, typ, name=None, defval=_NOTHING):
# type: (List[str], Type[_CData], Optional[str], Any) -> Tuple[List[str], Type[_CData], Optional[str], Any]
def _unpack_argspec(
idl: List[str],
typ: Type[_CData],
name: Optional[str] = None,
defval: Any = _NOTHING,
) -> Tuple[List[str], Type[_CData], Optional[str], Any]:
return idl, typ, name, defval


def _resolve_argspec(items):
# type: (Tuple[ArgSpecElmType, ...]) -> Tuple[Tuple[ParamFlagType, ...], Tuple[Type[_CData], ...]]
def _resolve_argspec(
items: Tuple[_ArgSpecElmType, ...]
) -> Tuple[Tuple[_ParamFlagType, ...], Tuple[Type[_CData], ...]]:
"""Unpacks and converts from argspec to paramflags and argtypes.

- paramflags is a sequence of `(pflags: int, argname: str, | None[, defval: Any])`.
Expand Down Expand Up @@ -83,12 +88,11 @@ class _MemberSpec(object):
__slots__ = ("name", "idlflags", "restype")

def __init__(self, name, idlflags, restype):
self.name = name # type: str
self.idlflags = idlflags # type: Tuple[_UnionT[str, int], ...]
self.restype = restype # type: Optional[Type[_CData]]
self.name: str = name
self.idlflags: Tuple[_UnionT[str, int], ...] = idlflags
self.restype: Optional[Type[_CData]] = restype

def is_prop(self):
# type: () -> bool
def is_prop(self) -> bool:
propflags = ("propget", "propput", "propputref")
return any(f in propflags for f in self.idlflags)

Expand All @@ -99,9 +103,9 @@ class _ComMemberSpec(_MemberSpec):
__slots__ = ("argtypes", "paramflags", "doc")

def __init__(self, restype, name, argtypes, paramflags, idlflags, doc):
self.argtypes = argtypes # type: Tuple[Type[_CData], ...]
self.paramflags = paramflags # type: Optional[Tuple[ParamFlagType, ...]]
self.doc = doc # type: Optional[str]
self.argtypes: Tuple[Type[_CData], ...] = argtypes
self.paramflags: Optional[Tuple[_ParamFlagType, ...]] = paramflags
self.doc: Optional[str] = doc
super(_ComMemberSpec, self).__init__(name, idlflags, restype)

def __iter__(self):
Expand All @@ -125,13 +129,12 @@ class _DispMemberSpec(_MemberSpec):
__slots__ = ("what", "argspec")

def __init__(self, what, name, idlflags, restype, argspec):
self.what = what # type: str
self.argspec = argspec # type: Tuple[ArgSpecElmType, ...]
self.what: str = what
self.argspec: Tuple[_ArgSpecElmType, ...] = argspec
super(_DispMemberSpec, self).__init__(name, idlflags, restype)

@property
def memid(self):
# type: () -> int
def memid(self) -> int:
try:
return [x for x in self.idlflags if isinstance(x, int)][0]
except IndexError:
Expand All @@ -145,8 +148,15 @@ def __iter__(self):
yield item


def _fix_inout_args(func, argtypes, paramflags):
# type: (Callable[..., Any], Tuple[Type[_CData], ...], Tuple[ParamFlagType, ...]) -> Callable[..., Any]
_PropFunc = Optional[Callable[..., Any]]
_DocType = Optional[str]


def _fix_inout_args(
func: Callable[..., Any],
argtypes: Tuple[Type[_CData], ...],
paramflags: Tuple[_ParamFlagType, ...],
) -> Callable[..., Any]:
"""This function provides a workaround for a bug in `ctypes`.

[in, out] parameters must be converted with the argtype's `from_param`
Expand Down Expand Up @@ -230,24 +240,24 @@ def call_with_inout(self, *args, **kw):

class PropertyMapping(object):
def __init__(self):
self._data = (
{}
) # type: Dict[Tuple[str, Optional[str], int], List[Optional[Callable[..., Any]]]]
self._data: Dict[Tuple[str, _DocType, int], List[_PropFunc]] = {}

def add_propget(self, name, doc, nargs, func):
# type: (str, Optional[str], int, Callable[..., Any]) -> None
def add_propget(
self, name: str, doc: _DocType, nargs: int, func: Callable[..., Any]
) -> None:
self._data.setdefault((name, doc, nargs), [None, None, None])[0] = func

def add_propput(self, name, doc, nargs, func):
# type: (str, Optional[str], int, Callable[..., Any]) -> None
def add_propput(
self, name: str, doc: _DocType, nargs: int, func: Callable[..., Any]
) -> None:
self._data.setdefault((name, doc, nargs), [None, None, None])[1] = func

def add_propputref(self, name, doc, nargs, func):
# type: (str, Optional[str], int, Callable[..., Any]) -> None
def add_propputref(
self, name: str, doc: _DocType, nargs: int, func: Callable[..., Any]
) -> None:
self._data.setdefault((name, doc, nargs), [None, None, None])[2] = func

def __iter__(self):
# type: () -> Iterator[Tuple[str, Optional[str], int, Optional[Callable[..., Any]], Optional[Callable[..., Any]]]]
def __iter__(self) -> Iterator[Tuple[str, _DocType, int, _PropFunc, _PropFunc]]:
for (name, doc, nargs), (fget, propput, propputref) in self._data.items():
if propput is not None and propputref is not None:
# Create a setter method that examines the argument type
Expand All @@ -269,13 +279,11 @@ def put_or_putref(self, *args):


class PropertyGenerator(object):
def __init__(self, cls_name):
# type: (str) -> None
def __init__(self, cls_name: str) -> None:
self._mapping = PropertyMapping()
self._cls_name = cls_name

def add(self, m, func):
# type: (_MemberSpec, Callable[..., Any]) -> None
def add(self, m: _MemberSpec, func: Callable[..., Any]) -> None:
"""Adds member spec and func to mapping."""
if "propget" in m.idlflags:
name, doc, nargs = self.to_propget_keys(m)
Expand All @@ -291,8 +299,7 @@ def add(self, m, func):

# The following code assumes that the docstrings for
# propget and propput are identical.
def __iter__(self):
# type: () -> Iterator[Tuple[str, _UnionT[property, named_property]]]
def __iter__(self) -> Iterator[Tuple[str, _UnionT[property, "named_property"]]]:
for name, doc, nargs, fget, fset in self._mapping:
if nargs == 0:
prop = property(fget, fset, None, doc)
Expand All @@ -303,75 +310,62 @@ def __iter__(self):
prop = named_property("%s.%s" % (self._cls_name, name), fget, fset, doc)
yield (name, prop)

def to_propget_keys(self, m):
# type: (_MemberSpec) -> Tuple[str, Optional[str], int]
def to_propget_keys(self, m: _MemberSpec) -> Tuple[str, _DocType, int]:
raise NotImplementedError

def to_propput_keys(self, m):
# type: (_MemberSpec) -> Tuple[str, Optional[str], int]
def to_propput_keys(self, m: _MemberSpec) -> Tuple[str, _DocType, int]:
raise NotImplementedError

def to_propputref_keys(self, m):
# type: (_MemberSpec) -> Tuple[str, Optional[str], int]
def to_propputref_keys(self, m: _MemberSpec) -> Tuple[str, _DocType, int]:
raise NotImplementedError


class ComPropertyGenerator(PropertyGenerator):
# XXX Hm. What, when paramflags is None?
# Or does have '0' values?
# Seems we loose then, at least for properties...
def to_propget_keys(self, m):
# type: (_ComMemberSpec) -> Tuple[str, Optional[str], int]
def to_propget_keys(self, m: _ComMemberSpec) -> Tuple[str, _DocType, int]:
assert m.name.startswith("_get_")
assert m.paramflags is not None
nargs = len([f for f in m.paramflags if f[0] & 7 in (0, 1)])
# XXX or should we do this?
# nargs = len([f for f in paramflags if (f[0] & 1) or (f[0] == 0)])
return m.name[len("_get_") :], m.doc, nargs

def to_propput_keys(self, m):
# type: (_ComMemberSpec) -> Tuple[str, Optional[str], int]
def to_propput_keys(self, m: _ComMemberSpec) -> Tuple[str, _DocType, int]:
assert m.name.startswith("_set_")
assert m.paramflags is not None
nargs = len([f for f in m.paramflags if f[0] & 7 in (0, 1)]) - 1
return m.name[len("_set_") :], m.doc, nargs

def to_propputref_keys(self, m):
# type: (_ComMemberSpec) -> Tuple[str, Optional[str], int]
def to_propputref_keys(self, m: _ComMemberSpec) -> Tuple[str, _DocType, int]:
assert m.name.startswith("_setref_")
assert m.paramflags is not None
nargs = len([f for f in m.paramflags if f[0] & 7 in (0, 1)]) - 1
return m.name[len("_setref_") :], m.doc, nargs


class DispPropertyGenerator(PropertyGenerator):
def to_propget_keys(self, m):
# type: (_DispMemberSpec) -> Tuple[str, Optional[str], int]
def to_propget_keys(self, m: _DispMemberSpec) -> Tuple[str, _DocType, int]:
return m.name, None, len(m.argspec)

def to_propput_keys(self, m):
# type: (_DispMemberSpec) -> Tuple[str, Optional[str], int]
def to_propput_keys(self, m: _DispMemberSpec) -> Tuple[str, _DocType, int]:
return m.name, None, len(m.argspec) - 1

def to_propputref_keys(self, m):
# type: (_DispMemberSpec) -> Tuple[str, Optional[str], int]
def to_propputref_keys(self, m: _DispMemberSpec) -> Tuple[str, _DocType, int]:
return m.name, None, len(m.argspec) - 1


class ComMemberGenerator(object):
def __init__(self, cls_name, vtbl_offset, iid):
# type: (str, int, comtypes.GUID) -> None
def __init__(self, cls_name: str, vtbl_offset: int, iid: comtypes.GUID) -> None:
self._vtbl_offset = vtbl_offset
self._iid = iid
self._props = ComPropertyGenerator(cls_name)
# sequence of (name: str, func: Callable, raw_func: Callable, is_prop: bool)
self._mths = (
[]
) # type: List[Tuple[str, Callable[..., Any], Callable[..., Any], bool]]
self._mths: List[Tuple[str, Callable[..., Any], Callable[..., Any], bool]] = []
self._member_index = 0

def add(self, m):
# type: (_ComMemberSpec) -> None
def add(self, m: _ComMemberSpec) -> None:
proto = ctypes.WINFUNCTYPE(m.restype, *m.argtypes)
# a low level unbound method calling the com method.
# attach it with a private name (__com_AddRef, for example),
Expand All @@ -390,8 +384,9 @@ def add(self, m):
self._mths.append((m.name, func, raw_func, is_prop))
self._member_index += 1

def _fix_args(self, m, func):
# type: (_ComMemberSpec, Callable[..., Any]) -> Callable[..., Any]
def _fix_args(
self, m: _ComMemberSpec, func: Callable[..., Any]
) -> Callable[..., Any]:
"""This is a workaround. See `_fix_inout_args` docstring and comments."""
if m.paramflags:
dirflags = [(p[0] & 3) for p in m.paramflags]
Expand All @@ -407,16 +402,12 @@ def properties(self):


class DispMemberGenerator(object):
def __init__(self, cls_name):
# type: (str) -> None
def __init__(self, cls_name: str) -> None:
self._props = DispPropertyGenerator(cls_name)
# sequence of (name: str, func_or_prop: Callable | property, is_prop: bool)
self._items = (
[]
) # type: List[Tuple[str, _UnionT[Callable[..., Any], property], bool]]
self._items: List[Tuple[str, _UnionT[Callable[..., Any], property], bool]] = []

def add(self, m):
# type: (_DispMemberSpec) -> None
def add(self, m: _DispMemberSpec) -> None:
if m.what == "DISPPROPERTY": # DISPPROPERTY
assert not m.argspec # XXX does not yet work for properties with parameters
is_prop = True
Expand All @@ -431,8 +422,7 @@ def add(self, m):
else:
self._items.append((m.name, func, is_prop))

def _make_disp_property(self, m):
# type: (_DispMemberSpec) -> property
def _make_disp_property(self, m: _DispMemberSpec) -> property:
# XXX doc string missing in property
memid = m.memid

Expand All @@ -451,8 +441,7 @@ def fset(obj, value):
return property(fget, fset)

# Should the funcs/mths we create have restype and/or argtypes attributes?
def _make_disp_method(self, m):
# type: (_DispMemberSpec) -> Callable[..., Any]
def _make_disp_method(self, m: _DispMemberSpec) -> Callable[..., Any]:
memid = m.memid
if "propget" in m.idlflags:

Expand Down