Skip to content

Poetry 1.2+ incorrectly appears to validate 'platform_release' markers against PEP 440 #7418

Closed
python-poetry/poetry-core
#722
@j-baker

Description

  • Poetry version: 1.3.2
  • Python version: 3.11.1
  • OS version and name: macOS 13.1
  • pyproject.toml: not publicly available pyproject.toml, but doesn't seem relevant.
  • I am on the latest stable Poetry version, installed using a recommended method.
  • I have searched the issues of this repo and believe that this is not a duplicate.
  • I have consulted the FAQ and blog for any relevant entries or release notes.
  • If an exception occurs when executing a command, I executed it again in debug mode (-vvv option) and have included the output below.

Issue

We have a package with a marker on a platform_constraint. I'm not fully spun up on what it's doing, but I think it's downloading different versions of a dependency depending on which embedded platform Poetry is being run on.

I believe that this is a regression between Poetry 1.1.15 and Poetry 1.2 because Poetry 1.2 stopped supporting Python 3.6 and this project was stuck on that until recently.

The constraint looks something like:

some-package = [
    {version="1.0.0", optional = true, source = "source", markers = "platform_release == '1.0.0-platformname'}
    {version="1.2.1", optional = true, source = "source", markers = "platform_release == '1.0.0-otherplatformname'}
]

What I'm seeing is that PEP440 constraint validation is failing on the platform_release, and clearly that's not a valid PEP440 constraint. It's also not meant to be, though - PEP508 describes that a platform_release might be something like 3.14.1-x86_64-linode39. From my read of the code, I have a hunch that... platform_releases are considered to be 'version like' because they could be of the form 13.0 or the like, and at some point, someone started validating version like constraints against PEP 440. But I'm not familiar with this codebase so it's just a hunch.

  Stack trace:

  20  ~/.local/pipx/venvs/poetry/lib/python3.11/site-packages/cleo/application.py:327 in run
       325│
       326│             try:
     → 327│                 exit_code = self._run(io)
       328│             except BrokenPipeError:
       329│                 # If we are piped to another process, it may close early and send a

  19  ~/.local/pipx/venvs/poetry/lib/python3.11/site-packages/poetry/console/application.py:190 in _run
       188│         self._load_plugins(io)
       189│
     → 190│         exit_code: int = super()._run(io)
       191│         return exit_code
       192│

  18  ~/.local/pipx/venvs/poetry/lib/python3.11/site-packages/cleo/application.py:431 in _run
       429│             io.input.interactive(interactive)
       430│
     → 431│         exit_code = self._run_command(command, io)
       432│         self._running_command = None
       433│

  17  ~/.local/pipx/venvs/poetry/lib/python3.11/site-packages/cleo/application.py:473 in _run_command
       471│
       472│         if error is not None:
     → 473│             raise error
       474│
       475│         return terminate_event.exit_code

  16  ~/.local/pipx/venvs/poetry/lib/python3.11/site-packages/cleo/application.py:457 in _run_command
       455│
       456│             if command_event.command_should_run():
     → 457│                 exit_code = command.run(io)
       458│             else:
       459│                 exit_code = ConsoleCommandEvent.RETURN_CODE_DISABLED

  15  ~/.local/pipx/venvs/poetry/lib/python3.11/site-packages/cleo/commands/base_command.py:119 in run
       117│         io.input.validate()
       118│
     → 119│         status_code = self.execute(io)
       120│
       121│         if status_code is None:

  14  ~/.local/pipx/venvs/poetry/lib/python3.11/site-packages/cleo/commands/command.py:62 in execute
        60│
        61│         try:
     →  62│             return self.handle()
        63│         except KeyboardInterrupt:
        64│             return 1

  13  ~/.local/pipx/venvs/poetry/lib/python3.11/site-packages/poetry/console/commands/version.py:87 in handle
        85│             else:
        86│                 self.line(
     →  87│                     f"{self.poetry.package.name}"
        88│                     f" {self.poetry.package.pretty_version}"
        89│                 )

  12  ~/.local/pipx/venvs/poetry/lib/python3.11/site-packages/poetry/console/commands/command.py:23 in poetry
        21│     def poetry(self) -> Poetry:
        22│         if self._poetry is None:
     →  23│             return self.get_application().poetry
        24│
        25│         return self._poetry

  11  ~/.local/pipx/venvs/poetry/lib/python3.11/site-packages/poetry/console/application.py:129 in poetry
       127│             project_path = self._io.input.option("directory")
       128│
     → 129│         self._poetry = Factory().create_poetry(
       130│             cwd=project_path,
       131│             io=self._io,

  10  ~/.local/pipx/venvs/poetry/lib/python3.11/site-packages/poetry/factory.py:55 in create_poetry
        53│             io = NullIO()
        54│
     →  55│         base_poetry = super().create_poetry(cwd=cwd, with_groups=with_groups)
        56│
        57│         locker = Locker(

   9  ~/.local/pipx/venvs/poetry/lib/python3.11/site-packages/poetry/core/factory.py:65 in create_poetry
        63│         assert isinstance(version, str)
        64│         package = self.get_package(name, version)
     →  65│         package = self.configure_package(
        66│             package, local_config, poetry_file.parent, with_groups=with_groups
        67│         )

   8  ~/.local/pipx/venvs/poetry/lib/python3.11/site-packages/poetry/core/factory.py:159 in configure_package
       157│
       158│         if "dependencies" in config:
     → 159│             cls._add_package_group_dependencies(
       160│                 package=package, group=MAIN_GROUP, dependencies=config["dependencies"]
       161│             )

   7  ~/.local/pipx/venvs/poetry/lib/python3.11/site-packages/poetry/core/factory.py:105 in _add_package_group_dependencies
       103│
       104│                 group.add_dependency(
     → 105│                     cls.create_dependency(
       106│                         name,
       107│                         _constraint,

   6  ~/.local/pipx/venvs/poetry/lib/python3.11/site-packages/poetry/core/factory.py:347 in create_dependency
       345│                 )
       346│
     → 347│             marker = parse_marker(markers) if markers else AnyMarker()
       348│
       349│             if python_versions:

   5  ~/.local/pipx/venvs/poetry/lib/python3.11/site-packages/poetry/core/version/markers.py:791 in parse_marker
       789│     parsed = _parser.parse(marker)
       790│
     → 791│     markers = _compact_markers(parsed.children)
       792│
       793│     return markers

   4  ~/.local/pipx/venvs/poetry/lib/python3.11/site-packages/poetry/core/version/markers.py:809 in _compact_markers
       807│         if token.data == "marker":
       808│             groups[-1] = MultiMarker.of(
     → 809│                 groups[-1], _compact_markers(token.children, tree_prefix=tree_prefix)
       810│             )
       811│         elif token.data == f"{tree_prefix}item":

   3  ~/.local/pipx/venvs/poetry/lib/python3.11/site-packages/poetry/core/version/markers.py:821 in _compact_markers
       819│             value = value[1:-1]
       820│             groups[-1] = MultiMarker.of(
     → 821│                 groups[-1], SingleMarker(str(name), f"{op}{value}")
       822│             )
       823│         elif token.data == f"{tree_prefix}BOOL_OP" and token.children[0] == "or":

   2  ~/.local/pipx/venvs/poetry/lib/python3.11/site-packages/poetry/core/version/markers.py:232 in __init__
       230│                 self._constraint = self._parser(glue.join(versions))
       231│             else:
     → 232│                 self._constraint = self._parser(constraint_string)
       233│         else:
       234│             # if we have a in/not in operator we split the constraint

   1  ~/.local/pipx/venvs/poetry/lib/python3.11/site-packages/poetry/core/constraints/version/parser.py:36 in parse_constraint
        34│                 constraint_objects.append(parse_single_constraint(constraint))
        35│         else:
     →  36│             constraint_objects.append(parse_single_constraint(and_constraints[0]))
        37│
        38│         if len(constraint_objects) == 1:

  ParseConstraintError

  Could not parse version constraint: ==1.0.0-ourversion

  at ~/.local/pipx/venvs/poetry/lib/python3.11/site-packages/poetry/core/constraints/version/parser.py:167 in parse_single_constraint
      163│         if op == "!=":
      164│             return VersionUnion(VersionRange(max=version), VersionRange(min=version))
      165│         return version
      166│
    → 167│     raise ParseConstraintError(f"Could not parse version constraint: {constraint}")
      168│

Metadata

Assignees

No one assigned

    Labels

    area/coreRelated to the poetry-core librarykind/bugSomething isn't working as expected

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions