diff --git a/docs/pyproject.md b/docs/pyproject.md
index 5149515df8c..a344ffc0db5 100644
--- a/docs/pyproject.md
+++ b/docs/pyproject.md
@@ -395,6 +395,14 @@ You can install all extras with the `--all-extras` option:
poetry install --all-extras
```
+{{% note %}}
+Note that `install --extras` and the variations mentioned above (`--all-extras`, `--extras foo`, etc.) only work on dependencies defined in the current project. If you want to install extras defined by dependencies, you'll have to express that in the dependency itself:
+```toml
+[tool.poetry.group.dev.dependencies]
+fastapi = {version="^0.92.0", extras=["all"]}
+```
+{{% /note %}}
+
When installing or specifying Poetry-built packages, the extras defined in this section can be activated
as described in [PEP 508](https://www.python.org/dev/peps/pep-0508/#extras).
diff --git a/src/poetry/console/commands/init.py b/src/poetry/console/commands/init.py
index 0393351c1d5..fdf48832ce7 100644
--- a/src/poetry/console/commands/init.py
+++ b/src/poetry/console/commands/init.py
@@ -292,6 +292,11 @@ def _determine_requirements(
)
question.set_validator(self._validate_package)
+ follow_up_question = self.create_question(
+ "\nAdd a package (leave blank to skip):"
+ )
+ follow_up_question.set_validator(self._validate_package)
+
package = self.ask(question)
while package:
constraint = self._parse_requirements([package])[0]
@@ -303,7 +308,7 @@ def _determine_requirements(
):
self.line(f"Adding {package}")
result.append(constraint)
- package = self.ask("\nAdd a package (leave blank to skip):")
+ package = self.ask(follow_up_question)
continue
canonicalized_name = canonicalize_name(constraint["name"])
@@ -371,7 +376,7 @@ def _determine_requirements(
result.append(constraint)
if self.io.is_interactive():
- package = self.ask("\nAdd a package (leave blank to skip):")
+ package = self.ask(follow_up_question)
return result
diff --git a/src/poetry/installation/executor.py b/src/poetry/installation/executor.py
index 9f5601a2d30..e69a376ce1f 100644
--- a/src/poetry/installation/executor.py
+++ b/src/poetry/installation/executor.py
@@ -507,7 +507,7 @@ def _install(self, operation: Install | Update) -> int:
elif package.source_type == "file":
archive = self._prepare_archive(operation)
elif package.source_type == "directory":
- archive = self._prepare_directory_archive(operation)
+ archive = self._prepare_archive(operation)
cleanup_archive = True
elif package.source_type == "url":
assert package.source_url is not None
@@ -574,6 +574,8 @@ def _prepare_archive(self, operation: Install | Update) -> Path:
assert package.source_url is not None
archive = Path(package.source_url)
+ if package.source_subdirectory:
+ archive = archive / package.source_subdirectory
if not Path(package.source_url).is_absolute() and package.root_dir:
archive = package.root_dir / archive
@@ -581,27 +583,6 @@ def _prepare_archive(self, operation: Install | Update) -> Path:
return self._chef.prepare(archive, editable=package.develop)
- def _prepare_directory_archive(self, operation: Install | Update) -> Path:
- package = operation.package
- operation_message = self.get_operation_message(operation)
-
- message = (
- f" •> {operation_message}:"
- " Building..."
- )
- self._write(operation, message)
-
- assert package.source_url is not None
- if package.root_dir:
- req = package.root_dir / package.source_url
- else:
- req = Path(package.source_url).resolve(strict=False)
-
- if package.source_subdirectory:
- req /= package.source_subdirectory
-
- return self._prepare_archive(operation)
-
def _prepare_git_archive(self, operation: Install | Update) -> Path:
from poetry.vcs.git import Git
@@ -624,7 +605,7 @@ def _prepare_git_archive(self, operation: Install | Update) -> Path:
original_url = package.source_url
package._source_url = str(source.path)
- archive = self._prepare_directory_archive(operation)
+ archive = self._prepare_archive(operation)
package._source_url = original_url
diff --git a/src/poetry/utils/dependency_specification.py b/src/poetry/utils/dependency_specification.py
index e80a2b97019..adcfd3d55ab 100644
--- a/src/poetry/utils/dependency_specification.py
+++ b/src/poetry/utils/dependency_specification.py
@@ -114,7 +114,7 @@ def _parse_dependency_specification_simple(
require: DependencySpec = {}
if " " in pair:
- name, version = pair.split(" ", 2)
+ name, version = pair.split(" ", 1)
extras_m = re.search(r"\[([\w\d,-_]+)\]$", name)
if extras_m:
extras = [e.strip() for e in extras_m.group(1).split(",")]
diff --git a/tests/console/commands/test_init.py b/tests/console/commands/test_init.py
index c4d0171f43a..90b50b5f3cc 100644
--- a/tests/console/commands/test_init.py
+++ b/tests/console/commands/test_init.py
@@ -595,9 +595,6 @@ def test_interactive_with_file_dependency(
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
@@ -606,10 +603,8 @@ def test_interactive_with_wrong_dependency_inputs(
"MIT", # License
"^3.8", # Python
"", # Interactive packages
+ "foo 1.19.2",
"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
@@ -633,6 +628,7 @@ def test_interactive_with_wrong_dependency_inputs(
[tool.poetry.dependencies]
python = "^3.8"
+foo = "1.19.2"
pendulum = "^2.0.0"
[tool.poetry.group.dev.dependencies]
diff --git a/tests/installation/test_executor.py b/tests/installation/test_executor.py
index 50371ae7fcd..fe0ce46cb44 100644
--- a/tests/installation/test_executor.py
+++ b/tests/installation/test_executor.py
@@ -849,6 +849,37 @@ def test_executor_should_write_pep610_url_references_for_git(
)
+def test_executor_should_append_subdirectory_for_git(
+ mocker: MockerFixture,
+ tmp_venv: VirtualEnv,
+ pool: RepositoryPool,
+ config: Config,
+ io: BufferedIO,
+ mock_file_downloads: None,
+ wheel: Path,
+) -> None:
+ package = Package(
+ "demo",
+ "0.1.2",
+ source_type="git",
+ source_reference="master",
+ source_resolved_reference="123456",
+ source_url="https://github.com/demo/subdirectories.git",
+ source_subdirectory="two",
+ )
+
+ chef = Chef(config, tmp_venv, Factory.create_pool(config))
+ chef.set_directory_wheel(wheel)
+ spy = mocker.spy(chef, "prepare")
+
+ executor = Executor(tmp_venv, pool, config, io)
+ executor._chef = chef
+ executor.execute([Install(package)])
+
+ archive_arg = spy.call_args[0][0]
+ assert archive_arg == tmp_venv.path / "src/demo/subdirectories/two"
+
+
def test_executor_should_write_pep610_url_references_for_git_with_subdirectories(
tmp_venv: VirtualEnv,
pool: RepositoryPool,