Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce non-package-mode #8650

Merged
merged 3 commits into from
Feb 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions docs/basic-usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,29 @@ cd pre-existing-project
poetry init
```

### Operating modes

Poetry can be operated in two different modes. The default mode is the **package mode**, which is the right mode
if you want to package your project into an sdist or a wheel and perhaps publish it to a package index.
In this mode, some metadata such as `name` and `version`, which are required for packaging, are mandatory.
Further, the project itself will be installed in editable mode when running `poetry install`.

If you want to use Poetry only for dependency management but not for packaging, you can use the **non-package mode**:

```toml
[tool.poetry]
package-mode = false
```

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will the setting work in poetry.toml as well? If so, I would add an example for that as well.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think so. Actually, I don't think it would be a good idea to put it in poetry.toml because it's clearly a project setting and not a user setting. (It's not like user A wants to have this setting for project X while user B does not want this setting for project X.)

Copy link

@silverwind silverwind Feb 5, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I meant poetry.toml inside a project directory, which is meant to hold project-specific poetry configuration as per docs:

Your local configuration of Poetry application is stored in the poetry.toml file, which is separate from pyproject.toml.

In any case, both variants are fine to me, and I guess this setting will only work in the tool.poetry section then. It even seems that tool.poetry is kind of a mislabeled thing because it does not configure poetry.


In this mode, metadata such as `name` and `version` are optional.
Therefore, it is not possible to build a distribution or publish the project to a package index.
Further, when running `poetry install`, Poetry does not try to install the project itself,
but only its dependencies (same as `poetry install --no-root`).

{{% note %}}
In the [pyproject section]({{< relref "pyproject" >}}) you can see which fields are required in package mode.
{{% /note %}}

### Specifying dependencies

If you want to add dependencies to your project, you can specify them in the `tool.poetry.dependencies` section.
Expand Down
18 changes: 14 additions & 4 deletions docs/pyproject.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,19 @@ menu:

The `tool.poetry` section of the `pyproject.toml` file is composed of multiple sections.

## package-mode

Whether Poetry operates in package mode (default) or not. **Optional**

See [basic usage]({{< relref "basic-usage#operating-modes" >}}) for more information.

```toml
package-mode = false
```

## name

The name of the package. **Required**
The name of the package. **Required in package mode**

This should be a valid name as defined by [PEP 508](https://peps.python.org/pep-0508/#names).

Expand All @@ -26,7 +36,7 @@ name = "my-package"

## version

The version of the package. **Required**
The version of the package. **Required in package mode**

This should be a valid [PEP 440](https://peps.python.org/pep-0440/) string.

Expand All @@ -43,7 +53,7 @@ If you would like to use semantic versioning for your project, please see

## description

A short description of the package. **Required**
A short description of the package. **Required in package mode**

```toml
description = "A short description of the package."
Expand Down Expand Up @@ -81,7 +91,7 @@ If your project is proprietary and does not use a specific licence, you can set

## authors

The authors of the package. **Required**
The authors of the package. **Required in package mode**

This is a list of authors and should contain at least one author. Authors must be in the form `name <email>`.

Expand Down
4 changes: 4 additions & 0 deletions src/poetry/console/commands/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ def _build(
builder(self.poetry, executable=executable).build(target_dir)

def handle(self) -> int:
if not self.poetry.is_package_mode:
self.line_error("Building a package is not possible in non-package mode.")
return 1

with build_environment(poetry=self.poetry, env=self.env, io=self.io) as env:
fmt = self.option("format") or "all"
dist_dir = Path(self.option("output"))
Expand Down
13 changes: 10 additions & 3 deletions src/poetry/console/commands/install.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,9 @@ class InstallCommand(InstallerCommand):
<info>--no-root</info> option like below:

<info> poetry install --no-root</info>

If you want to use Poetry only for dependency management but not for packaging,
you can set the "package-mode" to false in your pyproject.toml file.
"""

_loggers = ["poetry.repositories.pypi_repository", "poetry.inspection.info"]
Expand Down Expand Up @@ -152,7 +155,7 @@ def handle(self) -> int:
if return_code != 0:
return return_code

if self.option("no-root"):
if self.option("no-root") or not self.poetry.is_package_mode:
return 0

log_install = (
Expand Down Expand Up @@ -184,9 +187,13 @@ def handle(self) -> int:
# No need for an editable install in this case.
self.line("")
self.line_error(
f"The current project could not be installed: <error>{e}</error>\n"
f"Warning: The current project could not be installed: {e}\n"
"If you do not want to install the current project"
" use <c1>--no-root</c1>",
" use <c1>--no-root</c1>.\n"
"If you want to use Poetry only for dependency management"
" but not for packaging, you can set the operating mode to "
'"non-package" in your pyproject.toml file.\n'
"In a future version of Poetry this warning will become an error!",
style="warning",
)
return 0
Expand Down
4 changes: 4 additions & 0 deletions src/poetry/console/commands/publish.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ class PublishCommand(Command):
def handle(self) -> int:
from poetry.publishing.publisher import Publisher

if not self.poetry.is_package_mode:
self.line_error("Publishing a package is not possible in non-package mode.")
return 1

dist_dir = self.option("dist-dir")

publisher = Publisher(self.poetry, self.io, Path(dist_dir))
Expand Down
16 changes: 16 additions & 0 deletions tests/console/commands/test_build.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,22 @@ def test_build_creates_packages_in_dist_directory_if_no_output_is_specified(
assert all(archive.exists() for archive in build_artifacts)


def test_build_not_possible_in_non_package_mode(
fixture_dir: FixtureDirGetter,
command_tester_factory: CommandTesterFactory,
) -> None:
source_dir = fixture_dir("non_package_mode")

poetry = Factory().create_poetry(source_dir)
tester = command_tester_factory("build", poetry)

assert tester.execute() == 1
assert (
tester.io.fetch_error()
== "Building a package is not possible in non-package mode.\n"
)


def test_build_with_multiple_readme_files(
fixture_dir: FixtureDirGetter,
tmp_path: Path,
Expand Down
18 changes: 18 additions & 0 deletions tests/console/commands/test_check.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,24 @@ def test_check_private(
assert tester.io.fetch_output() == expected


def test_check_non_package_mode(
mocker: MockerFixture, tester: CommandTester, fixture_dir: FixtureDirGetter
) -> None:
mocker.patch(
"poetry.poetry.Poetry.file",
return_value=TOMLFile(fixture_dir("non_package_mode") / "pyproject.toml"),
new_callable=mocker.PropertyMock,
)

tester.execute()

expected = """\
All set!
"""

assert tester.io.fetch_output() == expected


@pytest.mark.parametrize(
("options", "expected", "expected_status"),
[
Expand Down
17 changes: 17 additions & 0 deletions tests/console/commands/test_install.py
Original file line number Diff line number Diff line change
Expand Up @@ -506,3 +506,20 @@ def test_install_missing_directory_dependency_with_no_directory(
else:
with pytest.raises(ValueError, match="does not exist"):
tester.execute(options)


def test_non_package_mode_does_not_try_to_install_root(
command_tester_factory: CommandTesterFactory,
project_factory: ProjectFactory,
) -> None:
content = """\
[tool.poetry]
package-mode = false
"""
poetry = project_factory(name="non-package-mode", pyproject_content=content)

tester = command_tester_factory("install", poetry=poetry)
tester.execute()

assert tester.status_code == 0
assert tester.io.fetch_error() == ""
16 changes: 16 additions & 0 deletions tests/console/commands/test_publish.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,22 @@
from tests.types import FixtureDirGetter


def test_publish_not_possible_in_non_package_mode(
fixture_dir: FixtureDirGetter,
command_tester_factory: CommandTesterFactory,
) -> None:
source_dir = fixture_dir("non_package_mode")

poetry = Factory().create_poetry(source_dir)
tester = command_tester_factory("publish", poetry)

assert tester.execute() == 1
assert (
tester.io.fetch_error()
== "Publishing a package is not possible in non-package mode.\n"
)


def test_publish_returns_non_zero_code_for_upload_errors(
app: PoetryTestApplication,
app_tester: ApplicationTester,
Expand Down
7 changes: 7 additions & 0 deletions tests/fixtures/non_package_mode/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[tool.poetry]
package-mode = false

[tool.poetry.dependencies]
python = "^3.8"
cleo = "^0.6"
pendulum = { git = "https://github.com/sdispater/pendulum.git", branch = "2.0" }
6 changes: 6 additions & 0 deletions tests/test_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,12 @@ def test_create_poetry_with_multi_constraints_dependency(
assert len(package.requires) == 2


def test_create_poetry_non_package_mode(fixture_dir: FixtureDirGetter) -> None:
poetry = Factory().create_poetry(fixture_dir("non_package_mode"))

assert not poetry.is_package_mode


def test_poetry_with_default_source_legacy(
fixture_dir: FixtureDirGetter, with_simple_keyring: None
) -> None:
Expand Down
Loading