hadialqattan / pycln

A formatter for finding and removing unused import statements.

Home Page:https://hadialqattan.github.io/pycln

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

[BUG] 2.0.3 update causes 'Tuple' object has no attribute 'value'

sdebruyn opened this issue Β· comments

After the update from 2.0.2 to 2.0.3 I get 100+ errors mentioning 'Tuple' object has no attribute 'value'
The code with the error doesn't have any tuples, however its imports do have an from typing import Tuple

Python 3.9, ubuntu 20.04

I'm seeing this with both Tuple and Name in multiple files in my project. However, I'm not even seeing those keys in the files

I've worked up a simple reproduction case:

It appears that the fixes to allow generic types to work better now have an issue if you don't use a string in the generic type definition.

This generates the error 'Name' object has no attribute 'value':

def reproduction(value: list[dict]) -> None:
    pass

This works fine:

def reproduction(value: list['dict']) -> None:
    pass

If you do the below you get 'BinOp' object has no attribute 'value'

def reproduction(value: list[int | str]) -> None:
    pass

I've not figured out exactly what can trigger the Tuple version of this error, but it all appears to be a lack of type checking when parsing the subtype of the generics?

Hi, I'm so sorry for that...this issue is under investigation right now. Thank you both @sdebruyn for reporting the issue and @Kaelten for giving further details.

After investigating, this seems to be related to some ast module changes in Python3.9+...

I'll fix it as soon as possible and release v2.0.4...

Thanks for the prompt engagement on both this and my last report! :)

I've not figured out exactly what can trigger the Tuple version of this error, but it all appears to be a lack of type checking when parsing the subtype of the generics?

pycln/pycln/utils/scan.py

Lines 381 to 396 in d1ac94f

def _visit_string_type_annotation(
self, node: Union[ast.AnnAssign, ast.arg, FunctionDefT]
) -> None:
# Support string type annotations.
if isinstance(node, (ast.AnnAssign, ast.arg)):
annotation = node.annotation
else:
annotation = node.returns
if isinstance(annotation, ast.Subscript):
if isinstance(annotation.slice, ast.Constant):
annotation = annotation.slice
else:
annotation = annotation.slice.value # type: ignore
self._parse_string(annotation, True) # type: ignore

It's line 394.

actually using the else statement in line388 and 394 is a really bad idea πŸ˜“

actually using the else statement in line388 and 394 is a really bad idea πŸ˜“

I almost always wonder wtf past me was thinking when I'm bug fixing <_<

actually using the else statement in line388 and 394 is a really bad idea πŸ˜“

I almost always wonder wtf past me was thinking when I'm bug fixing <_<

That always happens, actually, this time I've well tested the edge cases but I've missed the normal/main one πŸ˜‚.

@Kaelten if you don't mind, could you double-check my fix? PR #162

I mean running it against some possible edge cases (if any).

@Kaelten if you don't mind, could you double-check my fix? PR #162

I mean running it against some possible edge cases (if any).

for now, I'll merge the PR and create a new release so this issue affects fewer projects. in case you have any updates please let me know.

+ Thanks a lot for your support.

@hadialqattan I've tested 2.0.4 against my project and both #161 and #154 are looking good. Thanks again!