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

Make setuptools schema definitions up-to-date. #112

Merged
merged 4 commits into from
Oct 11, 2023
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
11 changes: 6 additions & 5 deletions src/validate_pyproject/plugins/distutils.schema.json
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
{
"$schema": "http://json-schema.org/draft-07/schema",

"$id": "https://docs.python.org/3/install/",
"$id": "https://setuptools.pypa.io/en/latest/deprecated/distutils/configfile.html",
"title": "``tool.distutils`` table",
"$$description": [
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why is this $$description? As far as I can tell, such as with https://json-schema.org/understanding-json-schema/reference/annotations, this field is supposed to be description, and schema store's validator doesn't like $$description.

Copy link
Collaborator

@henryiii henryiii Oct 11, 2023

Choose a reason for hiding this comment

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

Ahh, this is a sphinx-jsonschema addition just to allow a list of strings instead of a string (at the expense of it not being standard)? https://pypi.org/project/sphinx-jsonschema/

Copy link
Owner Author

Choose a reason for hiding this comment

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

Yes that is the reason.

It is very difficult to write long strings in vanilla JSON schema. $$description helps with that. The files can still be used by tools that don't support $$description with the drawback that they don't show the long explanations we have in the files.

We could generate the schemas by using YAML, or other solutions, but the problem is to take in more dependencies.

Since I designed the project to be compatible with build backends, I try to keep the dependencies at bay...

Copy link
Collaborator

Choose a reason for hiding this comment

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

There's always pre-processing, where you write a something.yml and convert it to the json schema, but do that in the repo. I did this with cibuildwheel, https://github.com/pypa/cibuildwheel/blob/main/bin/generate_schema.py (and nox job). That avoids a runtime dependency, only a development dependency.

But that's fine, I have to process this anyway.

"**EXPERIMENTAL** (NOT OFFICIALLY SUPPORTED): Use ``tool.distutils``",
"subtables to configure arguments for ``distutils`` commands.",
"Originally, ``distutils`` allowed developers to configure arguments for",
"``setup.py`` scripts via `distutils configuration files",
"<https://docs.python.org/3/install/#distutils-configuration-files>`_.",
"``tool.distutils`` subtables could be used with the same purpose",
"(NOT CURRENTLY IMPLEMENTED)."
"``setup.py`` commands via `distutils configuration files",
"<https://setuptools.pypa.io/en/latest/deprecated/distutils/configfile.html>`_.",
"See also `the old Python docs <https://docs.python.org/3.11/install/>_`."
],

"type": "object",
Expand Down
82 changes: 58 additions & 24 deletions src/validate_pyproject/plugins/setuptools.schema.json
Original file line number Diff line number Diff line change
@@ -1,20 +1,19 @@
{
"$schema": "http://json-schema.org/draft-07/schema",

"$id": "https://setuptools.pypa.io/en/latest/references/keywords.html",
"$id": "https://setuptools.pypa.io/en/latest/userguide/pyproject_config.html",
"title": "``tool.setuptools`` table",
"$$description": [
"Please notice for the time being the ``setuptools`` project does not specify",
"a way of configuring builds via ``pyproject.toml``.",
"Therefore this schema should be taken just as a *\"thought experiment\"* on how",
"this *might be done*, by following the principles established in",
"`ini2toml <https://ini2toml.readthedocs.io/en/latest/setuptools_pep621.html>`_.",
"``setuptools``-specific configurations that can be set by users that require",
"customization.",
"These configurations are completely optional and probably can be skipped when",
"creating simple packages. They are equivalent to some of the `Keywords",
"<https://setuptools.pypa.io/en/latest/references/keywords.html>`_",
"used by the ``setup.py`` file, and can be set via the ``tool.setuptools`` table.",
"It considers only ``setuptools`` `parameters",
"<https://setuptools.pypa.io/en/latest/userguide/declarative_config.html>`_",
"that can currently be configured via ``setup.cfg`` and are not covered by :pep:`621`",
"but intentionally excludes ``dependency_links`` and ``setup_requires``.",
"NOTE: ``scripts`` was renamed to ``script-files`` to avoid confusion with",
"entry-point based scripts (defined in :pep:`621`)."
"<https://setuptools.pypa.io/en/latest/userguide/pyproject_config.html#setuptools-specific-configuration>`_",
"that are not covered by :pep:`621`; and intentionally excludes ``dependency_links``",
"and ``setup_requires`` (incompatible with modern workflows/standards)."
],

"type": "object",
Expand All @@ -41,20 +40,32 @@
"items": {"type": "string", "format": "pep508-identifier"}
},
"zip-safe": {
"description":
"$$description": [
"Whether the project can be safely installed and run from a zip file.",
"**OBSOLETE**: only relevant for ``pkg_resources``, ``easy_install`` and",
"``setup.py install`` in the context of ``eggs`` (**DEPRECATED**)."
],
"type": "boolean"
},
"script-files": {
"description": "Legacy way of defining scripts (entry-points are preferred).",
"$$description": [
"Legacy way of defining scripts (entry-points are preferred).",
"Equivalent to the ``script`` keyword in ``setup.py``",
"(it was renamed to avoid confusion with entry-point based ``project.scripts``",
"defined in :pep:`621`).",
"**DISCOURAGED**: generic script wrappers are tricky and may not work properly.",
"Whenever possible, please use ``project.scripts`` instead."
],
"type": "array",
"items": {"type": "string"},
"$comment": "TODO: is this field deprecated/should be removed?"
},
"eager-resources": {
"$$description": [
"Resources that should be extracted together, if any of them is needed,",
"or if any C extensions included in the project are imported."
"or if any C extensions included in the project are imported.",
"**OBSOLETE**: only relevant for ``pkg_resources``, ``easy_install`` and",
"``setup.py install`` in the context of ``eggs`` (**DEPRECATED**)."
],
"type": "array",
"items": {"type": "string"}
Expand Down Expand Up @@ -138,7 +149,8 @@
"namespace-packages": {
"type": "array",
"items": {"type": "string", "format": "python-module-name"},
"$comment": "https://setuptools.pypa.io/en/latest/userguide/package_discovery.html"
"$comment": "https://setuptools.pypa.io/en/latest/userguide/package_discovery.html",
"description": "**DEPRECATED**: use implicit namespaces instead (:pep:`420`)."
},
"py-modules": {
"description": "Modules that setuptools will manipulate",
Expand All @@ -148,10 +160,13 @@
},
"data-files": {
"$$description": [
"**DEPRECATED**: dict-like structure where each key represents a directory and",
"``dict``-like structure where each key represents a directory and",
"the value is a list of glob patterns that should be installed in them.",
"Please notice this don't work with wheels. See `data files support",
"<https://setuptools.pypa.io/en/latest/userguide/datafiles.html>`_"
"**DISCOURAGED**: please notice this might not work as expected with wheels.",
"Whenever possible, consider using data files inside the package directories",
"(or create a new namespace package that only contains data files).",
"See `data files support",
"<https://setuptools.pypa.io/en/latest/userguide/datafiles.html>`_."
],
"type": "object",
"patternProperties": {
Expand All @@ -176,8 +191,8 @@
"type": "array",
"items": {"type": "string"},
"$$description": [
"PROVISIONAL: List of glob patterns for all license files being distributed.",
"(might become standard with PEP 639).",
"**PROVISIONAL**: list of glob patterns for all license files being distributed.",
"(likely to become standard with :pep:`639`).",
"By default: ``['LICEN[CS]E*', 'COPYING*', 'NOTICE*', 'AUTHORS*']``"
],
"$comment": "TODO: revise if PEP 639 is accepted. Probably ``project.license-files``?"
Expand All @@ -190,7 +205,8 @@
"version": {
"$$description": [
"A version dynamically loaded via either the ``attr:`` or ``file:``",
"directives. Please make sure the given file or attribute respects :pep:`440`."
"directives. Please make sure the given file or attribute respects :pep:`440`.",
"Also ensure to set ``project.dynamic`` accordingly."
],
"oneOf": [
{"$ref": "#/definitions/attr-directive"},
Expand All @@ -199,13 +215,15 @@
},
"classifiers": {"$ref": "#/definitions/file-directive"},
"description": {"$ref": "#/definitions/file-directive"},
"dependencies": {"$ref": "#/definitions/file-directive"},
"entry-points": {"$ref": "#/definitions/file-directive"},
"dependencies": {"$ref": "#/definitions/file-directive-for-dependencies"},
"optional-dependencies": {
"type": "object",
"propertyNames": {"format": "python-identifier"},
"additionalProperties": false,
"patternProperties": {".+": {"$ref": "#/definitions/file-directive"}}
"patternProperties": {
".+": {"$ref": "#/definitions/file-directive-for-dependencies"}
}
},
"readme": {
"anyOf": [
Expand All @@ -222,7 +240,7 @@
"package-name": {
"$id": "#/definitions/package-name",
"title": "Valid package name",
"description": "Valid package name (importable or PEP 561).",
"description": "Valid package name (importable or :pep:`561`).",
"type": "string",
"anyOf": [
{"format": "python-module-name"},
Expand All @@ -246,6 +264,22 @@
},
"required": ["file"]
},
"file-directive-for-dependencies": {
"title": "'file:' directive for dependencies",
"allOf": [
{
"$$description": [
"**BETA**: subset of the ``requirements.txt`` format",
"without ``pip`` flags and options",
"(one :pep:`508`-compliant string per line,",
"lines that are blank or start with ``#`` are excluded).",
"See `dynamic metadata",
"<https://setuptools.pypa.io/en/latest/userguide/pyproject_config.html#dynamic-metadata>`_."
]
},
{"$ref": "#/definitions/file-directive"}
]
},
"attr-directive": {
"title": "'attr:' directive",
"$id": "#/definitions/attr-directive",
Expand Down
8 changes: 4 additions & 4 deletions tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,12 @@ def test_load():

def test_load_plugin():
spec = api.load_builtin_plugin("distutils")
assert spec["$id"] == "https://docs.python.org/3/install/"
assert spec["$id"].startswith("https://setuptools.pypa.io")
assert "deprecated/distutils" in spec["$id"]

spec = api.load_builtin_plugin("setuptools")
assert (
spec["$id"] == "https://setuptools.pypa.io/en/latest/references/keywords.html"
)
assert spec["$id"].startswith("https://setuptools.pypa.io")
assert "pyproject" in spec["$id"]


class TestRegistry:
Expand Down
7 changes: 4 additions & 3 deletions tests/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,9 +105,10 @@ class TestDisable:

@pytest.mark.parametrize("tool, other_tool", zip(TOOLS, reversed(TOOLS)))
def test_parse(self, valid_example, tool, other_tool):
params = parse_args([str(valid_example), "-D", tool])
assert len(params.plugins) == 1
assert params.plugins[0].tool == other_tool
all_plugins = parse_args([str(valid_example), "-D", tool]).plugins
our_plugins = [p for p in all_plugins if p.id.startswith("validate_pyproject")]
assert len(our_plugins) == 1
assert our_plugins[0].tool == other_tool

def test_valid(self, valid_example):
assert cli.run([str(valid_example), "-D", "distutils"]) == 0
Expand Down