Poetry Repositories
Poetry installs from a CloudRepo Python repository and publishes to it. CloudRepo serves the same simple index and the same upload API that pip and twine use, so Poetry needs the repository’s address and a credential.
Before you start
Section titled “Before you start”- A Python repository. If you have none, see Creating a Repository.
- A repository token that reaches it, with Read + write if you will publish. See Repository Tokens: Create One and Authenticate. The username is the email address of the account that created the token, and the password is the token.
- Poetry, installed from Poetry’s own instructions.
Add CloudRepo as an explicit source
Section titled “Add CloudRepo as an explicit source”Name CloudRepo as an explicit source, and pin each private package to it. Poetry asks an
explicit source only for the packages pinned to it, so each private package comes from CloudRepo and
nothing else, and every other package comes from PyPI. List every package in [project]
dependencies, the table that poetry init writes, and pin each private one under
[tool.poetry.dependencies]. The source URL ends in /simple/:
[project]name = "my-service"version = "0.1.0"requires-python = ">=3.9"dependencies = [ "requests (>=2.31.0,<3.0.0)", # public: from PyPI "acme-shared-lib (>=1.2.0,<2.0.0)", # private: from CloudRepo alone "acme-utils (>=1.0.0,<2.0.0)", # a private dependency of acme-shared-lib]
[tool.poetry.dependencies]acme-shared-lib = { source = "cloudrepo" }acme-utils = { source = "cloudrepo" }
[[tool.poetry.source]]name = "cloudrepo"url = "https://your-org.mycloudrepo.io/repositories/your-repo/simple/"priority = "explicit"List and pin every private package, including each private package that your private packages depend
on. A pin alone is ignored: once [project] dependencies lists any package, Poetry reads a
[tool.poetry.dependencies] entry only for a package in that list. It prints no warning, and
poetry check still prints All set!. When another package needs a private package that is pinned but
not listed, Poetry looks it up on PyPI, as it does any dependency that names no source, and anyone can
publish a package on PyPI under your private package’s name. Do not use priority = "supplemental" for
private packages either: Poetry asks a supplemental source only when no primary source has a version that
satisfies the constraint, and whoever publishes a package on PyPI under your private package’s name can
choose a version that does.
poetry add installs at once. A private dependency that it meets before you have named its source is
installed from PyPI. So to add a private package from the command line, name every private package it
needs in one command, each with the source:
poetry add acme-utils acme-shared-lib --source cloudrepoIf you instead add only acme-shared-lib, with poetry add acme-shared-lib --source cloudrepo, while
acme-utils has no source yet, Poetry installs whatever package PyPI holds under the name acme-utils.
CloudRepo is never asked for it.
When a private package starts to need another private package, add that one too, with poetry add and
--source cloudrepo or by listing and pinning it by hand, before you run poetry update or
poetry lock --regenerate. Otherwise Poetry takes it from PyPI.
Give Poetry the credential
Section titled “Give Poetry the credential”Poetry reads the credential for a source from two environment variables. Their names carry the source’s
name in upper case, so the source called cloudrepo takes these. Set both from your secret store, here
as CLOUDREPO_USERNAME and CLOUDREPO_TOKEN:
export POETRY_HTTP_BASIC_CLOUDREPO_USERNAME="$CLOUDREPO_USERNAME"export POETRY_HTTP_BASIC_CLOUDREPO_PASSWORD="$CLOUDREPO_TOKEN"poetry installDo not use poetry config http-basic.cloudrepo. Given the token as an argument, it sits on the command
line where a process listing shows it. Without the argument, Poetry prompts for the token, and on a machine
with no keyring it prints Using a plaintext file to store credentials and writes the token to auth.toml
in Poetry’s configuration directory.
Publish
Section titled “Publish”Build, then publish to the repository URL without /simple/. Poetry reads the address from a third
variable named for the repository, so nothing is written to Poetry’s configuration, and the credential is
the same pair as above:
export POETRY_REPOSITORIES_CLOUDREPO_URL=https://your-org.mycloudrepo.io/repositories/your-repoexport POETRY_HTTP_BASIC_CLOUDREPO_USERNAME="$CLOUDREPO_USERNAME"export POETRY_HTTP_BASIC_CLOUDREPO_PASSWORD="$CLOUDREPO_TOKEN"poetry buildpoetry publish --repository cloudrepoExpected: Poetry prints Publishing and the project name, then Uploading and the file name for the
source distribution and the wheel, and exits without an error. The files are then in the repository, and
the admin portal lists them.
When Poetry answers 401, 403, 404 or 409
Section titled “When Poetry answers 401, 403, 404 or 409”Authorization error accessing. Poetry printsSource (cloudrepo): Authorization error accessingand the index URL, for a401and for a403alike. For a401the credential was refused or never sent: the username must be the email address of the account that created the token (__token__is refused: that is the convention on pypi.org, and CloudRepo does not use it), the password must be the token itself, and a token that is expired or revoked fails the same way. Check that the variable names match the source’s name in upper case. For a403the token does not reach this repository: a token reaches only the repositories ticked when it was created.doesn't match any versions. Poetry printsBecause ... depends on <package> (<version>) which doesn't match any versions, version solving failed. The repository does not hold that name and version, or the URL is wrong, or the dependency names no source and Poetry looked on PyPI. A proxy repository that the token does not reach also answers404, not403.HTTP Error 409: Conflict, on publish. The repository has Overwrite Protection on, and a file at that path already exists. Poetry prints the explanation CloudRepo sends with it after the status. Upload a new version, or turn Overwrite Protection off for that repository: see Python Repositories.
More: Repository tokens, for every client’s credential; Python Repositories, for pip and twine and the Python repository settings; uv Repositories, for uv.