Skip to content
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

Infinite recursion, while loading numpy modules #155

Closed
aktech opened this issue May 4, 2023 · 9 comments
Closed

Infinite recursion, while loading numpy modules #155

aktech opened this issue May 4, 2023 · 9 comments
Assignees

Comments

@aktech
Copy link

aktech commented May 4, 2023

Describe the bug

We're trying to use griffe in https://github.com/jupyter/papyri (See PR: jupyter/papyri#250) to get structured function signatures. However we had a roadblock while loading numpy modules, we see infinite recursion.

To Reproduce
Steps to reproduce the behavior:

In [1]: import griffe
   ...: griffe_numpy = griffe.load('numpy')
   ...: griffe_numpy.modules
---------------------------------------------------------------------------
RecursionError                            Traceback (most recent call last)
Cell In[1], line 3
      1 import griffe
      2 griffe_numpy = griffe.load('numpy')
----> 3 griffe_numpy.modules

File ~/miniconda3/envs/papyri/lib/python3.9/site-packages/griffe/dataclasses.py:486, in Object.modules(self)
    479 @property
    480 def modules(self) -> dict[str, Module]:
    481     """Return the module members.
    482
    483     Returns:
    484         A dictionary of modules.
    485     """
--> 486     return {name: member for name, member in self.members.items() if member.kind is Kind.MODULE}

File ~/miniconda3/envs/papyri/lib/python3.9/site-packages/griffe/dataclasses.py:486, in <dictcomp>(.0)
    479 @property
    480 def modules(self) -> dict[str, Module]:
    481     """Return the module members.
    482
    483     Returns:
    484         A dictionary of modules.
    485     """
--> 486     return {name: member for name, member in self.members.items() if member.kind is Kind.MODULE}

File ~/miniconda3/envs/papyri/lib/python3.9/site-packages/griffe/dataclasses.py:861, in Alias.kind(self)
    859 # custom behavior to avoid raising exceptions
    860 try:
--> 861     return self.target.kind
    862 except (AliasResolutionError, CyclicAliasError):
    863     return Kind.ALIAS

File ~/miniconda3/envs/papyri/lib/python3.9/site-packages/griffe/dataclasses.py:1102, in Alias.target(self)
   1093 """Resolve and return the target, if possible.
   1094
   1095 Upon accessing this property, if the target is not already resolved,
   (...)
   1099     The resolved target.
   1100 """
   1101 if not self.resolved:
-> 1102     self.resolve_target()
   1103 return self._target

File ~/miniconda3/envs/papyri/lib/python3.9/site-packages/griffe/dataclasses.py:1143, in Alias.resolve_target(self)
   1141 self._passed_through = True
   1142 try:
-> 1143     self._resolve_target()
   1144 finally:
   1145     self._passed_through = False

File ~/miniconda3/envs/papyri/lib/python3.9/site-packages/griffe/dataclasses.py:1161, in Alias._resolve_target(self)
   1159 self._target = resolved
   1160 if self.parent is not None:
-> 1161     self._target.aliases[self.path] = self

File ~/miniconda3/envs/papyri/lib/python3.9/site-packages/griffe/dataclasses.py:954, in Alias.aliases(self)
    952 @property
    953 def aliases(self) -> dict[str, Alias]:  # noqa: D102
--> 954     return self.target.aliases

File ~/miniconda3/envs/papyri/lib/python3.9/site-packages/griffe/dataclasses.py:954, in Alias.aliases(self)
    952 @property
    953 def aliases(self) -> dict[str, Alias]:  # noqa: D102
--> 954     return self.target.aliases

File ~/miniconda3/envs/papyri/lib/python3.9/site-packages/griffe/dataclasses.py:1102, in Alias.target(self)
   1093 """Resolve and return the target, if possible.
   1094
   1095 Upon accessing this property, if the target is not already resolved,
   (...)
   1099     The resolved target.
   1100 """
   1101 if not self.resolved:
-> 1102     self.resolve_target()
   1103 return self._target

File ~/miniconda3/envs/papyri/lib/python3.9/site-packages/griffe/dataclasses.py:1143, in Alias.resolve_target(self)
   1141 self._passed_through = True
   1142 try:
-> 1143     self._resolve_target()
   1144 finally:
   1145     self._passed_through = False

File ~/miniconda3/envs/papyri/lib/python3.9/site-packages/griffe/dataclasses.py:1161, in Alias._resolve_target(self)
   1159 self._target = resolved
   1160 if self.parent is not None:
-> 1161     self._target.aliases[self.path] = self

File ~/miniconda3/envs/papyri/lib/python3.9/site-packages/griffe/dataclasses.py:954, in Alias.aliases(self)
    952 @property
    953 def aliases(self) -> dict[str, Alias]:  # noqa: D102
--> 954     return self.target.aliases

File ~/miniconda3/envs/papyri/lib/python3.9/site-packages/griffe/dataclasses.py:954, in Alias.aliases(self)
    952 @property
    953 def aliases(self) -> dict[str, Alias]:  # noqa: D102
--> 954     return self.target.aliases

    [... skipping similar frames: Alias.aliases at line 954 (2970 times)]

File ~/miniconda3/envs/papyri/lib/python3.9/site-packages/griffe/dataclasses.py:954, in Alias.aliases(self)
    952 @property
    953 def aliases(self) -> dict[str, Alias]:  # noqa: D102
--> 954     return self.target.aliases

File ~/miniconda3/envs/papyri/lib/python3.9/site-packages/griffe/dataclasses.py:1101, in Alias.target(self)
   1091 @property
   1092 def target(self) -> Object | Alias:
   1093     """Resolve and return the target, if possible.
   1094
   1095     Upon accessing this property, if the target is not already resolved,
   (...)
   1099         The resolved target.
   1100     """
-> 1101     if not self.resolved:
   1102         self.resolve_target()
   1103     return self._target

RecursionError: maximum recursion depth exceeded

Expected behavior
We expect to get modules instead of infinite recursion.

Screenshots
If applicable, add screenshots to help explain your problem.

System (please complete the following information):

  • griffe version: 0.27.1
  • Python version: 3.9.16
  • OS: MacOS

Additional context
Add any other context about the problem here.

Another question we wanted to ask: is there an easier way to load a module/function into griffe by using the imported instance of function, module?

pawamoy added a commit that referenced this issue May 5, 2023
Previous code was using an object's `attributes` property to early in the process,
triggering alias resolution and infinite recursion.

Issue #155: #155
@pawamoy
Copy link
Member

pawamoy commented May 5, 2023

Should be fixed in 0.27.3, let me know otherwise 🙂

@pawamoy pawamoy closed this as completed May 5, 2023
@aktech
Copy link
Author

aktech commented May 5, 2023

@pawamoy Thanks a lot! By the way is there an easier way to load a module/function into griffe by using the imported instance of function, module?

@pawamoy
Copy link
Member

pawamoy commented May 5, 2023

Oh yes sorry I forgot to answer that.

It's actually not clear from the code or documentation but you can pass any qualified name to griffe.load or GriffeLoader.load_module, not just a module name. So given a function with a qualified name, you can do something like this:

full_qualname = f"{func.__module__}.{func.__qualname__}"
sig = griffe.load(full_qualname)

Of interest as well is the modules collection, that you can reuse when loading things or accessing objects:

from griffe import load
from griffe.collections import ModulesCollection

modules_collection = ModulesCollection()

# ...later
full_qualname = f"{func.__module__}.{func.__qualname__}"
try:
    sig = modules_collection[full_qualname]
except KeyError:
    sig = load(full_qualname, modules_collection=modules_collection)

@aktech
Copy link
Author

aktech commented May 5, 2023

Seems like I can still reproduce this issue with griffe==0.27.3

@pawamoy
Copy link
Member

pawamoy commented May 5, 2023

What version of Numpy do you have?

@aktech
Copy link
Author

aktech commented May 5, 2023

What version of Numpy do you have?

numpy==1.24.2

@pawamoy pawamoy reopened this May 6, 2023
@pawamoy
Copy link
Member

pawamoy commented May 8, 2023

Thanks, I was able to replicate and fix the issue. I'll push the fix soon 🙂

@pawamoy pawamoy self-assigned this May 8, 2023
@aktech
Copy link
Author

aktech commented May 9, 2023

Thanks, I was able to replicate and fix the issue. I'll push the fix soon 🙂

Awesome, thanks!

pawamoy added a commit that referenced this issue May 10, 2023
@pawamoy
Copy link
Member

pawamoy commented May 10, 2023

Will push a new release soon.

@pawamoy pawamoy closed this as completed May 10, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants