diff --git a/docs/cli.md b/docs/cli.md
index a4c682a757d..fe9969a428a 100644
--- a/docs/cli.md
+++ b/docs/cli.md
@@ -758,7 +758,7 @@ You cannot use the name `pypi` as it is reserved for use by the default PyPI sou
#### Options
-* `--default`: Set this source as the [default]({{< relref "repositories#disabling-the-pypi-repository" >}}) (disable PyPI).
+* `--default`: Set this source as the default (**Deprecated**, use TODO to disable PyPI).
* `--secondary`: Set this source as a [secondary]({{< relref "repositories#install-dependencies-from-a-private-repository" >}}) source.
{{% note %}}
diff --git a/docs/repositories.md b/docs/repositories.md
index 8d52a10994f..722060e7a23 100644
--- a/docs/repositories.md
+++ b/docs/repositories.md
@@ -120,7 +120,6 @@ This will generate the following configuration snippet in your
[[tool.poetry.source]]
name = "foo"
url = "https://foo.bar/simple/"
-default = false
secondary = false
```
@@ -129,7 +128,8 @@ Any package source not marked as `secondary` will take precedence over [PyPI](ht
{{% note %}}
-If you prefer to disable [PyPI](https://pypi.org) completely, you may choose to set one of your package sources to be the [default](#default-package-source).
+If you prefer to disable [PyPI](https://pypi.org) completely, TODO new command.
+If you disable PyPI, you have to configure at least one other source.
If you prefer to specify a package source for a specific dependency, see [Secondary Package Sources](#secondary-package-sources).
@@ -144,20 +144,24 @@ you must declare **all** package sources to be [secondary](#secondary-package-so
{{% /warning %}}
-#### Default Package Source
+#### Default Package Source PyPI
-By default, Poetry configures [PyPI](https://pypi.org) as the default package source for your
-project. You can alter this behaviour and exclusively look up packages only from the configured
-package sources by adding a **single** source with `default = true`.
+By default, Poetry configures [PyPI](https://pypi.org) as the default package source for
+your project. If you configure additional sources, these are preferred to PyPI unless
+they are configured as secondary. Nevertheless, packages are looked up on PyPI.
+
+You can alter this behaviour and exclusively look up packages only
+from the configured package sources by TODO new command.
+Adding a **single** source with `default = true` (**deprecated**) also disables PyPI.
```bash
-poetry source add --default foo https://foo.bar/simple/
+poetry source TODO
```
{{% warning %}}
-Configuring a custom package source as default, will effectively disable [PyPI](https://pypi.org)
-as a package source for your project.
+Configuring a custom package source as default (**deprecated**),
+will effectively disable [PyPI](https://pypi.org) as a package source for your project.
{{% /warning %}}
diff --git a/src/poetry/console/commands/source/add.py b/src/poetry/console/commands/source/add.py
index 2848ce8a3be..e910c006d7b 100644
--- a/src/poetry/console/commands/source/add.py
+++ b/src/poetry/console/commands/source/add.py
@@ -2,7 +2,6 @@
from cleo.helpers import argument
from cleo.helpers import option
-from cleo.io.null_io import NullIO
from tomlkit.items import AoT
from poetry.config.source import Source
@@ -88,7 +87,7 @@ def handle(self) -> int:
self.poetry._pool = RepositoryPool()
try:
Factory.configure_sources(
- self.poetry, sources, self.poetry.config, NullIO()
+ self.poetry, sources, self.poetry.config, self._io
)
self.poetry.pool.repository(name)
except ValueError as e:
diff --git a/src/poetry/factory.py b/src/poetry/factory.py
index c20f224272c..1d96e44b93a 100644
--- a/src/poetry/factory.py
+++ b/src/poetry/factory.py
@@ -96,6 +96,7 @@ def create_poetry(
config,
io,
disable_cache=disable_cache,
+ disable_pypi=poetry.local_config.get("disable-pypi", False),
)
plugin_manager = PluginManager(Plugin.group, disable_plugins=disable_plugins)
@@ -117,6 +118,8 @@ def configure_sources(
config: Config,
io: IO,
disable_cache: bool = False,
+ *,
+ disable_pypi: bool = False,
) -> None:
if disable_cache:
logger.debug("Disabling source caches")
@@ -135,13 +138,28 @@ def configure_sources(
message += " and setting it as secondary"
io.write_line(message)
+ if is_default:
+ # TODO: replace command
+ io.write_error_line(
+ ""
+ "The 'default' option is deprecated.\n"
+ " If you want to disable PyPI, TODO command\n"
+ " If you want to set a source as the first source to be searched"
+ " for packages, just make it the first source in your"
+ " pyproject.toml."
+ ""
+ )
poetry.pool.add_repository(repository, is_default, secondary=is_secondary)
# Put PyPI last to prefer private repositories
# unless we have no default source AND no primary sources
# (default = false, secondary = false)
- if poetry.pool.has_default():
+ if poetry.pool.has_default() or disable_pypi:
+ if not sources:
+ raise RuntimeError(
+ 'If no sources are configured, "disable-pypi" must not be set!'
+ )
if io.is_debug():
io.write_line("Deactivating the PyPI repository")
else:
diff --git a/src/poetry/json/schemas/poetry.json b/src/poetry/json/schemas/poetry.json
index 7532fd836b4..ab980d693bb 100644
--- a/src/poetry/json/schemas/poetry.json
+++ b/src/poetry/json/schemas/poetry.json
@@ -4,6 +4,10 @@
"type": "object",
"required": [],
"properties": {
+ "disable-pypi": {
+ "type": "boolean",
+ "description": "Whether PyPI is implicitly used to search for packages."
+ },
"source": {
"type": "array",
"description": "A set of additional repositories where packages can be found.",
diff --git a/src/poetry/utils/source.py b/src/poetry/utils/source.py
index dc8e1c8c92f..c3c843dd384 100644
--- a/src/poetry/utils/source.py
+++ b/src/poetry/utils/source.py
@@ -15,6 +15,9 @@ def source_to_table(source: Source) -> Table:
source_table: Table = table()
for key, value in source.to_dict().items():
+ if key == "default" and not value:
+ # default is deprecated, so we don't add it if it is not set
+ continue
source_table.add(key, value)
source_table.add(nl())
return source_table
diff --git a/tests/console/commands/source/test_add.py b/tests/console/commands/source/test_add.py
index 7e43b9e2014..4c9ca0dde0a 100644
--- a/tests/console/commands/source/test_add.py
+++ b/tests/console/commands/source/test_add.py
@@ -33,6 +33,9 @@ def assert_source_added(
== f"Adding source with name {source_added.name}."
)
poetry.pyproject.reload()
+ for source_table in poetry.pyproject.poetry_config["source"]:
+ # "default" is deprecated and should only be written if set to True
+ assert "default" not in source_table or source_table["default"] is True
sources = poetry.get_sources()
assert sources == [source_existing, source_added]
assert tester.status_code == 0
@@ -55,6 +58,7 @@ def test_source_add_default(
poetry_with_source: Poetry,
):
tester.execute(f"--default {source_default.name} {source_default.url}")
+ assert "deprecated" in tester.io.fetch_error()
assert_source_added(tester, poetry_with_source, source_existing, source_default)
@@ -95,6 +99,7 @@ def test_source_add_existing(
tester.io.fetch_output().strip()
== f"Source with name {source_existing.name} already exists. Updating."
)
+ assert "deprecated" in tester.io.fetch_error()
poetry_with_source.pyproject.reload()
sources = poetry_with_source.get_sources()
diff --git a/tests/fixtures/with_no_explicit_source_pypi_disabled/pyproject.toml b/tests/fixtures/with_no_explicit_source_pypi_disabled/pyproject.toml
new file mode 100644
index 00000000000..3d85a3fc5d3
--- /dev/null
+++ b/tests/fixtures/with_no_explicit_source_pypi_disabled/pyproject.toml
@@ -0,0 +1,15 @@
+[tool.poetry]
+name = "my-package"
+version = "1.2.3"
+description = "Some description."
+authors = [
+ "Your Name "
+]
+license = "MIT"
+disable-pypi = true
+
+# Requirements
+[tool.poetry.dependencies]
+python = "~2.7 || ^3.6"
+
+[tool.poetry.dev-dependencies]
diff --git a/tests/fixtures/with_non_default_source_pypi_disabled/pyproject.toml b/tests/fixtures/with_non_default_source_pypi_disabled/pyproject.toml
new file mode 100644
index 00000000000..e98b79fd484
--- /dev/null
+++ b/tests/fixtures/with_non_default_source_pypi_disabled/pyproject.toml
@@ -0,0 +1,19 @@
+[tool.poetry]
+name = "my-package"
+version = "1.2.3"
+description = "Some description."
+authors = [
+ "Your Name "
+]
+license = "MIT"
+disable-pypi = true
+
+# Requirements
+[tool.poetry.dependencies]
+python = "~2.7 || ^3.6"
+
+[tool.poetry.dev-dependencies]
+
+[[tool.poetry.source]]
+name = "foo"
+url = "https://foo.bar/simple/"
diff --git a/tests/test_factory.py b/tests/test_factory.py
index 7eafc85d210..098be5e3606 100644
--- a/tests/test_factory.py
+++ b/tests/test_factory.py
@@ -5,6 +5,7 @@
import pytest
+from cleo.io.buffered_io import BufferedIO
from deepdiff import DeepDiff
from packaging.utils import canonicalize_name
from poetry.core.constraints.version import parse_constraint
@@ -207,10 +208,25 @@ def test_create_poetry_with_multi_constraints_dependency():
def test_poetry_with_default_source(with_simple_keyring: None):
- poetry = Factory().create_poetry(fixtures_dir / "with_default_source")
+ io = BufferedIO()
+ poetry = Factory().create_poetry(fixtures_dir / "with_default_source", io=io)
assert len(poetry.pool.repositories) == 1
+ assert poetry.pool.has_default()
+
+ assert poetry.pool.repositories[0].name == "foo"
+ assert isinstance(poetry.pool.repositories[0], LegacyRepository)
+
+ assert "deprecated" in io.fetch_error()
+
+
+def test_poetry_with_two_default_sources(with_simple_keyring: None):
+ with pytest.raises(ValueError) as e:
+ Factory().create_poetry(fixtures_dir / "with_two_default_sources")
+
+ assert str(e.value) == "Only one repository can be the default."
+
def test_poetry_with_non_default_source(with_simple_keyring: None):
poetry = Factory().create_poetry(fixtures_dir / "with_non_default_source")
@@ -226,6 +242,19 @@ def test_poetry_with_non_default_source(with_simple_keyring: None):
assert isinstance(poetry.pool.repositories[1], PyPiRepository)
+def test_poetry_with_nondefault_source_pypi_disabled(with_simple_keyring: None):
+ poetry = Factory().create_poetry(
+ fixtures_dir / "with_non_default_source_pypi_disabled"
+ )
+
+ assert len(poetry.pool.repositories) == 1
+
+ assert not poetry.pool.has_default()
+
+ assert poetry.pool.repositories[0].name == "foo"
+ assert isinstance(poetry.pool.repositories[0], LegacyRepository)
+
+
def test_poetry_with_non_default_secondary_source(with_simple_keyring: None):
poetry = Factory().create_poetry(fixtures_dir / "with_non_default_secondary_source")
@@ -284,7 +313,7 @@ def test_poetry_with_non_default_multiple_sources(with_simple_keyring: None):
assert isinstance(repository, PyPiRepository)
-def test_poetry_with_no_default_source():
+def test_poetry_with_no_explicit_source():
poetry = Factory().create_poetry(fixtures_dir / "sample_project")
assert len(poetry.pool.repositories) == 1
@@ -295,11 +324,9 @@ def test_poetry_with_no_default_source():
assert isinstance(poetry.pool.repositories[0], PyPiRepository)
-def test_poetry_with_two_default_sources(with_simple_keyring: None):
- with pytest.raises(ValueError) as e:
- Factory().create_poetry(fixtures_dir / "with_two_default_sources")
-
- assert str(e.value) == "Only one repository can be the default."
+def test_poetry_with_no_explicit_source_pypi_disabled():
+ with pytest.raises(RuntimeError, match="no sources"):
+ Factory().create_poetry(fixtures_dir / "with_no_explicit_source_pypi_disabled")
def test_validate():