diff --git a/src/poetry/console/commands/init.py b/src/poetry/console/commands/init.py
index 1897829a4a4..5501624c22f 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"):
@@ -143,13 +140,9 @@ def handle(self) -> int:
else:
authors = [author]
- license = self.option("license") or ""
-
- question = self.create_question(
- f"License [{license}]: ", default=license
- )
- question.set_validator(self._validate_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:
@@ -175,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\
@@ -272,9 +265,12 @@ def _determine_requirements(
if not requires:
result = []
- package = self.ask(
- "Search for package to add (or leave blank to continue):"
+ question = self.create_question(
+ "Package to add or search for (leave blank to skip):"
)
+ question.set_validator(self._validate_package)
+
+ package = self.ask(question)
while package:
constraint = self._parse_requirements([package])[0]
if (
@@ -457,13 +453,12 @@ 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)
+ @staticmethod
+ def _validate_package(package: str | None) -> str | None:
+ if package and len(package.split()) > 2:
+ raise ValueError("Invalid package definition.")
- return license
+ return package
def _get_pool(self) -> Pool:
from poetry.repositories import Pool
diff --git a/tests/console/commands/test_init.py b/tests/console/commands/test_init.py
index c733bba2dfb..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
@@ -779,6 +830,51 @@ 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
+ "", # Author
+ "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]"])
@@ -861,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)