Commit ddbcfcda by Arun Babu Neelicattu Committed by Bjorn Neergaard

schema: validate source objects in poetry

This change is intended to help migrate validation of sections in
pyproject.toml that are not relevant to poetry-core into poetry. This
allows for poetry frontend specific configuration to be introduced
without dependent changes in poetry-core.
parent 711cca93
...@@ -17,6 +17,7 @@ from poetry.core.toml.file import TOMLFile ...@@ -17,6 +17,7 @@ from poetry.core.toml.file import TOMLFile
from tomlkit.toml_document import TOMLDocument from tomlkit.toml_document import TOMLDocument
from poetry.config.config import Config from poetry.config.config import Config
from poetry.json import validate_object
from poetry.packages.locker import Locker from poetry.packages.locker import Locker
from poetry.plugins.plugin import Plugin from poetry.plugins.plugin import Plugin
from poetry.plugins.plugin_manager import PluginManager from poetry.plugins.plugin_manager import PluginManager
...@@ -300,3 +301,13 @@ class Factory(BaseFactory): ...@@ -300,3 +301,13 @@ class Factory(BaseFactory):
) )
return cast(TOMLDocument, pyproject) return cast(TOMLDocument, pyproject)
@classmethod
def validate(
cls, config: dict[str, Any], strict: bool = False
) -> dict[str, list[str]]:
results = super().validate(config, strict)
results["errors"].extend(validate_object(config))
return results
...@@ -3,10 +3,13 @@ from __future__ import annotations ...@@ -3,10 +3,13 @@ from __future__ import annotations
import json import json
import os import os
from pathlib import Path
from typing import Any from typing import Any
import jsonschema import jsonschema
from poetry.core.json import SCHEMA_DIR as CORE_SCHEMA_DIR
SCHEMA_DIR = os.path.join(os.path.dirname(__file__), "schemas") SCHEMA_DIR = os.path.join(os.path.dirname(__file__), "schemas")
...@@ -16,14 +19,9 @@ class ValidationError(ValueError): ...@@ -16,14 +19,9 @@ class ValidationError(ValueError):
pass pass
def validate_object(obj: dict[str, Any], schema_name: str) -> list[str]: def validate_object(obj: dict[str, Any]) -> list[str]:
schema_file = os.path.join(SCHEMA_DIR, f"{schema_name}.json") schema_file = Path(SCHEMA_DIR, "poetry.json")
schema = json.loads(schema_file.read_text(encoding="utf-8"))
if not os.path.exists(schema_file):
raise ValueError(f"Schema {schema_name} does not exist.")
with open(schema_file, encoding="utf-8") as f:
schema = json.loads(f.read())
validator = jsonschema.Draft7Validator(schema) validator = jsonschema.Draft7Validator(schema)
validation_errors = sorted( validation_errors = sorted(
...@@ -41,4 +39,17 @@ def validate_object(obj: dict[str, Any], schema_name: str) -> list[str]: ...@@ -41,4 +39,17 @@ def validate_object(obj: dict[str, Any], schema_name: str) -> list[str]:
errors.append(message) errors.append(message)
core_schema = json.loads(
Path(CORE_SCHEMA_DIR, "poetry-schema.json").read_text(encoding="utf-8")
)
if core_schema["additionalProperties"]:
# TODO: make this un-conditional once core update to >1.1.0b2
properties = {*schema["properties"].keys(), *core_schema["properties"].keys()}
additional_properties = set(obj.keys()) - properties
for key in additional_properties:
errors.append(
f"Additional properties are not allowed ('{key}' was unexpected)"
)
return errors return errors
{
"$schema": "http://json-schema.org/draft-04/schema#",
"additionalProperties": true,
"type": "object",
"required": [],
"properties": {
"source": {
"type": "array",
"description": "A set of additional repositories where packages can be found.",
"additionalProperties": {
"$ref": "#/definitions/repository"
},
"items": {
"$ref": "#/definitions/repository"
}
}
},
"definitions": {
"repository": {
"type": "object",
"additionalProperties": false,
"required": [
"name",
"url"
],
"properties": {
"name": {
"type": "string",
"description": "The name of the repository"
},
"url": {
"type": "string",
"description": "The url of the repository",
"format": "uri"
},
"default": {
"type": "boolean",
"description": "Make this repository the default (disable PyPI)"
},
"secondary": {
"type": "boolean",
"description": "Declare this repository as secondary, i.e. it will only be looked up last for packages."
},
"links": {
"type": "boolean",
"description": "Declare this as a link source. Links at uri/path can point to sdist or bdist archives."
},
"indexed": {
"type": "boolean",
"description": "For PEP 503 simple API repositories, pre-fetch and index the available packages. (experimental)"
}
}
}
}
}
[tool.poetry]
name = "foobar"
version = "0.1.0"
description = ""
[tool.poetry.dependencies]
python = "^3.10"
[[tool.poetry.source]]
name = "pypi-simple"
default = false
secondary = false
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
[tool.poetry]
name = "foobar"
version = "0.1.0"
description = ""
[tool.poetry.dependencies]
python = "^3.10"
[[tool.poetry.source]]
name = "pypi-simple"
url = "https://pypi.org/simple/"
default = false
secondary = false
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
from __future__ import annotations
from pathlib import Path
from poetry.core.toml import TOMLFile
from poetry.factory import Factory
FIXTURE_DIR = Path(__file__).parent / "fixtures" / "source"
def test_pyproject_toml_valid() -> None:
toml = TOMLFile(FIXTURE_DIR / "complete_valid.toml").read()
content = toml["tool"]["poetry"]
assert Factory.validate(content) == {"errors": [], "warnings": []}
def test_pyproject_toml_invalid() -> None:
toml = TOMLFile(FIXTURE_DIR / "complete_invalid.toml").read()
content = toml["tool"]["poetry"]
assert Factory.validate(content) == {
"errors": ["[source.0] 'url' is a required property"],
"warnings": [],
}
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