diff --git a/src/mo2/stubs/generator/__main__.py b/src/mo2/stubs/generator/__main__.py index 0c1d05f..722ce45 100644 --- a/src/mo2/stubs/generator/__main__.py +++ b/src/mo2/stubs/generator/__main__.py @@ -12,15 +12,15 @@ from .mtypes import Class, Constant, Enum, Function, PyTyping from .parser import is_enum from .register import MobaseRegister from .utils import Settings, clean_class -from .writer import Writer, is_list_of_functions +from .writer import Writer, is_list_of LOGGER = logging.getLogger(__package__) def extract_objects( module: object, skips: Sequence[str] = [] -) -> list[tuple[str, type]]: - objects: list[tuple[str, type]] = [] +) -> list[tuple[str, object]]: + objects: list[tuple[str, object]] = [] assert hasattr(module, "__name__") module_name: str = module.__name__ # type: ignore @@ -140,7 +140,7 @@ def main() -> None: } # list of objects directly in mobase - module_objects: dict[str, list[tuple[str, type]]] = { + module_objects: dict[str, list[tuple[str, object]]] = { "mobase": extract_objects( mobase, [ @@ -181,7 +181,7 @@ def main() -> None: elif isinstance(c, (PyTyping, Constant)): ... - elif is_list_of_functions(c): + elif is_list_of(c, Function): settings.patch_functions(c) else: diff --git a/src/mo2/stubs/generator/parser.py b/src/mo2/stubs/generator/parser.py index 46fee9e..0ca335d 100644 --- a/src/mo2/stubs/generator/parser.py +++ b/src/mo2/stubs/generator/parser.py @@ -4,7 +4,7 @@ import re import types from collections import OrderedDict, defaultdict from itertools import chain -from typing import Any, Iterable, cast +from typing import Any, Callable, Iterable, cast from .mtypes import ( Argument, @@ -118,7 +118,7 @@ def parse_python_signature(s: str, name: str) -> tuple[PyType, list[Argument]]: return PyType(return_type), arguments -def is_enum(e: type) -> bool: +def is_enum(e: object) -> bool: """Check if the given class is an enumeration. Args: @@ -144,17 +144,18 @@ class Overload: self.arguments = arguments -def parse_pybind11_function_docstring(e: type) -> list[Overload]: +def parse_pybind11_function_docstring(name: str, doc: str | None) -> list[Overload]: """ - Parse the docstring of the given element. + Parse the docstring of a Pybind11 function. Args: - e: The function to "parse". + name: Name of the function. + doc: The docstring of the function generated by Pybind11. Returns: A list of overloads for the given function. """ - lines = (e.__doc__ or "").strip().split("\n") + lines = (doc or "").strip().split("\n") signatures: list[str] if len(lines) == 1: @@ -162,7 +163,7 @@ def parse_pybind11_function_docstring(e: type) -> list[Overload]: else: signatures = [] for line in lines: - m = re.match(rf"^[0-9]+[.]\s+({e.__name__}.*)$", line) + m = re.match(rf"^[0-9]+[.]\s+({name}.*)$", line) if m: signatures.append(m.group(1).strip()) @@ -174,16 +175,16 @@ def parse_pybind11_function_docstring(e: type) -> list[Overload]: signature = signature.replace("MOBase::", "mobase.").replace("::", ".") try: - return_type, arguments = parse_python_signature(signature, e.__name__) + return_type, arguments = parse_python_signature(signature, name) except ValueError as err: - raise ValueError(f"invalid signature: {e.__name__}, {e.__doc__}") from err + raise ValueError(f"invalid signature: {name}, {doc}") from err overloads.append(Overload(return_type=return_type, arguments=arguments)) return overloads -def make_functions(e: type) -> list[Function]: - overloads = parse_pybind11_function_docstring(e) +def make_functions(e: Callable[..., Any]) -> list[Function]: + overloads = parse_pybind11_function_docstring(e.__name__, e.__doc__) return [ Function( @@ -295,7 +296,9 @@ def make_class(e: type, register: MobaseRegister) -> Class: # otherwise we parse the docstring else: - overloads = parse_pybind11_function_docstring(method) + overloads = parse_pybind11_function_docstring( + method.__name__, method.__doc__ + ) for overload in overloads: args = overload.arguments diff --git a/src/mo2/stubs/generator/register.py b/src/mo2/stubs/generator/register.py index 560df95..63adb7d 100644 --- a/src/mo2/stubs/generator/register.py +++ b/src/mo2/stubs/generator/register.py @@ -15,14 +15,14 @@ class MobaseRegister: objects: dict[str, Class | Constant | list[Function] | PyTyping] def __init__(self) -> None: - self.raw_objects: dict[str, type] = OrderedDict() + self.raw_objects: dict[str, object] = OrderedDict() self.objects = {} - def add_object(self, name: str, object: type) -> None: - self.raw_objects[name] = object + def add_object(self, n: str, o: object, /) -> None: + self.raw_objects[n] = o def make_object( - self, name: str, e: type | None = None + self, name: str, e: object | None = None ) -> Class | list[Function] | Constant | PyTyping: """ Construct a Function, Class, Constant or Enum for the given object. diff --git a/src/mo2/stubs/generator/utils.py b/src/mo2/stubs/generator/utils.py index 77b2dab..30e86ad 100644 --- a/src/mo2/stubs/generator/utils.py +++ b/src/mo2/stubs/generator/utils.py @@ -215,7 +215,7 @@ class Settings: # Check the args: if function_settings.args is not None: if len(function_settings.args) != len(fn.args): - LOGGER.warn( + LOGGER.warning( f"Mismatch number of arguments for function " f"mobase.{setting_name}." ) @@ -243,7 +243,7 @@ class Settings: fn.deprecated = function_settings.deprecated else: - LOGGER.warn( + LOGGER.warning( "Missing settings for function mobase.{}.".format(setting_name) ) @@ -268,7 +268,7 @@ class Settings: class_settings = self._get_class_settings(cls.canonical_name) if class_settings is None: - LOGGER.warn("Class {} not found in settings.".format(cls.canonical_name)) + LOGGER.warning("Class {} not found in settings.".format(cls.canonical_name)) return if "__doc__" in class_settings and class_settings["__doc__"] is not None: @@ -306,7 +306,7 @@ class Settings: if "type" in settings_property: prop.type = PyType(settings_property["type"]) else: - LOGGER.warn( + LOGGER.warning( "Missing type for property {}.{}.".format( cls.canonical_name, prop.name ) @@ -320,7 +320,7 @@ class Settings: prop.doc = settings_property["desc"] else: - LOGGER.warn( + LOGGER.warning( "Missing description for property {}.{}.".format( cls.canonical_name, prop.name ) @@ -366,7 +366,7 @@ class Settings: if function_settings.args is not None: method_arguments = m.args if m.is_static() else m.args[1:] if len(function_settings.args) != len(method_arguments): - LOGGER.warn( + LOGGER.warning( "Mismatch number of arguments for method {}.{}.".format( cls.canonical_name, settings_name ) @@ -380,7 +380,7 @@ class Settings: not method_arg.name.startswith("arg") and method_arg.name != settings_arg.name ): - LOGGER.warn( + LOGGER.warning( ( "Mismatch argument name for method {}.{}: " "{} {}, using {}." @@ -429,7 +429,7 @@ class Settings: if n_overloads > 0 and missing_settings: for settings_name in missing_settings: - LOGGER.warn( + LOGGER.warning( "Missing settings for method {}.{}.".format( cls.canonical_name, settings_name ) @@ -447,7 +447,7 @@ class Settings: # Print items missing in mobase missing_items = [k for k, v in keys.items() if not v] if missing_items: - LOGGER.warn( + LOGGER.warning( "The following members were found in settings but not in the actual" " class {}: {}.".format(cls.canonical_name, ", ".join(missing_items)) ) diff --git a/src/mo2/stubs/generator/writer.py b/src/mo2/stubs/generator/writer.py index 5efb8b1..923bcf5 100644 --- a/src/mo2/stubs/generator/writer.py +++ b/src/mo2/stubs/generator/writer.py @@ -1,5 +1,5 @@ import logging -from typing import Any, Iterable, TextIO +from typing import Any, TextIO from typing_extensions import TypeIs @@ -9,10 +9,12 @@ from .utils import Settings LOGGER = logging.getLogger(__package__) -def is_list_of_functions(e: Any | Iterable[Any]) -> TypeIs[list[Function]]: - if not isinstance(e, list): - return False - return all(isinstance(x, Function) for x in e) +def is_list_of_any(e: Any) -> TypeIs[list[Any]]: + return isinstance(e, list) + + +def is_list_of[T](e: Any, t: type[T]) -> TypeIs[list[T]]: + return is_list_of_any(e) and all(isinstance(x, t) for x in e) class Writer: @@ -270,7 +272,7 @@ class Writer: if isinstance(e, Class): self.print_class(e) - elif is_list_of_functions(e): + elif is_list_of(e, Function): for fn in e: self.print_function(fn)