Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-typeguard for openSUSE:Factory checked in at 2025-03-06 14:48:09 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-typeguard (Old) and /work/SRC/openSUSE:Factory/.python-typeguard.new.19136 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-typeguard" Thu Mar 6 14:48:09 2025 rev:9 rq:1250003 version:4.4.2 Changes: -------- --- /work/SRC/openSUSE:Factory/python-typeguard/python-typeguard.changes 2024-11-21 15:13:54.553685669 +0100 +++ /work/SRC/openSUSE:Factory/.python-typeguard.new.19136/python-typeguard.changes 2025-03-06 14:48:35.341088108 +0100 @@ -1,0 +2,17 @@ +Tue Mar 4 09:14:50 UTC 2025 - Nico Krapp <nico.kr...@suse.com> + +- drop unneeded dependency + +------------------------------------------------------------------- +Fri Feb 28 09:51:28 UTC 2025 - John Paul Adrian Glaubitz <adrian.glaub...@suse.com> + +- Update to 4.4.2 + * Fixed ``TypeCheckError`` in unpacking assignment involving + properties of a parameter of the function + * Fixed display of module name for forward references + * Fixed ``TypeError`` when using an assignment expression + * Fixed ``ValueError: no signature found for builtin`` when + checking against a protocol and a matching attribute in the + subject is a built-in function + +------------------------------------------------------------------- Old: ---- typeguard-4.4.1-gh.tar.gz New: ---- typeguard-4.4.2-gh.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-typeguard.spec ++++++ --- /var/tmp/diff_new_pack.pI4pOB/_old 2025-03-06 14:48:37.313170810 +0100 +++ /var/tmp/diff_new_pack.pI4pOB/_new 2025-03-06 14:48:37.317170977 +0100 @@ -1,7 +1,7 @@ # # spec file for package python-typeguard # -# Copyright (c) 2024 SUSE LLC +# Copyright (c) 2025 SUSE LLC # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -18,7 +18,7 @@ %{?sle15_python_module_pythons} Name: python-typeguard -Version: 4.4.1 +Version: 4.4.2 Release: 0 Summary: Library for runtime checking of Python types License: MIT @@ -33,7 +33,6 @@ BuildRequires: fdupes BuildRequires: python-rpm-macros BuildArch: noarch -Requires: python-importlib-metadata >= 3.6 Requires: python-typing-extensions >= 4.10.0 %python_subpackages ++++++ typeguard-4.4.1-gh.tar.gz -> typeguard-4.4.2-gh.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/typeguard-4.4.1/.github/workflows/test.yml new/typeguard-4.4.2/.github/workflows/test.yml --- old/typeguard-4.4.1/.github/workflows/test.yml 2024-11-03 13:04:35.000000000 +0100 +++ new/typeguard-4.4.2/.github/workflows/test.yml 2025-02-16 17:27:08.000000000 +0100 @@ -10,7 +10,7 @@ strategy: fail-fast: false matrix: - python-version: ["3.9", "3.10", "3.11", "3.12", "3.13", pypy-3.10] + python-version: ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14", pypy-3.10] runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/typeguard-4.4.1/.pre-commit-config.yaml new/typeguard-4.4.2/.pre-commit-config.yaml --- old/typeguard-4.4.1/.pre-commit-config.yaml 2024-11-03 13:04:35.000000000 +0100 +++ new/typeguard-4.4.2/.pre-commit-config.yaml 2025-02-16 17:27:08.000000000 +0100 @@ -14,14 +14,14 @@ - id: trailing-whitespace - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.7.2 + rev: v0.8.6 hooks: - id: ruff args: [--fix, --show-fixes] - id: ruff-format - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.13.0 + rev: v1.14.1 hooks: - id: mypy additional_dependencies: [ "typing_extensions" ] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/typeguard-4.4.1/docs/versionhistory.rst new/typeguard-4.4.2/docs/versionhistory.rst --- old/typeguard-4.4.1/docs/versionhistory.rst 2024-11-03 13:04:35.000000000 +0100 +++ new/typeguard-4.4.2/docs/versionhistory.rst 2025-02-16 17:27:08.000000000 +0100 @@ -4,6 +4,19 @@ This library adheres to `Semantic Versioning 2.0 <https://semver.org/#semantic-versioning-200>`_. +**4.4.2** (2025-02-16) + +- Fixed ``TypeCheckError`` in unpacking assignment involving properties of a parameter + of the function (`#506 <https://github.com/agronholm/typeguard/issues/506>`_; + regression introduced in v4.4.1) +- Fixed display of module name for forward references + (`#492 <https://github.com/agronholm/typeguard/pull/492>`_; PR by @JelleZijlstra) +- Fixed ``TypeError`` when using an assignment expression + (`#510 <https://github.com/agronholm/typeguard/issues/510>`_; PR by @JohannesK71083) +- Fixed ``ValueError: no signature found for builtin`` when checking against a protocol + and a matching attribute in the subject is a built-in function + (`#504 <https://github.com/agronholm/typeguard/issues/504>`_) + **4.4.1** (2024-11-03) - Dropped Python 3.8 support @@ -22,9 +35,6 @@ - Fixed checks against annotations wrapped in ``NotRequired`` not being run unless the ``NotRequired`` is a forward reference (`#454 <https://github.com/agronholm/typeguard/issues/454>`_) -- Fixed the ``pytest_ignore_collect`` hook in the pytest plugin blocking default pytest - collection ignoring behavior by returning ``None`` instead of ``False`` - (PR by @mgorny) **4.4.0** (2024-10-27) @@ -32,8 +42,6 @@ (`#465 <https://github.com/agronholm/typeguard/pull/465>`_) - Fixed basic support for intersection protocols (`#490 <https://github.com/agronholm/typeguard/pull/490>`_; PR by @antonagestam) -- Fixed protocol checks running against the class of an instance and not the instance - itself (this produced wrong results for non-method member checks) **4.3.0** (2024-05-27) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/typeguard-4.4.1/pyproject.toml new/typeguard-4.4.2/pyproject.toml --- old/typeguard-4.4.1/pyproject.toml 2024-11-03 13:04:35.000000000 +0100 +++ new/typeguard-4.4.2/pyproject.toml 2025-02-16 17:27:08.000000000 +0100 @@ -22,6 +22,7 @@ "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3.14", ] requires-python = ">= 3.9" dependencies = [ @@ -99,7 +100,7 @@ pretty = true [tool.tox] -env_list = ["py39", "py310", "py311", "py312", "py313"] +env_list = ["py39", "py310", "py311", "py312", "py313", "py314"] skip_missing_interpreters = true [tool.tox.env_run_base] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/typeguard-4.4.1/src/typeguard/_checkers.py new/typeguard-4.4.2/src/typeguard/_checkers.py --- old/typeguard-4.4.1/src/typeguard/_checkers.py 2024-11-03 13:04:35.000000000 +0100 +++ new/typeguard-4.4.2/src/typeguard/_checkers.py 2025-02-16 17:27:08.000000000 +0100 @@ -533,7 +533,7 @@ ) -> None: if origin_type.__bound__ is not None: annotation = ( - Type[origin_type.__bound__] if subclass_check else origin_type.__bound__ + type[origin_type.__bound__] if subclass_check else origin_type.__bound__ ) check_type_internal(value, annotation, memo) elif origin_type.__constraints__: @@ -648,7 +648,12 @@ def check_signature_compatible(subject: type, protocol: type, attrname: str) -> None: - subject_sig = inspect.signature(getattr(subject, attrname)) + subject_attr = getattr(subject, attrname) + try: + subject_sig = inspect.signature(subject_attr) + except ValueError: + return # this can happen with builtins where the signature cannot be retrieved + protocol_sig = inspect.signature(getattr(protocol, attrname)) protocol_type: typing.Literal["instance", "class", "static"] = "instance" subject_type: typing.Literal["instance", "class", "static"] = "instance" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/typeguard-4.4.1/src/typeguard/_decorators.py new/typeguard-4.4.2/src/typeguard/_decorators.py --- old/typeguard-4.4.1/src/typeguard/_decorators.py 2024-11-03 13:04:35.000000000 +0100 +++ new/typeguard-4.4.2/src/typeguard/_decorators.py 2025-02-16 17:27:08.000000000 +0100 @@ -117,7 +117,10 @@ new_function.__module__ = f.__module__ new_function.__name__ = f.__name__ new_function.__qualname__ = f.__qualname__ - new_function.__annotations__ = f.__annotations__ + if sys.version_info >= (3, 14): + new_function.__annotate__ = f.__annotate__ + else: + new_function.__annotations__ = f.__annotations__ new_function.__doc__ = f.__doc__ new_function.__defaults__ = f.__defaults__ new_function.__kwdefaults__ = f.__kwdefaults__ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/typeguard-4.4.1/src/typeguard/_transformer.py new/typeguard-4.4.2/src/typeguard/_transformer.py --- old/typeguard-4.4.1/src/typeguard/_transformer.py 2024-11-03 13:04:35.000000000 +0100 +++ new/typeguard-4.4.2/src/typeguard/_transformer.py 2025-02-16 17:27:08.000000000 +0100 @@ -1073,8 +1073,9 @@ path.insert(0, exp.id) name = prefix + ".".join(path) - annotation = self._memo.variable_annotations.get(exp.id) - if annotation: + if len(path) == 1 and ( + annotation := self._memo.variable_annotations.get(exp.id) + ): annotations_.append((Constant(name), annotation)) check_required = True else: @@ -1137,8 +1138,20 @@ func_name, [ node.value, - Constant(node.target.id), - annotation, + List( + [ + List( + [ + Tuple( + [Constant(node.target.id), annotation], + ctx=Load(), + ) + ], + ctx=Load(), + ) + ], + ctx=Load(), + ), self._memo.get_memo_name(), ], [], diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/typeguard-4.4.1/src/typeguard/_utils.py new/typeguard-4.4.2/src/typeguard/_utils.py --- old/typeguard-4.4.1/src/typeguard/_utils.py 2024-11-03 13:04:35.000000000 +0100 +++ new/typeguard-4.4.2/src/typeguard/_utils.py 2025-02-16 17:27:08.000000000 +0100 @@ -11,7 +11,15 @@ if TYPE_CHECKING: from ._memo import TypeCheckMemo -if sys.version_info >= (3, 13): +if sys.version_info >= (3, 14): + from typing import get_args, get_origin + + def evaluate_forwardref(forwardref: ForwardRef, memo: TypeCheckMemo) -> Any: + return forwardref.evaluate( + globals=memo.globals, locals=memo.locals, type_params=() + ) + +elif sys.version_info >= (3, 13): from typing import get_args, get_origin def evaluate_forwardref(forwardref: ForwardRef, memo: TypeCheckMemo) -> Any: @@ -85,7 +93,11 @@ name += f"[{formatted_args}]" - module = getattr(type_, "__module__", None) + # For ForwardRefs, use the module stored on the object if available + if hasattr(type_, "__forward_module__"): + module = type_.__forward_module__ + else: + module = getattr(type_, "__module__", None) if module and module not in (None, "typing", "typing_extensions", "builtins"): name = module + "." + name diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/typeguard-4.4.1/tests/deferredannos.py new/typeguard-4.4.2/tests/deferredannos.py --- old/typeguard-4.4.1/tests/deferredannos.py 1970-01-01 01:00:00.000000000 +0100 +++ new/typeguard-4.4.2/tests/deferredannos.py 2025-02-16 17:27:08.000000000 +0100 @@ -0,0 +1,10 @@ +from typeguard import typechecked + + +@typechecked +def uses_forwardref(x: NotYetDefined) -> NotYetDefined: # noqa: F821 + return x + + +class NotYetDefined: + pass diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/typeguard-4.4.1/tests/dummymodule.py new/typeguard-4.4.2/tests/dummymodule.py --- old/typeguard-4.4.1/tests/dummymodule.py 2024-11-03 13:04:35.000000000 +0100 +++ new/typeguard-4.4.2/tests/dummymodule.py 2025-02-16 17:27:08.000000000 +0100 @@ -74,6 +74,9 @@ @typechecked class DummyClass(metaclass=Metaclass): + bar: str + baz: int + def type_checked_method(self, x: int, y: int) -> int: return x * y @@ -270,6 +273,11 @@ return x, y, z +@typechecked +def attribute_assign_unpacking(obj: DummyClass) -> None: + obj.bar, obj.baz = "foo", 123123 + + @typechecked(forward_ref_policy=ForwardRefPolicy.ERROR) def override_forward_ref_policy(value: "NonexistentType") -> None: # noqa: F821 pass diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/typeguard-4.4.1/tests/mypy/test_type_annotations.py new/typeguard-4.4.2/tests/mypy/test_type_annotations.py --- old/typeguard-4.4.1/tests/mypy/test_type_annotations.py 2024-11-03 13:04:35.000000000 +0100 +++ new/typeguard-4.4.2/tests/mypy/test_type_annotations.py 2025-02-16 17:27:08.000000000 +0100 @@ -1,14 +1,12 @@ +import json import os import platform -import re import subprocess -from typing import Dict, List import pytest POSITIVE_FILE = "positive.py" NEGATIVE_FILE = "negative.py" -LINE_PATTERN = NEGATIVE_FILE + ":([0-9]+):" pytestmark = [ pytest.mark.skipif( @@ -18,8 +16,8 @@ ] -def get_mypy_cmd(filename: str) -> List[str]: - return ["mypy", "--strict", filename] +def get_mypy_cmd(filename: str) -> list[str]: + return ["mypy", "-O", "json", "--strict", filename] def get_negative_mypy_output() -> str: @@ -34,7 +32,7 @@ return output -def get_expected_errors() -> Dict[int, str]: +def get_expected_errors() -> dict[int, str]: """ Extract the expected errors from comments in the negative examples file. """ @@ -46,14 +44,14 @@ for idx, line in enumerate(lines): line = line.rstrip() if "# error" in line: - expected[idx + 1] = line[line.index("# error") + 2 :] + expected[idx + 1] = line[line.index("# error") + 9 :] # Sanity check. Should update if negative.py changes. assert len(expected) == 9 return expected -def get_mypy_errors() -> Dict[int, str]: +def get_mypy_errors() -> dict[int, str]: """ Extract the errors from running mypy on the negative examples file. """ @@ -61,10 +59,8 @@ got = {} for line in mypy_output.splitlines(): - m = re.match(LINE_PATTERN, line) - if m is None: - continue - got[int(m.group(1))] = line[len(m.group(0)) + 1 :] + error = json.loads(line) + got[error["line"]] = f"{error['message']} [{error['code']}]" return got @@ -109,5 +105,6 @@ ] for idx, expected, got in mismatches: print(f"Line {idx}", f"Expected: {expected}", f"Got: {got}", sep="\n\t") + if mismatches: raise RuntimeError("Error messages changed") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/typeguard-4.4.1/tests/test_checkers.py new/typeguard-4.4.2/tests/test_checkers.py --- old/typeguard-4.4.1/tests/test_checkers.py 2024-11-03 13:04:35.000000000 +0100 +++ new/typeguard-4.4.2/tests/test_checkers.py 2025-02-16 17:27:08.000000000 +0100 @@ -2,6 +2,7 @@ import sys import types from contextlib import nullcontext +from datetime import timedelta from functools import partial from io import BytesIO, StringIO from pathlib import Path @@ -1383,6 +1384,18 @@ f"be a class method but it's an instance method" ) + def test_builtin_signature_check(self) -> None: + class MyProtocol(Protocol): + def attr(self) -> None: + pass + + class Foo: + attr = timedelta + + # Foo.attr is incompatible but timedelta has not inspectable signature so the + # check is skipped + check_type(Foo(), MyProtocol) + class TestRecursiveType: def test_valid(self): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/typeguard-4.4.1/tests/test_instrumentation.py new/typeguard-4.4.2/tests/test_instrumentation.py --- old/typeguard-4.4.1/tests/test_instrumentation.py 2024-11-03 13:04:35.000000000 +0100 +++ new/typeguard-4.4.2/tests/test_instrumentation.py 2025-02-16 17:27:08.000000000 +0100 @@ -1,4 +1,5 @@ import asyncio +import importlib import sys import warnings from importlib import import_module @@ -8,15 +9,16 @@ import pytest from pytest import FixtureRequest -from typeguard import TypeCheckError, config, install_import_hook, suppress_type_checks +from typeguard import TypeCheckError, install_import_hook, suppress_type_checks from typeguard._importhook import OPTIMIZATION pytestmark = pytest.mark.filterwarnings("error:no type annotations present") this_dir = Path(__file__).parent dummy_module_path = this_dir / "dummymodule.py" -cached_module_path = Path( +instrumented_cached_module_path = Path( cache_from_source(str(dummy_module_path), optimization=OPTIMIZATION) ) +cached_module_path = Path(cache_from_source(str(dummy_module_path))) # This block here is to test the recipe mentioned in the user guide if "pytest" in sys.modules: @@ -35,27 +37,50 @@ return request.param -@pytest.fixture(scope="module") -def dummymodule(method: str): - config.debug_instrumentation = True +def _fixture_module(name: str, method: str): + # config.debug_instrumentation = True sys.path.insert(0, str(this_dir)) try: - sys.modules.pop("dummymodule", None) - if cached_module_path.exists(): - cached_module_path.unlink() - + # sys.modules.pop(name, None) if method == "typechecked": - return import_module("dummymodule") + if cached_module_path.exists(): + cached_module_path.unlink() + + if name in sys.modules: + module = import_module(name) + importlib.reload(module) + else: + module = import_module(name) + return module + + if instrumented_cached_module_path.exists(): + instrumented_cached_module_path.unlink() - with install_import_hook(["dummymodule"]): + with install_import_hook([name]): with warnings.catch_warnings(): warnings.filterwarnings("error", module="typeguard") - module = import_module("dummymodule") + if name in sys.modules: + module = import_module(name) + importlib.reload(module) + else: + module = import_module(name) return module finally: sys.path.remove(str(this_dir)) +@pytest.fixture(scope="module") +def dummymodule(method: str): + return _fixture_module("dummymodule", method) + + +@pytest.fixture(scope="module") +def deferredannos(method: str): + if sys.version_info < (3, 14): + raise pytest.skip("Deferred annotations are only supported in Python 3.14+") + return _fixture_module("deferredannos", method) + + def test_type_checked_func(dummymodule): assert dummymodule.type_checked_func(2, 3) == 6 @@ -250,6 +275,11 @@ ) +def test_attribute_assign_unpacking(dummymodule): + foo = dummymodule.DummyClass() + dummymodule.attribute_assign_unpacking(foo) + + def test_unpacking_assign_star_no_annotation_fail(dummymodule): with pytest.raises( TypeCheckError, match=r"value assigned to z \(bytes\) is not an instance of str" @@ -330,6 +360,7 @@ def test_typevar_forwardref(dummymodule): + print(f"id of typevar_forwardref: {id(dummymodule.typevar_forwardref):x}") instance = dummymodule.typevar_forwardref(dummymodule.DummyClass) assert isinstance(instance, dummymodule.DummyClass) @@ -342,3 +373,16 @@ def test_suppress_annotated_multi_assignment(dummymodule): with suppress_type_checks(): assert dummymodule.multi_assign_single_value() == (6, 6, 6) + + +class TestUsesForwardRef: + def test_success(self, deferredannos): + obj = deferredannos.NotYetDefined() + assert deferredannos.uses_forwardref(obj) is obj + + def test_failure(self, deferredannos): + with pytest.raises( + TypeCheckError, + match=r'argument "x" \(int\) is not an instance of deferredannos.NotYetDefined', + ): + deferredannos.uses_forwardref(1) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/typeguard-4.4.1/tests/test_transformer.py new/typeguard-4.4.2/tests/test_transformer.py --- old/typeguard-4.4.1/tests/test_transformer.py 2024-11-03 13:04:35.000000000 +0100 +++ new/typeguard-4.4.2/tests/test_transformer.py 2025-02-16 17:27:08.000000000 +0100 @@ -1475,7 +1475,7 @@ def foo() -> None: memo = TypeCheckMemo(globals(), locals()) x: int - if (x := check_variable_assignment(otherfunc(), 'x', int, \ + if (x := check_variable_assignment(otherfunc(), [[('x', int)]], \ memo)): pass """ @@ -1504,7 +1504,7 @@ def foo(x: int) -> None: memo = TypeCheckMemo(globals(), locals()) check_argument_types('foo', {'x': (x, int)}, memo) - if (x := check_variable_assignment(otherfunc(), 'x', int, memo)): + if (x := check_variable_assignment(otherfunc(), [[('x', int)]], memo)): pass """ ).strip()