diff --git a/src/poetry/console/commands/init.py b/src/poetry/console/commands/init.py index 7412aab95fe..775699fdf25 100644 --- a/src/poetry/console/commands/init.py +++ b/src/poetry/console/commands/init.py @@ -40,7 +40,9 @@ class InitCommand(Command): options: ClassVar[list[Option]] = [ option("name", None, "Name of the package.", flag=False), option("description", None, "Description of the package.", flag=False), - option("author", None, "Author name of the package.", flag=False), + option( + "author", None, "Author name of the package.", flag=False, multiple=True + ), option("python", None, "Compatible Python versions.", flag=False), option( "dependency", @@ -148,21 +150,28 @@ def _init_pyproject( if not description and is_interactive: description = self.ask(self.create_question("Description []: ", default="")) - author = self.option("author") - if not author and vcs_config.get("user.name"): + authors = self.option("author") + if not authors and vcs_config.get("user.name"): author = vcs_config["user.name"] author_email = vcs_config.get("user.email") if author_email: author += f" <{author_email}>" + authors = [author] if is_interactive: + author_str = ", ".join(authors) question = self.create_question( - f"Author [{author}, n to skip]: ", default=author + f"Author [{author_str}, n to skip]: ", + default=author_str, ) - question.set_validator(lambda v: self._validate_author(v, author)) + question.set_validator(lambda v: self._validate_author(v, authors)) author = self.ask(question) + if author == author_str: # user entered nothing, dont change authors + author = "" + else: + authors = author - authors = [author] if author else [] + authors = authors if authors else [] license_name = self.option("license") if not license_name and is_interactive: @@ -237,7 +246,7 @@ def _init_pyproject( name, version, description=description, - author=authors[0] if authors else None, + author=authors if authors else None, readme_format=readme_format, license=license_name, python=python, diff --git a/src/poetry/layouts/layout.py b/src/poetry/layouts/layout.py index 18f72e903ea..05230f7783a 100644 --- a/src/poetry/layouts/layout.py +++ b/src/poetry/layouts/layout.py @@ -63,7 +63,7 @@ def __init__( version: str = "0.1.0", description: str = "", readme_format: str = "md", - author: str | None = None, + author: str | list[str] | None = None, license: str | None = None, python: str | None = None, dependencies: Mapping[str, str | Mapping[str, Any]] | None = None, @@ -85,9 +85,11 @@ def __init__( self._dev_dependencies = dev_dependencies or {} if not author: - author = "Your Name " - - self._author = author + self._authors = ["Your Name "] + elif isinstance(author, str): # check if only 1 author was added + self._authors = [author] + else: + self._authors = author @property def basedir(self) -> Path: @@ -143,15 +145,16 @@ def generate_project_content(self) -> TOMLDocument: project_content["name"] = self._project project_content["version"] = self._version project_content["description"] = self._description - m = AUTHOR_REGEX.match(self._author) - if m is None: - # This should not happen because author has been validated before. - raise ValueError(f"Invalid author: {self._author}") - else: - author = {"name": m.group("name")} - if email := m.group("email"): - author["email"] = email - project_content["authors"].append(author) + for author_string in self._authors: # Iterate through the list of authors + m = AUTHOR_REGEX.match(author_string) + if m is None: + # This should not happen because author has been validated before. + raise ValueError(f"Invalid author: {author_string}") + else: + author = {"name": m.group("name")} + if email := m.group("email"): + author["email"] = email + project_content["authors"].append(author) if self._license: project_content["license"]["text"] = self._license diff --git a/tests/console/commands/test_init.py b/tests/console/commands/test_init.py index 7412d75990e..9bdfaa5b145 100644 --- a/tests/console/commands/test_init.py +++ b/tests/console/commands/test_init.py @@ -894,6 +894,56 @@ def test_predefined_all_options(tester: CommandTester, repo: TestRepository) -> assert expected in output +def test_predefined_2_authors(tester: CommandTester, repo: TestRepository) -> None: + 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 ' " + "--author 'Author 2 ' " + "--python '>=3.8' " + "--license MIT " + "--dependency pendulum " + "--dev-dependency pytest", + inputs="\n".join(inputs), + ) + + expected = """\ +[project] +name = "my-package" +version = "1.2.3" +description = "This is a description" +authors = [ + {name = "Foo Bar",email = "foo@example.com"}, + {name = "Author 2",email = "bar@example.com"} +] +license = {text = "MIT"} +readme = "README.md" +requires-python = ">=3.8" +dependencies = [ + "pendulum (>=2.0.0,<3.0.0)" +] + +[tool.poetry] + +[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) -> None: command = tester.command assert isinstance(command, InitCommand)