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,