Skip to content
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

Support for full pip requirements.txt syntax in environment.yml? #171

Open
lesteve opened this issue Mar 11, 2022 · 11 comments
Open

Support for full pip requirements.txt syntax in environment.yml? #171

lesteve opened this issue Mar 11, 2022 · 11 comments

Comments

@lesteve
Copy link
Contributor

lesteve commented Mar 11, 2022

This may be stretching conda-lock a bit, but would there be a chance to support full pip requirements.txt syntax in environment.yml like the following one? This is supported by conda and mamba, see conda/conda#3969 for conda support:

# /tmp/environment.yml
channels:
  - conda-forge

dependencies:
  - pip
  - pip:
    - --pre
    - --extra-index https://pypi.anaconda.org/scipy-wheels-nightly/simple
    - numpy
    - https://github.com/joblib/joblib/archive/master.zip

The use case we have in scikit-learn:

  • we test against dev dependencies for scikit-learn (mostly numpy, scipy, pandas)
  • this would be nice to be able to conda-lock such an environment

Right now I get an error when trying to lock the environment because --pre does not look like a "standard" requirement e.g. something like package>version.

The full output with the error:

❯ conda-lock lock --mamba -p linux-64 -f /tmp/environment.yml 
Traceback (most recent call last):
  File "/home/lesteve/miniconda3/envs/conda-lock/lib/python3.10/site-packages/pkg_resources/_vendor/packaging/requirements.py", line 102, in __init__
    req = REQUIREMENT.parseString(requirement_string)
  File "/home/lesteve/miniconda3/envs/conda-lock/lib/python3.10/site-packages/pkg_resources/_vendor/pyparsing.py", line 1654, in parseString
    raise exc
  File "/home/lesteve/miniconda3/envs/conda-lock/lib/python3.10/site-packages/pkg_resources/_vendor/pyparsing.py", line 1644, in parseString
    loc, tokens = self._parse( instring, 0 )
  File "/home/lesteve/miniconda3/envs/conda-lock/lib/python3.10/site-packages/pkg_resources/_vendor/pyparsing.py", line 1402, in _parseNoCache
    loc,tokens = self.parseImpl( instring, preloc, doActions )
  File "/home/lesteve/miniconda3/envs/conda-lock/lib/python3.10/site-packages/pkg_resources/_vendor/pyparsing.py", line 3417, in parseImpl
    loc, exprtokens = e._parse( instring, loc, doActions )
  File "/home/lesteve/miniconda3/envs/conda-lock/lib/python3.10/site-packages/pkg_resources/_vendor/pyparsing.py", line 1402, in _parseNoCache
    loc,tokens = self.parseImpl( instring, preloc, doActions )
  File "/home/lesteve/miniconda3/envs/conda-lock/lib/python3.10/site-packages/pkg_resources/_vendor/pyparsing.py", line 3739, in parseImpl
    return self.expr._parse( instring, loc, doActions, callPreParse=False )
  File "/home/lesteve/miniconda3/envs/conda-lock/lib/python3.10/site-packages/pkg_resources/_vendor/pyparsing.py", line 1402, in _parseNoCache
    loc,tokens = self.parseImpl( instring, preloc, doActions )
  File "/home/lesteve/miniconda3/envs/conda-lock/lib/python3.10/site-packages/pkg_resources/_vendor/pyparsing.py", line 3400, in parseImpl
    loc, resultlist = self.exprs[0]._parse( instring, loc, doActions, callPreParse=False )
  File "/home/lesteve/miniconda3/envs/conda-lock/lib/python3.10/site-packages/pkg_resources/_vendor/pyparsing.py", line 1406, in _parseNoCache
    loc,tokens = self.parseImpl( instring, preloc, doActions )
  File "/home/lesteve/miniconda3/envs/conda-lock/lib/python3.10/site-packages/pkg_resources/_vendor/pyparsing.py", line 2711, in parseImpl
    raise ParseException(instring, loc, self.errmsg, self)
pkg_resources._vendor.pyparsing.ParseException: Expected W:(abcd...) (at char 0), (line:1, col:1)

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/lesteve/miniconda3/envs/conda-lock/bin/conda-lock", line 33, in <module>
    sys.exit(load_entry_point('conda-lock', 'console_scripts', 'conda-lock')())
  File "/home/lesteve/miniconda3/envs/conda-lock/lib/python3.10/site-packages/click/core.py", line 1128, in __call__
    return self.main(*args, **kwargs)
  File "/home/lesteve/miniconda3/envs/conda-lock/lib/python3.10/site-packages/click/core.py", line 1053, in main
    rv = self.invoke(ctx)
  File "/home/lesteve/miniconda3/envs/conda-lock/lib/python3.10/site-packages/click/core.py", line 1659, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
  File "/home/lesteve/miniconda3/envs/conda-lock/lib/python3.10/site-packages/click/core.py", line 1395, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/home/lesteve/miniconda3/envs/conda-lock/lib/python3.10/site-packages/click/core.py", line 754, in invoke
    return __callback(*args, **kwargs)
  File "/home/lesteve/miniconda3/envs/conda-lock/lib/python3.10/site-packages/click/decorators.py", line 26, in new_func
    return f(get_current_context(), *args, **kwargs)
  File "/home/lesteve/dev/conda-lock/conda_lock/conda_lock.py", line 1166, in lock
    lock_func(
  File "/home/lesteve/dev/conda-lock/conda_lock/conda_lock.py", line 936, in run_lock
    make_lock_files(
  File "/home/lesteve/dev/conda-lock/conda_lock/conda_lock.py", line 335, in make_lock_files
    lock_spec = make_lock_spec(
  File "/home/lesteve/dev/conda-lock/conda_lock/conda_lock.py", line 241, in make_lock_spec
    lock_specs = parse_source_files(
  File "/home/lesteve/dev/conda-lock/conda_lock/conda_lock.py", line 770, in parse_source_files
    parse_environment_file(src_file, pip_support=PIP_SUPPORT)
  File "/home/lesteve/dev/conda-lock/conda_lock/src_parser/environment_yaml.py", line 97, in parse_environment_file
    parse_python_requirement(
  File "/home/lesteve/dev/conda-lock/conda_lock/src_parser/pyproject_toml.py", line 239, in parse_python_requirement
    parsed_req = Requirement.parse(requirement_specifier)
  File "/home/lesteve/miniconda3/envs/conda-lock/lib/python3.10/site-packages/pkg_resources/__init__.py", line 3134, in parse
    req, = parse_requirements(s)
  File "/home/lesteve/miniconda3/envs/conda-lock/lib/python3.10/site-packages/pkg_resources/__init__.py", line 3089, in __init__
    super(Requirement, self).__init__(requirement_string)
  File "/home/lesteve/miniconda3/envs/conda-lock/lib/python3.10/site-packages/pkg_resources/_vendor/packaging/requirements.py", line 104, in __init__
    raise InvalidRequirement(
pkg_resources.extern.packaging.requirements.InvalidRequirement: Parse error at "'--pre'": Expected W:(abcd...)
@mariusvniekerk
Copy link
Collaborator

So part of that is possible and part of it is not entirely,

Since the pip solver being used is the poetry solver the configuration for allow-prereleases is not a global setting but a local one per dependency as defined over here
https://github.com/python-poetry/poetry-core/blob/ffc22b22a2e9d075ba93fea1348729bf9af2c3fd/src/poetry/core/packages/dependency.py#L39
I assume in this case you probably want just a prerelease of just numpy, and not everything else.

The pypi repositories being used are defined in https://github.com/conda-incubator/conda-lock/blob/9a1132d703dd34a5524becba15b976769781d52d/conda_lock/pypi_solver.py#L200-L201 , there is already a feature request to support those a bit better in #135 so adding in that should potentially be feasible.

@mariusvniekerk
Copy link
Collaborator

The harder part is which pip install arguments to support generically as there are quite a few of them and the mapping of them to poetry flags isn't necessarily trivial

@lesteve
Copy link
Contributor Author

lesteve commented Mar 11, 2022

I assume in this case you probably want just a prerelease of just numpy, and not everything else.

Yep indeed in practice we would want prerelease versions only for a few packages e.g. numpy, scipy, pandas so it would be fine to do it on a per-package basis.

there is already a feature request to support those a bit better in #135 so adding in that should potentially be feasible.

OK nice.

There was actually a third hidden feature request in my original post: having dependencies like https://github.com/joblib/joblib/archive/master.zip (and I assume git+https:// as well). Right now I am getting a parsing error:

pkg_resources.extern.packaging.requirements.InvalidRequirement: Parse error at "'://githu'": Expected stringEnd
Full error
conda-lock ❯ conda-lock lock --mamba -p linux-64 -f /tmp/test-environment.yml --lockfile /tmp/test-conda-lock.yml
Traceback (most recent call last):
  File "/home/lesteve/miniconda3/envs/conda-lock/lib/python3.10/site-packages/pkg_resources/_vendor/packaging/requirements.py", line 102, in __init__
    req = REQUIREMENT.parseString(requirement_string)
  File "/home/lesteve/miniconda3/envs/conda-lock/lib/python3.10/site-packages/pkg_resources/_vendor/pyparsing.py", line 1654, in parseString
    raise exc
  File "/home/lesteve/miniconda3/envs/conda-lock/lib/python3.10/site-packages/pkg_resources/_vendor/pyparsing.py", line 1644, in parseString
    loc, tokens = self._parse( instring, 0 )
  File "/home/lesteve/miniconda3/envs/conda-lock/lib/python3.10/site-packages/pkg_resources/_vendor/pyparsing.py", line 1402, in _parseNoCache
    loc,tokens = self.parseImpl( instring, preloc, doActions )
  File "/home/lesteve/miniconda3/envs/conda-lock/lib/python3.10/site-packages/pkg_resources/_vendor/pyparsing.py", line 3417, in parseImpl
    loc, exprtokens = e._parse( instring, loc, doActions )
  File "/home/lesteve/miniconda3/envs/conda-lock/lib/python3.10/site-packages/pkg_resources/_vendor/pyparsing.py", line 1406, in _parseNoCache
    loc,tokens = self.parseImpl( instring, preloc, doActions )
  File "/home/lesteve/miniconda3/envs/conda-lock/lib/python3.10/site-packages/pkg_resources/_vendor/pyparsing.py", line 3205, in parseImpl
    raise ParseException(instring, loc, self.errmsg, self)
pkg_resources._vendor.pyparsing.ParseException: Expected stringEnd (at char 5), (line:1, col:6)

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/lesteve/miniconda3/envs/conda-lock/bin/conda-lock", line 33, in <module>
    sys.exit(load_entry_point('conda-lock', 'console_scripts', 'conda-lock')())
  File "/home/lesteve/miniconda3/envs/conda-lock/lib/python3.10/site-packages/click/core.py", line 1128, in __call__
    return self.main(*args, **kwargs)
  File "/home/lesteve/miniconda3/envs/conda-lock/lib/python3.10/site-packages/click/core.py", line 1053, in main
    rv = self.invoke(ctx)
  File "/home/lesteve/miniconda3/envs/conda-lock/lib/python3.10/site-packages/click/core.py", line 1659, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
  File "/home/lesteve/miniconda3/envs/conda-lock/lib/python3.10/site-packages/click/core.py", line 1395, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/home/lesteve/miniconda3/envs/conda-lock/lib/python3.10/site-packages/click/core.py", line 754, in invoke
    return __callback(*args, **kwargs)
  File "/home/lesteve/miniconda3/envs/conda-lock/lib/python3.10/site-packages/click/decorators.py", line 26, in new_func
    return f(get_current_context(), *args, **kwargs)
  File "/home/lesteve/dev/conda-lock/conda_lock/conda_lock.py", line 1166, in lock
    lock_func(
  File "/home/lesteve/dev/conda-lock/conda_lock/conda_lock.py", line 936, in run_lock
    make_lock_files(
  File "/home/lesteve/dev/conda-lock/conda_lock/conda_lock.py", line 335, in make_lock_files
    lock_spec = make_lock_spec(
  File "/home/lesteve/dev/conda-lock/conda_lock/conda_lock.py", line 241, in make_lock_spec
    lock_specs = parse_source_files(
  File "/home/lesteve/dev/conda-lock/conda_lock/conda_lock.py", line 770, in parse_source_files
    parse_environment_file(src_file, pip_support=PIP_SUPPORT)
  File "/home/lesteve/dev/conda-lock/conda_lock/src_parser/environment_yaml.py", line 97, in parse_environment_file
    parse_python_requirement(
  File "/home/lesteve/dev/conda-lock/conda_lock/src_parser/pyproject_toml.py", line 239, in parse_python_requirement
    parsed_req = Requirement.parse(requirement_specifier)
  File "/home/lesteve/miniconda3/envs/conda-lock/lib/python3.10/site-packages/pkg_resources/__init__.py", line 3134, in parse
    req, = parse_requirements(s)
  File "/home/lesteve/miniconda3/envs/conda-lock/lib/python3.10/site-packages/pkg_resources/__init__.py", line 3089, in __init__
    super(Requirement, self).__init__(requirement_string)
  File "/home/lesteve/miniconda3/envs/conda-lock/lib/python3.10/site-packages/pkg_resources/_vendor/packaging/requirements.py", line 104, in __init__
    raise InvalidRequirement(
pkg_resources.extern.packaging.requirements.InvalidRequirement: Parse error at "'://githu'": Expected stringEnd

@rcthomas
Copy link

rcthomas commented Sep 1, 2023

Maybe this should be a separate issue, but I think it's related. I was wondering how to get conda-lock to install pip dependencies a la pip install --no-cache-dir ... instead of manually deleting the cache before running conda-lock install. Instead I think my question should be restated to is there a way to get conda-lock to get poetry to clear the cache before building those dependencies?

@maresb
Copy link
Contributor

maresb commented Sep 1, 2023

@rcthomas, is this motivated by reducing disk space for Docker or other space-constrained environments?

Unfortunately I don't think there's a good way to this automatically with the way things are currently structured. Manually deleting the cache seems to me like the way to go.

@rcthomas
Copy link

rcthomas commented Sep 2, 2023

@maresb no, not disk space, I just sometimes want to make sure that I'm not using the pip cache directory when building packages from PyPI.

The reason I followed up on this thread instead of opening a new one is that I'm actually not looking for a way to do this automatically, I was wondering if I could tell conda-lock to pass arguments like OP asked about, but to prevent using the pip cache (as if one were passing --no-cache-dir to pip install). Initially I thought "if there's just a way to pass arguments to pip" that would work but I do see why it's maybe not as easy as that.

@tbenst
Copy link

tbenst commented Jan 9, 2024

A simpler but related usecase, would be nice if requirements.txt was supported in environment.yml

dependencies:
  - python=3.11
  - pip
  - pip:
    - -r requirements.txt
    - conda-lock

@maresb
Copy link
Contributor

maresb commented Jan 9, 2024

Ya, I see this thread as good motivation to eliminate conda-lock's use of Poetry, replacing it with a generic solver.

@ollie-bell
Copy link

ollie-bell commented Jun 6, 2024

Since the pip solver being used is the poetry solver the configuration for allow-prereleases is not a global setting but a local one per dependency as defined over here https://github.com/python-poetry/poetry-core/blob/ffc22b22a2e9d075ba93fea1348729bf9af2c3fd/src/poetry/core/packages/dependency.py#L39 I assume in this case you probably want just a prerelease of just numpy, and not everything else.

How does one get the poetry dependency solver in conda-lock to set allow_prereleases to True when finding the appropriate package version? Is this something that can be done with some special syntax in the environment.yaml file?

@maresb
Copy link
Contributor

maresb commented Jun 6, 2024

I don't think we currently have any way to activate allow_prereleases=True. I think you'd have to patch the source. If you add an option to pyproject.toml and a test I wouldn't see any problem with merging it in a PR.

@ollie-bell
Copy link

Ah ok. That's a shame because pip's default behaviour is to find pre-releases when it can't find a stable release (which is the issue in my case... installing the conda environment works fine but exporting it using conda-lock fails). I'll look into it but not familiar with poetry at all!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants