python-poetry/poetry

poetry publish fails when tool.poetry.source is specified throwing "a repository with name was already added"

Jakobhenningjensen opened this issue · 9 comments

Description

When releasing some code we have a system which step 1 is to run a unittest. If that passes, the code is published to our internal packages such that we can use them in production.
The code for the unittest/publish is

set -e
pip install poetry==1.8.3 keyring==24.0.0 keyrings.google-artifactregistry-auth==1.1.1

poetry install
poetry run pytest ./tests/unit_tests

poetry config repositories.my_repo https://my-package/packages"

poetry publish --build -r my_repo

The issue is that the publish part fails when I want to include pytorch with CUDA, thus I have to specify where to get the CUDA-torch from using the tool.poetry.source block.
The publish part throws the warning/error

A repository with name torch-gpu-linux was already added.

and exists with status 1, making the entire pipeline failing since the package cannot be published.

It seems like the repo specified in tool.poetry.source is being added twice, thus failing on the second one.

Workarounds

Not in the .toml-file.

The way we work around it later on, is to skip the torch-part completely and then install it manually later on when the package is downloaded (which easily can lead to bugs).

Poetry Installation Method

pip

Operating System

It is run in a docker-container

Poetry Version

1.8.3

Poetry Configuration

cache-dir = "/root/.cache/pypoetry"
experimental.system-git-client = false
installer.max-workers = null
installer.modern-installation = true
installer.no-binary = null
installer.parallel = true
repositories.dinero.url = "https://europe-west4-python.pkg.dev/test-dineroci-cm/ai-packages/"
repositories.torch-gpu-linux.url = "https://download.pytorch.org/whl/cu118"
virtualenvs.create = true
virtualenvs.in-project = null
virtualenvs.options.always-copy = false
virtualenvs.options.no-pip = false
virtualenvs.options.no-setuptools = false
virtualenvs.options.system-site-packages = false
virtualenvs.path = "{cache-dir}/virtualenvs"  # /root/.cache/pypoetry/virtualenvs
virtualenvs.prefer-active-python = false
virtualenvs.prompt = "{project_name}-py{python_version}"

Python Sysconfig

No response

Example pyproject.toml

The (minimalistic) toml-file is


[tool.poetry]
name = "Foo"
version = "0"
description = ""
authors = ["Me"]
readme = "README.md"

[tool.poetry.dependencies]
python = "~3.11"
sentence-transformers = "^2.7.0"
torch = [
    { version = "^2.3.0", markers = "sys_platform == 'darwin'" },   # macOS, no CUDA
    { version = "^2.3.0+cu118", markers = "sys_platform == 'linux'", source="torch-gpu-linux" }  # Linux with CUDA
]

[tool.poetry.dev-dependencies]
pytest = "^7.2.0"

[[tool.poetry.source]]
name = "my_repo"
url = "https://my-package/packages"
priority = "primary"


[[tool.poetry.source]]
name = "PyPI"
priority = "supplemental"

[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"

[[tool.poetry.source]]
name = "torch-gpu-linux"
url = "https://download.pytorch.org/whl/cu118"
priority = "explicit"

Poetry Runtime Logs

poetry publish --build -r my_repo
Loading configuration file /root/.config/pypoetry/config.toml
[11:37:55][Step 1/1] Adding repository repo (https://my-package/packages) and setting it as primary
[11:37:55][Step 1/1] Adding repository PyPI (https://pypi.org/simple/) and setting it as supplemental
[11:37:55][Step 1/1] Adding repository torch-gpu-linux (https://download.pytorch.org/whl/cu118) and setting it as explicit
[11:37:55][Step 1/1] Adding repository torch-gpu-linux (https://download.pytorch.org/whl/cu118) and setting it as explicit
[11:37:56][Step 1/1] 
[11:37:56][Step 1/1]   Stack trace:
[11:37:56][Step 1/1] 
[11:37:56][Step 1/1]   12  /usr/local/lib/python3.11/site-packages/cleo/application.py:327 in run
[11:37:56][Step 1/1]        325│ 
[11:37:56][Step 1/1]        326│             try:
[11:37:56][Step 1/1]      → 327│                 exit_code = self._run(io)
[11:37:56][Step 1/1]        328│             except BrokenPipeError:
[11:37:56][Step 1/1]        329│                 # If we are piped to another process, it may close early and send a
[11:37:56][Step 1/1] 
[11:37:56][Step 1/1]   11  /usr/local/lib/python3.11/site-packages/poetry/console/application.py:190 in _run
[11:37:56][Step 1/1]        188│         self._load_plugins(io)
[11:37:56][Step 1/1]        189│ 
[11:37:56][Step 1/1]      → 190│         exit_code: int = super()._run(io)
[11:37:56][Step 1/1]        191│         return exit_code
[11:37:56][Step 1/1]        192│ 
[11:37:56][Step 1/1] 
[11:37:56][Step 1/1]   10  /usr/local/lib/python3.11/site-packages/cleo/application.py:431 in _run
[11:37:56][Step 1/1]        429│             io.input.interactive(interactive)
[11:37:56][Step 1/1]        430│ 
[11:37:56][Step 1/1]      → 431│         exit_code = self._run_command(command, io)
[11:37:56][Step 1/1]        432│         self._running_command = None
[11:37:56][Step 1/1]        433│ 
[11:37:56][Step 1/1] 
[11:37:56][Step 1/1]    9  /usr/local/lib/python3.11/site-packages/cleo/application.py:473 in _run_command
[11:37:56][Step 1/1]        471│ 
[11:37:56][Step 1/1]        472│         if error is not None:
[11:37:56][Step 1/1]      → 473│             raise error
[11:37:56][Step 1/1]        474│ 
[11:37:56][Step 1/1]        475│         return terminate_event.exit_code
[11:37:56][Step 1/1] 
[11:37:56][Step 1/1]    8  /usr/local/lib/python3.11/site-packages/cleo/application.py:457 in _run_command
[11:37:56][Step 1/1]        455│ 
[11:37:56][Step 1/1]        456│             if command_event.command_should_run():
[11:37:56][Step 1/1]      → 457│                 exit_code = command.run(io)
[11:37:56][Step 1/1]        458│             else:
[11:37:56][Step 1/1]        459│                 exit_code = ConsoleCommandEvent.RETURN_CODE_DISABLED
[11:37:56][Step 1/1] 
[11:37:56][Step 1/1]    7  /usr/local/lib/python3.11/site-packages/cleo/commands/base_command.py:117 in run
[11:37:56][Step 1/1]        115│         io.input.validate()
[11:37:56][Step 1/1]        116│ 
[11:37:56][Step 1/1]      → 117│         return self.execute(io) or 0
[11:37:56][Step 1/1]        118│ 
[11:37:56][Step 1/1]        119│     def merge_application_definition(self, merge_args: bool = True) -> None:
[11:37:56][Step 1/1] 
[11:37:56][Step 1/1]    6  /usr/local/lib/python3.11/site-packages/cleo/commands/command.py:61 in execute
[11:37:56][Step 1/1]         59│ 
[11:37:56][Step 1/1]         60│         try:
[11:37:56][Step 1/1]      →  61│             return self.handle()
[11:37:56][Step 1/1]         62│         except KeyboardInterrupt:
[11:37:56][Step 1/1]         63│             return 1
[11:37:56][Step 1/1] 
[11:37:56][Step 1/1]    5  /usr/local/lib/python3.11/site-packages/poetry/console/commands/publish.py:52 in handle
[11:37:56][Step 1/1]         50│         from poetry.publishing.publisher import Publisher
[11:37:56][Step 1/1]         51│ 
[11:37:56][Step 1/1]      →  52│         publisher = Publisher(self.poetry, self.io)
[11:37:56][Step 1/1]         53│ 
[11:37:56][Step 1/1]         54│         # Building package first, if told
[11:37:56][Step 1/1] 
[11:37:56][Step 1/1]    4  /usr/local/lib/python3.11/site-packages/poetry/console/commands/command.py:23 in poetry
[11:37:56][Step 1/1]         21│     def poetry(self) -> Poetry:
[11:37:56][Step 1/1]         22│         if self._poetry is None:
[11:37:56][Step 1/1]      →  23│             return self.get_application().poetry
[11:37:56][Step 1/1]         24│ 
[11:37:56][Step 1/1]         25│         return self._poetry
[11:37:56][Step 1/1] 
[11:37:56][Step 1/1]    3  /usr/local/lib/python3.11/site-packages/poetry/console/application.py:129 in poetry
[11:37:56][Step 1/1]        127│             project_path = self._io.input.option("directory")
[11:37:56][Step 1/1]        128│ 
[11:37:56][Step 1/1]      → 129│         self._poetry = Factory().create_poetry(
[11:37:56][Step 1/1]        130│             cwd=project_path,
[11:37:56][Step 1/1]        131│             io=self._io,
[11:37:56][Step 1/1] 
[11:37:56][Step 1/1]    2  /usr/local/lib/python3.11/site-packages/poetry/factory.py:95 in create_poetry
[11:37:56][Step 1/1]         93│ 
[11:37:56][Step 1/1]         94│         poetry.set_pool(
[11:37:56][Step 1/1]      →  95│             self.create_pool(
[11:37:56][Step 1/1]         96│                 config,
[11:37:56][Step 1/1]         97│                 poetry.local_config.get("source", []),
[11:37:56][Step 1/1] 
[11:37:56][Step 1/1]    1  /usr/local/lib/python3.11/site-packages/poetry/factory.py:172 in create_pool
[11:37:56][Step 1/1]        170│                 io.write_line(message)
[11:37:56][Step 1/1]        171│ 
[11:37:56][Step 1/1]      → 172│             pool.add_repository(repository, priority=priority)
[11:37:56][Step 1/1]        173│             if repository.name.lower() == "pypi":
[11:37:56][Step 1/1]        174│                 explicit_pypi = True
[11:37:56][Step 1/1] 
[11:37:56][Step 1/1]   ValueError
[11:37:56][Step 1/1] 
[11:37:56][Step 1/1]   A repository with name torch-gpu-linux was already added.
[11:37:56][Step 1/1] 
[11:37:56][Step 1/1]   at /usr/local/lib/python3.11/site-packages/poetry/repositories/repository_pool.py:132 in add_repository
[11:37:56][Step 1/1]       128│         Adds a repository to the pool.
[11:37:56][Step 1/1]       129│         """
[11:37:56][Step 1/1]       130│         repository_name = repository.name.lower()
[11:37:56][Step 1/1]       131│         if self.has_repository(repository_name):
[11:37:56][Step 1/1]     → 132│             raise ValueError(
[11:37:56][Step 1/1]       133│                 f"A repository with name {repository_name} was already added."
[11:37:56][Step 1/1]       134│             )
[11:37:56][Step 1/1]       135│ 
[11:37:56][Step 1/1]       136│         if default or secondary:
[11:37:56][Step 1/1] Process exited with code 1

does not reproduce - as expected I see an error about connecting to "my_repo" but no sign of the error that you are reporting

$ poetry publish --build -r my_repo
Building Foo (0)
  - Building sdist
  - Built foo-0.tar.gz
  - Building wheel
  - Built foo-0-py3-none-any.whl

Publishing Foo (0) to my_repo
 - Uploading foo-0-py3-none-any.whl FAILED

Connection Error: We were unable to connect to the repository, ensure the url is correct and can be reached.

please provide a way to reproduce

I don't know how else I should reproduce apart from the code above, since it's the one causing the error.

If I remove the torch-gpu-linux source (and just have torch="2.3.0") it works fine

maybe provide a dockerfile in which the error happens, then we should get past any "works on my computer" differences

(still works on my computer, though!)

Just being curious; if you use the "-vvv" flag for publish, is "pytorch-gpu" only being added once?

For some odd reason, changing the version from "0" to "1" in my .toml file seemed to work. I also added "PyPI" as source for the "darwin" source, thus I don't know which of them did the trick but .. 🤷

perhaps you had previously made changes but forgot to hit "save"...

well anyway: I guess either provide a repro or close this out, please

It looks like it is adding torch-gpu-linux twice because it is configured in the poetry config as a repository and the pyproject.toml as a source. Poetry merges these 2 at run time and that is probably why you are running into this specific issue. Remove it from the poetry config and try again.

It looks like it is adding torch-gpu-linux twice because it is configured in the poetry config as a repository and the pyproject.toml as a source. Poetry merges these 2 at run time and that is probably why you are running into this specific issue. Remove it from the poetry config and try again.

Where is the poetry config? I have only modified the pyproject.toml

I always forget where it is but it doesn't matter, you can modify and see the contents using the 'poetry config' command.

'poetry config --unset repositories.' should do it I think.