Poetry: [RecursionError] maximum recursion depth exceeded while calling a Python object

Created on 15 Oct 2020  Β·  10Comments  Β·  Source: python-poetry/poetry

  • [x] I am on the latest Poetry version.
  • [x] I have searched the issues of this repo and believe that this is not a duplicate.
  • [x] If an exception occurs when executing a command, I executed it again in debug mode (-vvv option).
  • OS version and name: macOS Catalina 10.15.6
  • Poetry version: 1.1.3
  • Link of a Gist with the contents of your pyproject.toml file:

Issue

When I run poetry add scrapy, it raise an error:

[RecursionError]
maximum recursion depth exceeded while calling a Python object

However, when I run poetry shell first to enter the virtual env,and then run poetry add scrapy, then everying works fine.

Bug Triage

Most helpful comment

@sergekir at the moment this comes via propagation from dependency markers so, it does not take into account the pypt python constraint. The per dependency python constraint is expected at the moment since we are simply propagating whats in the lock file. Will see if we can remove that later on.

All 10 comments

@qiankunxienb I am unable to reproduce the issue see below. If this is is still occurring, can you please add an example pyproject.toml file along with the output of the command when run with -vvv please.

Using a container (podman | docker)

podman run --rm -i --entrypoint bash python:3.8 <<EOF
set -e
pip install -q poetry==1.1.3
poetry new foobar
pushd foobar
sed -i /pytest/d pyproject.toml
poetry add scrapy
EOF
Created package foobar in foobar
/foobar /
Creating virtualenv foobar-lWDpn5M1-py3.8 in /root/.cache/pypoetry/virtualenvs
Using version ^2.4.0 for Scrapy

Updating dependencies
Resolving dependencies...

Writing lock file

Package operations: 28 installs, 0 updates, 0 removals

  β€’ Installing pycparser (2.20)
  β€’ Installing six (1.15.0)
  β€’ Installing attrs (20.2.0)
  β€’ Installing cffi (1.14.3)
  β€’ Installing cssselect (1.1.0)
  β€’ Installing idna (2.10)
  β€’ Installing lxml (4.5.2)
  β€’ Installing pyasn1 (0.4.8)
  β€’ Installing w3lib (1.22.0)
  β€’ Installing automat (20.2.0)
  β€’ Installing constantly (15.1.0)
  β€’ Installing cryptography (3.1.1)
  β€’ Installing hyperlink (20.0.1)
  β€’ Installing incremental (17.5.0)
  β€’ Installing itemadapter (0.1.1)
  β€’ Installing parsel (1.6.0)
  β€’ Installing pyasn1-modules (0.2.8)
  β€’ Installing zope.interface (5.1.2)
  β€’ Installing pyhamcrest (2.0.2)
  β€’ Installing jmespath (0.10.0)
  β€’ Installing itemloaders (1.0.3)
  β€’ Installing protego (0.1.16)
  β€’ Installing pydispatcher (2.0.5)
  β€’ Installing pyopenssl (19.1.0)
  β€’ Installing queuelib (1.5.0)
  β€’ Installing service-identity (18.1.0)
  β€’ Installing twisted (20.3.0)
  β€’ Installing scrapy (2.4.0)

Strange, when I add -vvv argument, the issue can not be reproduced.

Popping in here to say that I'm getting this consistently when I attempt to export my lock file. Full traceback:

❯ poetry export -f requirements.txt --without-hashes -vvv

  Stack trace:

  992  ~/.poetry/lib/poetry/_vendor/py3.7/clikit/console_application.py:131 in run
        129β”‚             parsed_args = resolved_command.args
        130β”‚ 
      β†’ 131β”‚             status_code = command.handle(parsed_args, io)
        132β”‚         except KeyboardInterrupt:
        133β”‚             status_code = 1

  991  ~/.poetry/lib/poetry/_vendor/py3.7/clikit/api/command/command.py:120 in handle
        118β”‚     def handle(self, args, io):  # type: (Args, IO) -> int
        119β”‚         try:
      β†’ 120β”‚             status_code = self._do_handle(args, io)
        121β”‚         except KeyboardInterrupt:
        122β”‚             if io.is_debug():

  990  ~/.poetry/lib/poetry/_vendor/py3.7/clikit/api/command/command.py:171 in _do_handle
        169β”‚         handler_method = self._config.handler_method
        170β”‚ 
      β†’ 171β”‚         return getattr(handler, handler_method)(args, io, self)
        172β”‚ 
        173β”‚     def __repr__(self):  # type: () -> str

  989  ~/.poetry/lib/poetry/_vendor/py3.7/cleo/commands/command.py:92 in wrap_handle
         90β”‚         self._command = command
         91β”‚ 
      β†’  92β”‚         return self.handle()
         93β”‚ 
         94β”‚     def handle(self):  # type: () -> Optional[int]

  988  ~/.poetry/lib/poetry/console/commands/export.py:73 in handle
        71β”‚             dev=self.option("dev"),
        72β”‚             extras=self.option("extras"),
      β†’ 73β”‚             with_credentials=self.option("with-credentials"),
        74β”‚         )
        75β”‚ 

  987  ~/.poetry/lib/poetry/utils/exporter.py:44 in export
         42β”‚             dev=dev,
         43β”‚             extras=extras,
      β†’  44β”‚             with_credentials=with_credentials,
         45β”‚         )
         46β”‚ 

  986  ~/.poetry/lib/poetry/utils/exporter.py:61 in _export_requirements_txt
         59β”‚ 
         60β”‚         for dependency_package in self._poetry.locker.get_project_dependency_packages(
      β†’  61β”‚             project_requires=self._poetry.package.all_requires, dev=dev, extras=extras
         62β”‚         ):
         63β”‚             line = ""

  985  ~/.poetry/lib/poetry/packages/locker.py:367 in get_project_dependency_packages
        365β”‚             project_requires=selected,
        366β”‚             locked_packages=repository.packages,
      β†’ 367β”‚             with_nested=True,
        368β”‚         ):
        369β”‚             try:

  984  ~/.poetry/lib/poetry/packages/locker.py:316 in get_project_dependencies
        314β”‚             packages_by_name=packages_by_name,
        315β”‚             project_level_dependencies=project_level_dependencies,
      β†’ 316β”‚             nested_dependencies=dict(),
        317β”‚         )
        318β”‚ 

  ...  Previous frame repeated 970 times

   12  ~/.poetry/lib/poetry/packages/locker.py:272 in __walk_dependency_level
        270β”‚             packages_by_name=packages_by_name,
        271β”‚             project_level_dependencies=project_level_dependencies,
      β†’ 272β”‚             nested_dependencies=nested_dependencies,
        273β”‚         )
        274β”‚ 

   11  ~/.poetry/lib/poetry/packages/locker.py:272 in __walk_dependency_level
        270β”‚             packages_by_name=packages_by_name,
        271β”‚             project_level_dependencies=project_level_dependencies,
      β†’ 272β”‚             nested_dependencies=nested_dependencies,
        273β”‚         )
        274β”‚ 

   10  ~/.poetry/lib/poetry/packages/locker.py:240 in __walk_dependency_level
        238β”‚                 # if this is not done, we can end-up with incorrect nested dependencies
        239β”‚                 marker = requirement.marker
      β†’ 240β”‚                 requirement = locked_package.to_dependency()
        241β”‚                 requirement.marker = requirement.marker.intersect(marker)
        242β”‚             else:

    9  ~/.poetry/lib/poetry/_vendor/py3.7/poetry/core/packages/package.py:361 in to_dependency
        359β”‚ 
        360β”‚         if not self.python_constraint.is_any():
      β†’ 361β”‚             dep.python_versions = self.python_versions
        362β”‚ 
        363β”‚         if self._source_type not in ["directory", "file", "url", "git"]:

    8  ~/.poetry/lib/poetry/_vendor/py3.7/poetry/core/packages/dependency.py:117 in python_versions
        115β”‚                 parse_marker(
        116β”‚                     self._create_nested_marker(
      β†’ 117β”‚                         "python_version", self._python_constraint
        118β”‚                     )
        119β”‚                 )

    7  ~/.poetry/lib/poetry/_vendor/py3.7/poetry/core/version/markers.py:683 in parse_marker
        681β”‚         return AnyMarker()
        682β”‚ 
      β†’ 683β”‚     parsed = _parser.parse(marker)
        684β”‚ 
        685β”‚     markers = _compact_markers(parsed.children)

    6  ~/.poetry/lib/poetry/_vendor/py3.7/poetry/core/_vendor/lark/lark.py:391 in parse
        389β”‚         """
        390β”‚         try:
      β†’ 391β”‚             return self.parser.parse(text, start=start)
        392β”‚         except UnexpectedToken as e:
        393β”‚             if on_error is None:

    5  ~/.poetry/lib/poetry/_vendor/py3.7/poetry/core/_vendor/lark/parser_frontends.py:128 in parse
        126β”‚ 
        127β”‚         token_stream = self.lex(text, lambda: parser_state[0])
      β†’ 128β”‚         return self._parse(token_stream, start, set_parser_state)
        129β”‚ ###}
        130β”‚ 

    4  ~/.poetry/lib/poetry/_vendor/py3.7/poetry/core/_vendor/lark/parser_frontends.py:53 in _parse
         51β”‚                 raise ValueError("Lark initialized with more than 1 possible start rule. Must specify which start rule to parse", start)
         52β”‚             start ,= start
      β†’  53β”‚         return self.parser.parse(input, start, *args)
         54β”‚ 
         55β”‚ 

    3  ~/.poetry/lib/poetry/_vendor/py3.7/poetry/core/_vendor/lark/parsers/lalr_parser.py:36 in parse
         34β”‚ 
         35β”‚     def parse(self, *args):
      β†’  36β”‚         return self.parser.parse(*args)
         37β”‚ 
         38β”‚ 

    2  ~/.poetry/lib/poetry/_vendor/py3.7/poetry/core/_vendor/lark/parsers/lalr_parser.py:114 in parse
        112β”‚             _action, arg = get_action(token)
        113β”‚             assert(_action is Reduce)
      β†’ 114β”‚             reduce(arg)
        115β”‚             if state_stack[-1] == end_state:
        116β”‚                 return value_stack[-1]

    1  ~/.poetry/lib/poetry/_vendor/py3.7/poetry/core/_vendor/lark/parsers/lalr_parser.py:78 in reduce
         76β”‚                 s = []
         77β”‚ 
      β†’  78β”‚             value = self.callbacks[rule](s)
         79β”‚ 
         80β”‚             _action, new_state = states[state_stack[-1]][rule.origin.name]

  RecursionError

  maximum recursion depth exceeded

  at ~/.poetry/lib/poetry/_vendor/py3.7/poetry/core/_vendor/lark/parse_tree_builder.py:127 in __call__
      123β”‚                 else:   # Optimize for left-recursion
      124β”‚                     filtered = children[i].children
      125β”‚             else:
      126β”‚                 filtered.append(children[i])
    β†’ 127β”‚         return self.node_builder(filtered)
      128β”‚ 
      129β”‚ def _should_expand(sym):
      130β”‚     return not sym.is_term and sym.name.startswith('_')
      131β”‚ 

I've confirmed that this issue is _only_ occurring on poetry v1.1.3. Downgrading back to v1.1.2 resolves the RecursionError. I'm running these installations using the officially supported installer, not via pip or anything like that.

Here's a link to the current pyproject.toml: https://github.com/seandstewart/typical/blob/main/pyproject.toml

Also, I should note that I upgraded because I noticed poetry was exporting all of my optional dependencies by default...

I have the exact same issue as @seandstewart - install works fine, but export does not. Not sure if it is related to the OP or if it is better handled as a new issue?

Thank you for the reproducer @seandstewart.

Can you please try the fix at #3237. @estyrke @seandstewart @qiankunxienb

Using pipx

pipx install --suffix=@3237 'poetry @ git+https://github.com/python-poetry/poetry.git@refs/pull/3237/head'

Using a container (podman | docker)

podman run --rm -i --entrypoint bash python:3.8 <<EOF
set -xe
pip install -q git+https://github.com/python-poetry/poetry.git@refs/pull/3237/head
install -d foobar
pushd foobar
curl -sLO https://raw.githubusercontent.com/seandstewart/typical/main/pyproject.toml
poetry lock
poetry export -f requirements.txt --without-hashes
EOF

Note that the lock step will take a a minute or so.

Same problem here.
poetry@3237 worked fine and it took only a few seconds for 150+ deps πŸ‘
But it added python version restriction on every package.
Is it expected?
In pyproject.toml there is python = "^3.8" and i got:
flake8==3.8.4; (python_version >= "2.7" and python_full_version < "3.0.0") or (python_full_version >= "3.4.0")

@sergekir at the moment this comes via propagation from dependency markers so, it does not take into account the pypt python constraint. The per dependency python constraint is expected at the moment since we are simply propagating whats in the lock file. Will see if we can remove that later on.

@abn, poetry@3237 works great for me!

Was able to reproduce the maximum recursion depth exceeded on any dependency-resolving action on v1.0.9 but the issue was quickly fixed by updating to v1.1.3. Not sure if this is helpful or not.

Also providing the stacktrace from -vvv.

Hey @abn sorry for the late response - confirmed poetry@3237 works for me!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

etijskens picture etijskens  Β·  3Comments

thmo picture thmo  Β·  3Comments

ambv picture ambv  Β·  3Comments

ulope picture ulope  Β·  3Comments

jbarlow83 picture jbarlow83  Β·  3Comments