Skip to content

Commit

Permalink
Improve typings in server/register.py. (enthought#734)
Browse files Browse the repository at this point in the history
* Add more type annotations to `server/register.py`.

* Remove `Set = set` from `server/register.py`

* Fix `_non_zero`.
Because "The object that this function returns will be returned from the foreign function call".
https://docs.python.org/3/library/ctypes.html#ctypes._CFuncPtr.errcheck

* Add `# type: ignore`.

* Improve importing `_ctypes`.
  • Loading branch information
junkmd authored Jan 7, 2025
1 parent 781e8e2 commit bd40642
Showing 1 changed file with 20 additions and 22 deletions.
42 changes: 20 additions & 22 deletions comtypes/server/register.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,14 @@
python mycomobj.py /nodebug
"""

import _ctypes
import ctypes
import logging
import os
import sys
import winreg
from ctypes import WinError, windll
from typing import Iterator, Tuple
from typing import Iterator, List, Optional, Tuple, Type, Union

import comtypes
import comtypes.server.inprocserver
Expand All @@ -58,7 +59,7 @@
_debug = logging.getLogger(__name__).debug


def get_winerror(exception):
def get_winerror(exception: OSError) -> Optional[int]:
try:
return exception.winerror
except AttributeError:
Expand All @@ -69,14 +70,13 @@ def get_winerror(exception):
def _non_zero(retval, func, args):
if retval:
raise WinError(retval)
return retval


SHDeleteKey = windll.shlwapi.SHDeleteKeyW
SHDeleteKey.errcheck = _non_zero
SHDeleteKey.argtypes = ctypes.c_ulong, ctypes.c_wchar_p

Set = set


_KEYS = {
winreg.HKEY_CLASSES_ROOT: "HKCR",
Expand All @@ -85,7 +85,7 @@ def _non_zero(retval, func, args):
}


def _explain(hkey):
def _explain(hkey: int) -> Union[str, int]:
return _KEYS.get(hkey, hkey)


Expand All @@ -99,7 +99,7 @@ class Registrar(object):
work.
"""

def nodebug(self, cls):
def nodebug(self, cls: Type) -> None:
"""Delete logging entries from the registry."""
clsid = cls._reg_clsid_
try:
Expand All @@ -113,7 +113,7 @@ def nodebug(self, cls):
if get_winerror(detail) != 2:
raise

def debug(self, cls, levels, format):
def debug(self, cls: Type, levels: List[str], format: Optional[str]) -> None:
"""Write entries in the registry to setup logging for this clsid."""
# handlers
# format
Expand All @@ -140,7 +140,7 @@ def debug(self, cls, levels, format):
if get_winerror(detail) != 2:
raise

def register(self, cls, executable=None):
def register(self, cls: Type, executable: Optional[str] = None) -> None:
"""Register the COM server class."""
# First, we unregister the object with force=True, to force removal
# of all registry entries, even if we would not write them.
Expand All @@ -153,7 +153,7 @@ def register(self, cls, executable=None):
self._unregister(cls, force=True)
self._register(cls, executable)

def _register(self, cls, executable=None):
def _register(self, cls: Type, executable: Optional[str] = None) -> None:
table = sorted(RegistryEntries(cls))
_debug("Registering %s", cls)
for hkey, subkey, valuename, value in table:
Expand All @@ -179,15 +179,15 @@ def _register(self, cls, executable=None):
LoadTypeLibEx(path, REGKIND_REGISTER)
_debug("Done")

def unregister(self, cls, force=False):
def unregister(self, cls: Type, force: bool = False) -> None:
"""Unregister the COM server class."""
mth = getattr(cls, "_unregister", None)
if mth is not None:
mth(self)
else:
self._unregister(cls, force=force)

def _unregister(self, cls, force=False):
def _unregister(self, cls: Type, force: bool = False) -> None:
# If force==False, we only remove those entries that we
# actually would have written. It seems ATL does the same.
table = [t[:2] for t in RegistryEntries(cls)]
Expand Down Expand Up @@ -221,31 +221,29 @@ def _unregister(self, cls, force=False):
_debug("Done")


def _get_serverdll():
def _get_serverdll() -> str:
"""Return the pathname of the dll hosting the COM object."""
handle = getattr(sys, "frozendllhandle", None)
if handle is not None:
return GetModuleFileName(handle, 260)
import _ctypes

return _ctypes.__file__


class RegistryEntries(object):
def __init__(self, cls):
def __init__(self, cls: Type) -> None:
self._cls = cls

def _get_full_classname(self, cls):
def _get_full_classname(self, cls: Type) -> str:
"""Return <modulename>.<classname> for 'cls'."""
modname = cls.__module__
if modname == "__main__":
modname = os.path.splitext(os.path.basename(sys.argv[0]))[0]
return f"{modname}.{cls.__name__}"

def _get_pythonpath(self, cls):
def _get_pythonpath(self, cls: Type) -> str:
"""Return the filesystem path of the module containing 'cls'."""
modname = cls.__module__
dirname = os.path.dirname(sys.modules[modname].__file__)
dirname = os.path.dirname(sys.modules[modname].__file__) # type: ignore
return os.path.abspath(dirname)

def __iter__(self) -> Iterator[Tuple[int, str, str, str]]:
Expand Down Expand Up @@ -321,7 +319,7 @@ def __iter__(self) -> Iterator[Tuple[int, str, str, str]]:
if not hasattr(sys, "frozen"):
if not __debug__:
exe = f"{exe} -O"
script = os.path.abspath(sys.modules[cls.__module__].__file__)
script = os.path.abspath(sys.modules[cls.__module__].__file__) # type: ignore
if " " in script:
script = f'"{script}"'
yield (HKCR, rf"CLSID\{reg_clsid}\LocalServer32", "", f"{exe} {script}")
Expand Down Expand Up @@ -367,15 +365,15 @@ def __iter__(self) -> Iterator[Tuple[int, str, str, str]]:
################################################################


def register(cls):
def register(cls: Type) -> None:
Registrar().register(cls)


def unregister(cls):
def unregister(cls: Type) -> None:
Registrar().unregister(cls)


def UseCommandLine(*classes):
def UseCommandLine(*classes: Type) -> int:
usage = f"""Usage: {sys.argv[0]} [-regserver] [-unregserver] [-nodebug] [-f logformat] [-l loggername=level]"""
opts, args = w_getopt.w_getopt(
sys.argv[1:], "regserver unregserver embedding l: f: nodebug"
Expand Down

0 comments on commit bd40642

Please sign in to comment.