Skip to content

Strange fix behavior for UP006/NonPEP585Annotation fixer since ruff 0.8.5 #15245

@oprypin

Description

@oprypin

I am reporting strange behaviors since ruff 0.8.5. I have not tried ruff from master branch.

Example 1

Example file test.py:

import collections
import collections.abc
from typing import Callable, Iterable


def test(a: Iterable[str], b: Callable[[str], None]):
    return collections.ChainMap()

Command:

ruff --isolated check --target-version=py39 --select=UP006,UP035 --preview --fix --unsafe-fixes test.py
  • File content after ruff 0.8.4 applied:
    (doesn't fix Callable because it's marked as py310+)

    import collections
    import collections.abc
    from typing import Callable
    from collections.abc import Iterable
    
    
    def test(a: Iterable[str], b: Callable[[str], None]):
        return collections.ChainMap()
  • File content after ruff 0.8.5 applied:
    (weird!! explicit reference to collections.abc.Callable)

    import collections
    import collections.abc
    from typing import Callable
    from collections.abc import Iterable
    
    
    def test(a: Iterable[str], b: collections.abc.Callable[[str], None]):
        return collections.ChainMap()

Example 2

Example file test.py:

from typing import Callable, Iterable


def test(a: Iterable[str], b: Callable[[str], None]):
    pass

Command:

ruff --isolated check --target-version=py39 --select=UP006,UP035 --preview --fix --unsafe-fixes test.py
  • File content after ruff 0.8.4 applied:

    from typing import Callable
    from collections.abc import Iterable
    
    
    def test(a: Iterable[str], b: Callable[[str], None]):
        pass
  • File content after ruff 0.8.5 applied:

    Same, but with this additional output:

    error: Failed to create fix for NonPEP585Annotation: Unable to insert `Iterable` into scope due to name conflict
    error: Failed to create fix for NonPEP585Annotation: Unable to insert `Callable` into scope due to name conflict
    error: Failed to create fix for NonPEP585Annotation: Unable to insert `Callable` into scope due to name conflict
    test.py:5:31: UP006 Use `collections.abc.Callable` instead of `Callable` for type annotation
      |
    5 | def test(a: Iterable[str], b: Callable[[str], None]):
      |                               ^^^^^^^^ UP006
    6 |     pass
      |
      = help: Replace with `collections.abc.Callable`
    
    Found 2 errors (1 fixed, 1 remaining).
    

    This was referenced in Errors for attempted autofixes visible to users even without passing --fix and for noqa lines #15229
    but the description of the "fix" for that issue seems to imply that the error messages themselves are the only problem, which I think is not right.
    Ruff should be able to replace from typing import Callable.


Example 3

Example file test.py:

from __future__ import annotations

from typing import Callable, Iterable


def test(a: Iterable[str], b: Callable[[str], None]):
    pass

Command: (note py38 here, unlike all other examples)

ruff --isolated check --target-version=py38 --select=UP006,UP035 --preview --fix --unsafe-fixes test.py
  • File content after ruff 0.8.4 applied:

    No change, no errors

  • File content after ruff 0.8.5 applied:

    No change, but with this additional output (why does it fail to perform the fixes here??):

    error: Failed to create fix for NonPEP585Annotation: Unable to insert `Iterable` into scope due to name conflict
    error: Failed to create fix for NonPEP585Annotation: Unable to insert `Callable` into scope due to name conflict
    test.py:6:13: UP006 Use `collections.abc.Iterable` instead of `Iterable` for type annotation
      |
    6 | def test(a: Iterable[str], b: Callable[[str], None]):
      |             ^^^^^^^^ UP006
    7 |     return collections.ChainMap()
      |
      = help: Replace with `collections.abc.Iterable`
    
    test.py:6:31: UP006 Use `collections.abc.Callable` instead of `Callable` for type annotation
      |
    6 | def test(a: Iterable[str], b: Callable[[str], None]):
      |                               ^^^^^^^^ UP006
    7 |     return collections.ChainMap()
      |
      = help: Replace with `collections.abc.Callable`
    
    Found 2 errors.
    

Example 4

Example file test.py:

from __future__ import annotations

import collections
import collections.abc
from typing import Callable, Iterable


def test(a: Iterable[str], b: Callable[[str], None]):
    return collections.ChainMap()

Command:

ruff --isolated check --target-version=py39 --select=UP006,UP035 --preview --fix --unsafe-fixes test.py
  • File content after ruff 0.8.4 applied:

    from __future__ import annotations
    
    import collections
    import collections.abc
    from typing import Callable
    from collections.abc import Iterable
    
    
    def test(a: Iterable[str], b: Callable[[str], None]):
        return collections.ChainMap()
  • File content after ruff 0.8.5 applied:
    (weirdest one yet!!! changes only one of the two imports, and then proceeds to not even use the imports!!)

    from __future__ import annotations
    
    import collections
    import collections.abc
    from typing import Callable
    from collections.abc import Iterable
    
    
    def test(a: collections.abc.Iterable[str], b: collections.abc.Callable[[str], None]):
        return collections.ChainMap()

Metadata

Metadata

Assignees

No one assigned

    Labels

    fixesRelated to suggested fixes for violations

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions