From bec9644cb767f73bca7d8a6553ee06175777f61d Mon Sep 17 00:00:00 2001 From: Chris Mungall Date: Sun, 30 Mar 2025 13:09:32 -0700 Subject: [PATCH 01/16] restore dataclass_extensions. See #345 --- .../utils/dataclass_extensions_376.py | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 linkml_runtime/utils/dataclass_extensions_376.py diff --git a/linkml_runtime/utils/dataclass_extensions_376.py b/linkml_runtime/utils/dataclass_extensions_376.py new file mode 100644 index 00000000..d90b542f --- /dev/null +++ b/linkml_runtime/utils/dataclass_extensions_376.py @@ -0,0 +1,30 @@ +import dataclasses +# +# The dataclass library builds a rigid `__init__` function that doesn't allow any unrecognized named parameters +# +# The purpose of this extension is to enhance the library to allow additional keyword arguments to passed in +# and then on to the __post_init__ function that can deal with them accordingly + +# Beware that there is no promise that signature of the create function will remain consistent +loc_fn = dataclasses._create_fn + + +def dc_create_fn(name, args, body, *_posargs, **_kwargs): + # If overriding the initializer and using a post init + if name == '__init__' and dataclasses._POST_INIT_NAME in body[-1]: + # Then insert the kwargs into the both the call and the post init + pi_parms = body[-1].rsplit(')', 1)[0] + body[-1] = pi_parms + ('' if pi_parms[-1] == '(' else ',') + ' **_kwargs)' + return loc_fn(name, list(args) + ["**_kwargs"], body, *_posargs, **_kwargs) + else: + return loc_fn(name, args, body, *_posargs, **_kwargs) + + +dataclasses._create_fn = dc_create_fn + +# The following line is here solely to be backwards compatible. +dataclasses_init_fn_with_kwargs = dataclasses._init_fn + +# The following line can be used to make certain that the import of the new create function doesn't get +# discarded as being potentially unused +DC_CREATE_FN = True From fdf3302b18be4868ba6186da8a254e87b858ce11 Mon Sep 17 00:00:00 2001 From: Sierra Taylor Moxon Date: Sun, 30 Mar 2025 16:17:16 -0700 Subject: [PATCH 02/16] restore test to go along with dataclass_extensions_376 --- tests/test_issues/test_issue_718a.py | 51 ++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 tests/test_issues/test_issue_718a.py diff --git a/tests/test_issues/test_issue_718a.py b/tests/test_issues/test_issue_718a.py new file mode 100644 index 00000000..b5710e20 --- /dev/null +++ b/tests/test_issues/test_issue_718a.py @@ -0,0 +1,51 @@ +import dataclasses +import unittest +from dataclasses import dataclass +from typing import Optional, ClassVar + +import yaml + +import linkml_runtime.utils.dataclass_extensions_376 as dc_tweak +# This line makes certain that the import remains +DC_IN = dc_tweak.DC_CREATE_FN + +from linkml_runtime.utils.yamlutils import YAMLRoot, DupCheckYamlLoader + + +class Issue83TestCase(unittest.TestCase): + # The goal is to provide line numbers on error messages. We've tweaked the parser so that it returns augmented + # str's and int's with the line numbers on them. The problem we are trying to address now is that the dataclass + # constructor doesn't support **argv out of the box. We can certainly tweak the generator to emit the __init__ + # method to do this, but it would be really handy + + @dataclass + class FesterBesterTester(YAMLRoot): + cv: ClassVar[int] = 42 + + a: Optional[int] = 0 + b: Optional[str] = None + + def test_initvar(self): + with self.assertRaises(ValueError) as e: + Issue83TestCase.FesterBesterTester(a=12, b="Sell", c="buy") + self.assertEqual("Unknown argument: c = 'buy'", str(e.exception).strip()) + yaml_str = """base: + a: 17 + b: Ice Cream + c: sell +""" + parsed_yaml = yaml.load(yaml_str, DupCheckYamlLoader) + with self.assertRaises(ValueError) as e: + Issue83TestCase.FesterBesterTester(**parsed_yaml['base']) + self.assertEqual('File "", line 4, col 9: Unknown argument: c = \'sell\'', + str(e.exception).strip()) + + parsed_yaml['base'].pop('c', None) + try: + Issue83TestCase.FesterBesterTester(**parsed_yaml['base']) + except Exception as e: + self.fail(f'Raised exception unexpectedly: {str(e.exception)}') + + +if __name__ == '__main__': + unittest.main() From 638d87374498b2a2823b24104e84a984c3b5f031 Mon Sep 17 00:00:00 2001 From: Sierra Taylor Moxon Date: Sun, 30 Mar 2025 16:37:49 -0700 Subject: [PATCH 03/16] remove tests again - dataclass fn rm'd --- tests/test_issues/test_issue_718a.py | 51 ---------------------------- 1 file changed, 51 deletions(-) delete mode 100644 tests/test_issues/test_issue_718a.py diff --git a/tests/test_issues/test_issue_718a.py b/tests/test_issues/test_issue_718a.py deleted file mode 100644 index b5710e20..00000000 --- a/tests/test_issues/test_issue_718a.py +++ /dev/null @@ -1,51 +0,0 @@ -import dataclasses -import unittest -from dataclasses import dataclass -from typing import Optional, ClassVar - -import yaml - -import linkml_runtime.utils.dataclass_extensions_376 as dc_tweak -# This line makes certain that the import remains -DC_IN = dc_tweak.DC_CREATE_FN - -from linkml_runtime.utils.yamlutils import YAMLRoot, DupCheckYamlLoader - - -class Issue83TestCase(unittest.TestCase): - # The goal is to provide line numbers on error messages. We've tweaked the parser so that it returns augmented - # str's and int's with the line numbers on them. The problem we are trying to address now is that the dataclass - # constructor doesn't support **argv out of the box. We can certainly tweak the generator to emit the __init__ - # method to do this, but it would be really handy - - @dataclass - class FesterBesterTester(YAMLRoot): - cv: ClassVar[int] = 42 - - a: Optional[int] = 0 - b: Optional[str] = None - - def test_initvar(self): - with self.assertRaises(ValueError) as e: - Issue83TestCase.FesterBesterTester(a=12, b="Sell", c="buy") - self.assertEqual("Unknown argument: c = 'buy'", str(e.exception).strip()) - yaml_str = """base: - a: 17 - b: Ice Cream - c: sell -""" - parsed_yaml = yaml.load(yaml_str, DupCheckYamlLoader) - with self.assertRaises(ValueError) as e: - Issue83TestCase.FesterBesterTester(**parsed_yaml['base']) - self.assertEqual('File "", line 4, col 9: Unknown argument: c = \'sell\'', - str(e.exception).strip()) - - parsed_yaml['base'].pop('c', None) - try: - Issue83TestCase.FesterBesterTester(**parsed_yaml['base']) - except Exception as e: - self.fail(f'Raised exception unexpectedly: {str(e.exception)}') - - -if __name__ == '__main__': - unittest.main() From 15baee31d6018af1058463040096cdbed527d0f2 Mon Sep 17 00:00:00 2001 From: Sierra Taylor Moxon Date: Sun, 30 Mar 2025 20:50:20 -0700 Subject: [PATCH 04/16] DO NOT MERGE - testing a reimplementation of a previous version of code --- .../utils/dataclass_extensions_376.py | 29 ++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/linkml_runtime/utils/dataclass_extensions_376.py b/linkml_runtime/utils/dataclass_extensions_376.py index d90b542f..0f1af1d3 100644 --- a/linkml_runtime/utils/dataclass_extensions_376.py +++ b/linkml_runtime/utils/dataclass_extensions_376.py @@ -6,7 +6,34 @@ # and then on to the __post_init__ function that can deal with them accordingly # Beware that there is no promise that signature of the create function will remain consistent -loc_fn = dataclasses._create_fn + +def _create_fn(name, args, body, *, globals=None, locals=None, + return_type=MISSING): + # Note that we mutate locals when exec() is called. Caller + # beware! The only callers are internal to this module, so no + # worries about external callers. + if locals is None: + locals = {} + if 'BUILTINS' not in locals: + locals['BUILTINS'] = builtins + return_annotation = '' + if return_type is not MISSING: + locals['_return_type'] = return_type + return_annotation = '->_return_type' + args = ','.join(args) + body = '\n'.join(f' {b}' for b in body) + + # Compute the text of the entire function. + txt = f' def {name}({args}){return_annotation}:\n{body}' + + local_vars = ', '.join(locals.keys()) + txt = f"def __create_fn__({local_vars}):\n{txt}\n return {name}" + ns = {} + exec(txt, globals, ns) + return ns['__create_fn__'](**locals) + + +loc_fn = _create_fn() def dc_create_fn(name, args, body, *_posargs, **_kwargs): From 9666efd639b9ad9375eb3efd61db64cb4f9e6523 Mon Sep 17 00:00:00 2001 From: Sierra Taylor Moxon Date: Mon, 31 Mar 2025 11:06:27 -0700 Subject: [PATCH 05/16] add warning and patch tests to skip if > 3.13.0 --- .../utils/dataclass_extensions_376.py | 91 ++++++++----------- .../test_dataclass_extensions_376.py | 46 ++++++++++ 2 files changed, 82 insertions(+), 55 deletions(-) create mode 100644 tests/test_issues/test_dataclass_extensions_376.py diff --git a/linkml_runtime/utils/dataclass_extensions_376.py b/linkml_runtime/utils/dataclass_extensions_376.py index 0f1af1d3..d61dffa1 100644 --- a/linkml_runtime/utils/dataclass_extensions_376.py +++ b/linkml_runtime/utils/dataclass_extensions_376.py @@ -1,57 +1,38 @@ +import sys import dataclasses -# -# The dataclass library builds a rigid `__init__` function that doesn't allow any unrecognized named parameters -# -# The purpose of this extension is to enhance the library to allow additional keyword arguments to passed in -# and then on to the __post_init__ function that can deal with them accordingly +import warnings + +# Raise helpful error in unsupported Python versions +if sys.version_info >= (3, 13): + raise RuntimeError( + "The LinkML dataclass_extensions_376 is no longer compatible with Python 3.13 or newer.\n\n" + "Python 3.13 removed _create_fn), which this extension relies on.\n\n" + "To resolve this:\n" + " • Upgrade your LinkML schema and code to use LinkML >= 1.9.0, which no longer requires this patch\n" + " • Or migrate to Pydantic models for runtime dataclass behavior\n\n" + ) + +# Emit deprecation warning in all other Python versions +warnings.warn( + "The LinkML dataclass extension monkeypatch is deprecated and will be removed in a future release.\n" + "Consider upgrading to LinkML >=1.9.0 or switching to Pydantic.", + DeprecationWarning, + stacklevel=2 +) + +# Patch _create_fn if it still exists +if hasattr(dataclasses, "_create_fn"): + loc_fn = dataclasses._create_fn + + def dc_create_fn(name, args, body, *_posargs, **_kwargs): + if name == '__init__' and dataclasses._POST_INIT_NAME in body[-1]: + pi_parms = body[-1].rsplit(')', 1)[0] + body[-1] = pi_parms + ('' if pi_parms[-1] == '(' else ',') + ' **_kwargs)' + return loc_fn(name, list(args) + ["**_kwargs"], body, *_posargs, **_kwargs) + else: + return loc_fn(name, args, body, *_posargs, **_kwargs) + + dataclasses._create_fn = dc_create_fn + dataclasses_init_fn_with_kwargs = dataclasses._init_fn + DC_CREATE_FN = True -# Beware that there is no promise that signature of the create function will remain consistent - -def _create_fn(name, args, body, *, globals=None, locals=None, - return_type=MISSING): - # Note that we mutate locals when exec() is called. Caller - # beware! The only callers are internal to this module, so no - # worries about external callers. - if locals is None: - locals = {} - if 'BUILTINS' not in locals: - locals['BUILTINS'] = builtins - return_annotation = '' - if return_type is not MISSING: - locals['_return_type'] = return_type - return_annotation = '->_return_type' - args = ','.join(args) - body = '\n'.join(f' {b}' for b in body) - - # Compute the text of the entire function. - txt = f' def {name}({args}){return_annotation}:\n{body}' - - local_vars = ', '.join(locals.keys()) - txt = f"def __create_fn__({local_vars}):\n{txt}\n return {name}" - ns = {} - exec(txt, globals, ns) - return ns['__create_fn__'](**locals) - - -loc_fn = _create_fn() - - -def dc_create_fn(name, args, body, *_posargs, **_kwargs): - # If overriding the initializer and using a post init - if name == '__init__' and dataclasses._POST_INIT_NAME in body[-1]: - # Then insert the kwargs into the both the call and the post init - pi_parms = body[-1].rsplit(')', 1)[0] - body[-1] = pi_parms + ('' if pi_parms[-1] == '(' else ',') + ' **_kwargs)' - return loc_fn(name, list(args) + ["**_kwargs"], body, *_posargs, **_kwargs) - else: - return loc_fn(name, args, body, *_posargs, **_kwargs) - - -dataclasses._create_fn = dc_create_fn - -# The following line is here solely to be backwards compatible. -dataclasses_init_fn_with_kwargs = dataclasses._init_fn - -# The following line can be used to make certain that the import of the new create function doesn't get -# discarded as being potentially unused -DC_CREATE_FN = True diff --git a/tests/test_issues/test_dataclass_extensions_376.py b/tests/test_issues/test_dataclass_extensions_376.py new file mode 100644 index 00000000..11010d5c --- /dev/null +++ b/tests/test_issues/test_dataclass_extensions_376.py @@ -0,0 +1,46 @@ +import sys +import unittest +from dataclasses import dataclass +from typing import Optional +import pytest + +# Only import the LinkML patch module on supported Python versions +# Python 3.13+ removed dataclasses._create_fn, which breaks this patch. +# The test will be skipped on versions > 3.13.0. +if sys.version_info < (3, 13): + import linkml_runtime.utils.dataclass_extensions_376 as dc_tweak + DC_IN = dc_tweak.DC_CREATE_FN +else: + dc_tweak = None + DC_IN = False + + +@pytest.mark.skipif(sys.version_info >= (3, 13), reason="LinkML dataclass patch no longer supported in Python 3.13+") +class DataclassExtensionsTestCase(unittest.TestCase): + """Test the dataclass_extensions_376 module with Python <3.13""" + + @dataclass + class TestClass: + a: Optional[int] = 0 + b: Optional[str] = None + + def __post_init__(self, **kwargs): + if kwargs: + unknown_args = sorted(kwargs.keys()) + first_arg = unknown_args[0] + raise ValueError(f"Unknown argument: {first_arg} = {repr(kwargs[first_arg])}") + + def test_kwargs_passed_to_post_init(self): + self.TestClass(a=1, b="test") + + with self.assertRaises(ValueError) as e: + self.TestClass(a=1, b="test", c="unknown") + self.assertEqual("Unknown argument: c = 'unknown'", str(e.exception)) + + with self.assertRaises(ValueError) as e: + self.TestClass(a=1, b="test", c="unknown", z="also_unknown") + self.assertEqual("Unknown argument: c = 'unknown'", str(e.exception)) + + +if __name__ == '__main__': + unittest.main() From aaae754ea538d4a5a92488ef668f982b08603f0c Mon Sep 17 00:00:00 2001 From: Sierra Taylor Moxon Date: Mon, 31 Mar 2025 11:30:52 -0700 Subject: [PATCH 06/16] remove unused toml addition --- .../utils/dataclass_extensions_376.py | 2 +- poetry.lock | 30 +++++++++---------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/linkml_runtime/utils/dataclass_extensions_376.py b/linkml_runtime/utils/dataclass_extensions_376.py index d61dffa1..d20a68fa 100644 --- a/linkml_runtime/utils/dataclass_extensions_376.py +++ b/linkml_runtime/utils/dataclass_extensions_376.py @@ -14,7 +14,7 @@ # Emit deprecation warning in all other Python versions warnings.warn( - "The LinkML dataclass extension monkeypatch is deprecated and will be removed in a future release.\n" + "The LinkML dataclass extension is deprecated and will be removed in a future release.\n" "Consider upgrading to LinkML >=1.9.0 or switching to Pydantic.", DeprecationWarning, stacklevel=2 diff --git a/poetry.lock b/poetry.lock index 3732d198..c5ecd50b 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 2.0.0 and should not be changed by hand. +# This file is automatically @generated by Poetry 2.1.1 and should not be changed by hand. [[package]] name = "annotated-types" @@ -28,12 +28,12 @@ files = [ ] [package.extras] -benchmark = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-codspeed", "pytest-mypy-plugins", "pytest-xdist[psutil]"] -cov = ["cloudpickle", "coverage[toml] (>=5.3)", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] -dev = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pre-commit-uv", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +benchmark = ["cloudpickle ; platform_python_implementation == \"CPython\"", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pympler", "pytest (>=4.3.0)", "pytest-codspeed", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"] +cov = ["cloudpickle ; platform_python_implementation == \"CPython\"", "coverage[toml] (>=5.3)", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"] +dev = ["cloudpickle ; platform_python_implementation == \"CPython\"", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pre-commit-uv", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"] docs = ["cogapp", "furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier (<24.7)"] -tests = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] -tests-mypy = ["mypy (>=1.11.1)", "pytest-mypy-plugins"] +tests = ["cloudpickle ; platform_python_implementation == \"CPython\"", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"] +tests-mypy = ["mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\""] [[package]] name = "cattrs" @@ -56,8 +56,8 @@ typing-extensions = {version = ">=4.1.0,<4.6.3 || >4.6.3", markers = "python_ver bson = ["pymongo (>=4.4.0)"] cbor2 = ["cbor2 (>=5.4.6)"] msgpack = ["msgpack (>=1.0.5)"] -msgspec = ["msgspec (>=0.18.5)"] -orjson = ["orjson (>=3.9.2)"] +msgspec = ["msgspec (>=0.18.5) ; implementation_name == \"cpython\""] +orjson = ["orjson (>=3.9.2) ; implementation_name == \"cpython\""] pyyaml = ["pyyaml (>=6.0)"] tomlkit = ["tomlkit (>=0.11.8)"] ujson = ["ujson (>=5.7.0)"] @@ -265,7 +265,7 @@ files = [ ] [package.extras] -toml = ["tomli"] +toml = ["tomli ; python_full_version <= \"3.11.0a6\""] [[package]] name = "curies" @@ -308,7 +308,7 @@ files = [ wrapt = ">=1.10,<2" [package.extras] -dev = ["PyTest", "PyTest-Cov", "bump2version (<1)", "setuptools", "tox"] +dev = ["PyTest", "PyTest-Cov", "bump2version (<1)", "setuptools ; python_version >= \"3.12\"", "tox"] [[package]] name = "exceptiongroup" @@ -370,7 +370,7 @@ files = [ zipp = {version = ">=3.1.0", markers = "python_version < \"3.10\""} [package.extras] -check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)"] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\""] cover = ["pytest-cov"] doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] enabler = ["pytest-enabler (>=2.2)"] @@ -583,7 +583,7 @@ typing-extensions = ">=4.12.2" [package.extras] email = ["email-validator (>=2.0.0)"] -timezone = ["tzdata"] +timezone = ["tzdata ; python_version >= \"3.9\" and platform_system == \"Windows\""] [[package]] name = "pydantic-core" @@ -1141,7 +1141,7 @@ files = [ ] [package.extras] -brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] +brotli = ["brotli (>=1.0.9) ; platform_python_implementation == \"CPython\"", "brotlicffi (>=0.8.0) ; platform_python_implementation != \"CPython\""] h2 = ["h2 (>=4,<5)"] socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] zstd = ["zstandard (>=0.18.0)"] @@ -1249,11 +1249,11 @@ files = [ ] [package.extras] -check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)"] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\""] cover = ["pytest-cov"] doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] enabler = ["pytest-enabler (>=2.2)"] -test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-itertools", "pytest (>=6,!=8.1.*)", "pytest-ignore-flaky"] +test = ["big-O", "importlib-resources ; python_version < \"3.9\"", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-itertools", "pytest (>=6,!=8.1.*)", "pytest-ignore-flaky"] type = ["pytest-mypy"] [metadata] From 9e6ed7e77d57494e745d693d10c88b849d183802 Mon Sep 17 00:00:00 2001 From: Sierra Taylor Moxon Date: Mon, 31 Mar 2025 11:52:08 -0700 Subject: [PATCH 07/16] refactor to pytest instead of unittest --- .../utils/dataclass_extensions_376.py | 38 +++++++++++++------ .../test_dataclass_extensions_376.py | 33 ++++++++-------- 2 files changed, 45 insertions(+), 26 deletions(-) diff --git a/linkml_runtime/utils/dataclass_extensions_376.py b/linkml_runtime/utils/dataclass_extensions_376.py index d20a68fa..008cddfe 100644 --- a/linkml_runtime/utils/dataclass_extensions_376.py +++ b/linkml_runtime/utils/dataclass_extensions_376.py @@ -2,25 +2,25 @@ import dataclasses import warnings -# Raise helpful error in unsupported Python versions +# Block unsupported Python versions if sys.version_info >= (3, 13): raise RuntimeError( - "The LinkML dataclass_extensions_376 is no longer compatible with Python 3.13 or newer.\n\n" - "Python 3.13 removed _create_fn), which this extension relies on.\n\n" + "The LinkML dataclass_extensions_376 patch is no longer compatible with Python 3.13 or newer.\n\n" + "Python 3.13 removed internal support for `_create_fn`, which this patch depends on.\n\n" "To resolve this:\n" - " • Upgrade your LinkML schema and code to use LinkML >= 1.9.0, which no longer requires this patch\n" - " • Or migrate to Pydantic models for runtime dataclass behavior\n\n" + " • Upgrade your LinkML schema and code to use LinkML >= 1.9.0, which no longer uses this patch\n" + " • Or migrate to Pydantic models for dataclass behavior\n\n" ) -# Emit deprecation warning in all other Python versions +# Warn that this extension is deprecated warnings.warn( - "The LinkML dataclass extension is deprecated and will be removed in a future release.\n" - "Consider upgrading to LinkML >=1.9.0 or switching to Pydantic.", + "The LinkML dataclass extension patch is deprecated and will be removed in a future release.\n" + "Consider upgrading to LinkML >= 1.9.0 or switching Python class generation to Pydantic.", DeprecationWarning, - stacklevel=2 + stacklevel=2, ) -# Patch _create_fn if it still exists +# Conditionally patch only if _create_fn exists if hasattr(dataclasses, "_create_fn"): loc_fn = dataclasses._create_fn @@ -34,5 +34,21 @@ def dc_create_fn(name, args, body, *_posargs, **_kwargs): dataclasses._create_fn = dc_create_fn dataclasses_init_fn_with_kwargs = dataclasses._init_fn - DC_CREATE_FN = True + warnings.warn( + "LinkML dataclass patch successfully applied.", + UserWarning, + stacklevel=2, + ) +else: + raise RuntimeError( + "The LinkML dataclass_extensions_376 patch could not be applied: `dataclasses._create_fn` is missing.\n\n" + "This likely indicates a nonstandard or altered Python environment, or partial compatibility with this patch.\n\n" + "To proceed:\n" + " • Use a supported Python version where `_create_fn` is present (Python < 3.13)\n" + " • Or upgrade to LinkML >= 1.9.0 to remove reliance on this patch\n" + " • Or migrate to Pydantic models\n\n" + ) + +# Used to signal that this patch was imported/applied +DC_CREATE_FN = True \ No newline at end of file diff --git a/tests/test_issues/test_dataclass_extensions_376.py b/tests/test_issues/test_dataclass_extensions_376.py index 11010d5c..d2941b4b 100644 --- a/tests/test_issues/test_dataclass_extensions_376.py +++ b/tests/test_issues/test_dataclass_extensions_376.py @@ -1,14 +1,14 @@ import sys -import unittest +import pytest from dataclasses import dataclass from typing import Optional -import pytest +import importlib # Only import the LinkML patch module on supported Python versions # Python 3.13+ removed dataclasses._create_fn, which breaks this patch. -# The test will be skipped on versions > 3.13.0. if sys.version_info < (3, 13): import linkml_runtime.utils.dataclass_extensions_376 as dc_tweak + DC_IN = dc_tweak.DC_CREATE_FN else: dc_tweak = None @@ -16,8 +16,8 @@ @pytest.mark.skipif(sys.version_info >= (3, 13), reason="LinkML dataclass patch no longer supported in Python 3.13+") -class DataclassExtensionsTestCase(unittest.TestCase): - """Test the dataclass_extensions_376 module with Python <3.13""" +def test_kwargs_passed_to_post_init(): + """Test that kwargs are passed to __post_init__ in patched dataclass""" @dataclass class TestClass: @@ -30,17 +30,20 @@ def __post_init__(self, **kwargs): first_arg = unknown_args[0] raise ValueError(f"Unknown argument: {first_arg} = {repr(kwargs[first_arg])}") - def test_kwargs_passed_to_post_init(self): - self.TestClass(a=1, b="test") + # No extra kwargs – should not raise + TestClass(a=1, b="test") - with self.assertRaises(ValueError) as e: - self.TestClass(a=1, b="test", c="unknown") - self.assertEqual("Unknown argument: c = 'unknown'", str(e.exception)) + # One unknown kwarg – should raise + with pytest.raises(ValueError, match="Unknown argument: c = 'unknown'"): + TestClass(a=1, b="test", c="unknown") - with self.assertRaises(ValueError) as e: - self.TestClass(a=1, b="test", c="unknown", z="also_unknown") - self.assertEqual("Unknown argument: c = 'unknown'", str(e.exception)) + # Multiple unknown kwargs – should raise, first alphabetically + with pytest.raises(ValueError, match="Unknown argument: c = 'unknown'"): + TestClass(a=1, b="test", c="unknown", z="also_unknown") -if __name__ == '__main__': - unittest.main() +@pytest.mark.skipif(sys.version_info < (3, 13), reason="This test only applies to Python 3.13+") +def test_patch_fails_on_python_3_13_plus(): + """Ensure the patch raises a RuntimeError on Python 3.13+""" + with pytest.raises(RuntimeError, match="no longer compatible with Python 3.13 or newer"): + importlib.import_module("linkml_runtime.utils.dataclass_extensions_376") From 7c2164cfa6d9d4654d91171ab99e97b9622efb52 Mon Sep 17 00:00:00 2001 From: Sierra Taylor Moxon Date: Mon, 31 Mar 2025 12:40:39 -0700 Subject: [PATCH 08/16] fix tests to always emit warning --- .../utils/dataclass_extensions_376.py | 70 ++++++++----------- .../test_dataclass_extensions_376.py | 13 ++-- 2 files changed, 37 insertions(+), 46 deletions(-) diff --git a/linkml_runtime/utils/dataclass_extensions_376.py b/linkml_runtime/utils/dataclass_extensions_376.py index 008cddfe..17cc1bd1 100644 --- a/linkml_runtime/utils/dataclass_extensions_376.py +++ b/linkml_runtime/utils/dataclass_extensions_376.py @@ -1,54 +1,40 @@ import sys -import dataclasses import warnings -# Block unsupported Python versions -if sys.version_info >= (3, 13): - raise RuntimeError( - "The LinkML dataclass_extensions_376 patch is no longer compatible with Python 3.13 or newer.\n\n" - "Python 3.13 removed internal support for `_create_fn`, which this patch depends on.\n\n" - "To resolve this:\n" - " • Upgrade your LinkML schema and code to use LinkML >= 1.9.0, which no longer uses this patch\n" - " • Or migrate to Pydantic models for dataclass behavior\n\n" - ) - -# Warn that this extension is deprecated warnings.warn( "The LinkML dataclass extension patch is deprecated and will be removed in a future release.\n" - "Consider upgrading to LinkML >= 1.9.0 or switching Python class generation to Pydantic.", + "If you're currently using Python < 3.13, where this patch still applies, you should:\n" + " • Upgrade your LinkML tooling to version >= 1.9.0 (which no longer needs this patch), OR\n" + " • Migrate to Pydantic models if you're using LinkML's generated classes at runtime.\n\n" + "If you're currently using Python >= 3.13, this patch is ignored.", DeprecationWarning, - stacklevel=2, + stacklevel=2 ) -# Conditionally patch only if _create_fn exists -if hasattr(dataclasses, "_create_fn"): - loc_fn = dataclasses._create_fn +# In Python < 3.13, still apply the dataclass extension patch +if sys.version_info < (3, 13): + import dataclasses - def dc_create_fn(name, args, body, *_posargs, **_kwargs): - if name == '__init__' and dataclasses._POST_INIT_NAME in body[-1]: - pi_parms = body[-1].rsplit(')', 1)[0] - body[-1] = pi_parms + ('' if pi_parms[-1] == '(' else ',') + ' **_kwargs)' - return loc_fn(name, list(args) + ["**_kwargs"], body, *_posargs, **_kwargs) - else: - return loc_fn(name, args, body, *_posargs, **_kwargs) + if hasattr(dataclasses, "_create_fn"): + loc_fn = dataclasses._create_fn - dataclasses._create_fn = dc_create_fn - dataclasses_init_fn_with_kwargs = dataclasses._init_fn + def dc_create_fn(name, args, body, *_posargs, **_kwargs): + if name == '__init__' and dataclasses._POST_INIT_NAME in body[-1]: + pi_parms = body[-1].rsplit(')', 1)[0] + body[-1] = pi_parms + ('' if pi_parms[-1] == '(' else ',') + ' **_kwargs)' + return loc_fn(name, list(args) + ["**_kwargs"], body, *_posargs, **_kwargs) + else: + return loc_fn(name, args, body, *_posargs, **_kwargs) - warnings.warn( - "LinkML dataclass patch successfully applied.", - UserWarning, - stacklevel=2, - ) -else: - raise RuntimeError( - "The LinkML dataclass_extensions_376 patch could not be applied: `dataclasses._create_fn` is missing.\n\n" - "This likely indicates a nonstandard or altered Python environment, or partial compatibility with this patch.\n\n" - "To proceed:\n" - " • Use a supported Python version where `_create_fn` is present (Python < 3.13)\n" - " • Or upgrade to LinkML >= 1.9.0 to remove reliance on this patch\n" - " • Or migrate to Pydantic models\n\n" - ) + dataclasses._create_fn = dc_create_fn + dataclasses_init_fn_with_kwargs = dataclasses._init_fn -# Used to signal that this patch was imported/applied -DC_CREATE_FN = True \ No newline at end of file + DC_CREATE_FN = True + else: + warnings.warn( + "The LinkML dataclass patch could not be applied because `dataclasses._create_fn` is missing.\n" + "This may indicate a nonstandard Python environment. " + "Please upgrade to LinkML >= 1.9.0 or migrate to Pydantic.", + RuntimeWarning, + stacklevel=2, + ) diff --git a/tests/test_issues/test_dataclass_extensions_376.py b/tests/test_issues/test_dataclass_extensions_376.py index d2941b4b..ae4aa4af 100644 --- a/tests/test_issues/test_dataclass_extensions_376.py +++ b/tests/test_issues/test_dataclass_extensions_376.py @@ -43,7 +43,12 @@ def __post_init__(self, **kwargs): @pytest.mark.skipif(sys.version_info < (3, 13), reason="This test only applies to Python 3.13+") -def test_patch_fails_on_python_3_13_plus(): - """Ensure the patch raises a RuntimeError on Python 3.13+""" - with pytest.raises(RuntimeError, match="no longer compatible with Python 3.13 or newer"): - importlib.import_module("linkml_runtime.utils.dataclass_extensions_376") +def test_patch_module_is_ignored_on_python_3_13_plus(): + """Ensure the patch module is importable and emits a DeprecationWarning on Python 3.13+""" + with pytest.warns(DeprecationWarning, match="deprecated and will be removed in a future release"): + import importlib.util + + spec = importlib.util.find_spec("linkml_runtime.utils.dataclass_extensions_376") + mod = importlib.util.module_from_spec(spec) + spec.loader.exec_module(mod) + From 968e3ef9f605d908f01254f2d7725e7e9cfebb1c Mon Sep 17 00:00:00 2001 From: Sierra Taylor Moxon Date: Mon, 31 Mar 2025 15:28:27 -0700 Subject: [PATCH 09/16] alternative approach, just gut the module. --- .../utils/dataclass_extensions_376.py | 32 +-------- .../test_dataclass_extensions_376.py | 69 +++++++------------ 2 files changed, 29 insertions(+), 72 deletions(-) diff --git a/linkml_runtime/utils/dataclass_extensions_376.py b/linkml_runtime/utils/dataclass_extensions_376.py index 17cc1bd1..0a0e0475 100644 --- a/linkml_runtime/utils/dataclass_extensions_376.py +++ b/linkml_runtime/utils/dataclass_extensions_376.py @@ -5,36 +5,10 @@ "The LinkML dataclass extension patch is deprecated and will be removed in a future release.\n" "If you're currently using Python < 3.13, where this patch still applies, you should:\n" " • Upgrade your LinkML tooling to version >= 1.9.0 (which no longer needs this patch), OR\n" - " • Migrate to Pydantic models if you're using LinkML's generated classes at runtime.\n\n" - "If you're currently using Python >= 3.13, this patch is ignored.", + " • Migrate to Pydantic models if you're using LinkML's generated classes at runtime.\n", DeprecationWarning, stacklevel=2 ) -# In Python < 3.13, still apply the dataclass extension patch -if sys.version_info < (3, 13): - import dataclasses - - if hasattr(dataclasses, "_create_fn"): - loc_fn = dataclasses._create_fn - - def dc_create_fn(name, args, body, *_posargs, **_kwargs): - if name == '__init__' and dataclasses._POST_INIT_NAME in body[-1]: - pi_parms = body[-1].rsplit(')', 1)[0] - body[-1] = pi_parms + ('' if pi_parms[-1] == '(' else ',') + ' **_kwargs)' - return loc_fn(name, list(args) + ["**_kwargs"], body, *_posargs, **_kwargs) - else: - return loc_fn(name, args, body, *_posargs, **_kwargs) - - dataclasses._create_fn = dc_create_fn - dataclasses_init_fn_with_kwargs = dataclasses._init_fn - - DC_CREATE_FN = True - else: - warnings.warn( - "The LinkML dataclass patch could not be applied because `dataclasses._create_fn` is missing.\n" - "This may indicate a nonstandard Python environment. " - "Please upgrade to LinkML >= 1.9.0 or migrate to Pydantic.", - RuntimeWarning, - stacklevel=2, - ) +dataclasses_init_fn_with_kwargs = None +DC_CREATE_FN = False \ No newline at end of file diff --git a/tests/test_issues/test_dataclass_extensions_376.py b/tests/test_issues/test_dataclass_extensions_376.py index ae4aa4af..c6f46442 100644 --- a/tests/test_issues/test_dataclass_extensions_376.py +++ b/tests/test_issues/test_dataclass_extensions_376.py @@ -1,54 +1,37 @@ import sys import pytest -from dataclasses import dataclass -from typing import Optional -import importlib +import importlib.util -# Only import the LinkML patch module on supported Python versions -# Python 3.13+ removed dataclasses._create_fn, which breaks this patch. -if sys.version_info < (3, 13): - import linkml_runtime.utils.dataclass_extensions_376 as dc_tweak - DC_IN = dc_tweak.DC_CREATE_FN -else: - dc_tweak = None - DC_IN = False +def import_patch_module(): + """Fresh import to ensure warning is triggered""" + spec = importlib.util.find_spec("linkml_runtime.utils.dataclass_extensions_376") + mod = importlib.util.module_from_spec(spec) + spec.loader.exec_module(mod) + return mod -@pytest.mark.skipif(sys.version_info >= (3, 13), reason="LinkML dataclass patch no longer supported in Python 3.13+") -def test_kwargs_passed_to_post_init(): - """Test that kwargs are passed to __post_init__ in patched dataclass""" +def test_patch_module_emits_deprecation_warning(): + """All Python versions: emits DeprecationWarning and defines compatibility symbols""" + with pytest.warns(DeprecationWarning): + mod = import_patch_module() - @dataclass - class TestClass: - a: Optional[int] = 0 - b: Optional[str] = None + assert hasattr(mod, "DC_CREATE_FN") + assert hasattr(mod, "dataclasses_init_fn_with_kwargs") + assert mod.DC_CREATE_FN is False + assert mod.dataclasses_init_fn_with_kwargs is None - def __post_init__(self, **kwargs): - if kwargs: - unknown_args = sorted(kwargs.keys()) - first_arg = unknown_args[0] - raise ValueError(f"Unknown argument: {first_arg} = {repr(kwargs[first_arg])}") - # No extra kwargs – should not raise - TestClass(a=1, b="test") +@pytest.mark.skipif(sys.version_info >= (3, 13), reason="dataclass patch behavior was only relevant pre-3.13") +def test_behavior_without_patch_pre_3_13(): + """Ensure standard dataclass behavior (no patch) in <3.13""" + import dataclasses - # One unknown kwarg – should raise - with pytest.raises(ValueError, match="Unknown argument: c = 'unknown'"): - TestClass(a=1, b="test", c="unknown") - - # Multiple unknown kwargs – should raise, first alphabetically - with pytest.raises(ValueError, match="Unknown argument: c = 'unknown'"): - TestClass(a=1, b="test", c="unknown", z="also_unknown") - - -@pytest.mark.skipif(sys.version_info < (3, 13), reason="This test only applies to Python 3.13+") -def test_patch_module_is_ignored_on_python_3_13_plus(): - """Ensure the patch module is importable and emits a DeprecationWarning on Python 3.13+""" - with pytest.warns(DeprecationWarning, match="deprecated and will be removed in a future release"): - import importlib.util - - spec = importlib.util.find_spec("linkml_runtime.utils.dataclass_extensions_376") - mod = importlib.util.module_from_spec(spec) - spec.loader.exec_module(mod) + with pytest.raises(TypeError): + @dataclasses.dataclass + class Example: + a: int + def __post_init__(self, **kwargs): pass + # This will fail because unknown kwarg 'extra' is not accepted + Example(a=1, extra="not allowed") From 8fcfb009a6f4cddee86ade03c097ca041298e81e Mon Sep 17 00:00:00 2001 From: Sierra Taylor Moxon Date: Tue, 1 Apr 2025 15:42:24 -0700 Subject: [PATCH 10/16] test out change to dataclasses_init_fn_with_kwargs = dataclasses._init_fn --- linkml_runtime/utils/dataclass_extensions_376.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/linkml_runtime/utils/dataclass_extensions_376.py b/linkml_runtime/utils/dataclass_extensions_376.py index 0a0e0475..4321855d 100644 --- a/linkml_runtime/utils/dataclass_extensions_376.py +++ b/linkml_runtime/utils/dataclass_extensions_376.py @@ -1,5 +1,6 @@ import sys import warnings +import dataclasses warnings.warn( "The LinkML dataclass extension patch is deprecated and will be removed in a future release.\n" @@ -10,5 +11,5 @@ stacklevel=2 ) -dataclasses_init_fn_with_kwargs = None +dataclasses_init_fn_with_kwargs = dataclasses._init_fn DC_CREATE_FN = False \ No newline at end of file From 193cdb5b677561d40de9218d91c07d477b945d28 Mon Sep 17 00:00:00 2001 From: Sierra Taylor Moxon Date: Tue, 1 Apr 2025 16:12:40 -0700 Subject: [PATCH 11/16] fix tests --- .../test_dataclass_extensions_376.py | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/tests/test_issues/test_dataclass_extensions_376.py b/tests/test_issues/test_dataclass_extensions_376.py index c6f46442..093a233e 100644 --- a/tests/test_issues/test_dataclass_extensions_376.py +++ b/tests/test_issues/test_dataclass_extensions_376.py @@ -1,6 +1,7 @@ import sys import pytest import importlib.util +import dataclasses def import_patch_module(): @@ -10,7 +11,6 @@ def import_patch_module(): spec.loader.exec_module(mod) return mod - def test_patch_module_emits_deprecation_warning(): """All Python versions: emits DeprecationWarning and defines compatibility symbols""" with pytest.warns(DeprecationWarning): @@ -19,19 +19,9 @@ def test_patch_module_emits_deprecation_warning(): assert hasattr(mod, "DC_CREATE_FN") assert hasattr(mod, "dataclasses_init_fn_with_kwargs") assert mod.DC_CREATE_FN is False - assert mod.dataclasses_init_fn_with_kwargs is None - -@pytest.mark.skipif(sys.version_info >= (3, 13), reason="dataclass patch behavior was only relevant pre-3.13") -def test_behavior_without_patch_pre_3_13(): - """Ensure standard dataclass behavior (no patch) in <3.13""" - import dataclasses + # Check consistency with actual dataclasses module + init_fn = getattr(dataclasses, "_init_fn", None) + assert mod.dataclasses_init_fn_with_kwargs == init_fn - with pytest.raises(TypeError): - @dataclasses.dataclass - class Example: - a: int - def __post_init__(self, **kwargs): pass - # This will fail because unknown kwarg 'extra' is not accepted - Example(a=1, extra="not allowed") From 13dccbef2ccd3e6d8165af3956e6eca909540756 Mon Sep 17 00:00:00 2001 From: Sierra Taylor Moxon Date: Wed, 2 Apr 2025 11:49:34 -0700 Subject: [PATCH 12/16] relock with poetry 2.0 --- poetry.lock | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/poetry.lock b/poetry.lock index c5ecd50b..9cb73736 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 2.1.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 2.0.1 and should not be changed by hand. [[package]] name = "annotated-types" @@ -28,12 +28,12 @@ files = [ ] [package.extras] -benchmark = ["cloudpickle ; platform_python_implementation == \"CPython\"", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pympler", "pytest (>=4.3.0)", "pytest-codspeed", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"] -cov = ["cloudpickle ; platform_python_implementation == \"CPython\"", "coverage[toml] (>=5.3)", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"] -dev = ["cloudpickle ; platform_python_implementation == \"CPython\"", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pre-commit-uv", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"] +benchmark = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-codspeed", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +cov = ["cloudpickle", "coverage[toml] (>=5.3)", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +dev = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pre-commit-uv", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] docs = ["cogapp", "furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier (<24.7)"] -tests = ["cloudpickle ; platform_python_implementation == \"CPython\"", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"] -tests-mypy = ["mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\""] +tests = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +tests-mypy = ["mypy (>=1.11.1)", "pytest-mypy-plugins"] [[package]] name = "cattrs" @@ -56,8 +56,8 @@ typing-extensions = {version = ">=4.1.0,<4.6.3 || >4.6.3", markers = "python_ver bson = ["pymongo (>=4.4.0)"] cbor2 = ["cbor2 (>=5.4.6)"] msgpack = ["msgpack (>=1.0.5)"] -msgspec = ["msgspec (>=0.18.5) ; implementation_name == \"cpython\""] -orjson = ["orjson (>=3.9.2) ; implementation_name == \"cpython\""] +msgspec = ["msgspec (>=0.18.5)"] +orjson = ["orjson (>=3.9.2)"] pyyaml = ["pyyaml (>=6.0)"] tomlkit = ["tomlkit (>=0.11.8)"] ujson = ["ujson (>=5.7.0)"] @@ -265,7 +265,7 @@ files = [ ] [package.extras] -toml = ["tomli ; python_full_version <= \"3.11.0a6\""] +toml = ["tomli"] [[package]] name = "curies" @@ -308,7 +308,7 @@ files = [ wrapt = ">=1.10,<2" [package.extras] -dev = ["PyTest", "PyTest-Cov", "bump2version (<1)", "setuptools ; python_version >= \"3.12\"", "tox"] +dev = ["PyTest", "PyTest-Cov", "bump2version (<1)", "setuptools", "tox"] [[package]] name = "exceptiongroup" @@ -370,7 +370,7 @@ files = [ zipp = {version = ">=3.1.0", markers = "python_version < \"3.10\""} [package.extras] -check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\""] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)"] cover = ["pytest-cov"] doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] enabler = ["pytest-enabler (>=2.2)"] @@ -583,7 +583,7 @@ typing-extensions = ">=4.12.2" [package.extras] email = ["email-validator (>=2.0.0)"] -timezone = ["tzdata ; python_version >= \"3.9\" and platform_system == \"Windows\""] +timezone = ["tzdata"] [[package]] name = "pydantic-core" @@ -1141,7 +1141,7 @@ files = [ ] [package.extras] -brotli = ["brotli (>=1.0.9) ; platform_python_implementation == \"CPython\"", "brotlicffi (>=0.8.0) ; platform_python_implementation != \"CPython\""] +brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] h2 = ["h2 (>=4,<5)"] socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] zstd = ["zstandard (>=0.18.0)"] @@ -1249,11 +1249,11 @@ files = [ ] [package.extras] -check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\""] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)"] cover = ["pytest-cov"] doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] enabler = ["pytest-enabler (>=2.2)"] -test = ["big-O", "importlib-resources ; python_version < \"3.9\"", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-itertools", "pytest (>=6,!=8.1.*)", "pytest-ignore-flaky"] +test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-itertools", "pytest (>=6,!=8.1.*)", "pytest-ignore-flaky"] type = ["pytest-mypy"] [metadata] From 632f6fbde26315225fe071362a627270e35a28be Mon Sep 17 00:00:00 2001 From: Sierra Taylor Moxon Date: Wed, 2 Apr 2025 11:54:59 -0700 Subject: [PATCH 13/16] use same poetry version --- poetry.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/poetry.lock b/poetry.lock index 9cb73736..3732d198 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 2.0.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 2.0.0 and should not be changed by hand. [[package]] name = "annotated-types" From dc19eded398c6fdf694fb1c3d9cc0dfed8af024a Mon Sep 17 00:00:00 2001 From: Sierra Taylor Moxon Date: Wed, 2 Apr 2025 12:05:16 -0700 Subject: [PATCH 14/16] test previous version of poetry --- .github/workflows/test-upstream.yaml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test-upstream.yaml b/.github/workflows/test-upstream.yaml index 1aab649c..a841cc31 100644 --- a/.github/workflows/test-upstream.yaml +++ b/.github/workflows/test-upstream.yaml @@ -118,7 +118,10 @@ jobs: python-version: ${{ matrix.python-version }} - name: Install poetry - run: pipx install poetry + run: pipx install poetry==2.0.0 + + - name: Check Poetry version + run: poetry --version - name: Install dynamic versioning plugin run: poetry self add "poetry-dynamic-versioning[plugin]" From ea110a06a57902fe3f5a287affacbfc8be02385c Mon Sep 17 00:00:00 2001 From: Sierra Taylor Moxon Date: Wed, 2 Apr 2025 12:10:21 -0700 Subject: [PATCH 15/16] poetry 1.x --- .github/workflows/test-upstream.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-upstream.yaml b/.github/workflows/test-upstream.yaml index a841cc31..c767647a 100644 --- a/.github/workflows/test-upstream.yaml +++ b/.github/workflows/test-upstream.yaml @@ -118,7 +118,7 @@ jobs: python-version: ${{ matrix.python-version }} - name: Install poetry - run: pipx install poetry==2.0.0 + run: pipx install poetry==1.* - name: Check Poetry version run: poetry --version From 8f4ede4258d76c988263f31cbf73d58127a39044 Mon Sep 17 00:00:00 2001 From: Sierra Taylor Moxon Date: Fri, 4 Apr 2025 14:53:28 -0700 Subject: [PATCH 16/16] null change to retrigger actions using upstream - hopefully - branch --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4020b7c9..d48c3cc2 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ [![PyPIDownloadsMonth](https://img.shields.io/pypi/dm/linkml-runtime?logo=PyPI&color=blue)](https://pypi.org/project/linkml-runtime) [![codecov](https://codecov.io/gh/linkml/linkml-runtime/branch/main/graph/badge.svg?token=FOBHNSK5WG)](https://codecov.io/gh/linkml/linkml-runtime) -Runtime support for linkml generated data classes +Runtime support for linkml generated data classes. ## About