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

Reserving blank lines in the generated modules (part 3 of #745). #748

Merged
merged 3 commits into from
Jan 18, 2025
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
195 changes: 9 additions & 186 deletions comtypes/tools/codegenerator/codegenerator.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
import comtypes
from comtypes import typeinfo
from comtypes.tools import tlbparser, typedesc
from comtypes.tools.codegenerator import namespaces, packing, typeannotator
from comtypes.tools.codegenerator import heads, namespaces, packing
from comtypes.tools.codegenerator.comments import ComInterfaceBodyImplCommentWriter
from comtypes.tools.codegenerator.helpers import (
ASSUME_STRINGS,
Expand Down Expand Up @@ -124,8 +124,8 @@ def _generate_typelib_path(self, filename):
path = self._make_relative_path(filename, comtypes.gen.__path__[0])
self.imports.add("os")
definition = (
f"os.path.normpath(\n"
f" os.path.abspath(os.path.join(os.path.dirname(__file__),\n"
"os.path.normpath(\n"
" os.path.abspath(os.path.join(os.path.dirname(__file__),\n"
f" {path!r})))"
)
self.declarations.add("typelib_path", definition)
Expand Down Expand Up @@ -214,7 +214,7 @@ def generate_wrapper_code(
print(self._make_dunder_all_part(), file=output)
print(file=output)
if tlib_mtime is not None:
print("_check_version(%r, %f)" % (version, tlib_mtime), file=output)
print(f"_check_version({version!r}, {tlib_mtime:f})", file=output)
return output.getvalue()

def generate_friendly_code(self, modname: str) -> str:
Expand Down Expand Up @@ -284,13 +284,6 @@ def need_VARIANT_imports(self, value):
if "datetime.datetime(" in text:
self.imports.add("datetime")

def _to_docstring(self, orig: str, depth: int = 1) -> str:
# increasing `depth` by one increases indentation by one
indent = " " * depth
# some chars are replaced to avoid causing a `SyntaxError`
repled = orig.replace("\\", r"\\").replace('"', r"'")
return f'{indent}"""{repled}"""'

def ArrayType(self, tp: typedesc.ArrayType) -> None:
self.generate(get_real_type(tp.typ))
self.generate(tp.typ)
Expand Down Expand Up @@ -343,88 +336,8 @@ def StructureHead(self, head: typedesc.StructureHead) -> None:
self.more.add(struct)
if head.struct.location:
self.last_item_class = False
print(f"# {head.struct.location}", file=self.stream)
basenames = [self._to_type_name(b) for b in head.struct.bases]
if basenames:
self.imports.add("comtypes", "GUID")

if not self.last_item_class:
print(file=self.stream)
print(file=self.stream)

self.last_item_class = True

method_names = [
m.name for m in head.struct.members if type(m) is typedesc.Method
]
print(
f"class {head.struct.name}({', '.join(basenames)}):",
file=self.stream,
)
print(
" _iid_ = GUID('{}') # please look up iid and fill in!",
file=self.stream,
)
if "Enum" in method_names:
print(" def __iter__(self):", file=self.stream)
print(" return self.Enum()", file=self.stream)
elif method_names == "Next Skip Reset Clone".split():
print(" def __iter__(self):", file=self.stream)
print(" return self", file=self.stream)
print(file=self.stream)
print(" def next(self):", file=self.stream)
print(" arr, fetched = self.Next(1)", file=self.stream)
print(" if fetched == 0:", file=self.stream)
print(" raise StopIteration", file=self.stream)
print(" return arr[0]", file=self.stream)

print(file=self.stream)
print(file=self.stream)

else:
methods = [m for m in head.struct.members if type(m) is typedesc.Method]

if methods:
# Hm. We cannot generate code for IUnknown...
if not self.last_item_class:
print(file=self.stream)

self.last_item_class = True
print("assert 0, 'cannot generate code for IUnknown'", file=self.stream)
print(file=self.stream)
print(file=self.stream)
print(f"class {head.struct.name}(_com_interface):", file=self.stream)
print(" pass", file=self.stream)
print(file=self.stream)
print(file=self.stream)
elif type(head.struct) == typedesc.Structure:
if not self.last_item_class:
print(file=self.stream)
print(file=self.stream)

self.last_item_class = True

print(f"class {head.struct.name}(Structure):", file=self.stream)
if hasattr(head.struct, "_recordinfo_"):
print(
f" _recordinfo_ = {head.struct._recordinfo_!r}",
file=self.stream,
)
else:
print(" pass", file=self.stream)
print(file=self.stream)
print(file=self.stream)
elif type(head.struct) == typedesc.Union:
if not self.last_item_class:
print(file=self.stream)
print(file=self.stream)

self.last_item_class = True

print(f"class {head.struct.name}(Union):", file=self.stream)
print(" pass", file=self.stream)
print(file=self.stream)
print(file=self.stream)
heads.StructureHeadWriter(self.stream).write(head, basenames)
self.names.add(head.struct.name)

def Structure(self, struct: typedesc.Structure) -> None:
Expand Down Expand Up @@ -574,19 +487,7 @@ def TypeLib(self, lib: typedesc.TypeLib) -> None:

self.last_item_class = True

print("class Library(object):", file=self.stream)
if lib.doc:
print(self._to_docstring(lib.doc), file=self.stream)

if lib.name:
print(f" name = {lib.name!r}", file=self.stream)

print(
f" _reg_typelib_ = ({lib.guid!r}, {lib.major!r}, {lib.minor!r})",
file=self.stream,
)
print(file=self.stream)
print(file=self.stream)
heads.LibraryHeadWriter(self.stream).write(lib)
self.names.add("Library")

def External(self, ext: typedesc.External) -> None:
Expand Down Expand Up @@ -640,24 +541,7 @@ def CoClass(self, coclass: typedesc.CoClass) -> None:

self.last_item_class = True

print(f"class {coclass.name}(CoClass):", file=self.stream)
if coclass.doc:
print(self._to_docstring(coclass.doc), file=self.stream)
print(f" _reg_clsid_ = GUID({coclass.clsid!r})", file=self.stream)
print(f" _idlflags_ = {coclass.idlflags}", file=self.stream)
if self.filename is not None:
print(" _typelib_path_ = typelib_path", file=self.stream)
# X print
# >> self.stream, "POINTER(%s).__ctypes_from_outparam__ = wrap" % coclass.name

libid = coclass.tlibattr.guid
wMajor, wMinor = coclass.tlibattr.wMajorVerNum, coclass.tlibattr.wMinorVerNum
print(
f" _reg_typelib_ = ({str(libid)!r}, {wMajor}, {wMinor})",
file=self.stream,
)
print(file=self.stream)
print(file=self.stream)
heads.CoClassHeadWriter(self.stream, self.filename).write(coclass)

for itf, _ in coclass.interfaces:
self.generate(itf.get_head())
Expand Down Expand Up @@ -737,16 +621,6 @@ def _is_known_interface(
return self.known_interfaces[item.name] == item.iid
return False

def _is_enuminterface(self, itf: typedesc.ComInterface) -> bool:
# Check if this is an IEnumXXX interface
if not itf.name.startswith("IEnum"):
return False
member_names = [mth.name for mth in itf.members]
for name in ("Next", "Skip", "Reset", "Clone"):
if name not in member_names:
return False
return True

def ComInterfaceHead(self, head: typedesc.ComInterfaceHead) -> None:
if head.itf.base is None:
# we don't beed to generate IUnknown
Expand All @@ -763,43 +637,7 @@ def ComInterfaceHead(self, head: typedesc.ComInterfaceHead) -> None:

self.last_item_class = True

print(f"class {head.itf.name}({basename}):", file=self.stream)
if head.itf.doc:
print(self._to_docstring(head.itf.doc), file=self.stream)

print(" _case_insensitive_ = True", file=self.stream)
print(f" _iid_ = GUID({head.itf.iid!r})", file=self.stream)
print(f" _idlflags_ = {head.itf.idlflags}", file=self.stream)

if self._is_enuminterface(head.itf):
print(file=self.stream)
print(" def __iter__(self):", file=self.stream)
print(" return self", file=self.stream)
print(file=self.stream)

print(" def __next__(self):", file=self.stream)
print(" item, fetched = self.Next(1)", file=self.stream)
print(" if fetched:", file=self.stream)
print(" return item", file=self.stream)
print(" raise StopIteration", file=self.stream)
print(file=self.stream)

print(" def __getitem__(self, index):", file=self.stream)
print(" self.Reset()", file=self.stream)
print(" self.Skip(index)", file=self.stream)
print(" item, fetched = self.Next(1)", file=self.stream)
print(" if fetched:", file=self.stream)
print(" return item", file=self.stream)
print(" raise IndexError(index)", file=self.stream)

annotations = typeannotator.ComInterfaceMembersAnnotator(head.itf).generate()
if annotations:
print(file=self.stream)
print(" if TYPE_CHECKING: # commembers", file=self.stream)
print(annotations, file=self.stream)

print(file=self.stream)
print(file=self.stream)
heads.ComInterfaceHeadWriter(self.stream).write(head, basename)

def ComInterfaceBody(self, body: typedesc.ComInterfaceBody) -> None:
# The base class must be fully generated, including the
Expand Down Expand Up @@ -843,22 +681,7 @@ def DispInterfaceHead(self, head: typedesc.DispInterfaceHead) -> None:

self.last_item_class = True

print(f"class {head.itf.name}({basename}):", file=self.stream)
if head.itf.doc:
print(self._to_docstring(head.itf.doc), file=self.stream)
print(" _case_insensitive_ = True", file=self.stream)
print(f" _iid_ = GUID({head.itf.iid!r})", file=self.stream)
print(f" _idlflags_ = {head.itf.idlflags}", file=self.stream)
print(" _methods_ = []", file=self.stream)

annotations = typeannotator.DispInterfaceMembersAnnotator(head.itf).generate()
if annotations:
print(file=self.stream)
print(" if TYPE_CHECKING: # dispmembers", file=self.stream)
print(annotations, file=self.stream)

print(file=self.stream)
print(file=self.stream)
heads.DispInterfaceHeadWriter(self.stream).write(head, basename)

def DispInterfaceBody(self, body: typedesc.DispInterfaceBody) -> None:
# make sure we can generate the body
Expand Down
2 changes: 1 addition & 1 deletion comtypes/tools/codegenerator/comments.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ def write(self, body: typedesc.ComInterfaceBody) -> None:
# m.arguments is a sequence of tuples:
# (argtype, argname, idlflags, docstring)
# Some typelibs have unnamed method parameters!
inargs = [a[1] or "<unnamed>" for a in m.arguments if not "out" in a[2]]
inargs = [a[1] or "<unnamed>" for a in m.arguments if "out" not in a[2]]
outargs = [a[1] or "<unnamed>" for a in m.arguments if "out" in a[2]]
if "propget" in m.idlflags:
methods.setdefault(m.name, [0, inargs, outargs, m.doc])[0] |= 1
Expand Down
Loading
Loading