diff --git a/poetry/config/config.py b/poetry/config/config.py
index 54c73b0e170..583f906abd6 100644
--- a/poetry/config/config.py
+++ b/poetry/config/config.py
@@ -11,13 +11,16 @@
from poetry.utils._compat import Path
from poetry.utils._compat import basestring
+from .config_source import ConfigSource
+from .dict_config_source import DictConfigSource
+
_NOT_SET = object()
boolean_validator = lambda val: val in {"true", "false", "1", "0"}
boolean_normalizer = lambda val: val in ["true", "1"]
-class Config:
+class Config(object):
default_config = {
"cache-dir": str(CACHE_DIR),
@@ -34,6 +37,8 @@ def __init__(
self._config = deepcopy(self.default_config)
self._use_environment = use_environment
self._base_dir = base_dir
+ self._config_source = DictConfigSource()
+ self._auth_config_source = DictConfigSource()
@property
def name(self):
@@ -43,6 +48,24 @@ def name(self):
def config(self):
return self._config
+ @property
+ def config_source(self): # type: () -> ConfigSource
+ return self._config_source
+
+ @property
+ def auth_config_source(self): # type: () -> ConfigSource
+ return self._auth_config_source
+
+ def set_config_source(self, config_source): # type: (ConfigSource) -> Config
+ self._config_source = config_source
+
+ return self
+
+ def set_auth_config_source(self, config_source): # type: (ConfigSource) -> Config
+ self._auth_config_source = config_source
+
+ return self
+
def merge(self, config): # type: (Dict[str, Any]) -> None
from poetry.utils.helpers import merge_dicts
diff --git a/poetry/config/config_source.py b/poetry/config/config_source.py
index d2c2f02d309..63a4ad6b628 100644
--- a/poetry/config/config_source.py
+++ b/poetry/config/config_source.py
@@ -1,80 +1,9 @@
-import io
-import os
-from contextlib import contextmanager
from typing import Any
-from tomlkit import document
-from tomlkit import table
-
-from poetry.utils.toml_file import TomlFile
-
-
-class ConfigSource:
- def __init__(self, file, auth_config=False): # type: (TomlFile, bool) -> None
- self._file = file
- self._auth_config = auth_config
-
- @property
- def name(self): # type: () -> str
- return str(self._file.path)
-
- @property
- def file(self): # type: () -> TomlFile
- return self._file
+class ConfigSource(object):
def add_property(self, key, value): # type: (str, Any) -> None
- with self.secure() as config:
- keys = key.split(".")
-
- for i, key in enumerate(keys):
- if key not in config and i < len(keys) - 1:
- config[key] = table()
-
- if i == len(keys) - 1:
- config[key] = value
- break
-
- config = config[key]
+ raise NotImplementedError()
def remove_property(self, key): # type: (str) -> None
- with self.secure() as config:
- keys = key.split(".")
-
- current_config = config
- for i, key in enumerate(keys):
- if key not in current_config:
- return
-
- if i == len(keys) - 1:
- del current_config[key]
-
- break
-
- current_config = current_config[key]
-
- @contextmanager
- def secure(self):
- if self.file.exists():
- initial_config = self.file.read()
- config = self.file.read()
- else:
- initial_config = document()
- config = document()
-
- new_file = not self.file.exists()
-
- yield config
-
- try:
- # Ensuring the file is only readable and writable
- # by the current user
- mode = 0o600
-
- if new_file:
- self.file.touch(mode=mode)
-
- self.file.write(config)
- except Exception:
- self.file.write(initial_config)
-
- raise
+ raise NotImplementedError()
diff --git a/poetry/config/dict_config_source.py b/poetry/config/dict_config_source.py
new file mode 100644
index 00000000000..aaa6ee3b9d1
--- /dev/null
+++ b/poetry/config/dict_config_source.py
@@ -0,0 +1,42 @@
+from typing import Any
+from typing import Dict
+
+from .config_source import ConfigSource
+
+
+class DictConfigSource(ConfigSource):
+ def __init__(self): # type: () -> None
+ self._config = {}
+
+ @property
+ def config(self): # type: () -> Dict[str, Any]
+ return self._config
+
+ def add_property(self, key, value): # type: (str, Any) -> None
+ keys = key.split(".")
+ config = self._config
+
+ for i, key in enumerate(keys):
+ if key not in config and i < len(keys) - 1:
+ config[key] = {}
+
+ if i == len(keys) - 1:
+ config[key] = value
+ break
+
+ config = config[key]
+
+ def remove_property(self, key): # type: (str) -> None
+ keys = key.split(".")
+
+ config = self._config
+ for i, key in enumerate(keys):
+ if key not in config:
+ return
+
+ if i == len(keys) - 1:
+ del config[key]
+
+ break
+
+ config = config[key]
diff --git a/poetry/config/file_config_source.py b/poetry/config/file_config_source.py
new file mode 100644
index 00000000000..dda85839cd9
--- /dev/null
+++ b/poetry/config/file_config_source.py
@@ -0,0 +1,80 @@
+from contextlib import contextmanager
+from typing import Any
+
+from tomlkit import document
+from tomlkit import table
+
+from poetry.utils.toml_file import TomlFile
+
+from .config_source import ConfigSource
+
+
+class FileConfigSource(ConfigSource):
+ def __init__(self, file, auth_config=False): # type: (TomlFile, bool) -> None
+ self._file = file
+ self._auth_config = auth_config
+
+ @property
+ def name(self): # type: () -> str
+ return str(self._file.path)
+
+ @property
+ def file(self): # type: () -> TomlFile
+ return self._file
+
+ def add_property(self, key, value): # type: (str, Any) -> None
+ with self.secure() as config:
+ keys = key.split(".")
+
+ for i, key in enumerate(keys):
+ if key not in config and i < len(keys) - 1:
+ config[key] = table()
+
+ if i == len(keys) - 1:
+ config[key] = value
+ break
+
+ config = config[key]
+
+ def remove_property(self, key): # type: (str) -> None
+ with self.secure() as config:
+ keys = key.split(".")
+
+ current_config = config
+ for i, key in enumerate(keys):
+ if key not in current_config:
+ return
+
+ if i == len(keys) - 1:
+ del current_config[key]
+
+ break
+
+ current_config = current_config[key]
+
+ @contextmanager
+ def secure(self):
+ if self.file.exists():
+ initial_config = self.file.read()
+ config = self.file.read()
+ else:
+ initial_config = document()
+ config = document()
+
+ new_file = not self.file.exists()
+
+ yield config
+
+ try:
+ # Ensuring the file is only readable and writable
+ # by the current user
+ mode = 0o600
+
+ if new_file:
+ self.file.touch(mode=mode)
+
+ self.file.write(config)
+ except Exception:
+ self.file.write(initial_config)
+
+ raise
diff --git a/poetry/console/application.py b/poetry/console/application.py
index aec9e26fee9..a67e459d500 100644
--- a/poetry/console/application.py
+++ b/poetry/console/application.py
@@ -47,12 +47,13 @@ def __init__(self):
@property
def poetry(self):
- from poetry.poetry import Poetry
+ from poetry.factory import Factory
+ from poetry.utils._compat import Path
if self._poetry is not None:
return self._poetry
- self._poetry = Poetry.create(os.getcwd())
+ self._poetry = Factory().create_poetry(Path.cwd())
return self._poetry
diff --git a/poetry/console/commands/check.py b/poetry/console/commands/check.py
index 9505b8e4521..872e14fc519 100644
--- a/poetry/console/commands/check.py
+++ b/poetry/console/commands/check.py
@@ -1,4 +1,4 @@
-from poetry.poetry import Poetry
+from poetry.factory import Factory
from poetry.utils._compat import Path
from poetry.utils.toml_file import TomlFile
@@ -12,9 +12,9 @@ class CheckCommand(Command):
def handle(self):
# Load poetry config and display errors, if any
- poetry_file = Poetry.locate(Path.cwd())
+ poetry_file = Factory.locate(Path.cwd())
config = TomlFile(str(poetry_file)).read()["tool"]["poetry"]
- check_result = Poetry.check(config, strict=True)
+ check_result = Factory.validate(config, strict=True)
if not check_result["errors"] and not check_result["warnings"]:
self.info("All set!")
diff --git a/poetry/console/commands/config.py b/poetry/console/commands/config.py
index f45645de832..797a69cb7aa 100644
--- a/poetry/console/commands/config.py
+++ b/poetry/console/commands/config.py
@@ -4,6 +4,7 @@
from cleo import argument
from cleo import option
+from poetry.factory import Factory
from poetry.utils.helpers import (
keyring_repository_password_del,
keyring_repository_password_set,
@@ -37,6 +38,8 @@ class ConfigCommand(Command):
poetry config --unset repo.foo"""
+ LIST_PROHIBITED_SETTINGS = {"http-basic", "pypi-token"}
+
@property
def unique_config_values(self):
from poetry.locations import CACHE_DIR
@@ -63,28 +66,24 @@ def unique_config_values(self):
return unique_config_values
def handle(self):
- from poetry.config.config import Config
- from poetry.config.config_source import ConfigSource
+ from poetry.config.file_config_source import FileConfigSource
from poetry.locations import CONFIG_DIR
from poetry.utils._compat import Path
from poetry.utils._compat import basestring
from poetry.utils.toml_file import TomlFile
- config = Config()
+ config = Factory.create_config(self.io)
config_file = TomlFile(Path(CONFIG_DIR) / "config.toml")
- config_source = ConfigSource(config_file)
- if config_source.file.exists():
- config.merge(config_source.file.read())
-
- auth_config_file = TomlFile(Path(CONFIG_DIR) / "auth.toml")
- auth_config_source = ConfigSource(auth_config_file, auth_config=True)
- local_config_file = TomlFile(self.poetry.file.parent / "poetry.toml")
- if local_config_file.exists():
- config.merge(local_config_file.read())
+ try:
+ local_config_file = TomlFile(self.poetry.file.parent / "poetry.toml")
+ if local_config_file.exists():
+ config.merge(local_config_file.read())
+ except RuntimeError:
+ local_config_file = TomlFile(Path.cwd() / "poetry.toml")
if self.option("local"):
- config_source = ConfigSource(local_config_file)
+ config.set_config_source(FileConfigSource(local_config_file))
if not config_file.exists():
config_file.path.parent.mkdir(parents=True, exist_ok=True)
@@ -139,10 +138,13 @@ def handle(self):
unique_config_values = self.unique_config_values
if setting_key in unique_config_values:
if self.option("unset"):
- return config_source.remove_property(setting_key)
+ return config.config_source.remove_property(setting_key)
return self._handle_single_value(
- config_source, setting_key, unique_config_values[setting_key], values
+ config.config_source,
+ setting_key,
+ unique_config_values[setting_key],
+ values,
)
# handle repositories
@@ -158,14 +160,16 @@ def handle(self):
"There is no {} repository defined".format(m.group(1))
)
- config_source.remove_property("repositories.{}".format(m.group(1)))
+ config.config_source.remove_property(
+ "repositories.{}".format(m.group(1))
+ )
return 0
if len(values) == 1:
url = values[0]
- config_source.add_property(
+ config.config_source.add_property(
"repositories.{}.url".format(m.group(1)), url
)
@@ -181,7 +185,7 @@ def handle(self):
if m:
if self.option("unset"):
keyring_repository_password_del(config, m.group(2))
- auth_config_source.remove_property(
+ config.auth_config_source.remove_property(
"{}.{}".format(m.group(1), m.group(2))
)
@@ -207,7 +211,7 @@ def handle(self):
except RuntimeError:
property_value.update(password=password)
- auth_config_source.add_property(
+ config.auth_config_source.add_property(
"{}.{}".format(m.group(1), m.group(2)), property_value
)
elif m.group(1) == "pypi-token":
@@ -218,7 +222,7 @@ def handle(self):
token = values[0]
- auth_config_source.add_property(
+ config.auth_config_source.add_property(
"{}.{}".format(m.group(1), m.group(2)), token
)
@@ -245,6 +249,9 @@ def _list_configuration(self, config, raw, k=""):
orig_k = k
for key, value in sorted(config.items()):
+ if k + key in self.LIST_PROHIBITED_SETTINGS:
+ continue
+
raw_val = raw.get(key)
if isinstance(value, dict):
diff --git a/poetry/factory.py b/poetry/factory.py
new file mode 100644
index 00000000000..faf4de860e9
--- /dev/null
+++ b/poetry/factory.py
@@ -0,0 +1,321 @@
+from __future__ import absolute_import
+from __future__ import unicode_literals
+
+import shutil
+
+from typing import Dict
+from typing import List
+from typing import Optional
+
+from clikit.api.io.io import IO
+
+from .config.config import Config
+from .config.file_config_source import FileConfigSource
+from .io.null_io import NullIO
+from .json import validate_object
+from .locations import CONFIG_DIR
+from .packages.dependency import Dependency
+from .packages.locker import Locker
+from .packages.project_package import ProjectPackage
+from .poetry import Poetry
+from .repositories.pypi_repository import PyPiRepository
+from .spdx import license_by_id
+from .utils._compat import Path
+from .utils.toml_file import TomlFile
+
+
+class Factory:
+ """
+ Factory class to create various elements needed by Poetry.
+ """
+
+ def create_poetry(
+ self, cwd=None, io=None
+ ): # type: (Optional[Path], Optional[IO]) -> Poetry
+ if io is None:
+ io = NullIO()
+
+ poetry_file = self.locate(cwd)
+
+ local_config = TomlFile(poetry_file.as_posix()).read()
+ if "tool" not in local_config or "poetry" not in local_config["tool"]:
+ raise RuntimeError(
+ "[tool.poetry] section not found in {}".format(poetry_file.name)
+ )
+ local_config = local_config["tool"]["poetry"]
+
+ # Checking validity
+ check_result = self.validate(local_config)
+ if check_result["errors"]:
+ message = ""
+ for error in check_result["errors"]:
+ message += " - {}\n".format(error)
+
+ raise RuntimeError("The Poetry configuration is invalid:\n" + message)
+
+ # Load package
+ name = local_config["name"]
+ version = local_config["version"]
+ package = ProjectPackage(name, version, version)
+ package.root_dir = poetry_file.parent
+
+ for author in local_config["authors"]:
+ package.authors.append(author)
+
+ for maintainer in local_config.get("maintainers", []):
+ package.maintainers.append(maintainer)
+
+ package.description = local_config.get("description", "")
+ package.homepage = local_config.get("homepage")
+ package.repository_url = local_config.get("repository")
+ package.documentation_url = local_config.get("documentation")
+ try:
+ license_ = license_by_id(local_config.get("license", ""))
+ except ValueError:
+ license_ = None
+
+ package.license = license_
+ package.keywords = local_config.get("keywords", [])
+ package.classifiers = local_config.get("classifiers", [])
+
+ if "readme" in local_config:
+ package.readme = Path(poetry_file.parent) / local_config["readme"]
+
+ if "platform" in local_config:
+ package.platform = local_config["platform"]
+
+ if "dependencies" in local_config:
+ for name, constraint in local_config["dependencies"].items():
+ if name.lower() == "python":
+ package.python_versions = constraint
+ continue
+
+ if isinstance(constraint, list):
+ for _constraint in constraint:
+ package.add_dependency(name, _constraint)
+
+ continue
+
+ package.add_dependency(name, constraint)
+
+ if "dev-dependencies" in local_config:
+ for name, constraint in local_config["dev-dependencies"].items():
+ if isinstance(constraint, list):
+ for _constraint in constraint:
+ package.add_dependency(name, _constraint, category="dev")
+
+ continue
+
+ package.add_dependency(name, constraint, category="dev")
+
+ extras = local_config.get("extras", {})
+ for extra_name, requirements in extras.items():
+ package.extras[extra_name] = []
+
+ # Checking for dependency
+ for req in requirements:
+ req = Dependency(req, "*")
+
+ for dep in package.requires:
+ if dep.name == req.name:
+ dep.in_extras.append(extra_name)
+ package.extras[extra_name].append(dep)
+
+ break
+
+ if "build" in local_config:
+ package.build = local_config["build"]
+
+ if "include" in local_config:
+ package.include = local_config["include"]
+
+ if "exclude" in local_config:
+ package.exclude = local_config["exclude"]
+
+ if "packages" in local_config:
+ package.packages = local_config["packages"]
+
+ # Custom urls
+ if "urls" in local_config:
+ package.custom_urls = local_config["urls"]
+
+ # Moving lock if necessary (pyproject.lock -> poetry.lock)
+ lock = poetry_file.parent / "poetry.lock"
+ if not lock.exists():
+ # Checking for pyproject.lock
+ old_lock = poetry_file.with_suffix(".lock")
+ if old_lock.exists():
+ shutil.move(str(old_lock), str(lock))
+
+ locker = Locker(poetry_file.parent / "poetry.lock", local_config)
+
+ # Loading global configuration
+ config = self.create_config(io)
+
+ # Loading local configuration
+ local_config_file = TomlFile(poetry_file.parent / "poetry.toml")
+ if local_config_file.exists():
+ if io.is_debug():
+ io.write_line(
+ "Loading configuration file {}".format(local_config_file.path)
+ )
+
+ config.merge(local_config_file.read())
+
+ poetry = Poetry(poetry_file, local_config, package, locker, config)
+
+ # Configuring sources
+ for source in local_config.get("source", []):
+ repository = self.create_legacy_repository(source, config)
+ is_default = source.get("default", False)
+ is_secondary = source.get("secondary", False)
+ if io.is_debug():
+ message = "Adding repository {} ({})".format(
+ repository.name, repository.url
+ )
+ if is_default:
+ message += " and setting it as the default one"
+ elif is_secondary:
+ message += " and setting it as secondary"
+
+ io.write_line(message)
+
+ poetry.pool.add_repository(repository, is_default, secondary=is_secondary)
+
+ # Always put PyPI last to prefer private repositories
+ # but only if we have no other default source
+ if not poetry.pool.has_default():
+ poetry.pool.add_repository(PyPiRepository(), True)
+ else:
+ if io.is_debug():
+ io.write_line("Deactivating the PyPI repository")
+
+ return poetry
+
+ @classmethod
+ def create_config(cls, io=None): # type: (Optional[IO]) -> Config
+ if io is None:
+ io = NullIO()
+
+ config = Config()
+ # Load global config
+ config_file = TomlFile(Path(CONFIG_DIR) / "config.toml")
+ if config_file.exists():
+ if io.is_debug():
+ io.write_line(
+ "Loading configuration file {}".format(
+ config_file.path
+ )
+ )
+
+ config.merge(config_file.read())
+
+ config.set_config_source(FileConfigSource(config_file))
+
+ # Load global auth config
+ auth_config_file = TomlFile(Path(CONFIG_DIR) / "auth.toml")
+ if auth_config_file.exists():
+ if io.is_debug():
+ io.write_line(
+ "Loading configuration file {}".format(
+ auth_config_file.path
+ )
+ )
+
+ config.merge(auth_config_file.read())
+
+ config.set_auth_config_source(FileConfigSource(auth_config_file))
+
+ return config
+
+ def create_legacy_repository(
+ self, source, auth_config
+ ): # type: (Dict[str, str], Config) -> LegacyRepository
+ from .repositories.auth import Auth
+ from .repositories.legacy_repository import LegacyRepository
+ from .utils.helpers import get_http_basic_auth
+
+ if "url" in source:
+ # PyPI-like repository
+ if "name" not in source:
+ raise RuntimeError("Missing [name] in source.")
+ else:
+ raise RuntimeError("Unsupported source specified")
+
+ name = source["name"]
+ url = source["url"]
+ credentials = get_http_basic_auth(auth_config, name)
+ if not credentials:
+ return LegacyRepository(name, url)
+
+ auth = Auth(url, credentials[0], credentials[1])
+
+ return LegacyRepository(name, url, auth=auth)
+
+ @classmethod
+ def validate(
+ cls, config, strict=False
+ ): # type: (dict, bool) -> Dict[str, List[str]]
+ """
+ Checks the validity of a configuration
+ """
+ result = {"errors": [], "warnings": []}
+ # Schema validation errors
+ validation_errors = validate_object(config, "poetry-schema")
+
+ result["errors"] += validation_errors
+
+ if strict:
+ # If strict, check the file more thoroughly
+
+ # Checking license
+ license = config.get("license")
+ if license:
+ try:
+ license_by_id(license)
+ except ValueError:
+ result["errors"].append("{} is not a valid license".format(license))
+
+ if "dependencies" in config:
+ python_versions = config["dependencies"]["python"]
+ if python_versions == "*":
+ result["warnings"].append(
+ "A wildcard Python dependency is ambiguous. "
+ "Consider specifying a more explicit one."
+ )
+
+ # Checking for scripts with extras
+ if "scripts" in config:
+ scripts = config["scripts"]
+ for name, script in scripts.items():
+ if not isinstance(script, dict):
+ continue
+
+ extras = script["extras"]
+ for extra in extras:
+ if extra not in config["extras"]:
+ result["errors"].append(
+ 'Script "{}" requires extra "{}" which is not defined.'.format(
+ name, extra
+ )
+ )
+
+ return result
+
+ @classmethod
+ def locate(cls, cwd): # type: (Path) -> Path
+ candidates = [Path(cwd)]
+ candidates.extend(Path(cwd).parents)
+
+ for path in candidates:
+ poetry_file = path / "pyproject.toml"
+
+ if poetry_file.exists():
+ return poetry_file
+
+ else:
+ raise RuntimeError(
+ "Poetry could not find a pyproject.toml file in {} or its parents".format(
+ cwd
+ )
+ )
diff --git a/poetry/masonry/api.py b/poetry/masonry/api.py
index ab6ef13c2d6..49b1a884514 100644
--- a/poetry/masonry/api.py
+++ b/poetry/masonry/api.py
@@ -6,7 +6,7 @@
from clikit.io import NullIO
-from poetry.poetry import Poetry
+from poetry.factory import Factory
from poetry.utils._compat import Path
from poetry.utils._compat import unicode
from poetry.utils.env import SystemEnv
@@ -21,7 +21,7 @@ def get_requires_for_build_wheel(config_settings=None):
"""
Returns a list of requirements for building, as strings
"""
- poetry = Poetry.create(".")
+ poetry = Factory().create_poetry(Path("."))
main, _ = SdistBuilder.convert_dependencies(poetry.package, poetry.package.requires)
@@ -33,7 +33,7 @@ def get_requires_for_build_wheel(config_settings=None):
def prepare_metadata_for_build_wheel(metadata_directory, config_settings=None):
- poetry = Poetry.create(".")
+ poetry = Factory().create_poetry(Path("."))
builder = WheelBuilder(poetry, SystemEnv(Path(sys.prefix)), NullIO())
dist_info = Path(metadata_directory, builder.dist_info)
@@ -54,7 +54,7 @@ def prepare_metadata_for_build_wheel(metadata_directory, config_settings=None):
def build_wheel(wheel_directory, config_settings=None, metadata_directory=None):
"""Builds a wheel, places it in wheel_directory"""
- poetry = Poetry.create(".")
+ poetry = Factory().create_poetry(Path("."))
return unicode(
WheelBuilder.make_in(
@@ -65,7 +65,7 @@ def build_wheel(wheel_directory, config_settings=None, metadata_directory=None):
def build_sdist(sdist_directory, config_settings=None):
"""Builds an sdist, places it in sdist_directory"""
- poetry = Poetry.create(".")
+ poetry = Factory().create_poetry(Path("."))
path = SdistBuilder(poetry, SystemEnv(Path(sys.prefix)), NullIO()).build(
Path(sdist_directory)
diff --git a/poetry/masonry/builders/complete.py b/poetry/masonry/builders/complete.py
index d998d713d23..ec40014c42e 100644
--- a/poetry/masonry/builders/complete.py
+++ b/poetry/masonry/builders/complete.py
@@ -1,7 +1,7 @@
import os
import tarfile
-import poetry.poetry
+from poetry.factory import Factory
from poetry.io.null_io import NullIO
from poetry.utils._compat import Path
from poetry.utils.helpers import temporary_directory
@@ -43,7 +43,7 @@ def build(self):
with self.unpacked_tarball(sdist_file) as tmpdir:
WheelBuilder.make_in(
- poetry.poetry.Poetry.create(tmpdir),
+ Factory().create_poetry(tmpdir),
self._env,
self._io,
dist_dir,
@@ -52,7 +52,7 @@ def build(self):
else:
with self.unpacked_tarball(sdist_file) as tmpdir:
WheelBuilder.make_in(
- poetry.poetry.Poetry.create(tmpdir),
+ Factory().create_poetry(tmpdir),
self._env,
self._io,
dist_dir,
@@ -70,4 +70,4 @@ def unpacked_tarball(cls, path):
assert len(files) == 1, files
- yield os.path.join(tmpdir, files[0])
+ yield Path(tmpdir) / files[0]
diff --git a/poetry/poetry.py b/poetry/poetry.py
index 3c53244830b..4b28a5478ae 100644
--- a/poetry/poetry.py
+++ b/poetry/poetry.py
@@ -1,26 +1,14 @@
from __future__ import absolute_import
from __future__ import unicode_literals
-import shutil
-
-from typing import Dict
-from typing import List
+from typing import Optional
from .__version__ import __version__
from .config.config import Config
-from .json import validate_object
-from .locations import CONFIG_DIR
-from .packages import Dependency
from .packages import Locker
-from .packages import Package
from .packages import ProjectPackage
-from .repositories import Pool
-from .repositories.auth import Auth
-from .repositories.legacy_repository import LegacyRepository
-from .repositories.pypi_repository import PyPiRepository
-from .spdx import license_by_id
+from .repositories.pool import Pool
from .utils._compat import Path
-from .utils.helpers import get_http_basic_auth
from .utils.toml_file import TomlFile
@@ -32,7 +20,7 @@ def __init__(
self,
file, # type: Path
local_config, # type: dict
- package, # type: Package
+ package, # type: ProjectPackage
locker, # type: Locker
config, # type: Config
):
@@ -41,28 +29,14 @@ def __init__(
self._local_config = local_config
self._locker = locker
self._config = config
-
- # Configure sources
self._pool = Pool()
- for source in self._local_config.get("source", []):
- repository = self.create_legacy_repository(source)
- self._pool.add_repository(
- repository,
- source.get("default", False),
- secondary=source.get("secondary", False),
- )
-
- # Always put PyPI last to prefer private repositories
- # but only if we have no other default source
- if not self._pool.has_default():
- self._pool.add_repository(PyPiRepository(), True)
@property
def file(self):
return self._file
@property
- def package(self): # type: () -> Package
+ def package(self): # type: () -> ProjectPackage
return self._package
@property
@@ -81,221 +55,17 @@ def pool(self): # type: () -> Pool
def config(self): # type: () -> Config
return self._config
- @classmethod
- def create(cls, cwd): # type: (Path) -> Poetry
- poetry_file = cls.locate(cwd)
-
- local_config = TomlFile(poetry_file.as_posix()).read()
- if "tool" not in local_config or "poetry" not in local_config["tool"]:
- raise RuntimeError(
- "[tool.poetry] section not found in {}".format(poetry_file.name)
- )
- local_config = local_config["tool"]["poetry"]
-
- # Checking validity
- check_result = cls.check(local_config)
- if check_result["errors"]:
- message = ""
- for error in check_result["errors"]:
- message += " - {}\n".format(error)
-
- raise RuntimeError("The Poetry configuration is invalid:\n" + message)
-
- # Load package
- name = local_config["name"]
- version = local_config["version"]
- package = ProjectPackage(name, version, version)
- package.root_dir = poetry_file.parent
-
- for author in local_config["authors"]:
- package.authors.append(author)
-
- for maintainer in local_config.get("maintainers", []):
- package.maintainers.append(maintainer)
-
- package.description = local_config.get("description", "")
- package.homepage = local_config.get("homepage")
- package.repository_url = local_config.get("repository")
- package.documentation_url = local_config.get("documentation")
- try:
- license_ = license_by_id(local_config.get("license", ""))
- except ValueError:
- license_ = None
-
- package.license = license_
- package.keywords = local_config.get("keywords", [])
- package.classifiers = local_config.get("classifiers", [])
-
- if "readme" in local_config:
- package.readme = Path(poetry_file.parent) / local_config["readme"]
-
- if "platform" in local_config:
- package.platform = local_config["platform"]
-
- if "dependencies" in local_config:
- for name, constraint in local_config["dependencies"].items():
- if name.lower() == "python":
- package.python_versions = constraint
- continue
-
- if isinstance(constraint, list):
- for _constraint in constraint:
- package.add_dependency(name, _constraint)
-
- continue
-
- package.add_dependency(name, constraint)
-
- if "dev-dependencies" in local_config:
- for name, constraint in local_config["dev-dependencies"].items():
- if isinstance(constraint, list):
- for _constraint in constraint:
- package.add_dependency(name, _constraint, category="dev")
-
- continue
-
- package.add_dependency(name, constraint, category="dev")
-
- extras = local_config.get("extras", {})
- for extra_name, requirements in extras.items():
- package.extras[extra_name] = []
-
- # Checking for dependency
- for req in requirements:
- req = Dependency(req, "*")
-
- for dep in package.requires:
- if dep.name == req.name:
- dep.in_extras.append(extra_name)
- package.extras[extra_name].append(dep)
-
- break
-
- if "build" in local_config:
- package.build = local_config["build"]
-
- if "include" in local_config:
- package.include = local_config["include"]
-
- if "exclude" in local_config:
- package.exclude = local_config["exclude"]
-
- if "packages" in local_config:
- package.packages = local_config["packages"]
-
- # Custom urls
- if "urls" in local_config:
- package.custom_urls = local_config["urls"]
-
- # Moving lock if necessary (pyproject.lock -> poetry.lock)
- lock = poetry_file.parent / "poetry.lock"
- if not lock.exists():
- # Checking for pyproject.lock
- old_lock = poetry_file.with_suffix(".lock")
- if old_lock.exists():
- shutil.move(str(old_lock), str(lock))
-
- locker = Locker(poetry_file.parent / "poetry.lock", local_config)
-
- config = Config()
- # Load global config
- config_file = TomlFile(Path(CONFIG_DIR) / "config.toml")
- if config_file.exists():
- config.merge(config_file.read())
-
- local_config_file = TomlFile(poetry_file.parent / "poetry.toml")
- if local_config_file.exists():
- config.merge(local_config_file.read())
-
- # Load global auth config
- auth_config_file = TomlFile(Path(CONFIG_DIR) / "auth.toml")
- if auth_config_file.exists():
- config.merge(auth_config_file.read())
-
- return cls(poetry_file, local_config, package, locker, config)
-
- def create_legacy_repository(
- self, source
- ): # type: (Dict[str, str]) -> LegacyRepository
- if "url" in source:
- # PyPI-like repository
- if "name" not in source:
- raise RuntimeError("Missing [name] in source.")
- else:
- raise RuntimeError("Unsupported source specified")
-
- name = source["name"]
- url = source["url"]
- credentials = get_http_basic_auth(self._config, name)
- if not credentials:
- return LegacyRepository(name, url)
-
- auth = Auth(url, credentials[0], credentials[1])
-
- return LegacyRepository(name, url, auth=auth)
-
- @classmethod
- def locate(cls, cwd): # type: (Path) -> Poetry
- candidates = [Path(cwd)]
- candidates.extend(Path(cwd).parents)
-
- for path in candidates:
- poetry_file = path / "pyproject.toml"
-
- if poetry_file.exists():
- return poetry_file
-
- else:
- raise RuntimeError(
- "Poetry could not find a pyproject.toml file in {} or its parents".format(
- cwd
- )
- )
-
- @classmethod
- def check(cls, config, strict=False): # type: (dict, bool) -> Dict[str, List[str]]
- """
- Checks the validity of a configuration
- """
- result = {"errors": [], "warnings": []}
- # Schema validation errors
- validation_errors = validate_object(config, "poetry-schema")
-
- result["errors"] += validation_errors
-
- if strict:
- # If strict, check the file more thoroughly
+ def set_locker(self, locker): # type: (Locker) -> Poetry
+ self._locker = locker
- # Checking license
- license = config.get("license")
- if license:
- try:
- license_by_id(license)
- except ValueError:
- result["errors"].append("{} is not a valid license".format(license))
+ return self
- if "dependencies" in config:
- python_versions = config["dependencies"]["python"]
- if python_versions == "*":
- result["warnings"].append(
- "A wildcard Python dependency is ambiguous. "
- "Consider specifying a more explicit one."
- )
+ def set_pool(self, pool): # type: (Pool) -> Poetry
+ self._pool = pool
- # Checking for scripts with extras
- if "scripts" in config:
- scripts = config["scripts"]
- for name, script in scripts.items():
- if not isinstance(script, dict):
- continue
+ return self
- extras = script["extras"]
- for extra in extras:
- if extra not in config["extras"]:
- result["errors"].append(
- 'Script "{}" requires extra "{}" which is not defined.'.format(
- name, extra
- )
- )
+ def set_config(self, config): # type: (Config) -> Poetry
+ self._config = config
- return result
+ return self
diff --git a/poetry/puzzle/provider.py b/poetry/puzzle/provider.py
index 75c30195b96..3e4bc2d71e8 100644
--- a/poetry/puzzle/provider.py
+++ b/poetry/puzzle/provider.py
@@ -11,6 +11,7 @@
from typing import List
from typing import Optional
+from poetry.factory import Factory
from poetry.packages import Dependency
from poetry.packages import DependencyPackage
from poetry.packages import DirectoryDependency
@@ -300,9 +301,7 @@ def get_package_from_directory(
)
if supports_poetry:
- from poetry.poetry import Poetry
-
- poetry = Poetry.create(directory)
+ poetry = Factory().create_poetry(directory)
pkg = poetry.package
package = Package(pkg.name, pkg.version)
diff --git a/tests/config/test_config.py b/tests/config/test_config.py
index c1f6b81c029..8dda26eca37 100644
--- a/tests/config/test_config.py
+++ b/tests/config/test_config.py
@@ -8,7 +8,7 @@ def test_config_get_default_value(config):
def test_config_get_processes_depended_on_values(config):
- assert os.path.join(str(CACHE_DIR), "virtualenvs") == config.get("virtualenvs.path")
+ assert os.path.join("/foo", "virtualenvs") == config.get("virtualenvs.path")
def test_config_get_from_environment_variable(config, environ):
diff --git a/tests/conftest.py b/tests/conftest.py
index de7cf31ea31..a4f58b0acc8 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -10,43 +10,68 @@
except ImportError:
import urlparse
-from tomlkit import parse
+from typing import Any
+from typing import Dict
-from poetry.config.config import Config
+from poetry.config.config import Config as BaseConfig
+from poetry.config.dict_config_source import DictConfigSource
from poetry.utils._compat import PY2
from poetry.utils._compat import WINDOWS
from poetry.utils._compat import Path
-from poetry.utils.helpers import merge_dicts
-from poetry.utils.toml_file import TomlFile
+
+
+class Config(BaseConfig):
+ def get(self, setting_name, default=None): # type: (str, Any) -> Any
+ self.merge(self._config_source.config)
+ self.merge(self._auth_config_source.config)
+
+ return super(Config, self).get(setting_name, default=default)
+
+ def raw(self): # type: () -> Dict[str, Any]
+ self.merge(self._config_source.config)
+ self.merge(self._auth_config_source.config)
+
+ return super(Config, self).raw()
+
+ def all(self): # type: () -> Dict[str, Any]
+ self.merge(self._config_source.config)
+ self.merge(self._auth_config_source.config)
+
+ return super(Config, self).all()
+
+
+def tmp_dir():
+ dir_ = tempfile.mkdtemp(prefix="poetry_")
+
+ yield dir_
+
+ shutil.rmtree(dir_)
@pytest.fixture
-def config_document():
- content = """cache-dir = "/foo"
-"""
- doc = parse(content)
+def config_source():
+ source = DictConfigSource()
+ source.add_property("cache-dir", "/foo")
- return doc
+ return source
@pytest.fixture
-def config_source(config_document, mocker):
- file = TomlFile(Path(tempfile.mktemp()))
- mocker.patch.object(file, "exists", return_value=True)
- mocker.patch.object(file, "read", return_value=config_document)
- mocker.patch.object(
- file, "write", return_value=lambda new: merge_dicts(config_document, new)
- )
- mocker.patch(
- "poetry.config.config_source.ConfigSource.file",
- new_callable=mocker.PropertyMock,
- return_value=file,
- )
+def auth_config_source():
+ source = DictConfigSource()
+
+ return source
@pytest.fixture
-def config(config_source):
+def config(config_source, auth_config_source, mocker):
c = Config()
+ c.merge(config_source.config)
+ c.set_config_source(config_source)
+ c.set_auth_config_source(auth_config_source)
+
+ mocker.patch("poetry.factory.Factory.create_config", return_value=c)
+ mocker.patch("poetry.config.config.Config.set_config_source")
return c
diff --git a/tests/console/commands/test_check.py b/tests/console/commands/test_check.py
index 7a97d9c7e2b..bfc4ce9d0f2 100644
--- a/tests/console/commands/test_check.py
+++ b/tests/console/commands/test_check.py
@@ -2,7 +2,6 @@
from poetry.utils._compat import PY2
from poetry.utils._compat import Path
-from poetry.poetry import Poetry
def test_check_valid(app):
@@ -20,7 +19,7 @@ def test_check_valid(app):
def test_check_invalid(app, mocker):
mocker.patch(
- "poetry.poetry.Poetry.locate",
+ "poetry.factory.Factory.locate",
return_value=Path(__file__).parent.parent.parent
/ "fixtures"
/ "invalid_pyproject"
diff --git a/tests/console/commands/test_config.py b/tests/console/commands/test_config.py
index 94e4000c06a..b690b2a2f4d 100644
--- a/tests/console/commands/test_config.py
+++ b/tests/console/commands/test_config.py
@@ -4,13 +4,12 @@
from cleo.testers import CommandTester
from poetry.config.config_source import ConfigSource
-from poetry.poetry import Poetry
+from poetry.factory import Factory
-def test_list_displays_default_value_if_not_set(app, config_source):
+def test_list_displays_default_value_if_not_set(app, config):
command = app.find("config")
tester = CommandTester(command)
-
tester.execute("--list")
expected = """cache-dir = "/foo"
@@ -24,7 +23,7 @@ def test_list_displays_default_value_if_not_set(app, config_source):
assert expected == tester.io.fetch_output()
-def test_list_displays_set_get_setting(app, config_source, config_document):
+def test_list_displays_set_get_setting(app, config):
command = app.find("config")
tester = CommandTester(command)
@@ -40,10 +39,11 @@ def test_list_displays_set_get_setting(app, config_source, config_document):
path=json.dumps(os.path.join("{cache-dir}", "virtualenvs")), sep=os.path.sep
)
+ assert 0 == config.set_config_source.call_count
assert expected == tester.io.fetch_output()
-def test_display_single_setting(app, config_source):
+def test_display_single_setting(app, config):
command = app.find("config")
tester = CommandTester(command)
@@ -55,8 +55,8 @@ def test_display_single_setting(app, config_source):
assert expected == tester.io.fetch_output()
-def test_display_single_local_setting(app, config_source, fixture_dir):
- poetry = Poetry.create(fixture_dir("with_local_config"))
+def test_display_single_local_setting(app, config, fixture_dir):
+ poetry = Factory().create_poetry(fixture_dir("with_local_config"))
app._poetry = poetry
command = app.find("config")
@@ -70,10 +70,7 @@ def test_display_single_local_setting(app, config_source, fixture_dir):
assert expected == tester.io.fetch_output()
-def test_list_displays_set_get_local_setting(
- app, config_source, config_document, mocker
-):
- init = mocker.spy(ConfigSource, "__init__")
+def test_list_displays_set_get_local_setting(app, config):
command = app.find("config")
tester = CommandTester(command)
@@ -89,14 +86,11 @@ def test_list_displays_set_get_local_setting(
path=json.dumps(os.path.join("{cache-dir}", "virtualenvs")), sep=os.path.sep
)
- assert expected == tester.io.fetch_output()
-
- assert "poetry.toml" == init.call_args_list[2][0][1].path.name
+ assert 1 == config.set_config_source.call_count
assert expected == tester.io.fetch_output()
-def test_set_pypi_token(app, config_source, config_document, mocker):
- init = mocker.spy(ConfigSource, "__init__")
+def test_set_pypi_token(app, config, config_source, auth_config_source):
command = app.find("config")
tester = CommandTester(command)
@@ -104,4 +98,4 @@ def test_set_pypi_token(app, config_source, config_document, mocker):
tester.execute("--list")
- assert "mytoken" == config_document["pypi-token"]["pypi"]
+ assert "mytoken" == auth_config_source.config["pypi-token"]["pypi"]
diff --git a/tests/console/commands/test_export.py b/tests/console/commands/test_export.py
index 529acb9023f..45de47c6eb1 100644
--- a/tests/console/commands/test_export.py
+++ b/tests/console/commands/test_export.py
@@ -5,11 +5,13 @@
from cleo.testers import CommandTester
+from poetry.factory import Factory
+from poetry.repositories.pool import Pool
from tests.helpers import get_package
from ..conftest import Application
+from ..conftest import Locker
from ..conftest import Path
-from ..conftest import Poetry
PYPROJECT_CONTENT = """\
@@ -51,11 +53,15 @@ def poetry(repo, tmp_dir):
with (Path(tmp_dir) / "pyproject.toml").open("w", encoding="utf-8") as f:
f.write(PYPROJECT_CONTENT)
- p = Poetry.create(Path(tmp_dir))
+ p = Factory().create_poetry(Path(tmp_dir))
- p.pool.remove_repository("pypi")
- p.pool.add_repository(repo)
- p._locker.write()
+ locker = Locker(p.locker.lock.path, p.locker._local_config)
+ locker.write()
+ p.set_locker(locker)
+
+ pool = Pool()
+ pool.add_repository(repo)
+ p.set_pool(pool)
yield p
diff --git a/tests/console/conftest.py b/tests/console/conftest.py
index 85efd4bfea0..5f2a4d4923b 100644
--- a/tests/console/conftest.py
+++ b/tests/console/conftest.py
@@ -10,6 +10,7 @@
from cleo import ApplicationTester
from poetry.console import Application as BaseApplication
+from poetry.factory import Factory
from poetry.installation.noop_installer import NoopInstaller
from poetry.poetry import Poetry as BasePoetry
from poetry.packages import Locker as BaseLocker
@@ -112,8 +113,10 @@ def __init__(self, poetry):
def reset_poetry(self):
poetry = self._poetry
- self._poetry = Poetry.create(self._poetry.file.path.parent)
- self._poetry._pool = poetry.pool
+ self._poetry = Factory().create_poetry(self._poetry.file.path.parent)
+ self._poetry.set_pool(poetry.pool)
+ self._poetry.set_config(poetry.config)
+ self._poetry.set_locker(poetry.locker)
class Locker(BaseLocker):
@@ -189,14 +192,20 @@ def project_directory():
@pytest.fixture
-def poetry(repo, project_directory, config_source):
- p = Poetry.create(Path(__file__).parent.parent / "fixtures" / project_directory)
+def poetry(repo, project_directory, config):
+ p = Factory().create_poetry(
+ Path(__file__).parent.parent / "fixtures" / project_directory
+ )
+ p.set_locker(Locker(p.locker.lock.path, p.locker._local_config))
with p.file.path.open(encoding="utf-8") as f:
content = f.read()
- p.pool.remove_repository("pypi")
- p.pool.add_repository(repo)
+ p.set_config(config)
+
+ pool = Pool()
+ pool.add_repository(repo)
+ p.set_pool(pool)
yield p
diff --git a/tests/masonry/builders/test_builder.py b/tests/masonry/builders/test_builder.py
index 6b43e5280b8..b393022c3ab 100644
--- a/tests/masonry/builders/test_builder.py
+++ b/tests/masonry/builders/test_builder.py
@@ -2,8 +2,8 @@
from clikit.io import NullIO
from email.parser import Parser
+from poetry.factory import Factory
from poetry.masonry.builders.builder import Builder
-from poetry.poetry import Poetry
from poetry.utils._compat import Path
from poetry.utils.env import NullEnv
@@ -13,7 +13,7 @@ def test_builder_find_excluded_files(mocker):
p.return_value = []
builder = Builder(
- Poetry.create(Path(__file__).parent / "fixtures" / "complete"),
+ Factory().create_poetry(Path(__file__).parent / "fixtures" / "complete"),
NullEnv(),
NullIO(),
)
@@ -26,7 +26,9 @@ def test_builder_find_case_sensitive_excluded_files(mocker):
p.return_value = []
builder = Builder(
- Poetry.create(Path(__file__).parent / "fixtures" / "case_sensitive_exclusions"),
+ Factory().create_poetry(
+ Path(__file__).parent / "fixtures" / "case_sensitive_exclusions"
+ ),
NullEnv(),
NullIO(),
)
@@ -47,7 +49,7 @@ def test_builder_find_invalid_case_sensitive_excluded_files(mocker):
p.return_value = []
builder = Builder(
- Poetry.create(
+ Factory().create_poetry(
Path(__file__).parent / "fixtures" / "invalid_case_sensitive_exclusions"
),
NullEnv(),
@@ -59,7 +61,7 @@ def test_builder_find_invalid_case_sensitive_excluded_files(mocker):
def test_get_metadata_content():
builder = Builder(
- Poetry.create(Path(__file__).parent / "fixtures" / "complete"),
+ Factory().create_poetry(Path(__file__).parent / "fixtures" / "complete"),
NullEnv(),
NullIO(),
)
@@ -110,7 +112,7 @@ def test_get_metadata_content():
def test_metadata_homepage_default():
builder = Builder(
- Poetry.create(Path(__file__).parent / "fixtures" / "simple_version"),
+ Factory().create_poetry(Path(__file__).parent / "fixtures" / "simple_version"),
NullEnv(),
NullIO(),
)
@@ -122,7 +124,9 @@ def test_metadata_homepage_default():
def test_metadata_with_vcs_dependencies():
builder = Builder(
- Poetry.create(Path(__file__).parent / "fixtures" / "with_vcs_dependency"),
+ Factory().create_poetry(
+ Path(__file__).parent / "fixtures" / "with_vcs_dependency"
+ ),
NullEnv(),
NullIO(),
)
@@ -136,7 +140,9 @@ def test_metadata_with_vcs_dependencies():
def test_metadata_with_url_dependencies():
builder = Builder(
- Poetry.create(Path(__file__).parent / "fixtures" / "with_url_dependency"),
+ Factory().create_poetry(
+ Path(__file__).parent / "fixtures" / "with_url_dependency"
+ ),
NullEnv(),
NullIO(),
)
diff --git a/tests/masonry/builders/test_complete.py b/tests/masonry/builders/test_complete.py
index d12aec2add3..09771125b94 100644
--- a/tests/masonry/builders/test_complete.py
+++ b/tests/masonry/builders/test_complete.py
@@ -14,8 +14,8 @@
from clikit.io import NullIO
from poetry import __version__
+from poetry.factory import Factory
from poetry.masonry.builders import CompleteBuilder
-from poetry.poetry import Poetry
from poetry.utils._compat import Path
from poetry.utils._compat import decode
from poetry.utils.env import NullEnv
@@ -45,7 +45,7 @@ def clear_samples_dist():
def test_wheel_c_extension():
module_path = fixtures_dir / "extended"
builder = CompleteBuilder(
- Poetry.create(module_path), NullEnv(execute=True), NullIO()
+ Factory().create_poetry(module_path), NullEnv(execute=True), NullIO()
)
builder.build()
@@ -102,7 +102,7 @@ def test_wheel_c_extension():
def test_wheel_c_extension_src_layout():
module_path = fixtures_dir / "src_extended"
builder = CompleteBuilder(
- Poetry.create(module_path), NullEnv(execute=True), NullIO()
+ Factory().create_poetry(module_path), NullEnv(execute=True), NullIO()
)
builder.build()
@@ -155,7 +155,7 @@ def test_wheel_c_extension_src_layout():
def test_complete():
module_path = fixtures_dir / "complete"
builder = CompleteBuilder(
- Poetry.create(module_path), NullEnv(execute=True), NullIO()
+ Factory().create_poetry(module_path), NullEnv(execute=True), NullIO()
)
builder.build()
@@ -244,7 +244,7 @@ def test_complete_no_vcs():
shutil.copytree(module_path.as_posix(), temporary_dir.as_posix())
builder = CompleteBuilder(
- Poetry.create(temporary_dir), NullEnv(execute=True), NullIO()
+ Factory().create_poetry(temporary_dir), NullEnv(execute=True), NullIO()
)
builder.build()
@@ -341,7 +341,7 @@ def test_complete_no_vcs():
def test_module_src():
module_path = fixtures_dir / "source_file"
builder = CompleteBuilder(
- Poetry.create(module_path), NullEnv(execute=True), NullIO()
+ Factory().create_poetry(module_path), NullEnv(execute=True), NullIO()
)
builder.build()
@@ -367,7 +367,7 @@ def test_module_src():
def test_package_src():
module_path = fixtures_dir / "source_package"
builder = CompleteBuilder(
- Poetry.create(module_path), NullEnv(execute=True), NullIO()
+ Factory().create_poetry(module_path), NullEnv(execute=True), NullIO()
)
builder.build()
@@ -413,7 +413,7 @@ def test_package_with_include(mocker):
/ "vcs_excluded.txt"
),
]
- builder = CompleteBuilder(Poetry.create(module_path), NullEnv(), NullIO())
+ builder = CompleteBuilder(Factory().create_poetry(module_path), NullEnv(), NullIO())
builder.build()
sdist = fixtures_dir / "with-include" / "dist" / "with-include-1.2.3.tar.gz"
diff --git a/tests/masonry/builders/test_editable.py b/tests/masonry/builders/test_editable.py
index 7d35397ecfe..a909b3e2504 100644
--- a/tests/masonry/builders/test_editable.py
+++ b/tests/masonry/builders/test_editable.py
@@ -3,8 +3,8 @@
from clikit.io import NullIO
+from poetry.factory import Factory
from poetry.masonry.builders import EditableBuilder
-from poetry.poetry import Poetry
from poetry.utils._compat import Path
from poetry.utils.env import MockEnv
@@ -18,7 +18,7 @@ def test_build_should_delegate_to_pip_for_non_pure_python_packages(tmp_dir, mock
env.site_packages.mkdir(parents=True)
module_path = fixtures_dir / "extended"
- builder = EditableBuilder(Poetry.create(module_path), env, NullIO())
+ builder = EditableBuilder(Factory().create_poetry(module_path), env, NullIO())
builder.build()
expected = [["python", "-m", "pip", "install", "-e", str(module_path)]]
@@ -34,7 +34,7 @@ def test_build_should_temporarily_remove_the_pyproject_file(tmp_dir, mocker):
env.site_packages.mkdir(parents=True)
module_path = fixtures_dir / "extended"
- builder = EditableBuilder(Poetry.create(module_path), env, NullIO())
+ builder = EditableBuilder(Factory().create_poetry(module_path), env, NullIO())
builder.build()
expected = [["python", "-m", "pip", "install", "-e", str(module_path)]]
diff --git a/tests/masonry/builders/test_sdist.py b/tests/masonry/builders/test_sdist.py
index 4fcda1e4266..281016a3653 100644
--- a/tests/masonry/builders/test_sdist.py
+++ b/tests/masonry/builders/test_sdist.py
@@ -8,11 +8,11 @@
from clikit.io import NullIO
+from poetry.factory import Factory
from poetry.masonry.builders.sdist import SdistBuilder
from poetry.masonry.utils.package_include import PackageInclude
from poetry.packages import Package
from poetry.packages.vcs_dependency import VCSDependency
-from poetry.poetry import Poetry
from poetry.utils._compat import Path
from poetry.utils._compat import to_str
from poetry.utils.env import NullEnv
@@ -111,7 +111,7 @@ def test_convert_dependencies():
def test_make_setup():
- poetry = Poetry.create(project("complete"))
+ poetry = Factory().create_poetry(project("complete"))
builder = SdistBuilder(poetry, NullEnv(), NullIO())
setup = builder.build_setup()
@@ -144,7 +144,7 @@ def test_make_pkg_info(mocker):
get_metadata_content = mocker.patch(
"poetry.masonry.builders.builder.Builder.get_metadata_content"
)
- poetry = Poetry.create(project("complete"))
+ poetry = Factory().create_poetry(project("complete"))
builder = SdistBuilder(poetry, NullEnv(), NullIO())
builder.build_pkg_info()
@@ -153,7 +153,7 @@ def test_make_pkg_info(mocker):
def test_make_pkg_info_any_python():
- poetry = Poetry.create(project("module1"))
+ poetry = Factory().create_poetry(project("module1"))
builder = SdistBuilder(poetry, NullEnv(), NullIO())
pkg_info = builder.build_pkg_info()
@@ -164,7 +164,7 @@ def test_make_pkg_info_any_python():
def test_find_files_to_add():
- poetry = Poetry.create(project("complete"))
+ poetry = Factory().create_poetry(project("complete"))
builder = SdistBuilder(poetry, NullEnv(), NullIO())
result = builder.find_files_to_add()
@@ -184,7 +184,7 @@ def test_find_files_to_add():
def test_make_pkg_info_multi_constraints_dependency():
- poetry = Poetry.create(
+ poetry = Factory().create_poetry(
Path(__file__).parent.parent.parent
/ "fixtures"
/ "project_with_multi_constraints_dependency"
@@ -203,7 +203,7 @@ def test_make_pkg_info_multi_constraints_dependency():
def test_find_packages():
- poetry = Poetry.create(project("complete"))
+ poetry = Factory().create_poetry(project("complete"))
builder = SdistBuilder(poetry, NullEnv(), NullIO())
@@ -220,7 +220,7 @@ def test_find_packages():
"my_package.sub_pkg2": ["data2/*"],
}
- poetry = Poetry.create(project("source_package"))
+ poetry = Factory().create_poetry(project("source_package"))
builder = SdistBuilder(poetry, NullEnv(), NullIO())
@@ -235,7 +235,7 @@ def test_find_packages():
def test_package():
- poetry = Poetry.create(project("complete"))
+ poetry = Factory().create_poetry(project("complete"))
builder = SdistBuilder(poetry, NullEnv(), NullIO())
builder.build()
@@ -249,7 +249,7 @@ def test_package():
def test_module():
- poetry = Poetry.create(project("module1"))
+ poetry = Factory().create_poetry(project("module1"))
builder = SdistBuilder(poetry, NullEnv(), NullIO())
builder.build()
@@ -263,7 +263,7 @@ def test_module():
def test_prelease():
- poetry = Poetry.create(project("prerelease"))
+ poetry = Factory().create_poetry(project("prerelease"))
builder = SdistBuilder(poetry, NullEnv(), NullIO())
builder.build()
@@ -274,7 +274,7 @@ def test_prelease():
def test_with_c_extensions():
- poetry = Poetry.create(project("extended"))
+ poetry = Factory().create_poetry(project("extended"))
builder = SdistBuilder(poetry, NullEnv(), NullIO())
builder.build()
@@ -289,7 +289,7 @@ def test_with_c_extensions():
def test_with_c_extensions_src_layout():
- poetry = Poetry.create(project("src_extended"))
+ poetry = Factory().create_poetry(project("src_extended"))
builder = SdistBuilder(poetry, NullEnv(), NullIO())
builder.build()
@@ -304,7 +304,7 @@ def test_with_c_extensions_src_layout():
def test_with_src_module_file():
- poetry = Poetry.create(project("source_file"))
+ poetry = Factory().create_poetry(project("source_file"))
builder = SdistBuilder(poetry, NullEnv(), NullIO())
@@ -329,7 +329,7 @@ def test_with_src_module_file():
def test_with_src_module_dir():
- poetry = Poetry.create(project("source_package"))
+ poetry = Factory().create_poetry(project("source_package"))
builder = SdistBuilder(poetry, NullEnv(), NullIO())
@@ -372,7 +372,7 @@ def test_default_with_excluded_data(mocker):
.as_posix()
)
]
- poetry = Poetry.create(project("default_with_excluded_data"))
+ poetry = Factory().create_poetry(project("default_with_excluded_data"))
builder = SdistBuilder(poetry, NullEnv(), NullIO())
@@ -411,7 +411,7 @@ def test_default_with_excluded_data(mocker):
def test_proper_python_requires_if_two_digits_precision_version_specified():
- poetry = Poetry.create(project("simple_version"))
+ poetry = Factory().create_poetry(project("simple_version"))
builder = SdistBuilder(poetry, NullEnv(), NullIO())
pkg_info = builder.build_pkg_info()
@@ -422,7 +422,7 @@ def test_proper_python_requires_if_two_digits_precision_version_specified():
def test_proper_python_requires_if_three_digits_precision_version_specified():
- poetry = Poetry.create(project("single_python"))
+ poetry = Factory().create_poetry(project("single_python"))
builder = SdistBuilder(poetry, NullEnv(), NullIO())
pkg_info = builder.build_pkg_info()
diff --git a/tests/masonry/builders/test_wheel.py b/tests/masonry/builders/test_wheel.py
index 0f41c898102..6344a7f1435 100644
--- a/tests/masonry/builders/test_wheel.py
+++ b/tests/masonry/builders/test_wheel.py
@@ -5,8 +5,8 @@
from clikit.io import NullIO
+from poetry.factory import Factory
from poetry.masonry.builders import WheelBuilder
-from poetry.poetry import Poetry
from poetry.utils._compat import Path
from poetry.utils.env import NullEnv
@@ -31,7 +31,7 @@ def clear_samples_dist():
def test_wheel_module():
module_path = fixtures_dir / "module1"
- WheelBuilder.make(Poetry.create(str(module_path)), NullEnv(), NullIO())
+ WheelBuilder.make(Factory().create_poetry(module_path), NullEnv(), NullIO())
whl = module_path / "dist" / "module1-0.1-py2.py3-none-any.whl"
@@ -43,7 +43,7 @@ def test_wheel_module():
def test_wheel_package():
module_path = fixtures_dir / "complete"
- WheelBuilder.make(Poetry.create(str(module_path)), NullEnv(), NullIO())
+ WheelBuilder.make(Factory().create_poetry(module_path), NullEnv(), NullIO())
whl = module_path / "dist" / "my_package-1.2.3-py3-none-any.whl"
@@ -55,7 +55,7 @@ def test_wheel_package():
def test_wheel_prerelease():
module_path = fixtures_dir / "prerelease"
- WheelBuilder.make(Poetry.create(str(module_path)), NullEnv(), NullIO())
+ WheelBuilder.make(Factory().create_poetry(module_path), NullEnv(), NullIO())
whl = module_path / "dist" / "prerelease-0.1b1-py2.py3-none-any.whl"
@@ -64,7 +64,7 @@ def test_wheel_prerelease():
def test_wheel_localversionlabel():
module_path = fixtures_dir / "localversionlabel"
- WheelBuilder.make(Poetry.create(str(module_path)), NullEnv(), NullIO())
+ WheelBuilder.make(Factory().create_poetry(module_path), NullEnv(), NullIO())
local_version_string = "localversionlabel-0.1b1+gitbranch.buildno.1"
whl = module_path / "dist" / (local_version_string + "-py2.py3-none-any.whl")
@@ -76,7 +76,7 @@ def test_wheel_localversionlabel():
def test_wheel_package_src():
module_path = fixtures_dir / "source_package"
- WheelBuilder.make(Poetry.create(str(module_path)), NullEnv(), NullIO())
+ WheelBuilder.make(Factory().create_poetry(module_path), NullEnv(), NullIO())
whl = module_path / "dist" / "package_src-0.1-py2.py3-none-any.whl"
@@ -89,7 +89,7 @@ def test_wheel_package_src():
def test_wheel_module_src():
module_path = fixtures_dir / "source_file"
- WheelBuilder.make(Poetry.create(str(module_path)), NullEnv(), NullIO())
+ WheelBuilder.make(Factory().create_poetry(module_path), NullEnv(), NullIO())
whl = module_path / "dist" / "module_src-0.1-py2.py3-none-any.whl"
@@ -101,7 +101,7 @@ def test_wheel_module_src():
def test_dist_info_file_permissions():
module_path = fixtures_dir / "complete"
- WheelBuilder.make(Poetry.create(str(module_path)), NullEnv(), NullIO())
+ WheelBuilder.make(Factory().create_poetry(module_path), NullEnv(), NullIO())
whl = module_path / "dist" / "my_package-1.2.3-py3-none-any.whl"
diff --git a/tests/masonry/publishing/test_publisher.py b/tests/masonry/publishing/test_publisher.py
index 01399aeace3..e98e5e1312b 100644
--- a/tests/masonry/publishing/test_publisher.py
+++ b/tests/masonry/publishing/test_publisher.py
@@ -1,14 +1,14 @@
import pytest
+from poetry.factory import Factory
from poetry.io.null_io import NullIO
from poetry.masonry.publishing.publisher import Publisher
-from poetry.poetry import Poetry
def test_publish_publishes_to_pypi_by_default(fixture_dir, mocker, config):
uploader_auth = mocker.patch("poetry.masonry.publishing.uploader.Uploader.auth")
uploader_upload = mocker.patch("poetry.masonry.publishing.uploader.Uploader.upload")
- poetry = Poetry.create(fixture_dir("sample_project"))
+ poetry = Factory().create_poetry(fixture_dir("sample_project"))
poetry._config = config
poetry.config.merge(
{"http-basic": {"pypi": {"username": "foo", "password": "bar"}}}
@@ -24,7 +24,7 @@ def test_publish_publishes_to_pypi_by_default(fixture_dir, mocker, config):
def test_publish_can_publish_to_given_repository(fixture_dir, mocker, config):
uploader_auth = mocker.patch("poetry.masonry.publishing.uploader.Uploader.auth")
uploader_upload = mocker.patch("poetry.masonry.publishing.uploader.Uploader.upload")
- poetry = Poetry.create(fixture_dir("sample_project"))
+ poetry = Factory().create_poetry(fixture_dir("sample_project"))
poetry._config = config
poetry.config.merge(
{
@@ -41,7 +41,7 @@ def test_publish_can_publish_to_given_repository(fixture_dir, mocker, config):
def test_publish_raises_error_for_undefined_repository(fixture_dir, mocker, config):
- poetry = Poetry.create(fixture_dir("sample_project"))
+ poetry = Factory().create_poetry(fixture_dir("sample_project"))
poetry._config = config
poetry.config.merge(
{"http-basic": {"my-repo": {"username": "foo", "password": "bar"}}}
@@ -55,7 +55,7 @@ def test_publish_raises_error_for_undefined_repository(fixture_dir, mocker, conf
def test_publish_uses_token_if_it_exists(fixture_dir, mocker, config):
uploader_auth = mocker.patch("poetry.masonry.publishing.uploader.Uploader.auth")
uploader_upload = mocker.patch("poetry.masonry.publishing.uploader.Uploader.upload")
- poetry = Poetry.create(fixture_dir("sample_project"))
+ poetry = Factory().create_poetry(fixture_dir("sample_project"))
poetry._config = config
poetry.config.merge({"pypi-token": {"pypi": "my-token"}})
publisher = Publisher(poetry, NullIO())
diff --git a/tests/masonry/publishing/test_uploader.py b/tests/masonry/publishing/test_uploader.py
index 4c875e3c0ce..e9c5cc3c9f0 100644
--- a/tests/masonry/publishing/test_uploader.py
+++ b/tests/masonry/publishing/test_uploader.py
@@ -1,9 +1,9 @@
import pytest
+from poetry.factory import Factory
from poetry.io.null_io import NullIO
from poetry.masonry.publishing.uploader import UploadError
from poetry.masonry.publishing.uploader import Uploader
-from poetry.poetry import Poetry
from poetry.utils._compat import Path
@@ -16,7 +16,7 @@ def project(name):
def test_uploader_properly_handles_400_errors(http):
http.register_uri(http.POST, "https://foo.com", status=400, body="Bad request")
- uploader = Uploader(Poetry.create(project("simple_project")), NullIO())
+ uploader = Uploader(Factory().create_poetry(project("simple_project")), NullIO())
with pytest.raises(UploadError) as e:
uploader.upload("https://foo.com")
@@ -26,7 +26,7 @@ def test_uploader_properly_handles_400_errors(http):
def test_uploader_properly_handles_403_errors(http):
http.register_uri(http.POST, "https://foo.com", status=403, body="Unauthorized")
- uploader = Uploader(Poetry.create(project("simple_project")), NullIO())
+ uploader = Uploader(Factory().create_poetry(project("simple_project")), NullIO())
with pytest.raises(UploadError) as e:
uploader.upload("https://foo.com")
@@ -39,7 +39,7 @@ def test_uploader_registers_for_appropriate_400_errors(mocker, http):
http.register_uri(
http.POST, "https://foo.com", status=400, body="No package was ever registered"
)
- uploader = Uploader(Poetry.create(project("simple_project")), NullIO())
+ uploader = Uploader(Factory().create_poetry(project("simple_project")), NullIO())
with pytest.raises(UploadError):
uploader.upload("https://foo.com")
diff --git a/tests/test_poetry.py b/tests/test_factory.py
similarity index 83%
rename from tests/test_poetry.py
rename to tests/test_factory.py
index 1d1e298bc06..ae63054b08e 100644
--- a/tests/test_poetry.py
+++ b/tests/test_factory.py
@@ -4,7 +4,8 @@
import pytest
-from poetry.poetry import Poetry
+from poetry.io.null_io import NullIO
+from poetry.factory import Factory
from poetry.utils._compat import PY2
from poetry.utils._compat import Path
from poetry.utils.toml_file import TomlFile
@@ -13,8 +14,8 @@
fixtures_dir = Path(__file__).parent / "fixtures"
-def test_poetry():
- poetry = Poetry.create(str(fixtures_dir / "sample_project"))
+def test_create_poetry():
+ poetry = Factory().create_poetry(fixtures_dir / "sample_project")
package = poetry.package
@@ -111,9 +112,9 @@ def test_poetry():
]
-def test_poetry_with_packages_and_includes():
- poetry = Poetry.create(
- str(fixtures_dir.parent / "masonry" / "builders" / "fixtures" / "with-include")
+def test_create_poetry_with_packages_and_includes():
+ poetry = Factory().create_poetry(
+ fixtures_dir.parent / "masonry" / "builders" / "fixtures" / "with-include"
)
package = poetry.package
@@ -131,9 +132,9 @@ def test_poetry_with_packages_and_includes():
assert package.include == ["extra_dir/vcs_excluded.txt", "notes.txt"]
-def test_poetry_with_multi_constraints_dependency():
- poetry = Poetry.create(
- str(fixtures_dir / "project_with_multi_constraints_dependency")
+def test_create_poetry_with_multi_constraints_dependency():
+ poetry = Factory().create_poetry(
+ fixtures_dir / "project_with_multi_constraints_dependency"
)
package = poetry.package
@@ -142,26 +143,26 @@ def test_poetry_with_multi_constraints_dependency():
def test_poetry_with_default_source():
- poetry = Poetry.create(fixtures_dir / "with_default_source")
+ poetry = Factory().create_poetry(fixtures_dir / "with_default_source")
assert 1 == len(poetry.pool.repositories)
def test_poetry_with_two_default_sources():
with pytest.raises(ValueError) as e:
- Poetry.create(fixtures_dir / "with_two_default_sources")
+ Factory().create_poetry(fixtures_dir / "with_two_default_sources")
assert "Only one repository can be the default" == str(e.value)
-def test_check():
+def test_validate():
complete = TomlFile(fixtures_dir / "complete.toml")
content = complete.read()["tool"]["poetry"]
- assert Poetry.check(content) == {"errors": [], "warnings": []}
+ assert Factory.validate(content) == {"errors": [], "warnings": []}
-def test_check_fails():
+def test_validate_fails():
complete = TomlFile(fixtures_dir / "complete.toml")
content = complete.read()["tool"]["poetry"]
content["this key is not in the schema"] = ""
@@ -177,12 +178,12 @@ def test_check_fails():
"('this key is not in the schema' was unexpected)"
)
- assert Poetry.check(content) == {"errors": [expected], "warnings": []}
+ assert Factory.validate(content) == {"errors": [expected], "warnings": []}
-def test_create_fails_on_invalid_configuration():
+def test_create_poetry_fails_on_invalid_configuration():
with pytest.raises(RuntimeError) as e:
- Poetry.create(
+ Factory().create_poetry(
Path(__file__).parent / "fixtures" / "invalid_pyproject" / "pyproject.toml"
)
@@ -199,8 +200,8 @@ def test_create_fails_on_invalid_configuration():
assert expected == str(e.value)
-def test_poetry_with_local_config(fixture_dir):
- poetry = Poetry.create(fixture_dir("with_local_config"))
+def test_create_poetry_with_local_config(fixture_dir):
+ poetry = Factory().create_poetry(fixture_dir("with_local_config"))
assert not poetry.config.get("virtualenvs.in-project")
assert not poetry.config.get("virtualenvs.create")
diff --git a/tests/utils/test_exporter.py b/tests/utils/test_exporter.py
index 4c67820c346..ad5be296bf4 100644
--- a/tests/utils/test_exporter.py
+++ b/tests/utils/test_exporter.py
@@ -2,8 +2,8 @@
import pytest
+from poetry.factory import Factory
from poetry.packages import Locker as BaseLocker
-from poetry.poetry import Poetry
from poetry.repositories.auth import Auth
from poetry.repositories.legacy_repository import LegacyRepository
from poetry.utils._compat import Path
@@ -40,7 +40,7 @@ def locker():
@pytest.fixture
def poetry(fixture_dir, locker):
- p = Poetry.create(fixture_dir("sample_project"))
+ p = Factory().create_poetry(fixture_dir("sample_project"))
p._locker = locker
return p