Clean up dead code, fix type errors, and add publish workflow

Remove unused _append_ops_call_method, fix _property_data_from_member
call signature, replace sys.version_info guard with hasattr check for
__buffer__ protocol, fix implicit string concatenations, add msgbus
overrides for 4.0-4.4, add conformance tests, and add publish script.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-03 11:07:52 +02:00
co-authored by Claude Opus 4.6
parent 673b9e54bc
commit f4df542dd1
17 changed files with 954 additions and 165 deletions
+30 -5
View File
@@ -1,8 +1,9 @@
"""Tests for the introspection module."""
from typing_extensions import override
import unittest
from types import SimpleNamespace
from typing import cast
from typing import cast, final
from unittest.mock import patch
from introspect import (
@@ -134,6 +135,14 @@ class TestParseDocstringTypes(unittest.TestCase):
def test_module_maps_to_types_moduletype(self) -> None:
self.assertEqual(clean_type_str("Module"), "types.ModuleType")
self.assertEqual(clean_type_str("Module | None"), "types.ModuleType | None")
self.assertEqual(clean_type_str("module"), "types.ModuleType")
def test_old_typing_names_to_builtins(self) -> None:
self.assertEqual(clean_type_str("Dict[str, int]"), "dict[str, int]")
self.assertEqual(clean_type_str("Set[int]"), "set[int]")
self.assertEqual(clean_type_str("List[str]"), "list[str]")
self.assertEqual(clean_type_str("Tuple[int, str]"), "tuple[int, str]")
self.assertEqual(clean_type_str("FrozenSet[int]"), "frozenset[int]")
def test_nonetype_maps_to_none(self) -> None:
self.assertEqual(clean_type_str("NoneType"), "None")
@@ -225,6 +234,17 @@ class TestParseDocstringTypes(unittest.TestCase):
def test_callable_empty_params_preserved(self) -> None:
self.assertEqual(clean_type_str("Callable[[], None]"), "Callable[[], None]")
def test_callable_ellipsis_params_no_double_comma(self) -> None:
# Callable[[...], X] should become Callable[..., X] without double comma
self.assertEqual(
clean_type_str("Callable[[...], str | None]"),
"Callable[..., str | None]",
)
self.assertEqual(
clean_type_str("Callable[[...], object]"),
"Callable[..., object]",
)
def test_bare_generic_no_false_match(self) -> None:
# \bSequence\b should not match inside SequenceEntry
self.assertEqual(clean_type_str("SequenceEntry"), "SequenceEntry")
@@ -394,7 +414,7 @@ class TestParamNameMismatch(unittest.TestCase):
def fake_func(object: object) -> str: # noqa: A002
""":type string: str
:rtype: str"""
return ""
return str(object)
result = introspect_callable(fake_func, "escape_identifier")
self.assertIsNotNone(result)
@@ -406,7 +426,7 @@ class TestParamNameMismatch(unittest.TestCase):
def fake_func(path: str) -> str:
""":type path: str
:rtype: str"""
return ""
return path
result = introspect_callable(fake_func, "basename")
self.assertIsNotNone(result)
@@ -560,8 +580,9 @@ class TestInferGetterReturnTypes(unittest.TestCase):
class _ContextWithRaisingMember:
ok = 7
ok: int = 7
@override
def __dir__(self) -> list[str]:
return ["ok", "broken", "callable_member", "rna_type"]
@@ -574,20 +595,24 @@ class _ContextWithRaisingMember:
class _OpsNoCallableSubmodule:
non_callable = 123
non_callable: int = 123
@override
def __dir__(self) -> list[str]:
return ["non_callable"]
@final
class _OpsRootNoCallable:
mesh = _OpsNoCallableSubmodule()
@override
def __dir__(self) -> list[str]:
return ["mesh"]
class _OpsRootEmpty:
@override
def __dir__(self) -> list[str]:
return []