diff --git a/.github/requirements_min.txt b/.github/requirements_min.txt index 02c2602a..c315e132 100644 --- a/.github/requirements_min.txt +++ b/.github/requirements_min.txt @@ -4,6 +4,7 @@ cycler==0.10.0 docstring-parser==0.16 matplotlib==3.3.0 numpy==1.22.0 +packaging==24.1 pydantic==2.7.0 pyglotaran==0.7.0 ruamel-yaml==0.18.6 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 772b24f0..ac822eb6 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -36,6 +36,7 @@ repos: rev: v4.0.0-alpha.8 # Use the sha or tag you want to point at hooks: - id: prettier + additional_dependencies: ["prettier@3.3.3"] # Notebook tools - repo: https://github.com/kynan/nbstripout diff --git a/pyglotaran_extras/config/config.py b/pyglotaran_extras/config/config.py index 698edd43..21c673e3 100644 --- a/pyglotaran_extras/config/config.py +++ b/pyglotaran_extras/config/config.py @@ -9,10 +9,12 @@ from typing import TYPE_CHECKING from typing import Any +from packaging.version import Version from pydantic import BaseModel from pydantic import ConfigDict from pydantic import PrivateAttr from pydantic import PydanticUserError +from pydantic import __version__ as pydantic_version from pydantic import create_model from pydantic.fields import FieldInfo from ruamel.yaml import YAML @@ -447,9 +449,11 @@ def create_config_schema( general_kwargs |= func_json_schema["$defs"][kwargs_model_name]["properties"] json_schema["$defs"] |= func_json_schema.pop("$defs") json_schema["$defs"][config_model_name] = func_json_schema - json_schema["$defs"]["PlotConfig"]["properties"][function_name] = { - "allOf": [{"$ref": f"#/$defs/{config_model_name}"}] - } + json_schema["$defs"]["PlotConfig"]["properties"][function_name] = ( + {"$ref": f"#/$defs/{config_model_name}"} + if Version(pydantic_version) >= Version("2.9") + else {"allOf": [{"$ref": f"#/$defs/{config_model_name}"}]} # type:ignore[dict-item] + ) except PydanticUserError as error: raise UsePlotConfigError(function_name, error) # noqa: B904 json_schema["$defs"]["PerFunctionPlotConfig"]["properties"]["default_args_override"][ diff --git a/pyproject.toml b/pyproject.toml index 407fbf01..c4f4c605 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -36,6 +36,7 @@ dependencies = [ "docstring-parser>=0.16", "matplotlib>=3.3", "numpy>=1.22", + "packaging>=24.1", "pydantic>=2.7", "pyglotaran>=0.7", "ruamel-yaml>=0.18.6", diff --git a/requirements_pinned.txt b/requirements_pinned.txt index 6490b507..e69358d3 100644 --- a/requirements_pinned.txt +++ b/requirements_pinned.txt @@ -1,11 +1,12 @@ -# Runtime dependencies - +# This file was autogenerated by uv via the following command: +# uv pip compile pyproject.toml -o requirements_pinned.txt --no-deps --no-annotate cycler==0.12.1 -numpy==1.26.4 +docstring-parser==0.16 matplotlib==3.9.2 +numpy==1.26.4 +packaging==24.1 +pydantic==2.9.2 pyglotaran==0.7.3 +ruamel-yaml==0.18.6 tabulate==0.9.0 xarray==2024.7.0 -ruamel.yaml==0.18.6 -docstring_parser==0.16 -pydantic==2.9.2 diff --git a/tests/config/test_config.py b/tests/config/test_config.py index 2ed883c1..9a3736f7 100644 --- a/tests/config/test_config.py +++ b/tests/config/test_config.py @@ -11,6 +11,8 @@ import pytest from jsonschema import Draft202012Validator +from packaging.version import Version +from pydantic import __version__ as pydantic_version from ruamel.yaml import YAML from pyglotaran_extras import create_config_schema @@ -563,6 +565,8 @@ def test_func( json_schema = json.loads(create_config_schema(tmp_path).read_text()) expected_schema = json.loads( (TEST_DATA / f"config/{CONFIG_FILE_STEM}.schema.json").read_text() + if Version(pydantic_version) >= Version("2.9") + else (TEST_DATA / f"config/{CONFIG_FILE_STEM}.schema.pydantic_lt_2_9.json").read_text() ) assert json_schema == expected_schema @@ -585,7 +589,13 @@ def test_func( pass json_schema = json.loads(create_config_schema(tmp_path).read_text()) - expected_schema = json.loads((TEST_DATA / "config/broken_config.schema.json").read_text()) + expected_schema = ( + json.loads((TEST_DATA / "config/broken_config.schema.json").read_text()) + if Version(pydantic_version) >= Version("2.9") + else json.loads( + (TEST_DATA / "config/broken_config.schema.pydantic_lt_2_9.json").read_text() + ) + ) assert json_schema == expected_schema diff --git a/tests/data/config/broken_config.schema.json b/tests/data/config/broken_config.schema.json index 3b7a107d..171f56e1 100644 --- a/tests/data/config/broken_config.schema.json +++ b/tests/data/config/broken_config.schema.json @@ -39,19 +39,11 @@ "description": "Config for plot functions including default args and label overrides.", "properties": { "general": { - "allOf": [ - { - "$ref": "#/$defs/PerFunctionPlotConfig" - } - ], + "$ref": "#/$defs/PerFunctionPlotConfig", "description": "Config that gets applied to all functions if not specified otherwise." }, "test_func": { - "allOf": [ - { - "$ref": "#/$defs/TestFuncConfig" - } - ] + "$ref": "#/$defs/TestFuncConfig" } }, "title": "PlotConfig", @@ -108,19 +100,11 @@ "description": "Plot function configuration specific to ``test_func`` (overrides values in general).", "properties": { "default_args_override": { - "allOf": [ - { - "$ref": "#/$defs/TestFuncKwargs" - } - ], + "$ref": "#/$defs/TestFuncKwargs", "default": {} }, "axis_label_override": { - "allOf": [ - { - "$ref": "#/$defs/PlotLabelOverrideMap" - } - ], + "$ref": "#/$defs/PlotLabelOverrideMap", "default": {} } }, @@ -132,11 +116,7 @@ "description": "Main configuration class.", "properties": { "plotting": { - "allOf": [ - { - "$ref": "#/$defs/PlotConfig" - } - ], + "$ref": "#/$defs/PlotConfig", "default": { "general": {} } diff --git a/tests/data/config/broken_config.schema.pydantic_lt_2_9.json b/tests/data/config/broken_config.schema.pydantic_lt_2_9.json new file mode 100644 index 00000000..3b7a107d --- /dev/null +++ b/tests/data/config/broken_config.schema.pydantic_lt_2_9.json @@ -0,0 +1,147 @@ +{ + "$defs": { + "PerFunctionPlotConfig": { + "additionalProperties": false, + "description": "Per function plot configuration.", + "properties": { + "default_args_override": { + "description": "Default arguments to use if not specified in function call.", + "title": "Default Args Override", + "type": "object", + "properties": { + "will_update_arg": { + "default": "default update", + "title": "Will Update Arg" + } + }, + "additionalProperties": false + }, + "axis_label_override": { + "anyOf": [ + { + "$ref": "#/$defs/PlotLabelOverrideMap" + }, + { + "additionalProperties": { + "type": "string" + }, + "type": "object" + } + ], + "title": "Axis Label Override" + } + }, + "title": "PerFunctionPlotConfig", + "type": "object" + }, + "PlotConfig": { + "additionalProperties": true, + "description": "Config for plot functions including default args and label overrides.", + "properties": { + "general": { + "allOf": [ + { + "$ref": "#/$defs/PerFunctionPlotConfig" + } + ], + "description": "Config that gets applied to all functions if not specified otherwise." + }, + "test_func": { + "allOf": [ + { + "$ref": "#/$defs/TestFuncConfig" + } + ] + } + }, + "title": "PlotConfig", + "type": "object" + }, + "PlotLabelOverrideMap": { + "additionalProperties": { + "anyOf": [ + { + "$ref": "#/$defs/PlotLabelOverrideValue" + }, + { + "type": "string" + } + ] + }, + "description": "Mapping to override axis labels.", + "title": "PlotLabelOverrideMap", + "type": "object" + }, + "PlotLabelOverrideValue": { + "additionalProperties": false, + "description": "Value of ``PlotLabelOverrideMap``.", + "properties": { + "target_name": { + "title": "Target Name", + "type": "string" + }, + "axis": { + "default": "both", + "enum": ["x", "y", "both"], + "title": "Axis", + "type": "string" + } + }, + "required": ["target_name"], + "title": "PlotLabelOverrideValue", + "type": "object" + }, + "TestFuncKwargs": { + "additionalProperties": false, + "description": "Default arguments to use for ``test_func``, if not specified in function call.", + "properties": { + "will_update_arg": { + "default": "default update", + "title": "Will Update Arg" + } + }, + "title": "TestFuncKwargs", + "type": "object" + }, + "TestFuncConfig": { + "additionalProperties": false, + "description": "Plot function configuration specific to ``test_func`` (overrides values in general).", + "properties": { + "default_args_override": { + "allOf": [ + { + "$ref": "#/$defs/TestFuncKwargs" + } + ], + "default": {} + }, + "axis_label_override": { + "allOf": [ + { + "$ref": "#/$defs/PlotLabelOverrideMap" + } + ], + "default": {} + } + }, + "title": "TestFuncConfig", + "type": "object" + } + }, + "additionalProperties": false, + "description": "Main configuration class.", + "properties": { + "plotting": { + "allOf": [ + { + "$ref": "#/$defs/PlotConfig" + } + ], + "default": { + "general": {} + } + } + }, + "title": "Config", + "type": "object" +} diff --git a/tests/data/config/pygta_config.schema.json b/tests/data/config/pygta_config.schema.json index fee60dec..1f19ec9c 100644 --- a/tests/data/config/pygta_config.schema.json +++ b/tests/data/config/pygta_config.schema.json @@ -47,26 +47,14 @@ "description": "Config for plot functions including default args and label overrides.", "properties": { "general": { - "allOf": [ - { - "$ref": "#/$defs/PerFunctionPlotConfig" - } - ], + "$ref": "#/$defs/PerFunctionPlotConfig", "description": "Config that gets applied to all functions if not specified otherwise." }, "other": { - "allOf": [ - { - "$ref": "#/$defs/OtherConfig" - } - ] + "$ref": "#/$defs/OtherConfig" }, "test_func": { - "allOf": [ - { - "$ref": "#/$defs/TestFuncConfig" - } - ] + "$ref": "#/$defs/TestFuncConfig" } }, "title": "PlotConfig", @@ -123,19 +111,11 @@ "description": "Plot function configuration specific to ``other`` (overrides values in general).", "properties": { "default_args_override": { - "allOf": [ - { - "$ref": "#/$defs/OtherKwargs" - } - ], + "$ref": "#/$defs/OtherKwargs", "default": {} }, "axis_label_override": { - "allOf": [ - { - "$ref": "#/$defs/PlotLabelOverrideMap" - } - ], + "$ref": "#/$defs/PlotLabelOverrideMap", "default": {} } }, @@ -167,19 +147,11 @@ "description": "Plot function configuration specific to ``test_func`` (overrides values in general).", "properties": { "default_args_override": { - "allOf": [ - { - "$ref": "#/$defs/TestFuncKwargs" - } - ], + "$ref": "#/$defs/TestFuncKwargs", "default": {} }, "axis_label_override": { - "allOf": [ - { - "$ref": "#/$defs/PlotLabelOverrideMap" - } - ], + "$ref": "#/$defs/PlotLabelOverrideMap", "default": {} } }, @@ -191,11 +163,7 @@ "description": "Main configuration class.", "properties": { "plotting": { - "allOf": [ - { - "$ref": "#/$defs/PlotConfig" - } - ], + "$ref": "#/$defs/PlotConfig", "default": { "general": {} } diff --git a/tests/data/config/pygta_config.schema.pydantic_lt_2_9.json b/tests/data/config/pygta_config.schema.pydantic_lt_2_9.json new file mode 100644 index 00000000..fee60dec --- /dev/null +++ b/tests/data/config/pygta_config.schema.pydantic_lt_2_9.json @@ -0,0 +1,206 @@ +{ + "$defs": { + "PerFunctionPlotConfig": { + "additionalProperties": false, + "description": "Per function plot configuration.", + "properties": { + "default_args_override": { + "description": "Default arguments to use if not specified in function call.", + "title": "Default Args Override", + "type": "object", + "properties": { + "will_be_kept_arg": { + "default": "default keep", + "title": "Will Be Kept Arg" + }, + "will_update_arg": { + "default": "default update", + "title": "Will Update Arg" + }, + "will_be_added_arg": { + "default": "default add", + "title": "Will Be Added Arg" + } + }, + "additionalProperties": false + }, + "axis_label_override": { + "anyOf": [ + { + "$ref": "#/$defs/PlotLabelOverrideMap" + }, + { + "additionalProperties": { + "type": "string" + }, + "type": "object" + } + ], + "title": "Axis Label Override" + } + }, + "title": "PerFunctionPlotConfig", + "type": "object" + }, + "PlotConfig": { + "additionalProperties": true, + "description": "Config for plot functions including default args and label overrides.", + "properties": { + "general": { + "allOf": [ + { + "$ref": "#/$defs/PerFunctionPlotConfig" + } + ], + "description": "Config that gets applied to all functions if not specified otherwise." + }, + "other": { + "allOf": [ + { + "$ref": "#/$defs/OtherConfig" + } + ] + }, + "test_func": { + "allOf": [ + { + "$ref": "#/$defs/TestFuncConfig" + } + ] + } + }, + "title": "PlotConfig", + "type": "object" + }, + "PlotLabelOverrideMap": { + "additionalProperties": { + "anyOf": [ + { + "$ref": "#/$defs/PlotLabelOverrideValue" + }, + { + "type": "string" + } + ] + }, + "description": "Mapping to override axis labels.", + "title": "PlotLabelOverrideMap", + "type": "object" + }, + "PlotLabelOverrideValue": { + "additionalProperties": false, + "description": "Value of ``PlotLabelOverrideMap``.", + "properties": { + "target_name": { + "title": "Target Name", + "type": "string" + }, + "axis": { + "default": "both", + "enum": ["x", "y", "both"], + "title": "Axis", + "type": "string" + } + }, + "required": ["target_name"], + "title": "PlotLabelOverrideValue", + "type": "object" + }, + "OtherKwargs": { + "additionalProperties": false, + "description": "Default arguments to use for ``other``, if not specified in function call.", + "properties": { + "will_be_kept_arg": { + "default": "default update", + "title": "Will Be Kept Arg" + } + }, + "title": "OtherKwargs", + "type": "object" + }, + "OtherConfig": { + "additionalProperties": false, + "description": "Plot function configuration specific to ``other`` (overrides values in general).", + "properties": { + "default_args_override": { + "allOf": [ + { + "$ref": "#/$defs/OtherKwargs" + } + ], + "default": {} + }, + "axis_label_override": { + "allOf": [ + { + "$ref": "#/$defs/PlotLabelOverrideMap" + } + ], + "default": {} + } + }, + "title": "OtherConfig", + "type": "object" + }, + "TestFuncKwargs": { + "additionalProperties": false, + "description": "Default arguments to use for ``test_func``, if not specified in function call.", + "properties": { + "will_update_arg": { + "default": "default update", + "title": "Will Update Arg" + }, + "will_be_kept_arg": { + "default": "default keep", + "title": "Will Be Kept Arg" + }, + "will_be_added_arg": { + "default": "default add", + "title": "Will Be Added Arg" + } + }, + "title": "TestFuncKwargs", + "type": "object" + }, + "TestFuncConfig": { + "additionalProperties": false, + "description": "Plot function configuration specific to ``test_func`` (overrides values in general).", + "properties": { + "default_args_override": { + "allOf": [ + { + "$ref": "#/$defs/TestFuncKwargs" + } + ], + "default": {} + }, + "axis_label_override": { + "allOf": [ + { + "$ref": "#/$defs/PlotLabelOverrideMap" + } + ], + "default": {} + } + }, + "title": "TestFuncConfig", + "type": "object" + } + }, + "additionalProperties": false, + "description": "Main configuration class.", + "properties": { + "plotting": { + "allOf": [ + { + "$ref": "#/$defs/PlotConfig" + } + ], + "default": { + "general": {} + } + } + }, + "title": "Config", + "type": "object" +}