Commit 73a6dbe0 by Arun Babu Neelicattu Committed by Bjorn Neergaard

add: allow specification of PEP 508 dependencies

With this change, users can now add dependencies using valid PEP 508
strings.
parent bb97ba2e
from __future__ import annotations from __future__ import annotations
import contextlib
import os import os
import re import re
import urllib.parse import urllib.parse
...@@ -9,6 +10,10 @@ from typing import TYPE_CHECKING ...@@ -9,6 +10,10 @@ from typing import TYPE_CHECKING
from typing import Dict from typing import Dict
from typing import List from typing import List
from typing import Union from typing import Union
from typing import cast
from poetry.core.packages.dependency import Dependency
from poetry.core.packages.vcs_dependency import VCSDependency
from poetry.puzzle.provider import Provider from poetry.puzzle.provider import Provider
...@@ -53,7 +58,7 @@ def _parse_dependency_specification_url( ...@@ -53,7 +58,7 @@ def _parse_dependency_specification_url(
if url_parsed.scheme in ["http", "https"]: if url_parsed.scheme in ["http", "https"]:
package = Provider.get_package_from_url(requirement) package = Provider.get_package_from_url(requirement)
return {"name": package.name, "url": package.source_url} return {"name": package.name, "url": cast(str, package.source_url)}
return None return None
...@@ -131,12 +136,57 @@ def _parse_dependency_specification_simple( ...@@ -131,12 +136,57 @@ def _parse_dependency_specification_simple(
return require return require
def dependency_to_specification(dependency: Dependency) -> DependencySpec:
specification: DependencySpec = {}
if dependency.is_vcs():
dependency = cast(VCSDependency, dependency)
specification[dependency.vcs] = cast(str, dependency.source_url)
if dependency.reference:
specification["rev"] = dependency.reference
elif dependency.is_file() or dependency.is_directory():
specification["path"] = cast(str, dependency.source_url)
elif dependency.is_url():
specification["url"] = cast(str, dependency.source_url)
elif dependency.pretty_constraint != "*" and not dependency.constraint.is_empty():
specification["version"] = dependency.pretty_constraint
if not dependency.marker.is_any():
specification["markers"] = str(dependency.marker)
if dependency.extras:
specification["extras"] = sorted(dependency.extras)
return specification
def pep508_to_dependency_specification(requirement: str) -> DependencySpec | None:
if " ; " not in requirement and re.search(r"@[\^~!=<>\d]", requirement):
# this is of the form package@<semver>, do not attempt to parse it
return None
with contextlib.suppress(ValueError):
dependency = Dependency.create_from_pep_508(requirement)
specification = dependency_to_specification(dependency)
if specification:
specification["name"] = dependency.name
return specification
return None
def parse_dependency_specification( def parse_dependency_specification(
requirement: str, env: Env | None = None, cwd: Path | None = None requirement: str, env: Env | None = None, cwd: Path | None = None
) -> DependencySpec: ) -> DependencySpec:
requirement = requirement.strip() requirement = requirement.strip()
cwd = cwd or Path.cwd() cwd = cwd or Path.cwd()
specification = pep508_to_dependency_specification(requirement)
if specification is not None:
return specification
extras = [] extras = []
extras_m = re.search(r"\[([\w\d,-_ ]+)\]$", requirement) extras_m = re.search(r"\[([\w\d,-_ ]+)\]$", requirement)
if extras_m: if extras_m:
......
...@@ -38,6 +38,9 @@ if TYPE_CHECKING: ...@@ -38,6 +38,9 @@ if TYPE_CHECKING:
("demo", {"name": "demo"}), ("demo", {"name": "demo"}),
("demo@1.0.0", {"name": "demo", "version": "1.0.0"}), ("demo@1.0.0", {"name": "demo", "version": "1.0.0"}),
("demo@^1.0.0", {"name": "demo", "version": "^1.0.0"}), ("demo@^1.0.0", {"name": "demo", "version": "^1.0.0"}),
("demo@==1.0.0", {"name": "demo", "version": "==1.0.0"}),
("demo@!=1.0.0", {"name": "demo", "version": "!=1.0.0"}),
("demo@~1.0.0", {"name": "demo", "version": "~1.0.0"}),
("demo[a,b]@1.0.0", {"name": "demo", "version": "1.0.0", "extras": ["a", "b"]}), ("demo[a,b]@1.0.0", {"name": "demo", "version": "1.0.0", "extras": ["a", "b"]}),
("demo[a,b]", {"name": "demo", "extras": ["a", "b"]}), ("demo[a,b]", {"name": "demo", "extras": ["a", "b"]}),
("../demo", {"name": "demo", "path": "../demo"}), ("../demo", {"name": "demo", "path": "../demo"}),
...@@ -46,6 +49,47 @@ if TYPE_CHECKING: ...@@ -46,6 +49,47 @@ if TYPE_CHECKING:
"https://example.com/packages/demo-0.1.0.tar.gz", "https://example.com/packages/demo-0.1.0.tar.gz",
{"name": "demo", "url": "https://example.com/packages/demo-0.1.0.tar.gz"}, {"name": "demo", "url": "https://example.com/packages/demo-0.1.0.tar.gz"},
), ),
# PEP 508 inputs
(
"poetry-core (>=1.0.7,<1.1.0)",
{"name": "poetry-core", "version": ">=1.0.7,<1.1.0"},
),
(
'requests [security,tests] >= 2.8.1, == 2.8.* ; python_version < "2.7"',
{
"name": "requests",
"markers": 'python_version < "2.7"',
"version": ">=2.8.1,<2.9.0",
"extras": ["security", "tests"],
},
),
("name (>=3,<4)", {"name": "name", "version": ">=3,<4"}),
(
"name@http://foo.com",
{"name": "name", "url": "http://foo.com"},
),
(
"name [fred,bar] @ http://foo.com ; python_version=='2.7'",
{
"name": "name",
"markers": 'python_version == "2.7"',
"url": "http://foo.com",
# This is commented out as there is a bug in
# Dependency.create_from_pep_508 that leads to incorrect
# URL Dependency creation.
# should be: "extras": ["fred", "bar"],
},
),
(
'cachecontrol[filecache] (>=0.12.9,<0.13.0); python_version >= "3.6" and'
' python_version < "4.0"',
{
"version": ">=0.12.9,<0.13.0",
"markers": 'python_version >= "3.6" and python_version < "4.0"',
"extras": ["filecache"],
"name": "cachecontrol",
},
),
], ],
) )
def test_parse_dependency_specification( def test_parse_dependency_specification(
...@@ -60,4 +104,6 @@ def test_parse_dependency_specification( ...@@ -60,4 +104,6 @@ def test_parse_dependency_specification(
mocker.patch("pathlib.Path.exists", _mock) mocker.patch("pathlib.Path.exists", _mock)
assert not DeepDiff(parse_dependency_specification(requirement), specification) assert not DeepDiff(
parse_dependency_specification(requirement), specification, ignore_order=True
)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment