Commit c01f15a6 by Sébastien Eustace

Fix validation of the Poetry configuration

parent 93b5128c
from poetry.poetry import Poetry
from poetry.utils._compat import Path
from poetry.utils.toml_file import TomlFile
from .command import Command from .command import Command
...@@ -7,8 +11,10 @@ class CheckCommand(Command): ...@@ -7,8 +11,10 @@ class CheckCommand(Command):
description = "Checks the validity of the <comment>pyproject.toml</comment> file." description = "Checks the validity of the <comment>pyproject.toml</comment> file."
def handle(self): def handle(self):
# Load poetry and display errors, if any # Load poetry config and display errors, if any
check_result = self.poetry.check(self.poetry.local_config, strict=True) poetry_file = Poetry.locate(Path.cwd())
config = TomlFile(str(poetry_file)).read()["tool"]["poetry"]
check_result = Poetry.check(config, strict=True)
if not check_result["errors"] and not check_result["warnings"]: if not check_result["errors"] and not check_result["warnings"]:
self.info("All set!") self.info("All set!")
......
...@@ -404,6 +404,7 @@ ...@@ -404,6 +404,7 @@
"extra-script": { "extra-script": {
"type": "object", "type": "object",
"description": "A script that should be installed only if extras are activated.", "description": "A script that should be installed only if extras are activated.",
"additionalProperties": false,
"properties": { "properties": {
"callable": { "callable": {
"$ref": "#/definitions/script" "$ref": "#/definitions/script"
...@@ -419,6 +420,7 @@ ...@@ -419,6 +420,7 @@
}, },
"repository": { "repository": {
"type": "object", "type": "object",
"additionalProperties": false,
"properties": { "properties": {
"name": { "name": {
"type": "string", "type": "string",
......
...@@ -86,21 +86,7 @@ class Poetry: ...@@ -86,21 +86,7 @@ class Poetry:
@classmethod @classmethod
def create(cls, cwd): # type: (Path) -> Poetry def create(cls, cwd): # type: (Path) -> Poetry
candidates = [Path(cwd)] poetry_file = cls.locate(cwd)
candidates.extend(Path(cwd).parents)
for path in candidates:
poetry_file = path / "pyproject.toml"
if poetry_file.exists():
break
else:
raise RuntimeError(
"Poetry could not find a pyproject.toml file in {} or its parents".format(
cwd
)
)
local_config = TomlFile(poetry_file.as_posix()).read() local_config = TomlFile(poetry_file.as_posix()).read()
if "tool" not in local_config or "poetry" not in local_config["tool"]: if "tool" not in local_config or "poetry" not in local_config["tool"]:
...@@ -110,7 +96,13 @@ class Poetry: ...@@ -110,7 +96,13 @@ class Poetry:
local_config = local_config["tool"]["poetry"] local_config = local_config["tool"]["poetry"]
# Checking validity # Checking validity
cls.check(local_config) 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 # Load package
name = local_config["name"] name = local_config["name"]
...@@ -224,6 +216,24 @@ class Poetry: ...@@ -224,6 +216,24 @@ class Poetry:
return LegacyRepository(name, url, auth=auth) return LegacyRepository(name, url, auth=auth)
@classmethod @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]] def check(cls, config, strict=False): # type: (dict, bool) -> Dict[str, List[str]]
""" """
Checks the validity of a configuration Checks the validity of a configuration
......
...@@ -18,10 +18,15 @@ All set! ...@@ -18,10 +18,15 @@ All set!
assert expected == tester.io.fetch_output() assert expected == tester.io.fetch_output()
def test_check_invalid(app): def test_check_invalid(app, mocker):
app._poetry = Poetry.create( mocker.patch(
Path(__file__).parent.parent.parent / "fixtures" / "invalid_pyproject" "poetry.poetry.Poetry.locate",
return_value=Path(__file__).parent.parent.parent
/ "fixtures"
/ "invalid_pyproject"
/ "pyproject.toml",
) )
command = app.find("check") command = app.find("check")
tester = CommandTester(command) tester = CommandTester(command)
......
...@@ -169,3 +169,22 @@ def test_check_fails(): ...@@ -169,3 +169,22 @@ def test_check_fails():
) )
assert Poetry.check(content) == {"errors": [expected], "warnings": []} assert Poetry.check(content) == {"errors": [expected], "warnings": []}
def test_create_fails_on_invalid_configuration():
with pytest.raises(RuntimeError) as e:
Poetry.create(
Path(__file__).parent / "fixtures" / "invalid_pyproject" / "pyproject.toml"
)
if PY2:
expected = """\
The Poetry configuration is invalid:
- u'description' is a required property
"""
else:
expected = """\
The Poetry configuration is invalid:
- 'description' is a required property
"""
assert expected == str(e.value)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment