-
Notifications
You must be signed in to change notification settings - Fork 105
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
[WIP] support poetry sources for private pypi repositories #353
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -156,7 +156,33 @@ The default category is `main`. | |
[environment.yml][envyaml], using a vendored copy of [Poetry's][poetry] dependency solver. | ||
|
||
### private pip repositories | ||
Right now `conda-lock` only supports [legacy](https://warehouse.pypa.io/api-reference/legacy.html) pypi repos with basic auth. Most self-hosted repositories like Nexus, Artifactory etc. use this. To use this feature, add your private repo into Poetry's config _including_ the basic auth in the url: | ||
|
||
`conda-lock` currently only supports [legacy](https://warehouse.pypa.io/api-reference/legacy.html) pypi repos with basic auth. Most self-hosted repositories like Nexus, Artifactory etc. use this. | ||
|
||
#### pyproject.toml: via poetry sources | ||
|
||
conda-lock can fetch packages from (private) python indices using [poetry sources](https://python-poetry.org/docs/repositories/#project-configuration) in the pyproject.toml: | ||
|
||
```toml | ||
[[tool.poetry.source]] | ||
name = "my_pypi" | ||
url = "https://pypi.python.org/simple" | ||
default = false | ||
secondary = false | ||
``` | ||
|
||
You need to manually assign the source to the dependent with the `source` keyword. | ||
|
||
```toml | ||
[tool.poetry.dependencies] | ||
numpy = {version="*", source="my_pypi"} | ||
``` | ||
|
||
Should your source require login credentials you can provide them via poetry commandline: `poetry config http-basic.<source-name> <username> <password>`. | ||
|
||
#### private pypi repos without pyproject.toml | ||
|
||
For sources other than `pyprojoect.toml` add your private repo into Poetry's config _including_ the basic auth in the url: | ||
|
||
```bash | ||
poetry config repositories.foo https://username:[email protected]/simple/ | ||
|
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -16,13 +16,15 @@ | |||||
ProjectPackage as PoetryProjectPackage, | ||||||
) | ||||||
from conda_lock._vendor.poetry.core.packages import URLDependency as PoetryURLDependency | ||||||
from conda_lock._vendor.poetry.core.toml.file import TOMLFile | ||||||
from conda_lock._vendor.poetry.factory import Factory | ||||||
from conda_lock._vendor.poetry.installation.chooser import Chooser | ||||||
from conda_lock._vendor.poetry.installation.operations.uninstall import Uninstall | ||||||
from conda_lock._vendor.poetry.puzzle import Solver as PoetrySolver | ||||||
from conda_lock._vendor.poetry.repositories.pool import Pool | ||||||
from conda_lock._vendor.poetry.repositories.pypi_repository import PyPiRepository | ||||||
from conda_lock._vendor.poetry.repositories.repository import Repository | ||||||
from conda_lock._vendor.poetry.utils.appdirs import user_config_dir | ||||||
from conda_lock._vendor.poetry.utils.env import Env | ||||||
from conda_lock.lookup import conda_name_to_pypi_name | ||||||
|
||||||
|
@@ -146,9 +148,11 @@ def get_dependency(dep: src_parser.Dependency) -> PoetryDependency: | |||||
# FIXME: how do deal with extras? | ||||||
extras: List[str] = [] | ||||||
if isinstance(dep, src_parser.VersionedDependency): | ||||||
return PoetryDependency( | ||||||
dependency = PoetryDependency( | ||||||
name=dep.name, constraint=dep.version or "*", extras=dep.extras | ||||||
) | ||||||
dependency.source_name = dep.channel # type: ignore | ||||||
return dependency | ||||||
elif isinstance(dep, src_parser.URLDependency): | ||||||
return PoetryURLDependency( | ||||||
name=dep.name, | ||||||
|
@@ -178,6 +182,7 @@ def solve_pypi( | |||||
conda_locked: Dict[str, lockfile.LockedDependency], | ||||||
python_version: str, | ||||||
platform: str, | ||||||
pypi_channels: Optional[List[src_parser.PyPIChannel]] = None, | ||||||
allow_pypi_requests: bool = True, | ||||||
verbose: bool = False, | ||||||
) -> Dict[str, lockfile.LockedDependency]: | ||||||
|
@@ -213,7 +218,7 @@ def solve_pypi( | |||||
for dep in dependencies: | ||||||
dummy_package.add_dependency(dep) | ||||||
|
||||||
pool = _prepare_repositories_pool(allow_pypi_requests) | ||||||
pool = _prepare_repositories_pool(allow_pypi_requests, pypi_channels) | ||||||
|
||||||
installed = Repository() | ||||||
locked = Repository() | ||||||
|
@@ -322,7 +327,10 @@ def solve_pypi( | |||||
return {dep.name: dep for dep in requirements} | ||||||
|
||||||
|
||||||
def _prepare_repositories_pool(allow_pypi_requests: bool) -> Pool: | ||||||
def _prepare_repositories_pool( | ||||||
allow_pypi_requests: bool, | ||||||
repositories: Optional[List[src_parser.PyPIChannel]] = None, | ||||||
) -> Pool: | ||||||
""" | ||||||
Prepare the pool of repositories to solve pip dependencies | ||||||
|
||||||
|
@@ -333,12 +341,34 @@ def _prepare_repositories_pool(allow_pypi_requests: bool) -> Pool: | |||||
""" | ||||||
factory = Factory() | ||||||
config = factory.create_config() | ||||||
repos = [ | ||||||
factory.create_legacy_repository( | ||||||
{"name": source[0], "url": source[1]["url"]}, config | ||||||
) | ||||||
for source in config.get("repositories", {}).items() | ||||||
] | ||||||
|
||||||
# read auth from global poetry config | ||||||
auth_config_file = TOMLFile(Path(user_config_dir("pypoetry")) / "auth.toml") | ||||||
if auth_config_file.exists(): | ||||||
config.merge(auth_config_file.read()) | ||||||
|
||||||
if repositories is not None: | ||||||
repo_config = {} | ||||||
for repo in repositories: | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If the user only lists their private repo, but they want to fall back on the default pypi, do they need to list the fallback in their There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The pypi fallback is defined by a separate configuration option - they would not have to list pypi as a source, but make sure that conda-lock/conda_lock/pypi_solver.py Lines 372 to 373 in f09744d
|
||||||
repo_config[repo.name] = {"url": repo.url} | ||||||
config.merge(dict(repositories=repo_config)) | ||||||
repos = [ | ||||||
factory.create_legacy_repository( | ||||||
dict( | ||||||
name=poetry_repo.name, | ||||||
url=poetry_repo.url, | ||||||
), | ||||||
config, | ||||||
) | ||||||
for poetry_repo in repositories | ||||||
] | ||||||
else: | ||||||
repos = [ | ||||||
factory.create_legacy_repository( | ||||||
{"name": source[0], "url": source[1]["url"]}, config | ||||||
) | ||||||
for source in config.get("repositories", {}).items() | ||||||
] | ||||||
if allow_pypi_requests: | ||||||
repos.append(PyPiRepository()) | ||||||
return Pool(repositories=[*repos]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you walk me through what happens here? When would an
auth.toml
exsist? Should this instead be looking for aconfig.toml
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the auth.toml gets created by
poetry config http-basic.<private-source-name> <user> <password>
, see: https://python-poetry.org/docs/repositories/#installing-from-private-package-sources. The code here assumes that for each source you added to your your pyproject.toml that needs login, you provided those bypoetry config
prior to attempting to lock.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh interesting for my use case i need to be on the companies VPN and i will be able to access to private repo.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not an expert, so I might be completely wrong here - but I think it shouldn't matter too much whether you are using VPN or not, as long as during locking and environment creation you are in the same VPN. And in case you still need to authenticate, you can do that with http basic authentication and the auth credentials are provided in the auth.toml file.