Skip to content

BUG: is_list_like returns True even if __iter__ raises an error #54176

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
3 tasks done
mroeschke opened this issue Jul 18, 2023 · 6 comments
Open
3 tasks done

BUG: is_list_like returns True even if __iter__ raises an error #54176

mroeschke opened this issue Jul 18, 2023 · 6 comments
Assignees
Labels

Comments

@mroeschke
Copy link
Member

Pandas version checks

  • I have checked that this issue has not already been reported.

  • I have confirmed this bug exists on the latest version of pandas.

  • I have confirmed this bug exists on the main branch of pandas.

Reproducible Example

In [1]: class MyClass:
   ...:     def __iter__(self):
   ...:         raise Exception("I'm not listlike")
   ...: 

In [2]: from pandas.core.dtypes import inference

In [3]: inference.is_list_like(MyClass())
Out[3]: True

Issue Description

c_is_list_like checks

        # equiv: `isinstance(obj, abc.Iterable)`
        getattr(obj, "__iter__", None) is not None and not isinstance(obj, type)

But an object can override __iter__ to raise and is_list_like will still report that the object is True

Expected Behavior

In [3]: inference.is_list_like(MyClass())
Out[3]: False

Installed Versions

Replace this line with the output of pd.show_versions()

@mroeschke mroeschke added Bug Needs Triage Issue that has not been reviewed by a pandas team member and removed Needs Triage Issue that has not been reviewed by a pandas team member labels Jul 18, 2023
@Shreesha3112
Copy link

Would like to work on this issue

@Shreesha3112
Copy link

Shreesha3112 commented Jul 18, 2023

A potential solution

_is_iter_allowed = getattr(obj, "__iter__", None)
if _is_iter_allowed :
    try:
        #invoke
         obj.__iter__()
        _is_iter_allowed = True
    except Exception:
        #keep it as None
        pass

#then update the return statement as
return (
        # equiv: `isinstance(obj, abc.Iterable)`
        _is_iter_allowed  is not None and not isinstance(obj, type) #change
        ............
        .........

    )

@twoertwein
Copy link
Member

If the caller uses __iter__ = None instead of raising inside the method, it should work. Settings methods to None in child classes to indicate that the child class doesn't implement something seems to be common, e.g., __hash__ is set to None for list and np.ndarray

@jbrockmendel
Copy link
Member

Handling bespoke types in is_list_like comes up a lot and runs up against attempts to optimize this often-used function. I wonder if the solution is to move away from it in favor of a handful of explicitly supported types e.g. isinstance(obj, (ndarray, EA, Index, Series, list))

@mroeschke
Copy link
Member Author

For context, I ran into this while trying to make Series.str not iterable xref #54173. is_list_like (expectedly) checks that Series.str is not list like but defining __iter__ make it "list-like"

@ArchPh03nix
Copy link
Contributor

take

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants