From 1512587d7df7652ebb0055c05d7cab762503cfeb Mon Sep 17 00:00:00 2001 From: Claudio Jolowicz Date: Sun, 14 Mar 2021 00:05:57 +0100 Subject: [PATCH 01/20] test: Use Poetry 1.0 compatible lock file in test data --- .../test_functional/example/poetry.lock | 44 +++++++++---------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/tests/functional/test_functional/example/poetry.lock b/tests/functional/test_functional/example/poetry.lock index 872d1fd3..df608122 100644 --- a/tests/functional/test_functional/example/poetry.lock +++ b/tests/functional/test_functional/example/poetry.lock @@ -1,57 +1,57 @@ [[package]] -name = "first" -version = "2.0.0" -description = "Return the first true value of an iterable." category = "main" +description = "Return the first true value of an iterable." +name = "first" optional = false python-versions = "*" +version = "2.0.2" [[package]] -name = "pycodestyle" -version = "2.5.0" -description = "Python style guide checker" category = "dev" +description = "Python style guide checker" +name = "pycodestyle" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "2.6.0" [[package]] -name = "pyflakes" -version = "2.1.1" -description = "passive checker of Python programs" category = "dev" +description = "passive checker of Python programs" +name = "pyflakes" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "2.2.0" [[package]] -name = "pygments" -version = "2.7.1" -description = "Pygments is a syntax highlighting package written in Python." category = "main" +description = "Pygments is a syntax highlighting package written in Python." +name = "pygments" optional = true python-versions = ">=3.5" +version = "2.8.1" [extras] pygments = ["Pygments"] [metadata] -lock-version = "1.1" -python-versions = "^3.6.1" content-hash = "65a484a1a7ee49c3993d8103bddeeef3c94fc4fb6c3f3805d58941333e49e82a" +lock-version = "1.0" +python-versions = "^3.6.1" [metadata.files] first = [ - {file = "first-2.0.0-py2.py3-none-any.whl", hash = "sha256:7ce8c2d25d2f7f54ad6d8a725df71e7a35ae11052d41cbeafcd19f71661a1107"}, - {file = "first-2.0.0.tar.gz", hash = "sha256:c5711941f8ba8b091e73713eb0b45ddab663c060de324973b4cdd2290a1524ec"}, + {file = "first-2.0.2-py2.py3-none-any.whl", hash = "sha256:8d8e46e115ea8ac652c76123c0865e3ff18372aef6f03c22809ceefcea9dec86"}, + {file = "first-2.0.2.tar.gz", hash = "sha256:ff285b08c55f8c97ce4ea7012743af2495c9f1291785f163722bd36f6af6d3bf"}, ] pycodestyle = [ - {file = "pycodestyle-2.5.0-py2.py3-none-any.whl", hash = "sha256:95a2219d12372f05704562a14ec30bc76b05a5b297b21a5dfe3f6fac3491ae56"}, - {file = "pycodestyle-2.5.0.tar.gz", hash = "sha256:e40a936c9a450ad81df37f549d676d127b1b66000a6c500caa2b085bc0ca976c"}, + {file = "pycodestyle-2.6.0-py2.py3-none-any.whl", hash = "sha256:2295e7b2f6b5bd100585ebcb1f616591b652db8a741695b3d8f5d28bdc934367"}, + {file = "pycodestyle-2.6.0.tar.gz", hash = "sha256:c58a7d2815e0e8d7972bf1803331fb0152f867bd89adf8a01dfd55085434192e"}, ] pyflakes = [ - {file = "pyflakes-2.1.1-py2.py3-none-any.whl", hash = "sha256:17dbeb2e3f4d772725c777fabc446d5634d1038f234e77343108ce445ea69ce0"}, - {file = "pyflakes-2.1.1.tar.gz", hash = "sha256:d976835886f8c5b31d47970ed689944a0262b5f3afa00a5a7b4dc81e5449f8a2"}, + {file = "pyflakes-2.2.0-py2.py3-none-any.whl", hash = "sha256:0d94e0e05a19e57a99444b6ddcf9a6eb2e5c68d3ca1e98e90707af8152c90a92"}, + {file = "pyflakes-2.2.0.tar.gz", hash = "sha256:35b2d75ee967ea93b55750aa9edbbf72813e06a66ba54438df2cfac9e3c27fc8"}, ] pygments = [ - {file = "Pygments-2.7.1-py3-none-any.whl", hash = "sha256:307543fe65c0947b126e83dd5a61bd8acbd84abec11f43caebaf5534cbc17998"}, - {file = "Pygments-2.7.1.tar.gz", hash = "sha256:926c3f319eda178d1bd90851e4317e6d8cdb5e292a3386aac9bd75eca29cf9c7"}, + {file = "Pygments-2.8.1-py3-none-any.whl", hash = "sha256:534ef71d539ae97d4c3a4cf7d6f110f214b0e687e92f9cb9d2a3b0d3101289c8"}, + {file = "Pygments-2.8.1.tar.gz", hash = "sha256:2656e1a6edcdabf4275f9a3640db59fd5de107d88e8663c5d4e9a0fa62f77f94"}, ] From 36f9b1c8be255618754ce515e6b1ee3ab559bcf0 Mon Sep 17 00:00:00 2001 From: Claudio Jolowicz Date: Sun, 14 Mar 2021 00:06:53 +0100 Subject: [PATCH 02/20] test: Run tests againsts Poetry 1.0 as well --- noxfile.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/noxfile.py b/noxfile.py index c623d312..f969974e 100644 --- a/noxfile.py +++ b/noxfile.py @@ -3,6 +3,7 @@ import sys from pathlib import Path from textwrap import dedent +from typing import Optional import nox @@ -117,7 +118,8 @@ def mypy(session: Session) -> None: @session(python=python_versions) -def tests(session: Session) -> None: +@nox.parametrize("poetry", ["1.0.10", None]) +def tests(session: Session, poetry: Optional[str]) -> None: """Run the test suite.""" session.install(".") session.install( @@ -130,6 +132,14 @@ def tests(session: Session) -> None: if session.python == "3.6": session.install("dataclasses") + if poetry is not None: + if session.python != python_versions[0]: + session.skip() + + session.run_always( + "python", "-m", "pip", "install", f"poetry=={poetry}", silent=True + ) + try: session.run("coverage", "run", "--parallel", "-m", "pytest", *session.posargs) finally: From 074332a4d40e2f6691c7d293c89f01b255a9c2d9 Mon Sep 17 00:00:00 2001 From: Claudio Jolowicz Date: Sun, 14 Mar 2021 00:27:29 +0100 Subject: [PATCH 03/20] test: Fix missing subdependencies in Project.dependencies --- tests/functional/conftest.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/tests/functional/conftest.py b/tests/functional/conftest.py index 870d85c8..cd3713f9 100644 --- a/tests/functional/conftest.py +++ b/tests/functional/conftest.py @@ -66,15 +66,11 @@ def package(self) -> Package: @property def dependencies(self) -> List[Package]: """Return the package dependencies.""" - table = self._get_config("dependencies") + data = self._read_toml("poetry.lock") dependencies: List[str] = [ - package - for package, info in table.items() - if not ( - package == "python" - or isinstance(info, dict) - and info.get("optional", None) - ) + package["name"] + for package in data["package"] + if package["category"] == "main" and not package["optional"] ] return [self.get_dependency(package) for package in dependencies] From 2125d4cea8e36b26d09c4d6d0e6386382681b70f Mon Sep 17 00:00:00 2001 From: Claudio Jolowicz Date: Sat, 13 Mar 2021 18:00:52 +0100 Subject: [PATCH 04/20] test: Replace list_packages fixture by a plain function --- tests/functional/conftest.py | 12 ++----- tests/functional/test_functional.py | 50 ++++++++++------------------- 2 files changed, 19 insertions(+), 43 deletions(-) diff --git a/tests/functional/conftest.py b/tests/functional/conftest.py index cd3713f9..6aa2d45c 100644 --- a/tests/functional/conftest.py +++ b/tests/functional/conftest.py @@ -177,7 +177,8 @@ def _canonicalize_name(name: str) -> str: return _CANONICALIZE_PATTERN.sub("-", name).lower() -def _list_packages(project: Project, session: SessionFunction) -> List[Package]: +def list_packages(project: Project, session: SessionFunction) -> List[Package]: + """List the installed packages for a session in the given project.""" bindir = "Scripts" if sys.platform == "win32" else "bin" pip = project.path / ".nox" / session.__name__ / bindir / "pip" process = subprocess.run( # noqa: S603 @@ -197,12 +198,3 @@ def parse(line: str) -> Package: return Package(name, version) return [parse(line) for line in process.stdout.splitlines()] - - -ListPackages = Callable[[SessionFunction], List[Package]] - - -@pytest.fixture -def list_packages(project: Project) -> ListPackages: - """Return a function that lists the installed packages for a session.""" - return functools.partial(_list_packages, project) diff --git a/tests/functional/test_functional.py b/tests/functional/test_functional.py index f45063d7..c75425c6 100644 --- a/tests/functional/test_functional.py +++ b/tests/functional/test_functional.py @@ -1,6 +1,6 @@ """Functional tests.""" import nox.sessions -from tests.functional.conftest import ListPackages +from tests.functional.conftest import list_packages from tests.functional.conftest import Project from tests.functional.conftest import RunNoxWithNoxfile @@ -10,7 +10,6 @@ def test_install_local_using_patch( project: Project, run_nox_with_noxfile: RunNoxWithNoxfile, - list_packages: ListPackages, ) -> None: """It installs the local package.""" @@ -22,7 +21,7 @@ def test(session: nox.sessions.Session) -> None: run_nox_with_noxfile([test], [nox, nox.sessions, nox_poetry.patch]) expected = [project.package, *project.dependencies] - packages = list_packages(test) + packages = list_packages(project, test) assert set(expected) == set(packages) @@ -30,7 +29,6 @@ def test(session: nox.sessions.Session) -> None: def test_install_local_using_patch_with_extras( project: Project, run_nox_with_noxfile: RunNoxWithNoxfile, - list_packages: ListPackages, ) -> None: """It installs the extra.""" @@ -46,7 +44,7 @@ def test(session: nox.sessions.Session) -> None: *project.dependencies, project.get_dependency("pygments"), ] - packages = list_packages(test) + packages = list_packages(project, test) assert set(expected) == set(packages) @@ -54,7 +52,6 @@ def test(session: nox.sessions.Session) -> None: def test_install_local_wheel( project: Project, run_nox_with_noxfile: RunNoxWithNoxfile, - list_packages: ListPackages, ) -> None: """It builds and installs a wheel from the local package.""" @@ -66,7 +63,7 @@ def test(session: nox.sessions.Session) -> None: run_nox_with_noxfile([test], [nox, nox.sessions, nox_poetry]) expected = [project.package, *project.dependencies] - packages = list_packages(test) + packages = list_packages(project, test) assert set(expected) == set(packages) @@ -74,7 +71,6 @@ def test(session: nox.sessions.Session) -> None: def test_install_local_wheel_with_extras( project: Project, run_nox_with_noxfile: RunNoxWithNoxfile, - list_packages: ListPackages, ) -> None: """It installs the extra.""" @@ -90,7 +86,7 @@ def test(session: nox.sessions.Session) -> None: *project.dependencies, project.get_dependency("pygments"), ] - packages = list_packages(test) + packages = list_packages(project, test) assert set(expected) == set(packages) @@ -98,7 +94,6 @@ def test(session: nox.sessions.Session) -> None: def test_installroot_wheel( project: Project, run_nox_with_noxfile: RunNoxWithNoxfile, - list_packages: ListPackages, ) -> None: """It builds and installs a wheel from the local package.""" @@ -110,7 +105,7 @@ def test(session: nox.sessions.Session) -> None: run_nox_with_noxfile([test], [nox, nox.sessions, nox_poetry]) expected = [project.package, *project.dependencies] - packages = list_packages(test) + packages = list_packages(project, test) assert set(expected) == set(packages) @@ -118,7 +113,6 @@ def test(session: nox.sessions.Session) -> None: def test_installroot_wheel_with_extras( project: Project, run_nox_with_noxfile: RunNoxWithNoxfile, - list_packages: ListPackages, ) -> None: """It installs the extra.""" @@ -136,7 +130,7 @@ def test(session: nox.sessions.Session) -> None: *project.dependencies, project.get_dependency("pygments"), ] - packages = list_packages(test) + packages = list_packages(project, test) assert set(expected) == set(packages) @@ -144,7 +138,6 @@ def test(session: nox.sessions.Session) -> None: def test_installroot_sdist( project: Project, run_nox_with_noxfile: RunNoxWithNoxfile, - list_packages: ListPackages, ) -> None: """It builds and installs an sdist from the local package.""" @@ -156,7 +149,7 @@ def test(session: nox.sessions.Session) -> None: run_nox_with_noxfile([test], [nox, nox.sessions, nox_poetry]) expected = [project.package, *project.dependencies] - packages = list_packages(test) + packages = list_packages(project, test) assert set(expected) == set(packages) @@ -164,7 +157,6 @@ def test(session: nox.sessions.Session) -> None: def test_installroot_sdist_with_extras( project: Project, run_nox_with_noxfile: RunNoxWithNoxfile, - list_packages: ListPackages, ) -> None: """It installs the extra.""" @@ -182,7 +174,7 @@ def test(session: nox.sessions.Session) -> None: *project.dependencies, project.get_dependency("pygments"), ] - packages = list_packages(test) + packages = list_packages(project, test) assert set(expected) == set(packages) @@ -190,7 +182,6 @@ def test(session: nox.sessions.Session) -> None: def test_install_dependency_using_patch( project: Project, run_nox_with_noxfile: RunNoxWithNoxfile, - list_packages: ListPackages, ) -> None: """It installs the pinned dependency.""" @@ -202,7 +193,7 @@ def test(session: nox.sessions.Session) -> None: run_nox_with_noxfile([test], [nox, nox.sessions, nox_poetry.patch]) expected = [project.get_dependency("pyflakes")] - packages = list_packages(test) + packages = list_packages(project, test) assert set(expected) == set(packages) @@ -210,7 +201,6 @@ def test(session: nox.sessions.Session) -> None: def test_install_dependency_without_patch( project: Project, run_nox_with_noxfile: RunNoxWithNoxfile, - list_packages: ListPackages, ) -> None: """It installs the pinned dependency.""" @@ -222,7 +212,7 @@ def test(session: nox.sessions.Session) -> None: run_nox_with_noxfile([test], [nox, nox.sessions, nox_poetry]) expected = [project.get_dependency("pycodestyle")] - packages = list_packages(test) + packages = list_packages(project, test) assert set(expected) == set(packages) @@ -230,7 +220,6 @@ def test(session: nox.sessions.Session) -> None: def test_install_local_wheel_and_dependency_using_patch( project: Project, run_nox_with_noxfile: RunNoxWithNoxfile, - list_packages: ListPackages, ) -> None: """It installs the wheel with pinned dependencies.""" @@ -246,7 +235,7 @@ def test(session: nox.sessions.Session) -> None: *project.dependencies, project.get_dependency("pyflakes"), ] - packages = list_packages(test) + packages = list_packages(project, test) assert set(expected) == set(packages) @@ -254,7 +243,6 @@ def test(session: nox.sessions.Session) -> None: def test_install_local_wheel_and_dependency_without_patch( project: Project, run_nox_with_noxfile: RunNoxWithNoxfile, - list_packages: ListPackages, ) -> None: """It installs the wheel with pinned dependencies.""" @@ -270,7 +258,7 @@ def test(session: nox.sessions.Session) -> None: *project.dependencies, project.get_dependency("pycodestyle"), ] - packages = list_packages(test) + packages = list_packages(project, test) assert set(expected) == set(packages) @@ -278,7 +266,6 @@ def test(session: nox.sessions.Session) -> None: def test_session_install_local( project: Project, run_nox_with_noxfile: RunNoxWithNoxfile, - list_packages: ListPackages, ) -> None: """It installs the local package.""" @@ -290,7 +277,7 @@ def test(session: nox_poetry.Session) -> None: run_nox_with_noxfile([test], [nox_poetry]) expected = [project.package, *project.dependencies] - packages = list_packages(test) + packages = list_packages(project, test) assert set(expected) == set(packages) @@ -298,7 +285,6 @@ def test(session: nox_poetry.Session) -> None: def test_session_install_local_with_extras( project: Project, run_nox_with_noxfile: RunNoxWithNoxfile, - list_packages: ListPackages, ) -> None: """It installs the extra.""" @@ -314,7 +300,7 @@ def test(session: nox_poetry.Session) -> None: *project.dependencies, project.get_dependency("pygments"), ] - packages = list_packages(test) + packages = list_packages(project, test) assert set(expected) == set(packages) @@ -322,7 +308,6 @@ def test(session: nox_poetry.Session) -> None: def test_session_install_dependency( project: Project, run_nox_with_noxfile: RunNoxWithNoxfile, - list_packages: ListPackages, ) -> None: """It installs the pinned dependency.""" @@ -334,7 +319,7 @@ def test(session: nox_poetry.Session) -> None: run_nox_with_noxfile([test], [nox_poetry]) expected = [project.get_dependency("pyflakes")] - packages = list_packages(test) + packages = list_packages(project, test) assert set(expected) == set(packages) @@ -342,7 +327,6 @@ def test(session: nox_poetry.Session) -> None: def test_session_install_local_wheel_and_dependency( project: Project, run_nox_with_noxfile: RunNoxWithNoxfile, - list_packages: ListPackages, ) -> None: """It installs the wheel with pinned dependencies.""" @@ -358,7 +342,7 @@ def test(session: nox_poetry.Session) -> None: *project.dependencies, project.get_dependency("pyflakes"), ] - packages = list_packages(test) + packages = list_packages(project, test) assert set(expected) == set(packages) From ffdad5ed5d859b48f526fb658c2f25654d58943d Mon Sep 17 00:00:00 2001 From: Claudio Jolowicz Date: Sat, 13 Mar 2021 18:06:39 +0100 Subject: [PATCH 05/20] test: Replace run_nox_with_noxfile fixture by plain function --- tests/functional/conftest.py | 18 ++-------- tests/functional/test_functional.py | 53 ++++++++++------------------- 2 files changed, 20 insertions(+), 51 deletions(-) diff --git a/tests/functional/conftest.py b/tests/functional/conftest.py index 6aa2d45c..a656ff43 100644 --- a/tests/functional/conftest.py +++ b/tests/functional/conftest.py @@ -145,30 +145,16 @@ def write_noxfile(project: Project) -> WriteNoxfile: return functools.partial(_write_noxfile, project) -def _run_nox_with_noxfile( +def run_nox_with_noxfile( project: Project, sessions: Iterable[SessionFunction], imports: Iterable[ModuleType], ) -> None: + """Write a noxfile and run Nox in the project.""" _write_noxfile(project, sessions, imports) _run_nox(project) -RunNoxWithNoxfile = Callable[ - [ - Iterable[SessionFunction], - Iterable[ModuleType], - ], - None, -] - - -@pytest.fixture -def run_nox_with_noxfile(project: Project) -> RunNoxWithNoxfile: - """Write a noxfile and run Nox in the project.""" - return functools.partial(_run_nox_with_noxfile, project) - - _CANONICALIZE_PATTERN = re.compile(r"[-_.]+") diff --git a/tests/functional/test_functional.py b/tests/functional/test_functional.py index c75425c6..550ed634 100644 --- a/tests/functional/test_functional.py +++ b/tests/functional/test_functional.py @@ -2,14 +2,13 @@ import nox.sessions from tests.functional.conftest import list_packages from tests.functional.conftest import Project -from tests.functional.conftest import RunNoxWithNoxfile +from tests.functional.conftest import run_nox_with_noxfile import nox_poetry.patch def test_install_local_using_patch( project: Project, - run_nox_with_noxfile: RunNoxWithNoxfile, ) -> None: """It installs the local package.""" @@ -18,7 +17,7 @@ def test(session: nox.sessions.Session) -> None: """Install the local package.""" session.install(".") - run_nox_with_noxfile([test], [nox, nox.sessions, nox_poetry.patch]) + run_nox_with_noxfile(project, [test], [nox, nox.sessions, nox_poetry.patch]) expected = [project.package, *project.dependencies] packages = list_packages(project, test) @@ -28,7 +27,6 @@ def test(session: nox.sessions.Session) -> None: def test_install_local_using_patch_with_extras( project: Project, - run_nox_with_noxfile: RunNoxWithNoxfile, ) -> None: """It installs the extra.""" @@ -37,7 +35,7 @@ def test(session: nox.sessions.Session) -> None: """Install the local package.""" session.install(".[pygments]") - run_nox_with_noxfile([test], [nox, nox.sessions, nox_poetry.patch]) + run_nox_with_noxfile(project, [test], [nox, nox.sessions, nox_poetry.patch]) expected = [ project.package, @@ -51,7 +49,6 @@ def test(session: nox.sessions.Session) -> None: def test_install_local_wheel( project: Project, - run_nox_with_noxfile: RunNoxWithNoxfile, ) -> None: """It builds and installs a wheel from the local package.""" @@ -60,7 +57,7 @@ def test(session: nox.sessions.Session) -> None: """Install the local package.""" nox_poetry.install(session, ".") - run_nox_with_noxfile([test], [nox, nox.sessions, nox_poetry]) + run_nox_with_noxfile(project, [test], [nox, nox.sessions, nox_poetry]) expected = [project.package, *project.dependencies] packages = list_packages(project, test) @@ -70,7 +67,6 @@ def test(session: nox.sessions.Session) -> None: def test_install_local_wheel_with_extras( project: Project, - run_nox_with_noxfile: RunNoxWithNoxfile, ) -> None: """It installs the extra.""" @@ -79,7 +75,7 @@ def test(session: nox.sessions.Session) -> None: """Install the local package.""" nox_poetry.install(session, ".[pygments]") - run_nox_with_noxfile([test], [nox, nox.sessions, nox_poetry]) + run_nox_with_noxfile(project, [test], [nox, nox.sessions, nox_poetry]) expected = [ project.package, @@ -93,7 +89,6 @@ def test(session: nox.sessions.Session) -> None: def test_installroot_wheel( project: Project, - run_nox_with_noxfile: RunNoxWithNoxfile, ) -> None: """It builds and installs a wheel from the local package.""" @@ -102,7 +97,7 @@ def test(session: nox.sessions.Session) -> None: """Install the local package.""" nox_poetry.installroot(session, distribution_format=nox_poetry.WHEEL) - run_nox_with_noxfile([test], [nox, nox.sessions, nox_poetry]) + run_nox_with_noxfile(project, [test], [nox, nox.sessions, nox_poetry]) expected = [project.package, *project.dependencies] packages = list_packages(project, test) @@ -112,7 +107,6 @@ def test(session: nox.sessions.Session) -> None: def test_installroot_wheel_with_extras( project: Project, - run_nox_with_noxfile: RunNoxWithNoxfile, ) -> None: """It installs the extra.""" @@ -123,7 +117,7 @@ def test(session: nox.sessions.Session) -> None: session, distribution_format=nox_poetry.WHEEL, extras=["pygments"] ) - run_nox_with_noxfile([test], [nox, nox.sessions, nox_poetry]) + run_nox_with_noxfile(project, [test], [nox, nox.sessions, nox_poetry]) expected = [ project.package, @@ -137,7 +131,6 @@ def test(session: nox.sessions.Session) -> None: def test_installroot_sdist( project: Project, - run_nox_with_noxfile: RunNoxWithNoxfile, ) -> None: """It builds and installs an sdist from the local package.""" @@ -146,7 +139,7 @@ def test(session: nox.sessions.Session) -> None: """Install the local package.""" nox_poetry.installroot(session, distribution_format=nox_poetry.SDIST) - run_nox_with_noxfile([test], [nox, nox.sessions, nox_poetry]) + run_nox_with_noxfile(project, [test], [nox, nox.sessions, nox_poetry]) expected = [project.package, *project.dependencies] packages = list_packages(project, test) @@ -156,7 +149,6 @@ def test(session: nox.sessions.Session) -> None: def test_installroot_sdist_with_extras( project: Project, - run_nox_with_noxfile: RunNoxWithNoxfile, ) -> None: """It installs the extra.""" @@ -167,7 +159,7 @@ def test(session: nox.sessions.Session) -> None: session, distribution_format=nox_poetry.SDIST, extras=["pygments"] ) - run_nox_with_noxfile([test], [nox, nox.sessions, nox_poetry]) + run_nox_with_noxfile(project, [test], [nox, nox.sessions, nox_poetry]) expected = [ project.package, @@ -181,7 +173,6 @@ def test(session: nox.sessions.Session) -> None: def test_install_dependency_using_patch( project: Project, - run_nox_with_noxfile: RunNoxWithNoxfile, ) -> None: """It installs the pinned dependency.""" @@ -190,7 +181,7 @@ def test(session: nox.sessions.Session) -> None: """Install the dependency.""" session.install("pyflakes") - run_nox_with_noxfile([test], [nox, nox.sessions, nox_poetry.patch]) + run_nox_with_noxfile(project, [test], [nox, nox.sessions, nox_poetry.patch]) expected = [project.get_dependency("pyflakes")] packages = list_packages(project, test) @@ -200,7 +191,6 @@ def test(session: nox.sessions.Session) -> None: def test_install_dependency_without_patch( project: Project, - run_nox_with_noxfile: RunNoxWithNoxfile, ) -> None: """It installs the pinned dependency.""" @@ -209,7 +199,7 @@ def test(session: nox.sessions.Session) -> None: """Install the dependency.""" nox_poetry.install(session, "pycodestyle") - run_nox_with_noxfile([test], [nox, nox.sessions, nox_poetry]) + run_nox_with_noxfile(project, [test], [nox, nox.sessions, nox_poetry]) expected = [project.get_dependency("pycodestyle")] packages = list_packages(project, test) @@ -219,7 +209,6 @@ def test(session: nox.sessions.Session) -> None: def test_install_local_wheel_and_dependency_using_patch( project: Project, - run_nox_with_noxfile: RunNoxWithNoxfile, ) -> None: """It installs the wheel with pinned dependencies.""" @@ -228,7 +217,7 @@ def test(session: nox.sessions.Session) -> None: """Install the dependency.""" session.install(".", "pyflakes") - run_nox_with_noxfile([test], [nox, nox.sessions, nox_poetry.patch]) + run_nox_with_noxfile(project, [test], [nox, nox.sessions, nox_poetry.patch]) expected = [ project.package, @@ -242,7 +231,6 @@ def test(session: nox.sessions.Session) -> None: def test_install_local_wheel_and_dependency_without_patch( project: Project, - run_nox_with_noxfile: RunNoxWithNoxfile, ) -> None: """It installs the wheel with pinned dependencies.""" @@ -251,7 +239,7 @@ def test(session: nox.sessions.Session) -> None: """Install the dependency.""" nox_poetry.install(session, ".", "pycodestyle") - run_nox_with_noxfile([test], [nox, nox.sessions, nox_poetry]) + run_nox_with_noxfile(project, [test], [nox, nox.sessions, nox_poetry]) expected = [ project.package, @@ -265,7 +253,6 @@ def test(session: nox.sessions.Session) -> None: def test_session_install_local( project: Project, - run_nox_with_noxfile: RunNoxWithNoxfile, ) -> None: """It installs the local package.""" @@ -274,7 +261,7 @@ def test(session: nox_poetry.Session) -> None: """Install the local package.""" session.install(".") - run_nox_with_noxfile([test], [nox_poetry]) + run_nox_with_noxfile(project, [test], [nox_poetry]) expected = [project.package, *project.dependencies] packages = list_packages(project, test) @@ -284,7 +271,6 @@ def test(session: nox_poetry.Session) -> None: def test_session_install_local_with_extras( project: Project, - run_nox_with_noxfile: RunNoxWithNoxfile, ) -> None: """It installs the extra.""" @@ -293,7 +279,7 @@ def test(session: nox_poetry.Session) -> None: """Install the local package.""" session.install(".[pygments]") - run_nox_with_noxfile([test], [nox_poetry]) + run_nox_with_noxfile(project, [test], [nox_poetry]) expected = [ project.package, @@ -307,7 +293,6 @@ def test(session: nox_poetry.Session) -> None: def test_session_install_dependency( project: Project, - run_nox_with_noxfile: RunNoxWithNoxfile, ) -> None: """It installs the pinned dependency.""" @@ -316,7 +301,7 @@ def test(session: nox_poetry.Session) -> None: """Install the dependency.""" session.install("pyflakes") - run_nox_with_noxfile([test], [nox_poetry]) + run_nox_with_noxfile(project, [test], [nox_poetry]) expected = [project.get_dependency("pyflakes")] packages = list_packages(project, test) @@ -326,7 +311,6 @@ def test(session: nox_poetry.Session) -> None: def test_session_install_local_wheel_and_dependency( project: Project, - run_nox_with_noxfile: RunNoxWithNoxfile, ) -> None: """It installs the wheel with pinned dependencies.""" @@ -335,7 +319,7 @@ def test(session: nox_poetry.Session) -> None: """Install the dependency.""" session.install(".", "pyflakes") - run_nox_with_noxfile([test], [nox_poetry]) + run_nox_with_noxfile(project, [test], [nox_poetry]) expected = [ project.package, @@ -349,7 +333,6 @@ def test(session: nox_poetry.Session) -> None: def test_session_parametrize( project: Project, - run_nox_with_noxfile: RunNoxWithNoxfile, ) -> None: """It forwards parameters to sessions.""" @@ -358,4 +341,4 @@ def test_session_parametrize( def test(session: nox_poetry.Session, n: int) -> None: """Do nothing.""" - run_nox_with_noxfile([test], [nox, nox_poetry]) + run_nox_with_noxfile(project, [test], [nox, nox_poetry]) From 6b0022c82ac85e7a6bbfdb1ed5a2eba17a8484bd Mon Sep 17 00:00:00 2001 From: Claudio Jolowicz Date: Sat, 13 Mar 2021 18:07:55 +0100 Subject: [PATCH 06/20] test: Remove unused fixture run_nox --- tests/functional/conftest.py | 9 --------- 1 file changed, 9 deletions(-) diff --git a/tests/functional/conftest.py b/tests/functional/conftest.py index a656ff43..439cafbd 100644 --- a/tests/functional/conftest.py +++ b/tests/functional/conftest.py @@ -105,15 +105,6 @@ def _run_nox(project: Project) -> CompletedProcess: raise RuntimeError(f"{error}\n{error.stderr}") -RunNox = Callable[[], CompletedProcess] - - -@pytest.fixture -def run_nox(project: Project) -> RunNox: - """Invoke Nox in the project.""" - return functools.partial(_run_nox, project) - - SessionFunction = Callable[..., Any] From 93573fd3d8b01c7769def4b865d6150cc391be81 Mon Sep 17 00:00:00 2001 From: Claudio Jolowicz Date: Sat, 13 Mar 2021 18:08:26 +0100 Subject: [PATCH 07/20] test: Remove unused fixture write_noxfile --- tests/functional/conftest.py | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/tests/functional/conftest.py b/tests/functional/conftest.py index 439cafbd..770654ff 100644 --- a/tests/functional/conftest.py +++ b/tests/functional/conftest.py @@ -1,5 +1,4 @@ """Fixtures for functional tests.""" -import functools import inspect import os import re @@ -121,21 +120,6 @@ def _write_noxfile( path.write_text(text) -WriteNoxfile = Callable[ - [ - Iterable[SessionFunction], - Iterable[ModuleType], - ], - None, -] - - -@pytest.fixture -def write_noxfile(project: Project) -> WriteNoxfile: - """Write a noxfile with the given session functions.""" - return functools.partial(_write_noxfile, project) - - def run_nox_with_noxfile( project: Project, sessions: Iterable[SessionFunction], From af54897c6681496cce8bfb29a09d6d3d34534a4f Mon Sep 17 00:00:00 2001 From: Claudio Jolowicz Date: Sat, 13 Mar 2021 18:09:37 +0100 Subject: [PATCH 08/20] style: Reformat test_functional --- tests/functional/test_functional.py | 68 ++++++++--------------------- 1 file changed, 17 insertions(+), 51 deletions(-) diff --git a/tests/functional/test_functional.py b/tests/functional/test_functional.py index 550ed634..ec9fd22a 100644 --- a/tests/functional/test_functional.py +++ b/tests/functional/test_functional.py @@ -7,9 +7,7 @@ import nox_poetry.patch -def test_install_local_using_patch( - project: Project, -) -> None: +def test_install_local_using_patch(project: Project) -> None: """It installs the local package.""" @nox.session @@ -25,9 +23,7 @@ def test(session: nox.sessions.Session) -> None: assert set(expected) == set(packages) -def test_install_local_using_patch_with_extras( - project: Project, -) -> None: +def test_install_local_using_patch_with_extras(project: Project) -> None: """It installs the extra.""" @nox.session @@ -47,9 +43,7 @@ def test(session: nox.sessions.Session) -> None: assert set(expected) == set(packages) -def test_install_local_wheel( - project: Project, -) -> None: +def test_install_local_wheel(project: Project) -> None: """It builds and installs a wheel from the local package.""" @nox.session @@ -65,9 +59,7 @@ def test(session: nox.sessions.Session) -> None: assert set(expected) == set(packages) -def test_install_local_wheel_with_extras( - project: Project, -) -> None: +def test_install_local_wheel_with_extras(project: Project) -> None: """It installs the extra.""" @nox.session @@ -87,9 +79,7 @@ def test(session: nox.sessions.Session) -> None: assert set(expected) == set(packages) -def test_installroot_wheel( - project: Project, -) -> None: +def test_installroot_wheel(project: Project) -> None: """It builds and installs a wheel from the local package.""" @nox.session @@ -105,9 +95,7 @@ def test(session: nox.sessions.Session) -> None: assert set(expected) == set(packages) -def test_installroot_wheel_with_extras( - project: Project, -) -> None: +def test_installroot_wheel_with_extras(project: Project) -> None: """It installs the extra.""" @nox.session @@ -129,9 +117,7 @@ def test(session: nox.sessions.Session) -> None: assert set(expected) == set(packages) -def test_installroot_sdist( - project: Project, -) -> None: +def test_installroot_sdist(project: Project) -> None: """It builds and installs an sdist from the local package.""" @nox.session @@ -147,9 +133,7 @@ def test(session: nox.sessions.Session) -> None: assert set(expected) == set(packages) -def test_installroot_sdist_with_extras( - project: Project, -) -> None: +def test_installroot_sdist_with_extras(project: Project) -> None: """It installs the extra.""" @nox.session @@ -171,9 +155,7 @@ def test(session: nox.sessions.Session) -> None: assert set(expected) == set(packages) -def test_install_dependency_using_patch( - project: Project, -) -> None: +def test_install_dependency_using_patch(project: Project) -> None: """It installs the pinned dependency.""" @nox.session @@ -189,9 +171,7 @@ def test(session: nox.sessions.Session) -> None: assert set(expected) == set(packages) -def test_install_dependency_without_patch( - project: Project, -) -> None: +def test_install_dependency_without_patch(project: Project) -> None: """It installs the pinned dependency.""" @nox.session @@ -207,9 +187,7 @@ def test(session: nox.sessions.Session) -> None: assert set(expected) == set(packages) -def test_install_local_wheel_and_dependency_using_patch( - project: Project, -) -> None: +def test_install_local_wheel_and_dependency_using_patch(project: Project) -> None: """It installs the wheel with pinned dependencies.""" @nox.session @@ -229,9 +207,7 @@ def test(session: nox.sessions.Session) -> None: assert set(expected) == set(packages) -def test_install_local_wheel_and_dependency_without_patch( - project: Project, -) -> None: +def test_install_local_wheel_and_dependency_without_patch(project: Project) -> None: """It installs the wheel with pinned dependencies.""" @nox.session @@ -251,9 +227,7 @@ def test(session: nox.sessions.Session) -> None: assert set(expected) == set(packages) -def test_session_install_local( - project: Project, -) -> None: +def test_session_install_local(project: Project) -> None: """It installs the local package.""" @nox_poetry.session @@ -269,9 +243,7 @@ def test(session: nox_poetry.Session) -> None: assert set(expected) == set(packages) -def test_session_install_local_with_extras( - project: Project, -) -> None: +def test_session_install_local_with_extras(project: Project) -> None: """It installs the extra.""" @nox_poetry.session @@ -291,9 +263,7 @@ def test(session: nox_poetry.Session) -> None: assert set(expected) == set(packages) -def test_session_install_dependency( - project: Project, -) -> None: +def test_session_install_dependency(project: Project) -> None: """It installs the pinned dependency.""" @nox_poetry.session @@ -309,9 +279,7 @@ def test(session: nox_poetry.Session) -> None: assert set(expected) == set(packages) -def test_session_install_local_wheel_and_dependency( - project: Project, -) -> None: +def test_session_install_local_wheel_and_dependency(project: Project) -> None: """It installs the wheel with pinned dependencies.""" @nox_poetry.session @@ -331,9 +299,7 @@ def test(session: nox_poetry.Session) -> None: assert set(expected) == set(packages) -def test_session_parametrize( - project: Project, -) -> None: +def test_session_parametrize(project: Project) -> None: """It forwards parameters to sessions.""" @nox_poetry.session From d0092e55a70462dd140139d2afb69ef5d72e57e7 Mon Sep 17 00:00:00 2001 From: Claudio Jolowicz Date: Sat, 13 Mar 2021 17:50:09 +0100 Subject: [PATCH 09/20] test: Handle URL and path dependencies in list_packages fixture --- tests/functional/conftest.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/tests/functional/conftest.py b/tests/functional/conftest.py index 770654ff..4f391ef4 100644 --- a/tests/functional/conftest.py +++ b/tests/functional/conftest.py @@ -152,10 +152,15 @@ def list_packages(project: Project, session: SessionFunction) -> List[Package]: def parse(line: str) -> Package: name, _, version = line.partition("==") + if not version and " @ " in line: + # Abuse Package.version to store the URL or path. + name, _, version = line.partition(" @ ") + + if name == project.package.name: + # But use the known version for the local package. + return project.package + name = _canonicalize_name(name) - if not version and name.startswith(f"{project.package.name} @ file://"): - # Local package is listed without version, but it does not matter. - return project.package return Package(name, version) return [parse(line) for line in process.stdout.splitlines()] From 1ff58c4436a73f89cc6f45eeb653f81b19ac6dd9 Mon Sep 17 00:00:00 2001 From: Claudio Jolowicz Date: Sat, 13 Mar 2021 19:20:48 +0100 Subject: [PATCH 10/20] test: Handle URL dependencies in Project.get_dependency --- tests/functional/conftest.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/functional/conftest.py b/tests/functional/conftest.py index 4f391ef4..9dd35d2b 100644 --- a/tests/functional/conftest.py +++ b/tests/functional/conftest.py @@ -52,6 +52,10 @@ def get_dependency(self, name: str) -> Package: data = self._read_toml("poetry.lock") for package in data["package"]: if package["name"] == name: + url = package.get("source", {}).get("url") + if url is not None: + # Abuse Package.version to store the URL (for ``list_packages``). + return Package(name, url) return Package(name, package["version"]) raise ValueError(f"{name}: package not found") From ae48c40796abfa6413383b513ca5346e5adbc850 Mon Sep 17 00:00:00 2001 From: Claudio Jolowicz Date: Sat, 13 Mar 2021 17:51:23 +0100 Subject: [PATCH 11/20] test: Add test data for URL dependencies --- .../url-dependency/poetry.lock | 19 +++++++++++++++++++ .../url-dependency/pyproject.toml | 15 +++++++++++++++ .../src/url_dependency/__init__.py | 1 + 3 files changed, 35 insertions(+) create mode 100644 tests/functional/test_functional/url-dependency/poetry.lock create mode 100644 tests/functional/test_functional/url-dependency/pyproject.toml create mode 100644 tests/functional/test_functional/url-dependency/src/url_dependency/__init__.py diff --git a/tests/functional/test_functional/url-dependency/poetry.lock b/tests/functional/test_functional/url-dependency/poetry.lock new file mode 100644 index 00000000..26c218eb --- /dev/null +++ b/tests/functional/test_functional/url-dependency/poetry.lock @@ -0,0 +1,19 @@ +[[package]] +category = "main" +description = "" +name = "poyo" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "0.5.0" + +[package.source] +reference = "" +type = "url" +url = "https://github.com/hackebrot/poyo/archive/master.zip" +[metadata] +content-hash = "ff110fa8bd529837779d5f342f0367a2707ef9f31ece6f059ba47a616e5ebcb4" +lock-version = "1.0" +python-versions = "^3.6.1" + +[metadata.files] +poyo = [] diff --git a/tests/functional/test_functional/url-dependency/pyproject.toml b/tests/functional/test_functional/url-dependency/pyproject.toml new file mode 100644 index 00000000..9ca2b86c --- /dev/null +++ b/tests/functional/test_functional/url-dependency/pyproject.toml @@ -0,0 +1,15 @@ +[tool.poetry] +name = "url-dependency" +version = "0.1.0" +description = "" +authors = ["Your Name "] + +[tool.poetry.dependencies] +python = "^3.6.1" +poyo = {url = "https://github.com/hackebrot/poyo/archive/master.zip"} + +[tool.poetry.dev-dependencies] + +[build-system] +requires = ["poetry>=0.12"] +build-backend = "poetry.masonry.api" diff --git a/tests/functional/test_functional/url-dependency/src/url_dependency/__init__.py b/tests/functional/test_functional/url-dependency/src/url_dependency/__init__.py new file mode 100644 index 00000000..8171d78a --- /dev/null +++ b/tests/functional/test_functional/url-dependency/src/url_dependency/__init__.py @@ -0,0 +1 @@ +"""Example package for URL dependencies.""" From 1f6c7ef6c88cb3fbad6cb5fe70b19e57c6f0d857 Mon Sep 17 00:00:00 2001 From: Claudio Jolowicz Date: Sat, 13 Mar 2021 17:51:02 +0100 Subject: [PATCH 12/20] test: Add functional test for URL dependencies MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a failing test for URL dependencies. Test output below: nox > Command python -m pip install --constraint=.nox/test/tmp/requirements.txt file:///…/url-dependency/dist/url_dependency-0.1.0-py3-none-any.whl failed with exit code 1: DEPRECATION: Constraints are only allowed to take the form of a package name and a version specifier. Other forms were originally permitted as an accident of the implementation, but were undocumented. The new implementation of the resolver no longer supports these forms. A possible replacement is replacing the constraint with a requirement.. You can find discussion regarding this at https://github.com/pypa/pip/issues/8210. ERROR: Links are not allowed as constraints --- tests/functional/test_functional.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tests/functional/test_functional.py b/tests/functional/test_functional.py index ec9fd22a..cdf70781 100644 --- a/tests/functional/test_functional.py +++ b/tests/functional/test_functional.py @@ -1,4 +1,6 @@ """Functional tests.""" +from pathlib import Path + import nox.sessions from tests.functional.conftest import list_packages from tests.functional.conftest import Project @@ -308,3 +310,20 @@ def test(session: nox_poetry.Session, n: int) -> None: """Do nothing.""" run_nox_with_noxfile(project, [test], [nox, nox_poetry]) + + +def test_install_with_url_dependency(datadir: Path) -> None: + """It installs the package.""" + project = Project(datadir / "url-dependency") + + @nox_poetry.session + def test(session: nox_poetry.Session) -> None: + """Install the local package.""" + session.install(".") + + run_nox_with_noxfile(project, [test], [nox_poetry]) + + expected = [project.package, *project.dependencies] + packages = list_packages(project, test) + + assert set(expected) == set(packages) From fd097ac386de7dca1b52a09884b1c30df77483c0 Mon Sep 17 00:00:00 2001 From: Claudio Jolowicz Date: Sat, 13 Mar 2021 18:21:14 +0100 Subject: [PATCH 13/20] build: Add dependency on packaging >= 20.9 --- poetry.lock | 6 +++--- pyproject.toml | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/poetry.lock b/poetry.lock index 644b1230..b26fb5d4 100644 --- a/poetry.lock +++ b/poetry.lock @@ -686,7 +686,7 @@ tox_to_nox = ["jinja2", "tox"] name = "packaging" version = "20.9" description = "Core utilities for Python packages" -category = "dev" +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" @@ -903,7 +903,7 @@ python-versions = "*" name = "pyparsing" version = "2.4.7" description = "Python parsing module" -category = "dev" +category = "main" optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" @@ -1369,7 +1369,7 @@ testing = ["pytest (>=4.6)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pyt [metadata] lock-version = "1.1" python-versions = "^3.6.1" -content-hash = "872d04eb655eef4313348b96e496a32bea34ea30b5162473d1bbb2f8aac34e9a" +content-hash = "a27d49cafec75f4ffedf6e65849afe46d390f194ba13ecec899a970783b9e50b" [metadata.files] alabaster = [ diff --git a/pyproject.toml b/pyproject.toml index 1a1cc182..857c6138 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -23,6 +23,7 @@ Changelog = "https://github.com/cjolowicz/nox-poetry/releases" python = "^3.6.1" nox = ">=2020.8.22" tomlkit = "^0.7.0" +packaging = ">=20.9" [tool.poetry.dev-dependencies] pytest = "^6.2.2" From b0983145bf09913457f362111a21b7fb1b12a468 Mon Sep 17 00:00:00 2001 From: Claudio Jolowicz Date: Sat, 13 Mar 2021 19:04:58 +0100 Subject: [PATCH 14/20] refactor(poetry): Do not write exported requirements to disk --- src/nox_poetry/poetry.py | 13 ++++++++----- src/nox_poetry/sessions.py | 3 ++- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/nox_poetry/poetry.py b/src/nox_poetry/poetry.py index 7787f151..6ee546bf 100644 --- a/src/nox_poetry/poetry.py +++ b/src/nox_poetry/poetry.py @@ -61,22 +61,25 @@ def config(self) -> Config: self._config = Config(Path.cwd()) return self._config - def export(self, path: Path) -> None: + def export(self) -> str: """Export the lock file to requirements format. - Args: - path: The destination path. + Returns: + The generated requirements as text. """ - self.session.run_always( + output = self.session.run_always( "poetry", "export", "--format=requirements.txt", - f"--output={path}", "--dev", *[f"--extras={extra}" for extra in self.config.extras], "--without-hashes", external=True, + silent=True, + stderr=None, ) + assert isinstance(output, str) # noqa: S101 + return output def build(self, *, format: str) -> str: """Build the package. diff --git a/src/nox_poetry/sessions.py b/src/nox_poetry/sessions.py index 6d1bc050..2e71e906 100644 --- a/src/nox_poetry/sessions.py +++ b/src/nox_poetry/sessions.py @@ -170,7 +170,8 @@ def export_requirements(self) -> Path: digest = hashlib.blake2b(lockdata).hexdigest() if not hashfile.is_file() or hashfile.read_text() != digest: - self.poetry.export(path) + requirements = self.poetry.export() + path.write_text(requirements) hashfile.write_text(digest) return path From 30ba11df6c681fdd2fed3766409285e4361cee2d Mon Sep 17 00:00:00 2001 From: Claudio Jolowicz Date: Sat, 13 Mar 2021 19:06:04 +0100 Subject: [PATCH 15/20] fix: Convert exported requirements to constraints format --- src/nox_poetry/sessions.py | 40 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/src/nox_poetry/sessions.py b/src/nox_poetry/sessions.py index 2e71e906..538125fa 100644 --- a/src/nox_poetry/sessions.py +++ b/src/nox_poetry/sessions.py @@ -5,10 +5,13 @@ from pathlib import Path from typing import Any from typing import Iterable +from typing import Iterator from typing import Optional from typing import Tuple import nox +from packaging.requirements import InvalidRequirement +from packaging.requirements import Requirement from nox_poetry.poetry import DistributionFormat from nox_poetry.poetry import Poetry @@ -52,6 +55,39 @@ def _split_extras(arg: str) -> Tuple[str, Optional[str]]: return arg, None +def to_constraint(requirement_string: str, line: int) -> Optional[str]: + """Convert requirement to constraint.""" + if any( + requirement_string.startswith(prefix) + for prefix in ("-e ", "file://", "git+https://", "http://", "https://") + ): + return None + + try: + requirement = Requirement(requirement_string) + except InvalidRequirement as error: + raise RuntimeError(f"line {line}: {requirement_string!r}: {error}") + + if not (requirement.name and requirement.specifier): + return None + + constraint = f"{requirement.name}{requirement.specifier}" + return f"{constraint}; {requirement.marker}" if requirement.marker else constraint + + +def to_constraints(requirements: str) -> str: + """Convert requirements to constraints.""" + + def _to_constraints() -> Iterator[str]: + lines = requirements.strip().splitlines() + for line, requirement in enumerate(lines, start=1): + constraint = to_constraint(requirement, line) + if constraint is not None: + yield constraint + + return "\n".join(_to_constraints()) + + class _PoetrySession: """Poetry-related utilities for session functions.""" @@ -170,8 +206,8 @@ def export_requirements(self) -> Path: digest = hashlib.blake2b(lockdata).hexdigest() if not hashfile.is_file() or hashfile.read_text() != digest: - requirements = self.poetry.export() - path.write_text(requirements) + constraints = to_constraints(self.poetry.export()) + path.write_text(constraints) hashfile.write_text(digest) return path From 7339c4b61da0524332d5ccee549d47eee5173883 Mon Sep 17 00:00:00 2001 From: Claudio Jolowicz Date: Sat, 13 Mar 2021 20:10:57 +0100 Subject: [PATCH 16/20] test: Add unit tests for to_constraints --- tests/unit/test_sessions.py | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/tests/unit/test_sessions.py b/tests/unit/test_sessions.py index 0f25d201..1f3ecf22 100644 --- a/tests/unit/test_sessions.py +++ b/tests/unit/test_sessions.py @@ -8,6 +8,7 @@ import pytest import nox_poetry +from nox_poetry.sessions import to_constraints # type: ignore[attr-defined] IterSessions = Callable[[], Iterator[str]] @@ -136,3 +137,29 @@ def test_session_export_requirements(proxy: nox_poetry.Session) -> None: def test_session_build_package(proxy: nox_poetry.Session) -> None: """It exports the requirements.""" proxy.poetry.build_package(distribution_format=nox_poetry.SDIST) + + +@pytest.mark.parametrize( + "requirements,expected", + [ + ("", ""), + (" ", ""), + ("first @ https://github.com/hynek/first/archive/main.zip", ""), + ("https://github.com/hynek/first/archive/main.zip", ""), + ("first==2.0.2", "first==2.0.2"), + ("httpx[http2]==0.17.0", "httpx==0.17.0"), + ( + "regex==2020.10.28; python_version == '3.5'", + 'regex==2020.10.28; python_version == "3.5"', + ), + ], +) +def test_to_constraints(requirements: str, expected: str) -> None: + """It converts requirements to constraints.""" + assert to_constraints(requirements) == expected + + +def test_invalid_constraint() -> None: + """It raises an exception.""" + with pytest.raises(Exception): + to_constraints("example @ /tmp/example") From 215a61b998be0544b8aeea69cd0ef5d0ab951138 Mon Sep 17 00:00:00 2001 From: Claudio Jolowicz Date: Sat, 13 Mar 2021 22:30:10 +0100 Subject: [PATCH 17/20] test: Use canonicalize_name from packaging.utils --- tests/functional/conftest.py | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/tests/functional/conftest.py b/tests/functional/conftest.py index 9dd35d2b..212fa972 100644 --- a/tests/functional/conftest.py +++ b/tests/functional/conftest.py @@ -1,7 +1,6 @@ """Fixtures for functional tests.""" import inspect import os -import re import subprocess # noqa: S404 import sys from dataclasses import dataclass @@ -16,6 +15,7 @@ import pytest import tomlkit +from packaging.utils import canonicalize_name if TYPE_CHECKING: @@ -134,14 +134,6 @@ def run_nox_with_noxfile( _run_nox(project) -_CANONICALIZE_PATTERN = re.compile(r"[-_.]+") - - -def _canonicalize_name(name: str) -> str: - # From ``packaging.utils.canonicalize_name`` (PEP 503) - return _CANONICALIZE_PATTERN.sub("-", name).lower() - - def list_packages(project: Project, session: SessionFunction) -> List[Package]: """List the installed packages for a session in the given project.""" bindir = "Scripts" if sys.platform == "win32" else "bin" @@ -164,7 +156,7 @@ def parse(line: str) -> Package: # But use the known version for the local package. return project.package - name = _canonicalize_name(name) + name = canonicalize_name(name) return Package(name, version) return [parse(line) for line in process.stdout.splitlines()] From f5257b296619a125e5d94b58472438dec3cf7693 Mon Sep 17 00:00:00 2001 From: Claudio Jolowicz Date: Sat, 13 Mar 2021 22:30:35 +0100 Subject: [PATCH 18/20] test: Add test data for path dependencies --- .../path-dependency/poetry.lock | 39 +++++++++++++++++++ .../path-dependency/pyproject.toml | 15 +++++++ .../src/path_dependency/__init__.py | 1 + 3 files changed, 55 insertions(+) create mode 100644 tests/functional/test_functional/path-dependency/poetry.lock create mode 100644 tests/functional/test_functional/path-dependency/pyproject.toml create mode 100644 tests/functional/test_functional/path-dependency/src/path_dependency/__init__.py diff --git a/tests/functional/test_functional/path-dependency/poetry.lock b/tests/functional/test_functional/path-dependency/poetry.lock new file mode 100644 index 00000000..0ebe1cdf --- /dev/null +++ b/tests/functional/test_functional/path-dependency/poetry.lock @@ -0,0 +1,39 @@ +[[package]] +category = "main" +description = "" +develop = true +name = "example" +optional = false +python-versions = "^3.6.1" +version = "0.1.0" + +[package.dependencies] +first = "^2.0.0" + +[package.extras] +pygments = ["Pygments (^2.7.1)"] + +[package.source] +reference = "" +type = "directory" +url = "../example" + +[[package]] +category = "main" +description = "Return the first true value of an iterable." +name = "first" +optional = false +python-versions = "*" +version = "2.0.2" + +[metadata] +content-hash = "5b4bb67e14af611647b481be0b303a180d88713c270fd4f73f47e2f1321f7696" +lock-version = "1.0" +python-versions = "^3.6.1" + +[metadata.files] +example = [] +first = [ + {file = "first-2.0.2-py2.py3-none-any.whl", hash = "sha256:8d8e46e115ea8ac652c76123c0865e3ff18372aef6f03c22809ceefcea9dec86"}, + {file = "first-2.0.2.tar.gz", hash = "sha256:ff285b08c55f8c97ce4ea7012743af2495c9f1291785f163722bd36f6af6d3bf"}, +] diff --git a/tests/functional/test_functional/path-dependency/pyproject.toml b/tests/functional/test_functional/path-dependency/pyproject.toml new file mode 100644 index 00000000..a2ff7610 --- /dev/null +++ b/tests/functional/test_functional/path-dependency/pyproject.toml @@ -0,0 +1,15 @@ +[tool.poetry] +name = "path-dependency" +version = "0.1.0" +description = "" +authors = ["Your Name "] + +[tool.poetry.dependencies] +python = "^3.6.1" +example = {path = "../example"} + +[tool.poetry.dev-dependencies] + +[build-system] +requires = ["poetry-core>=1.0.0"] +build-backend = "poetry.core.masonry.api" diff --git a/tests/functional/test_functional/path-dependency/src/path_dependency/__init__.py b/tests/functional/test_functional/path-dependency/src/path_dependency/__init__.py new file mode 100644 index 00000000..84745ade --- /dev/null +++ b/tests/functional/test_functional/path-dependency/src/path_dependency/__init__.py @@ -0,0 +1 @@ +"""Example package for path dependencies.""" From c1319d8f3e4ea0e3b84012e9da249f9e76063560 Mon Sep 17 00:00:00 2001 From: Claudio Jolowicz Date: Sat, 13 Mar 2021 22:31:01 +0100 Subject: [PATCH 19/20] test: Add functional test for path dependency --- tests/functional/test_functional.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tests/functional/test_functional.py b/tests/functional/test_functional.py index cdf70781..5de3a933 100644 --- a/tests/functional/test_functional.py +++ b/tests/functional/test_functional.py @@ -327,3 +327,20 @@ def test(session: nox_poetry.Session) -> None: packages = list_packages(project, test) assert set(expected) == set(packages) + + +def test_install_with_path_dependency(datadir: Path) -> None: + """It installs the package.""" + project = Project(datadir / "path-dependency") + + @nox_poetry.session + def test(session: nox_poetry.Session) -> None: + """Install the local package.""" + session.install(".") + + run_nox_with_noxfile(project, [test], [nox_poetry]) + + expected = [project.package, *project.dependencies] + packages = list_packages(project, test) + + assert set(expected) == set(packages) From a06ae67c8c653006f6c4554f982303b60a79d915 Mon Sep 17 00:00:00 2001 From: Claudio Jolowicz Date: Sat, 13 Mar 2021 23:39:12 +0100 Subject: [PATCH 20/20] test: Mark test for path dependencies as XFAIL --- tests/functional/test_functional.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/functional/test_functional.py b/tests/functional/test_functional.py index 5de3a933..393d181f 100644 --- a/tests/functional/test_functional.py +++ b/tests/functional/test_functional.py @@ -2,6 +2,7 @@ from pathlib import Path import nox.sessions +import pytest from tests.functional.conftest import list_packages from tests.functional.conftest import Project from tests.functional.conftest import run_nox_with_noxfile @@ -329,6 +330,8 @@ def test(session: nox_poetry.Session) -> None: assert set(expected) == set(packages) +# https://github.com/python-poetry/poetry/issues/3468 +@pytest.mark.xfail(reason="Poetry exports path requirements in an invalid format.") def test_install_with_path_dependency(datadir: Path) -> None: """It installs the package.""" project = Project(datadir / "path-dependency")