-
Couldn't load subscription status.
- Fork 3.2k
Support Direct URL editable requirements #13495
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
Changes from all commits
8850376
f241d83
71e5a12
ddfc4d5
d3e377c
8a4d049
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 |
|---|---|---|
|
|
@@ -10,6 +10,26 @@ control system being used). It is used through URL prefixes: | |
| - Subversion -- `svn+` | ||
| - Bazaar -- `bzr+` | ||
|
|
||
| The general form of a VCS requirement is `ProjectName @ VCS_URL`, e.g. | ||
|
|
||
| ```none | ||
| MyProject @ git+https://git.example.com/MyProject | ||
| MyProject[extra] @ git+https:/git.example.com/MyProject | ||
| ``` | ||
|
|
||
| This is the {ref}`Direct URL <pypug:dependency-specifiers>` requirement syntax. | ||
| It is also permissible to remove `MyProject @` portion is removed and provide | ||
| a bare VCS URL. | ||
|
|
||
| ```none | ||
| git+https://git.example.com/MyProject | ||
| ``` | ||
|
|
||
| This is a pip specific extension. This form can be used as long as pip does | ||
| not need to know the project name in advance. pip is generally able to infer | ||
| the project name except in the case of {ref}`editable-vcs-installs`. In | ||
| addition, extras cannot be requested using a bare VCS URL. | ||
|
|
||
| ## Supported VCS | ||
|
|
||
| ### Git | ||
|
|
@@ -81,8 +101,8 @@ MyProject @ svn+ssh://[email protected]/MyProject | |
| You can also give specific revisions to an SVN URL, like so: | ||
|
|
||
| ```none | ||
| -e svn+http://svn.example.com/svn/MyProject/trunk@2019#egg=MyProject | ||
| -e svn+http://svn.example.com/svn/MyProject/trunk@{20080101}#egg=MyProject | ||
| -e MyProject @ svn+http://svn.example.com/svn/MyProject/trunk@2019 | ||
| -e MyProject @ svn+http://svn.example.com/svn/MyProject/trunk@{20080101} | ||
| ``` | ||
|
|
||
| Note that you need to use [Editable VCS installs](#editable-vcs-installs) for | ||
|
|
@@ -115,6 +135,9 @@ MyProject @ bzr+http://bzr.example.com/MyProject/[email protected] | |
| VCS projects can be installed in {ref}`editable mode <editable-installs>` (using | ||
| the {ref}`--editable <install_--editable>` option) or not. | ||
|
|
||
| In editable mode, the project name must be provided upfront using the Direct URL | ||
| (`MyProject @ URL`) form so pip can determine the VCS clone location. | ||
|
|
||
| - The default clone location (for editable installs) is: | ||
|
|
||
| - `<venv path>/src/SomeProject` in virtual environments | ||
|
|
@@ -133,15 +156,16 @@ take on the VCS requirement (not the commit itself). | |
| ## URL fragments | ||
|
|
||
| pip looks at the `subdirectory` fragments of VCS URLs for specifying the path to the | ||
| Python package, when it is not in the root of the VCS directory. eg: `pkg_dir`. | ||
| Python package, when it is not in the root of the VCS directory. | ||
|
|
||
| pip also looks at the `egg` fragment specifying the "project name". In practice the | ||
| `egg` fragment is only required to help pip determine the VCS clone location in editable | ||
| mode. In all other circumstances, the `egg` fragment is not necessary and its use is | ||
| discouraged. | ||
| ```{note} | ||
| pip also supports an `egg` fragment to specify the "project name". This is a legacy | ||
| feature and its use is discouraged in favour of the | ||
| {ref}`Direct URL <pypug:dependency-specifiers>` form. | ||
|
|
||
| The `egg` fragment **should** be a bare {ref}`project name <pypug:name-normalization>`. | ||
| Anything else is not guaranteed to work. | ||
| ``` | ||
|
|
||
| ````{admonition} Example | ||
| If your repository layout is: | ||
|
|
@@ -164,6 +188,6 @@ $ pip install "pkg @ vcs+protocol://repo_url/#subdirectory=pkg_dir" | |
| or: | ||
|
|
||
| ```{pip-cli} | ||
| $ pip install -e "vcs+protocol://repo_url/#egg=pkg&subdirectory=pkg_dir" | ||
| $ pip install -e "pkg @ vcs+protocol://repo_url/#subdirectory=pkg_dir" | ||
| ``` | ||
| ```` | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| Add support installing an editable requirement written as a Direct URL (``PackageName @ URL``). |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -86,17 +86,25 @@ def _set_requirement_extras(req: Requirement, new_extras: set[str]) -> Requireme | |
| return get_requirement(f"{pre}{extras}{post}") | ||
|
|
||
|
|
||
| def parse_editable(editable_req: str) -> tuple[str | None, str, set[str]]: | ||
| """Parses an editable requirement into: | ||
| - a requirement name | ||
| - an URL | ||
| - extras | ||
| - editable options | ||
| Accepted requirements: | ||
| svn+http://blahblah@rev#egg=Foobar[baz]&subdirectory=version_subdir | ||
| .[some_extra] | ||
| """ | ||
| def _parse_direct_url_editable(editable_req: str) -> tuple[str | None, str, set[str]]: | ||
| try: | ||
| req = Requirement(editable_req) | ||
| except InvalidRequirement: | ||
| pass | ||
| else: | ||
| if req.url: | ||
| # Join the marker back into the name part. This will be parsed out | ||
| # later into a Requirement again. | ||
| if req.marker: | ||
| name = f"{req.name} ; {req.marker}" | ||
| else: | ||
| name = req.name | ||
| return (name, req.url, req.extras) | ||
|
|
||
| raise ValueError | ||
|
|
||
|
|
||
| def _parse_pip_syntax_editable(editable_req: str) -> tuple[str | None, str, set[str]]: | ||
| url = editable_req | ||
|
|
||
| # If a file path is specified with extras, strip off the extras. | ||
|
|
@@ -122,23 +130,41 @@ def parse_editable(editable_req: str) -> tuple[str | None, str, set[str]]: | |
| url = f"{version_control}+{url}" | ||
| break | ||
|
|
||
| return Link(url).egg_fragment, url, set() | ||
|
|
||
|
|
||
| def parse_editable(editable_req: str) -> tuple[str | None, str, set[str]]: | ||
| """Parses an editable requirement into: | ||
| - a requirement name with environment markers | ||
| - an URL | ||
| - extras | ||
| Accepted requirements: | ||
| - svn+http://blahblah@rev#egg=Foobar[baz]&subdirectory=version_subdir | ||
| - local_path[some_extra] | ||
| - Foobar[extra] @ svn+http://blahblah@rev#subdirectory=subdir ; markers | ||
| """ | ||
| try: | ||
| package_name, url, extras = _parse_direct_url_editable(editable_req) | ||
| except ValueError: | ||
| package_name, url, extras = _parse_pip_syntax_editable(editable_req) | ||
|
|
||
| link = Link(url) | ||
|
|
||
| if not link.is_vcs: | ||
| if not link.is_vcs and not link.url.startswith("file:"): | ||
| backends = ", ".join(vcs.all_schemes) | ||
| raise InstallationError( | ||
| f"{editable_req} is not a valid editable requirement. " | ||
| f"It should either be a path to a local project or a VCS URL " | ||
| f"(beginning with {backends})." | ||
| ) | ||
|
|
||
| package_name = link.egg_fragment | ||
| if not package_name: | ||
| # The project name can be inferred from local file URIs easily. | ||
|
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. What do you mean with this comment? 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. With the extraction of |
||
| if not package_name and not link.url.startswith("file:"): | ||
| raise InstallationError( | ||
| f"Could not detect requirement name for '{editable_req}', " | ||
| "please specify one with #egg=your_package_name" | ||
| "please specify one with your_package_name @ URL" | ||
| ) | ||
| return package_name, url, set() | ||
| return package_name, url, extras | ||
|
|
||
|
|
||
| def check_first_requirement_in_file(filename: str) -> None: | ||
|
|
||
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.
Note: it could be convenient to support
pkgname[extras] @ ./localdiras an alternative to./localdir[extras]. But that can be discussed separately.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'd rather not add extensions to standard requirement syntax, but yes, this would be a follow up.