From ba81d8a1b8a29bffc98f7310618b30a2282361f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Eustace?= Date: Mon, 10 Jun 2019 21:45:41 -0500 Subject: [PATCH] Add support for environment markers specification in dependencies (#1142) --- docs/docs/versions.md | 11 +++++++ poetry/json/schemas/poetry-schema.json | 16 ++++++++++ poetry/packages/package.py | 32 +++++++++++-------- tests/fixtures/sample_project/pyproject.toml | 3 ++ .../builders/fixtures/complete/pyproject.toml | 5 ++- tests/masonry/builders/test_builder.py | 2 +- tests/masonry/builders/test_complete.py | 4 +-- tests/masonry/builders/test_sdist.py | 6 +++- tests/masonry/test_api.py | 2 +- tests/test_poetry.py | 8 +++++ 10 files changed, 69 insertions(+), 20 deletions(-) diff --git a/docs/docs/versions.md b/docs/docs/versions.md index e846d3e1723..a4e616c30be 100644 --- a/docs/docs/versions.md +++ b/docs/docs/versions.md @@ -129,6 +129,17 @@ pathlib2 = { version = "^2.2", python = "~2.7" } pathlib2 = { version = "^2.2", python = ["~2.7", "^3.2"] } ``` +### Using environment markers + +If you need more complex install conditions for your dependencies, +Poetry supports [environment markers](https://www.python.org/dev/peps/pep-0508/#environment-markers) +via the `markers` property: + +```toml +[tool.poetry.dependencies] +pathlib2 = { version = "^2.2", markers = "python_version ~= '2.7' or sys_platform == 'win32'" } +``` + ### Multiple constraints dependencies diff --git a/poetry/json/schemas/poetry-schema.json b/poetry/json/schemas/poetry-schema.json index 86f5dcbfee9..fac35fb1814 100644 --- a/poetry/json/schemas/poetry-schema.json +++ b/poetry/json/schemas/poetry-schema.json @@ -230,6 +230,10 @@ "type": "string", "description": "The platform(s) for which the dependency should be installed." }, + "markers": { + "type": "string", + "description": "The PEP 508 compliant environment markers for which the dependency should be installed." + }, "allows-prereleases": { "type": "boolean", "description": "Whether the dependency allows prereleases or not." @@ -283,6 +287,10 @@ "type": "string", "description": "The platform(s) for which the dependency should be installed." }, + "markers": { + "type": "string", + "description": "The PEP 508 compliant environment markers for which the dependency should be installed." + }, "allows-prereleases": { "type": "boolean", "description": "Whether the dependency allows prereleases or not." @@ -319,6 +327,10 @@ "type": "string", "description": "The platform(s) for which the dependency should be installed." }, + "markers": { + "type": "string", + "description": "The PEP 508 compliant environment markers for which the dependency should be installed." + }, "optional": { "type": "boolean", "description": "Whether the dependency is optional or not." @@ -351,6 +363,10 @@ "type": "string", "description": "The platform(s) for which the dependency should be installed." }, + "markers": { + "type": "string", + "description": "The PEP 508 compliant environment markers for which the dependency should be installed." + }, "optional": { "type": "boolean", "description": "Whether the dependency is optional or not." diff --git a/poetry/packages/package.py b/poetry/packages/package.py index 5d1e6fc76cd..242435a4666 100644 --- a/poetry/packages/package.py +++ b/poetry/packages/package.py @@ -245,6 +245,7 @@ def add_dependency( optional = constraint.get("optional", False) python_versions = constraint.get("python") platform = constraint.get("platform") + markers = constraint.get("markers") allows_prereleases = constraint.get("allows-prereleases", False) if "git" in constraint: @@ -301,25 +302,28 @@ def add_dependency( source_name=constraint.get("source"), ) - marker = AnyMarker() - if python_versions: - dependency.python_versions = python_versions - marker = marker.intersect( - parse_marker( - create_nested_marker( - "python_version", dependency.python_constraint + if not markers: + marker = AnyMarker() + if python_versions: + dependency.python_versions = python_versions + marker = marker.intersect( + parse_marker( + create_nested_marker( + "python_version", dependency.python_constraint + ) ) ) - ) - if platform: - marker = marker.intersect( - parse_marker( - create_nested_marker( - "sys_platform", parse_generic_constraint(platform) + if platform: + marker = marker.intersect( + parse_marker( + create_nested_marker( + "sys_platform", parse_generic_constraint(platform) + ) ) ) - ) + else: + marker = parse_marker(markers) if not marker.is_any(): dependency.marker = marker diff --git a/tests/fixtures/sample_project/pyproject.toml b/tests/fixtures/sample_project/pyproject.toml index ac7730ddf56..526a6b91f0d 100644 --- a/tests/fixtures/sample_project/pyproject.toml +++ b/tests/fixtures/sample_project/pyproject.toml @@ -39,6 +39,9 @@ my-package = { path = "../project_with_setup/" } # Dir dependency with pyproject.toml simple-project = { path = "../simple_project/" } +# Dependency with markers +functools32 = { version = "^3.2.3", markers = "python_version ~= '2.7' and sys_platform == 'win32' or python_version in '3.4 3.5'" } + [tool.poetry.extras] db = [ "orator" ] diff --git a/tests/masonry/builders/fixtures/complete/pyproject.toml b/tests/masonry/builders/fixtures/complete/pyproject.toml index 5e9142f5c7a..71006e23ede 100644 --- a/tests/masonry/builders/fixtures/complete/pyproject.toml +++ b/tests/masonry/builders/fixtures/complete/pyproject.toml @@ -30,7 +30,10 @@ python = "^3.6" cleo = "^0.6" cachy = { version = "^0.2.0", extras = ["msgpack"] } -pendulum = { version = "^1.4", optional = true } +[tool.poetry.dependencies.pendulum] +version = "^1.4" +markers= 'python_version ~= "2.7" and sys_platform == "win32" or python_version in "3.4 3.5"' +optional = true [tool.poetry.dev-dependencies] pytest = "~3.4" diff --git a/tests/masonry/builders/test_builder.py b/tests/masonry/builders/test_builder.py index 152c2cd11e0..cddcc9c9cef 100644 --- a/tests/masonry/builders/test_builder.py +++ b/tests/masonry/builders/test_builder.py @@ -97,7 +97,7 @@ def test_get_metadata_content(): assert requires == [ "cachy[msgpack] (>=0.2.0,<0.3.0)", "cleo (>=0.6,<0.7)", - 'pendulum (>=1.4,<2.0); extra == "time"', + 'pendulum (>=1.4,<2.0); (python_version ~= "2.7" and sys_platform == "win32" or python_version in "3.4 3.5") and (extra == "time")', ] urls = parsed.get_all("Project-URL") diff --git a/tests/masonry/builders/test_complete.py b/tests/masonry/builders/test_complete.py index eb80cebfb63..ca2d675329e 100644 --- a/tests/masonry/builders/test_complete.py +++ b/tests/masonry/builders/test_complete.py @@ -219,7 +219,7 @@ def test_complete(): Provides-Extra: time Requires-Dist: cachy[msgpack] (>=0.2.0,<0.3.0) Requires-Dist: cleo (>=0.6,<0.7) -Requires-Dist: pendulum (>=1.4,<2.0); extra == "time" +Requires-Dist: pendulum (>=1.4,<2.0); (python_version ~= "2.7" and sys_platform == "win32" or python_version in "3.4 3.5") and (extra == "time") Project-URL: Documentation, https://poetry.eustace.io/docs Project-URL: Issue Tracker, https://github.com/sdispater/poetry/issues Project-URL: Repository, https://github.com/sdispater/poetry @@ -319,7 +319,7 @@ def test_complete_no_vcs(): Provides-Extra: time Requires-Dist: cachy[msgpack] (>=0.2.0,<0.3.0) Requires-Dist: cleo (>=0.6,<0.7) -Requires-Dist: pendulum (>=1.4,<2.0); extra == "time" +Requires-Dist: pendulum (>=1.4,<2.0); (python_version ~= "2.7" and sys_platform == "win32" or python_version in "3.4 3.5") and (extra == "time") Project-URL: Documentation, https://poetry.eustace.io/docs Project-URL: Issue Tracker, https://github.com/sdispater/poetry/issues Project-URL: Repository, https://github.com/sdispater/poetry diff --git a/tests/masonry/builders/test_sdist.py b/tests/masonry/builders/test_sdist.py index 59084b92840..4fcda1e4266 100644 --- a/tests/masonry/builders/test_sdist.py +++ b/tests/masonry/builders/test_sdist.py @@ -133,7 +133,11 @@ def test_make_setup(): "my-script = my_package:main", ] } - assert ns["extras_require"] == {"time": ["pendulum>=1.4,<2.0"]} + assert ns["extras_require"] == { + 'time:python_version ~= "2.7" and sys_platform == "win32" or python_version in "3.4 3.5"': [ + "pendulum>=1.4,<2.0" + ] + } def test_make_pkg_info(mocker): diff --git a/tests/masonry/test_api.py b/tests/masonry/test_api.py index 55b1297cf05..1efd3fa4814 100644 --- a/tests/masonry/test_api.py +++ b/tests/masonry/test_api.py @@ -97,7 +97,7 @@ def test_prepare_metadata_for_build_wheel(): Provides-Extra: time Requires-Dist: cachy[msgpack] (>=0.2.0,<0.3.0) Requires-Dist: cleo (>=0.6,<0.7) -Requires-Dist: pendulum (>=1.4,<2.0); extra == "time" +Requires-Dist: pendulum (>=1.4,<2.0); (python_version ~= "2.7" and sys_platform == "win32" or python_version in "3.4 3.5") and (extra == "time") Project-URL: Documentation, https://poetry.eustace.io/docs Project-URL: Issue Tracker, https://github.com/sdispater/poetry/issues Project-URL: Repository, https://github.com/sdispater/poetry diff --git a/tests/test_poetry.py b/tests/test_poetry.py index 918d24d0232..f74a3caa8a1 100644 --- a/tests/test_poetry.py +++ b/tests/test_poetry.py @@ -82,6 +82,14 @@ def test_poetry(): assert simple_project.name == "simple-project" assert simple_project.pretty_constraint == "*" + functools32 = dependencies["functools32"] + assert functools32.name == "functools32" + assert functools32.pretty_constraint == "^3.2.3" + assert ( + str(functools32.marker) + == 'python_version ~= "2.7" and sys_platform == "win32" or python_version in "3.4 3.5"' + ) + assert "db" in package.extras classifiers = package.classifiers