Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-flake8-pyi for openSUSE:Factory checked in at 2024-04-07 22:13:14 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-flake8-pyi (Old) and /work/SRC/openSUSE:Factory/.python-flake8-pyi.new.1905 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-flake8-pyi" Sun Apr 7 22:13:14 2024 rev:14 rq:1165947 version:24.3.1 Changes: -------- --- /work/SRC/openSUSE:Factory/python-flake8-pyi/python-flake8-pyi.changes 2024-03-26 19:29:52.350701315 +0100 +++ /work/SRC/openSUSE:Factory/.python-flake8-pyi.new.1905/python-flake8-pyi.changes 2024-04-07 22:15:05.050554239 +0200 @@ -1,0 +2,11 @@ +Sun Apr 7 09:02:03 UTC 2024 - Dirk Müller <dmuel...@suse.com> + +- update to 24.3.1: + * Y064: Use simpler syntax to define final literal types. + * For example, use `x: Final = 42` instead of `x: + Final[Literal[42]]` + * Y065: Don't use bare `Incomplete` in parameter and return + annotations. + * Y090: Fix false positive for `tuple[Unpack[Ts]]`. + +------------------------------------------------------------------- Old: ---- flake8_pyi-24.3.0.tar.gz New: ---- flake8_pyi-24.3.1.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-flake8-pyi.spec ++++++ --- /var/tmp/diff_new_pack.qYSSD6/_old 2024-04-07 22:15:05.454569043 +0200 +++ /var/tmp/diff_new_pack.qYSSD6/_new 2024-04-07 22:15:05.454569043 +0200 @@ -18,7 +18,7 @@ %{?sle15_python_module_pythons} Name: python-flake8-pyi -Version: 24.3.0 +Version: 24.3.1 Release: 0 Summary: A plugin for flake8 to enable linting .pyi files License: MIT ++++++ flake8_pyi-24.3.0.tar.gz -> flake8_pyi-24.3.1.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/flake8_pyi-24.3.0/.github/workflows/check.yml new/flake8_pyi-24.3.1/.github/workflows/check.yml --- old/flake8_pyi-24.3.0/.github/workflows/check.yml 2020-02-02 01:00:00.000000000 +0100 +++ new/flake8_pyi-24.3.1/.github/workflows/check.yml 2020-02-02 01:00:00.000000000 +0100 @@ -36,10 +36,9 @@ - uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - cache: pip - cache-dependency-path: pyproject.toml allow-prereleases: true - - run: pip install -e .[dev] + - run: curl -LsSf https://astral.sh/uv/install.sh | sh + - run: uv pip install -e .[dev] --system - run: mypy flake8: @@ -50,10 +49,9 @@ - uses: actions/checkout@v4 - uses: actions/setup-python@v4 with: - python-version: "3.11" - cache: pip - cache-dependency-path: pyproject.toml - - run: pip install -e .[dev] + python-version: "3.12" + - run: curl -LsSf https://astral.sh/uv/install.sh | sh + - run: uv pip install -e .[dev] --system - run: | flake8 $(git ls-files | grep 'py$') --color always diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/flake8_pyi-24.3.0/.github/workflows/publish.yml new/flake8_pyi-24.3.1/.github/workflows/publish.yml --- old/flake8_pyi-24.3.0/.github/workflows/publish.yml 2020-02-02 01:00:00.000000000 +0100 +++ new/flake8_pyi-24.3.1/.github/workflows/publish.yml 2020-02-02 01:00:00.000000000 +0100 @@ -20,7 +20,7 @@ - name: Set up Python 3.10 uses: actions/setup-python@v4 with: - python-version: "3.10" + python-version: "3.12" - name: Install pypa/build run: >- python -m diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/flake8_pyi-24.3.0/.github/workflows/typeshed_primer.yml new/flake8_pyi-24.3.1/.github/workflows/typeshed_primer.yml --- old/flake8_pyi-24.3.0/.github/workflows/typeshed_primer.yml 2020-02-02 01:00:00.000000000 +0100 +++ new/flake8_pyi-24.3.1/.github/workflows/typeshed_primer.yml 2020-02-02 01:00:00.000000000 +0100 @@ -39,21 +39,21 @@ - name: Setup Python uses: actions/setup-python@v4 with: - python-version: "3.11" - cache: pip - cache-dependency-path: new_plugin/pyproject.toml - - run: pip install flake8-noqa + python-version: "3.12" + - name: Install uv + run: curl -LsSf https://astral.sh/uv/install.sh | sh + - run: uv pip install flake8-noqa --system # We cd so that "old_plugin"/"new_plugin"/typeshed" don't appear in the error path - name: flake8 typeshed using target branch run: | cd old_plugin - pip install -e . + uv pip install -e . --system cd ../typeshed flake8 --exit-zero --color never --output-file ../old_errors.txt - name: flake8 typeshed using PR branch run: | cd new_plugin - pip install -e . + uv pip install -e . --system cd ../typeshed flake8 --exit-zero --color never --output-file ../new_errors.txt - name: Get diff between the two runs diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/flake8_pyi-24.3.0/CHANGELOG.md new/flake8_pyi-24.3.1/CHANGELOG.md --- old/flake8_pyi-24.3.0/CHANGELOG.md 2020-02-02 01:00:00.000000000 +0100 +++ new/flake8_pyi-24.3.1/CHANGELOG.md 2020-02-02 01:00:00.000000000 +0100 @@ -1,5 +1,15 @@ # Change Log +## 24.3.1 + +New error codes: +* Y064: Use simpler syntax to define final literal types. + For example, use `x: Final = 42` instead of `x: Final[Literal[42]]` +* Y065: Don't use bare `Incomplete` in parameter and return annotations. + +Bugfixes: +* Y090: Fix false positive for `tuple[Unpack[Ts]]`. + ## 24.3.0 New error codes: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/flake8_pyi-24.3.0/ERRORCODES.md new/flake8_pyi-24.3.1/ERRORCODES.md --- old/flake8_pyi-24.3.0/ERRORCODES.md 2020-02-02 01:00:00.000000000 +0100 +++ new/flake8_pyi-24.3.1/ERRORCODES.md 2020-02-02 01:00:00.000000000 +0100 @@ -77,6 +77,8 @@ | Y061 | Do not use `None` inside a `Literal[]` slice. For example, use `Literal["foo"] \| None` instead of `Literal["foo", None]`. While both are legal according to [PEP 586](https://peps.python.org/pep-0586/), the former is preferred for stylistic consistency. Note that this warning is not emitted if Y062 is emitted for the same `Literal[]` slice. For example, `Literal[None, None, True, True]` only causes Y062 to be emitted. | Style | Y062 | `Literal[]` slices shouldn't contain duplicates, e.g. `Literal[True, True]` is not allowed. | Redundant code | Y063 | Use [PEP 570 syntax](https://peps.python.org/pep-0570/) (e.g. `def foo(x: int, /) -> None: ...`) to denote positional-only arguments, rather than [the older Python 3.7-compatible syntax described in PEP 484](https://peps.python.org/pep-0484/#positional-only-arguments) (`def foo(__x: int) -> None: ...`, etc.). | Style +| Y064 | Use simpler syntax to define final literal types. For example, use `x: Final = 42` instead of `x: Final[Literal[42]]`. | Style +| Y065 | Don't use bare `Incomplete` in argument and return annotations. Instead, leave them unannotated. Omitting an annotation entirely from a function will cause some type checkers to view the parameter or return type as "untyped"; this may result in stricter type-checking on code that makes use of the stubbed function. | Style ## Warnings disabled by default diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/flake8_pyi-24.3.0/PKG-INFO new/flake8_pyi-24.3.1/PKG-INFO --- old/flake8_pyi-24.3.0/PKG-INFO 2020-02-02 01:00:00.000000000 +0100 +++ new/flake8_pyi-24.3.1/PKG-INFO 2020-02-02 01:00:00.000000000 +0100 @@ -1,6 +1,6 @@ -Metadata-Version: 2.1 +Metadata-Version: 2.3 Name: flake8-pyi -Version: 24.3.0 +Version: 24.3.1 Summary: A plugin for flake8 to enable linting .pyi stub files. Project-URL: Homepage, https://github.com/PyCQA/flake8-pyi Project-URL: Source, https://github.com/PyCQA/flake8-pyi diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/flake8_pyi-24.3.0/pyi.py new/flake8_pyi-24.3.1/pyi.py --- old/flake8_pyi-24.3.0/pyi.py 2020-02-02 01:00:00.000000000 +0100 +++ new/flake8_pyi-24.3.1/pyi.py 2020-02-02 01:00:00.000000000 +0100 @@ -337,6 +337,7 @@ _is_builtins_object = partial(_is_object, name="object", from_={"builtins"}) _is_builtins_type = partial(_is_object, name="type", from_={"builtins"}) _is_Unused = partial(_is_object, name="Unused", from_={"_typeshed"}) +_is_Incomplete = partial(_is_object, name="Incomplete", from_={"_typeshed"}) _is_Iterable = partial(_is_object, name="Iterable", from_=_TYPING_OR_COLLECTIONS_ABC) _is_AsyncIterable = partial( _is_object, name="AsyncIterable", from_=_TYPING_OR_COLLECTIONS_ABC @@ -349,6 +350,7 @@ _is_object, name="AsyncGenerator", from_=_TYPING_OR_COLLECTIONS_ABC ) _is_Generic = partial(_is_object, name="Generic", from_=_TYPING_MODULES) +_is_Unpack = partial(_is_object, name="Unpack", from_=_TYPING_MODULES) def _is_object_or_Unused(node: ast.expr | None) -> bool: @@ -1041,6 +1043,7 @@ long_strings_allowed: NestingCounter in_function: NestingCounter visiting_arg: NestingCounter + Y061_suppressed: NestingCounter # This is only relevant for visiting classes enclosing_class_ctx: EnclosingClassContext | None = None @@ -1058,6 +1061,7 @@ self.long_strings_allowed = NestingCounter() self.in_function = NestingCounter() self.visiting_arg = NestingCounter() + self.Y061_suppressed = NestingCounter() def __repr__(self) -> str: return f"{self.__class__.__name__}(filename={self.filename!r})" @@ -1318,7 +1322,14 @@ ) self.visit(node_target) - self.visit(node_annotation) + + Y064_encountered = self._check_for_Y064_violations(node) + if Y064_encountered: + with self.Y061_suppressed.enabled(): + self.visit(node_annotation) + else: + self.visit(node_annotation) + if node_value is not None: if is_typealias: self.visit(node_value) @@ -1354,6 +1365,35 @@ self.generic_visit(node) self._check_typealias(node=node, alias_name=node.name.id) + def _check_for_Y064_violations(self, node: ast.AnnAssign) -> bool: + annotation = node.annotation + + if node.value or not isinstance(annotation, ast.Subscript): + return False + + value = annotation.value + slice_ = annotation.slice + + if ( + _is_Final(value) + and isinstance(slice_, ast.Subscript) + and _is_Literal(slice_.value) + and isinstance(slice_.slice, ast.Constant) + ): + final = ast.Name(id="Final", ctx=ast.Load()) + suggestion = ast.AnnAssign( + target=node.target, + annotation=final, + value=slice_.slice, + simple=node.simple, + ) + self.error( + node, + Y064.format(suggestion=unparse(suggestion), original=unparse(node)), + ) + return True + return False + def _check_union_members( self, members: Sequence[ast.expr], is_pep_604_union: bool ) -> None: @@ -1499,7 +1539,9 @@ self._visit_slice_tuple(node.slice, subscripted_object_name) else: self.visit(node.slice) - if subscripted_object_name in {"tuple", "Tuple"}: + if subscripted_object_name in {"tuple", "Tuple"} and not ( + isinstance(node.slice, ast.Subscript) and _is_Unpack(node.slice.value) + ): self._Y090_error(node) def _visit_typing_Literal(self, node: ast.Subscript) -> None: @@ -1513,7 +1555,7 @@ Y062_encountered = True self.error(member_list[1], Y062.format(unparse(member_list[1]))) - if not Y062_encountered: + if not Y062_encountered and not self.Y061_suppressed.active: if analysis.contains_only_none: self.error(node.slice, Y061.format(suggestion="None")) elif analysis.none_members: @@ -2121,6 +2163,9 @@ with self.in_function.enabled(): self.generic_visit(node) + if node.name != "__getattr__" and node.returns and _is_Incomplete(node.returns): + self.error(node.returns, Y065.format(what="return type")) + body = node.body if len(body) > 1: self.error(body[1], Y048) @@ -2145,6 +2190,8 @@ def visit_arg(self, node: ast.arg) -> None: if _is_NoReturn(node.annotation): self.error(node, Y050) + if _is_Incomplete(node.annotation): + self.error(node, Y065.format(what=f'parameter "{node.arg}"')) with self.visiting_arg.enabled(): self.generic_visit(node) @@ -2366,6 +2413,8 @@ Y061 = 'Y061 None inside "Literal[]" expression. Replace with "{suggestion}"' Y062 = 'Y062 Duplicate "Literal[]" member "{}"' Y063 = "Y063 Use PEP-570 syntax to indicate positional-only arguments" +Y064 = 'Y064 Use "{suggestion}" instead of "{original}"' +Y065 = 'Y065 Leave {what} unannotated rather than using "Incomplete"' Y090 = ( 'Y090 "{original}" means ' '"a tuple of length 1, in which the sole element is of type {typ!r}". ' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/flake8_pyi-24.3.0/tests/incomplete.pyi new/flake8_pyi-24.3.1/tests/incomplete.pyi --- old/flake8_pyi-24.3.0/tests/incomplete.pyi 1970-01-01 01:00:00.000000000 +0100 +++ new/flake8_pyi-24.3.1/tests/incomplete.pyi 2020-02-02 01:00:00.000000000 +0100 @@ -0,0 +1,39 @@ +from _typeshed import Incomplete +from typing_extensions import TypeAlias + +IncompleteAlias: TypeAlias = Incomplete # ok + +att: Incomplete # ok + +def ok(x: Incomplete | None) -> list[Incomplete]: ... +def aliased(x: IncompleteAlias) -> IncompleteAlias: ... # ok +def err1( + x: Incomplete, # Y065 Leave parameter "x" unannotated rather than using "Incomplete" +) -> None: ... +def err2() -> ( + Incomplete # Y065 Leave return type unannotated rather than using "Incomplete" +): ... + +class Foo: + att: Incomplete + def ok(self, x: Incomplete | None) -> list[Incomplete]: ... + def err1( + self, + x: Incomplete, # Y065 Leave parameter "x" unannotated rather than using "Incomplete" + ) -> None: ... + def err2( + self, + ) -> ( + Incomplete # Y065 Leave return type unannotated rather than using "Incomplete" + ): ... + def __getattr__( + self, name: str + ) -> Incomplete: ... # allowed in __getattr__ return type + +class Bar: + def __getattr__( + self, + name: Incomplete, # Y065 Leave parameter "name" unannotated rather than using "Incomplete" + ) -> Incomplete: ... + +def __getattr__(name: str) -> Incomplete: ... # allowed in __getattr__ return type diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/flake8_pyi-24.3.0/tests/literals.pyi new/flake8_pyi-24.3.1/tests/literals.pyi --- old/flake8_pyi-24.3.0/tests/literals.pyi 2020-02-02 01:00:00.000000000 +0100 +++ new/flake8_pyi-24.3.1/tests/literals.pyi 2020-02-02 01:00:00.000000000 +0100 @@ -1,4 +1,4 @@ -from typing import Literal +from typing import Final, Literal Literal[None] # Y061 None inside "Literal[]" expression. Replace with "None" Literal[True, None] # Y061 None inside "Literal[]" expression. Replace with "Literal[True] | None" @@ -21,3 +21,8 @@ # and there are no None members in the Literal[] slice, # only emit Y062: Literal[None, True, None, True] # Y062 Duplicate "Literal[]" member "True" + +x: Final[Literal[True]] # Y064 Use "x: Final = True" instead of "x: Final[Literal[True]]" +# If Y061 and Y064 both apply, only emit Y064 +y: Final[Literal[None]] # Y064 Use "y: Final = None" instead of "y: Final[Literal[None]]" +z: Final[Literal[True, False]] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/flake8_pyi-24.3.0/tests/pep646_py311.pyi new/flake8_pyi-24.3.1/tests/pep646_py311.pyi --- old/flake8_pyi-24.3.0/tests/pep646_py311.pyi 1970-01-01 01:00:00.000000000 +0100 +++ new/flake8_pyi-24.3.1/tests/pep646_py311.pyi 2020-02-02 01:00:00.000000000 +0100 @@ -0,0 +1,7 @@ +# flags: --extend-select=Y090 +import typing + +_Ts = typing.TypeVarTuple("_Ts") + +e: tuple[*_Ts] +f: typing.Tuple[*_Ts] # Y022 Use "tuple[Foo, Bar]" instead of "typing.Tuple[Foo, Bar]" (PEP 585 syntax) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/flake8_pyi-24.3.0/tests/single_element_tuples.pyi new/flake8_pyi-24.3.1/tests/single_element_tuples.pyi --- old/flake8_pyi-24.3.0/tests/single_element_tuples.pyi 2020-02-02 01:00:00.000000000 +0100 +++ new/flake8_pyi-24.3.1/tests/single_element_tuples.pyi 2020-02-02 01:00:00.000000000 +0100 @@ -2,7 +2,11 @@ import builtins import typing +_Ts = typing.TypeVarTuple("_Ts") + a: tuple[int] # Y090 "tuple[int]" means "a tuple of length 1, in which the sole element is of type 'int'". Perhaps you meant "tuple[int, ...]"? b: typing.Tuple[builtins.str] # Y022 Use "tuple[Foo, Bar]" instead of "typing.Tuple[Foo, Bar]" (PEP 585 syntax) # Y090 "typing.Tuple[builtins.str]" means "a tuple of length 1, in which the sole element is of type 'builtins.str'". Perhaps you meant "typing.Tuple[builtins.str, ...]"? c: tuple[int, ...] d: typing.Tuple[builtins.str, builtins.complex] # Y022 Use "tuple[Foo, Bar]" instead of "typing.Tuple[Foo, Bar]" (PEP 585 syntax) +e: tuple[typing.Unpack[_Ts]] +f: typing.Tuple[typing.Unpack[_Ts]] # Y022 Use "tuple[Foo, Bar]" instead of "typing.Tuple[Foo, Bar]" (PEP 585 syntax)