uv icon indicating copy to clipboard operation
uv copied to clipboard

Support URL and path dependencies without a package name

Open charliermarsh opened this issue 1 year ago • 34 comments

Apparently this works with pip?

git+https://github.com/pallets/flask.git@refs/pull/5313/head

As opposed to:

flask @ git+https://github.com/pallets/flask.git@refs/pull/5313/head

We could decide not to support these. I don't know if they're spec-compliant.

charliermarsh avatar Nov 03 '23 18:11 charliermarsh

\cc @konstin - do you know if these are spec-compliant? Or legacy?

charliermarsh avatar Nov 03 '23 18:11 charliermarsh

They are iirc not part of PEP 621 and PEP 508, but they are supported in many places (pip install https://... makes sense)

konstin avatar Nov 03 '23 18:11 konstin

Sadly, adds a lot of complexity.

charliermarsh avatar Nov 03 '23 18:11 charliermarsh

Oh this is the syntax I use every time I install a package from git using pip 😬

I'm not sure if we really need to support it in a requirements file? Unless it's common in the wild. Generally it seems reasonable to have a nice error suggesting inclusion of the package name.

zanieb avatar Nov 04 '23 04:11 zanieb

If we support it at all, then it’s not too hard to support it in a requirements file too.

charliermarsh avatar Nov 04 '23 13:11 charliermarsh

Although, I guess it lets us skip supporting it in the parser. Anyway, we probably do need to support this long-term if it’s allowed in pyproject.toml.

charliermarsh avatar Nov 04 '23 13:11 charliermarsh

But yeah we should support them :)

charliermarsh avatar Nov 04 '23 13:11 charliermarsh

@konstin - Do you think we should make name optional on Requirement, or convert Requirement to an enum? Names can only be omitted when the version specific is a URL. Similarly, you can't have extras without a name. Feels like all of this could be encoded in the type system.

charliermarsh avatar Nov 05 '23 15:11 charliermarsh

We should add a RequirementsTxtRequirement which allows not having a name (or where name can be a url), i'd keep PEP 508 Requirement as-is.

konstin avatar Nov 06 '23 09:11 konstin

I'll give this another try.

charliermarsh avatar Dec 13 '23 06:12 charliermarsh

Would you mind waiting until #587 is merged? Editables will profit from this, but doing it now would clash badly.

konstin avatar Dec 13 '23 14:12 konstin

Will do!

charliermarsh avatar Dec 13 '23 14:12 charliermarsh

It seems like this is also an issue for installing a local whl file?

% uv pip install ./streamlit-1.31.1-py2.py3-none-any.whl 
error: Failed to parse `./streamlit-1.31.1-py2.py3-none-any.whl`
  Caused by: Expected package name starting with an alphanumeric character, found '.'
./streamlit-1.31.1-py2.py3-none-any.whl
^

% uv pip install "streamlit @ ./streamlit-1.31.1-py2.py3-none-any.whl"
Resolved 40 packages in 680ms
Downloaded 40 packages in 1.74s
Installed 40 packages in 97ms
...

BTW uv seems awesome!! Thank you!!!

sfc-gh-jcarroll avatar Feb 16 '24 21:02 sfc-gh-jcarroll

Yup, all the same issue! Although we can probably support local wheels "trivially" since the file name is required to be encoded in the wheel.

charliermarsh avatar Feb 16 '24 21:02 charliermarsh

This is probably the biggest blocker to experimenting with uv in Meltano since dependencies of the type git+https://... are very widely used by plugins.

edgarrmondragon avatar Feb 17 '24 05:02 edgarrmondragon

👍 I want to support this, requires a bunch of internal refactors but definitely doable.

charliermarsh avatar Feb 17 '24 14:02 charliermarsh

Hopefully not to add to the confusion - I've been running scenarios against integrating with pdm.

While investigating my own feature request, pdm-project/pdm#2641 I discovered pdm is handling requirements.txt-style exports in a way that falls back to pip's behavior...and works with uv if I remove the #egg= fragments.

Here's some quirks I was able to discover. Being able to do uv v --seed for running through was very helpful, I use the .venv/bin/pip for wherever pip install is used. I believe these quirks would be universal, anywhere there's a python package with a pyproject.toml.

I'm using the pdm-example-monorepo below in the latest Python Docker image under a freshly made user in their home directory.

When in a git directory:

pip will end up resolving an editable install (pip install -e 'file://'$PWD'relative/path') of a local path that's inside a git directory differently than one that is not.

When inside a git directory, pip will include an #egg= fragment along with another fragment param for its relative directory, subdirectory.

e.g.;

# replace .venv
$ uv v --seed
# install the package as editable with relative path
$ .venv/bin/pip install -e 'file://'$PWD'packages/pkg-second'

# ...

# show pip installation
$ .venv/bin/pip freeze | grep pkg-core

-e git+https://github.com/pdm-project/pdm-example-monorepo@b85261555ea063e68eaf744e225804149c27e64f#egg=pkg_core&subdirectory=packages/pkg-core

When it's not a git directory, and it's still an editable install:

# replace .venv
$ uv v --seed
# get rid of .git, so it's not detected as a git repository
$ mv .git .gitold
# install the package as editable with relative installation, again
$ .venv/bin/pip install -e 'file://'$PWD'/packages/pkg-core'

# ...

# show pip installation
$ .venv/bin/pip freeze | grep pkg-core

# Editable install with no version control (pkg-core==0.1.0+editable)
-e /home/python/pdm-example-monorepo/packages/pkg-core

Non-editable installs for comparison

There's also this way that will lend itself to the next example - pkg-name @ file:///..., which cannot be installed as editable, regardless of git directory or not:

# replace .venv
$ uv v --seed
# install relative package, non-editable, pkg @ file://... way
$ .venv/bin/pip install 'pkg-core @ file://'$PWD'/packages/pkg-core'

# ...

# freezes the same way whether in a git repository or not
$ venv/bin/pip freeze | grep pkg-core

pkg-core @ file:///home/python/pdm-example-monorepo/packages/pkg-core

And lastly - pip install 'file://... will result in the same package-name @ file://... expansion regardless if it's in a git directory or not 😅

# replace .venv
$ uv v --seed
# install non-editable, just 'file://...' 
$ .venv/bin/pip install 'file://'$PWD'/packages/pkg-core'

# ...

# freezes the same way whether in git repository or not
$ .venv/bin/pip freeze | grep pkg-core
pkg-core @ file:///home/python/pdm-example-monorepo/packages/pkg-core

yyolk avatar Feb 21 '24 01:02 yyolk

We have a similar use case; we want to install a package in a local directory without editable.

We have several Python packages in a mono repo. Sometimes we need to create a python venv, install those packages into the venv, then pack the venv and distribute it to CI or production environment.

So we want to be able to install a local package like this:

uv pip install ./path/to/package/dir

We don't want to use -e here because the venv will be redistributed.

kkpattern avatar Feb 22 '24 07:02 kkpattern

@kkpattern - that is supported, but you need to include the package name, like “ uv pip install ‘foo @ ./path/to/package/dir’”. We’ll lift this restriction in time, I’m mostly focused on correctness issues right now.

charliermarsh avatar Feb 22 '24 13:02 charliermarsh

@charliermarsh Yes. We figured that out. We have already switched to uv on our main branch. Massive speed up. Thanks for this awesome tool. (And ruff too!)

kkpattern avatar Feb 22 '24 13:02 kkpattern

I could able to install the package as mentioned above ways. but uv pip sync requirements.txt is failing. I am running uv pip freeze > requirements.txt to generate the txt file.

error: Couldn't parse requirement in `requirements.txt` at position 384
  Caused by: Trailing `(from https://<url>/<package>-0.7.1-py3-none-any.whl)` is not allowed

shekharidentv avatar Feb 22 '24 15:02 shekharidentv

@shekharidentv - do you mind opening a new issue for this? We may want to strip those URLs from freeze.

charliermarsh avatar Feb 22 '24 16:02 charliermarsh

👍 for this feature. I'm liking UV so much that I'm using pip install path/to/my.whl (which is slow) and then uv pip install after.

jkgenser avatar Mar 09 '24 18:03 jkgenser

@jkgenser note you can just provide a package name e.g. uv pip install "foo@path/to/my.whl" in the meantime.

zanieb avatar Mar 09 '24 19:03 zanieb

@jkgenser note you can just provide a package name e.g. uv pip install "foo@path/to/my.whl" in the meantime.

Wow amazing thank you that worked! I was having trouble because I saw other examples in github issues that referred to "package @ path/to/my.whl" and it wasn't working me. However removing the spaces was what was needed.

jkgenser avatar Mar 10 '24 14:03 jkgenser

How to install optional deps? uv pip install xxx@./xxx[yy] dont work and says Distribution not found

aliencaocao avatar Mar 10 '24 16:03 aliencaocao

How to install optional deps? uv pip install xxx@./xxx[yy] dont work

I'd guess uv pip install package[extra]@location.

akx avatar Mar 10 '24 16:03 akx

Loving uv so far!

Will supporting this also allow the very basic uv pip install . (non-editable) to work?

jeremander avatar Mar 15 '24 21:03 jeremander

Yup!

charliermarsh avatar Mar 16 '24 13:03 charliermarsh

Publicly committing to this one.

charliermarsh avatar Mar 18 '24 18:03 charliermarsh