From a8d42e00d38ba0574b78d41ea51ffca73c5be882 Mon Sep 17 00:00:00 2001 From: Mathieu Kniewallner Date: Sun, 12 Jun 2022 22:46:19 +0200 Subject: [PATCH 1/6] test(init): add tests for all options --- tests/console/commands/test_init.py | 47 +++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/tests/console/commands/test_init.py b/tests/console/commands/test_init.py index c733bba2dfb..a9868ab5c0c 100644 --- a/tests/console/commands/test_init.py +++ b/tests/console/commands/test_init.py @@ -779,6 +779,53 @@ def test_predefined_and_interactive_dev_dependencies( assert 'pytest = "^3.6.0"' in output +def test_predefined_all_options(tester: CommandTester, repo: TestRepository): + repo.add_package(get_package("pendulum", "2.0.0")) + repo.add_package(get_package("pytest", "3.6.0")) + + inputs = [ + "1.2.3", # Version + "", # Description + "", # Author + "", # License + "n", # Interactive packages + "n", # Interactive dev packages + "\n", # Generate + ] + + tester.execute( + "--name my-package " + "--description 'This is a description' " + "--author 'Foo Bar ' " + "--python '^3.8' " + "--license MIT " + "--dependency pendulum " + "--dev-dependency pytest", + inputs="\n".join(inputs), + ) + + expected = """\ +[tool.poetry] +name = "my-package" +version = "1.2.3" +description = "This is a description" +authors = ["Foo Bar "] +license = "MIT" +readme = "README.md" +packages = [{include = "my_package"}] + +[tool.poetry.dependencies] +python = "^3.8" +pendulum = "^2.0.0" + +[tool.poetry.group.dev.dependencies] +pytest = "^3.6.0" +""" + + output = tester.io.fetch_output() + assert expected in output + + def test_add_package_with_extras_and_whitespace(tester: CommandTester): result = tester.command._parse_requirements(["databases[postgresql, sqlite]"]) From 4fd1f5d9c5a755d94896e0390b9c625145eeecba Mon Sep 17 00:00:00 2001 From: Mathieu Kniewallner Date: Sun, 12 Jun 2022 22:48:55 +0200 Subject: [PATCH 2/6] feat(init): only ask description when necessary --- src/poetry/console/commands/init.py | 9 +++------ tests/console/commands/test_init.py | 1 - 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/poetry/console/commands/init.py b/src/poetry/console/commands/init.py index 1897829a4a4..a4411d5761a 100644 --- a/src/poetry/console/commands/init.py +++ b/src/poetry/console/commands/init.py @@ -118,12 +118,9 @@ def handle(self) -> int: ) version = self.ask(question) - description = self.option("description") or "" - question = self.create_question( - f"Description [{description}]: ", - default=description, - ) - description = self.ask(question) + description = self.option("description") + if not description: + description = self.ask(self.create_question("Description []: ", default="")) author = self.option("author") if not author and vcs_config.get("user.name"): diff --git a/tests/console/commands/test_init.py b/tests/console/commands/test_init.py index a9868ab5c0c..6f83624baa1 100644 --- a/tests/console/commands/test_init.py +++ b/tests/console/commands/test_init.py @@ -785,7 +785,6 @@ def test_predefined_all_options(tester: CommandTester, repo: TestRepository): inputs = [ "1.2.3", # Version - "", # Description "", # Author "", # License "n", # Interactive packages From 6cfd4a24c8b15849f125ccb1b0e70ba8607cdf09 Mon Sep 17 00:00:00 2001 From: Mathieu Kniewallner Date: Sun, 12 Jun 2022 22:50:23 +0200 Subject: [PATCH 3/6] refactor(init): remove useless license validator --- src/poetry/console/commands/init.py | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/poetry/console/commands/init.py b/src/poetry/console/commands/init.py index a4411d5761a..de987bba3cf 100644 --- a/src/poetry/console/commands/init.py +++ b/src/poetry/console/commands/init.py @@ -145,7 +145,6 @@ def handle(self) -> int: question = self.create_question( f"License [{license}]: ", default=license ) - question.set_validator(self._validate_license) license = self.ask(question) python = self.option("python") @@ -454,14 +453,6 @@ def _validate_author(self, author: str, default: str) -> str | None: return author - def _validate_license(self, license: str) -> str: - from poetry.core.spdx.helpers import license_by_id - - if license: - license_by_id(license) - - return license - def _get_pool(self) -> Pool: from poetry.repositories import Pool from poetry.repositories.pypi_repository import PyPiRepository From ebd03d3ec65e6eb40d8382af4698fb520c440194 Mon Sep 17 00:00:00 2001 From: Mathieu Kniewallner Date: Sun, 12 Jun 2022 22:54:58 +0200 Subject: [PATCH 4/6] feat(init): only ask license when necessary --- src/poetry/console/commands/init.py | 9 +++------ tests/console/commands/test_init.py | 1 - 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/poetry/console/commands/init.py b/src/poetry/console/commands/init.py index de987bba3cf..3b4b6cbe4e6 100644 --- a/src/poetry/console/commands/init.py +++ b/src/poetry/console/commands/init.py @@ -140,12 +140,9 @@ def handle(self) -> int: else: authors = [author] - license = self.option("license") or "" - - question = self.create_question( - f"License [{license}]: ", default=license - ) - license = self.ask(question) + license = self.option("license") + if not license: + license = self.ask(self.create_question("License []: ", default="")) python = self.option("python") if not python: diff --git a/tests/console/commands/test_init.py b/tests/console/commands/test_init.py index 6f83624baa1..47485d3fd48 100644 --- a/tests/console/commands/test_init.py +++ b/tests/console/commands/test_init.py @@ -786,7 +786,6 @@ def test_predefined_all_options(tester: CommandTester, repo: TestRepository): inputs = [ "1.2.3", # Version "", # Author - "", # License "n", # Interactive packages "n", # Interactive dev packages "\n", # Generate From d165ccefd85ef5a7c025961dd5d8d8479c69b5e9 Mon Sep 17 00:00:00 2001 From: Mathieu Kniewallner Date: Mon, 13 Jun 2022 00:46:57 +0200 Subject: [PATCH 5/6] feat(init): validate package definition --- src/poetry/console/commands/init.py | 12 ++++- tests/console/commands/test_init.py | 77 +++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+), 1 deletion(-) diff --git a/src/poetry/console/commands/init.py b/src/poetry/console/commands/init.py index 3b4b6cbe4e6..8c9a6896526 100644 --- a/src/poetry/console/commands/init.py +++ b/src/poetry/console/commands/init.py @@ -265,9 +265,12 @@ def _determine_requirements( if not requires: result = [] - package = self.ask( + question = self.create_question( "Search for package to add (or leave blank to continue):" ) + question.set_validator(self._validate_package) + + package = self.ask(question) while package: constraint = self._parse_requirements([package])[0] if ( @@ -450,6 +453,13 @@ def _validate_author(self, author: str, default: str) -> str | None: return author + @staticmethod + def _validate_package(package: str | None) -> str | None: + if package and len(package.split()) > 2: + raise ValueError("Invalid package definition.") + + return package + def _get_pool(self) -> Pool: from poetry.repositories import Pool from poetry.repositories.pypi_repository import PyPiRepository diff --git a/tests/console/commands/test_init.py b/tests/console/commands/test_init.py index 47485d3fd48..b43c03bc760 100644 --- a/tests/console/commands/test_init.py +++ b/tests/console/commands/test_init.py @@ -11,6 +11,7 @@ from cleo.testers.command_tester import CommandTester +from poetry.console.commands.init import InitCommand from poetry.repositories import Pool from poetry.utils._compat import decode from poetry.utils.helpers import canonicalize_name @@ -587,6 +588,56 @@ def test_interactive_with_file_dependency( assert expected in tester.io.fetch_output() +def test_interactive_with_wrong_dependency_inputs( + tester: CommandTester, repo: TestRepository +): + repo.add_package(get_package("pendulum", "2.0.0")) + repo.add_package(get_package("pytest", "3.6.0")) + + inputs = [ + "my-package", # Package name + "1.2.3", # Version + "This is a description", # Description + "n", # Author + "MIT", # License + "^3.8", # Python + "", # Interactive packages + "pendulum 2.0.0 foo", # Package name and constraint (invalid) + "pendulum 2.0.0", # Package name and constraint (invalid) + "pendulum 2.0.0", # Package name and constraint (invalid) + "pendulum 2.0.0", # Package name and constraint (invalid) + "pendulum@^2.0.0", # Package name and constraint (valid) + "", # End package selection + "", # Interactive dev packages + "pytest 3.6.0 foo", # Dev package name and constraint (invalid) + "pytest 3.6.0", # Dev package name and constraint (invalid) + "pytest@3.6.0", # Dev package name and constraint (valid) + "", # End package selection + "\n", # Generate + ] + tester.execute(inputs="\n".join(inputs)) + + expected = """\ +[tool.poetry] +name = "my-package" +version = "1.2.3" +description = "This is a description" +authors = ["Your Name "] +license = "MIT" +readme = "README.md" +packages = [{include = "my_package"}] + +[tool.poetry.dependencies] +python = "^3.8" +pendulum = "^2.0.0" + +[tool.poetry.group.dev.dependencies] +pytest = "3.6.0" +""" + + assert expected in tester.io.fetch_output() + + def test_python_option(tester: CommandTester): inputs = [ "my-package", # Package name @@ -906,3 +957,29 @@ def test_init_existing_pyproject_with_build_system_fails( == "A pyproject.toml file with a defined build-system already exists." ) assert existing_section in pyproject_file.read_text() + + +@pytest.mark.parametrize( + "name", + [ + None, + "", + "foo", + " foo ", + "foo==2.0", + "foo@2.0", + " foo@2.0 ", + "foo 2.0", + " foo 2.0 ", + ], +) +def test__validate_package_valid(name: str | None): + assert InitCommand._validate_package(name) == name + + +@pytest.mark.parametrize( + "name", ["foo bar 2.0", " foo bar 2.0 ", "foo bar foobar 2.0"] +) +def test__validate_package_invalid(name: str): + with pytest.raises(ValueError): + assert InitCommand._validate_package(name) From cfc126583cef52165b6132ee0f67816ac25a2f7f Mon Sep 17 00:00:00 2001 From: Mathieu Kniewallner Date: Mon, 13 Jun 2022 01:06:44 +0200 Subject: [PATCH 6/6] feat(init): reword package add prompt --- src/poetry/console/commands/init.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/poetry/console/commands/init.py b/src/poetry/console/commands/init.py index 8c9a6896526..5501624c22f 100644 --- a/src/poetry/console/commands/init.py +++ b/src/poetry/console/commands/init.py @@ -168,7 +168,7 @@ def handle(self) -> int: question = "Would you like to define your main dependencies interactively?" help_message = """\ You can specify a package in the following forms: - - A single name (requests) + - A single name (requests): this will search for matches on PyPI - A name and a constraint (requests@^2.23.0) - A git url (git+https://github.com/python-poetry/poetry.git) - A git url with a revision\ @@ -266,7 +266,7 @@ def _determine_requirements( result = [] question = self.create_question( - "Search for package to add (or leave blank to continue):" + "Package to add or search for (leave blank to skip):" ) question.set_validator(self._validate_package)