Script 'mail_helper' called by obssrc
Hello community,
here is the log from the commit of package python-mashumaro for
openSUSE:Factory checked in at 2026-02-05 18:00:32
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-mashumaro (Old)
and /work/SRC/openSUSE:Factory/.python-mashumaro.new.1670 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-mashumaro"
Thu Feb 5 18:00:32 2026 rev:7 rq:1331141 version:3.19
Changes:
--------
--- /work/SRC/openSUSE:Factory/python-mashumaro/python-mashumaro.changes
2026-02-03 21:32:04.906123437 +0100
+++
/work/SRC/openSUSE:Factory/.python-mashumaro.new.1670/python-mashumaro.changes
2026-02-05 18:05:51.129329167 +0100
@@ -1,0 +2,7 @@
+Wed Feb 4 07:55:29 UTC 2026 - Johannes Kastl
<[email protected]>
+
+- update to 3.19:
+ * Added support for recursive types in JSON Schema (#303)
+ * Added "Trusted Publishing" workflow (#304)
+
+-------------------------------------------------------------------
Old:
----
mashumaro-3.18.tar.gz
New:
----
mashumaro-3.19.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-mashumaro.spec ++++++
--- /var/tmp/diff_new_pack.t8dCYU/_old 2026-02-05 18:05:52.169372795 +0100
+++ /var/tmp/diff_new_pack.t8dCYU/_new 2026-02-05 18:05:52.185373466 +0100
@@ -18,7 +18,7 @@
%{?sle15_python_module_pythons}
Name: python-mashumaro
-Version: 3.18
+Version: 3.19
Release: 0
Summary: Fast and well tested serialization library
License: Apache-2.0
++++++ mashumaro-3.18.tar.gz -> mashumaro-3.19.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/mashumaro-3.18/.github/workflows/publish.yml
new/mashumaro-3.19/.github/workflows/publish.yml
--- old/mashumaro-3.18/.github/workflows/publish.yml 1970-01-01
01:00:00.000000000 +0100
+++ new/mashumaro-3.19/.github/workflows/publish.yml 2026-02-03
20:07:21.000000000 +0100
@@ -0,0 +1,38 @@
+name: publish.yml
+on:
+ release:
+ types:
+ - published
+
+jobs:
+ pypi-publish:
+ name: Upload release to PyPI
+ runs-on: ubuntu-latest
+ permissions:
+ contents: read
+ id-token: write
+ environment:
+ name: pypi
+ url: https://pypi.org/project/mashumaro/
+
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v6
+
+ - name: Set up Python 3.14
+ uses: actions/setup-python@v6
+ with:
+ python-version: "3.14"
+
+ - name: Install Poetry
+ run: |
+ curl -sSL https://install.python-poetry.org | python - -y
+
+ - name: Install dependencies
+ run: poetry install --no-interaction --no-root
+
+ - name: Build
+ run: poetry build
+
+ - name: Publish to PyPI
+ uses: pypa/gh-action-pypi-publish@release/v1
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/mashumaro-3.18/mashumaro/jsonschema/models.py
new/mashumaro-3.19/mashumaro/jsonschema/models.py
--- old/mashumaro-3.18/mashumaro/jsonschema/models.py 2026-01-30
19:30:35.000000000 +0100
+++ new/mashumaro-3.19/mashumaro/jsonschema/models.py 2026-02-03
20:07:21.000000000 +0100
@@ -210,3 +210,5 @@
all_refs: Optional[bool] = None
ref_prefix: Optional[str] = None
plugins: Sequence[BasePlugin] = ()
+ # PEP 695 TypeAliasType recursion guard
+ _building_type_aliases: set[int] = field(default_factory=set, repr=False)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/mashumaro-3.18/mashumaro/jsonschema/schema.py
new/mashumaro-3.19/mashumaro/jsonschema/schema.py
--- old/mashumaro-3.18/mashumaro/jsonschema/schema.py 2026-01-30
19:30:35.000000000 +0100
+++ new/mashumaro-3.19/mashumaro/jsonschema/schema.py 2026-02-03
20:07:21.000000000 +0100
@@ -317,6 +317,15 @@
register = Registry.register
+def _type_alias_definition_name(alias_type: Any) -> str:
+ """Return a stable $defs key for PEP 695 TypeAliasType."""
+
+ name = getattr(alias_type, "__name__", None)
+ if isinstance(name, str) and name:
+ return name
+ return clean_id(str(id(alias_type)))
+
+
BASIC_TYPES = {str, int, float, bool}
@@ -474,7 +483,36 @@
if evaluated is not None:
return get_schema(instance.derive(type=evaluated), ctx)
elif is_type_alias_type(instance.type):
- return get_schema(instance.derive(type=instance.type.__value__), ctx)
+ alias_type = instance.type
+ def_name = _type_alias_definition_name(alias_type)
+ alias_id = id(alias_type)
+ ref_prefix = ctx.ref_prefix or ctx.dialect.definitions_root_pointer
+
+ # If we're already building this alias, it's recursion.
+ # In that case, force using $ref/$defs.
+ if alias_id in ctx._building_type_aliases:
+ # The $defs placeholder may not exist yet (mutual recursion).
+ ctx.definitions.setdefault(def_name, EmptyJSONSchema())
+ return JSONSchema(reference=f"{ref_prefix}/{def_name}")
+
+ ctx._building_type_aliases.add(alias_id)
+ try:
+ value_schema = get_schema(
+ instance.derive(type=alias_type.__value__), ctx
+ )
+ finally:
+ ctx._building_type_aliases.discard(alias_id)
+
+ # If the alias is marked as recursive (direct or mutual),
+ # store its definition in $defs and return a $ref.
+ if def_name in ctx.definitions or ctx.all_refs:
+ existing = ctx.definitions.get(def_name)
+ if existing is None or isinstance(existing, EmptyJSONSchema):
+ ctx.definitions[def_name] = value_schema
+ return JSONSchema(reference=f"{ref_prefix}/{def_name}")
+
+ # Non-recursive alias: return the schema directly, without $defs.
+ return value_schema
@register
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/mashumaro-3.18/pyproject.toml
new/mashumaro-3.19/pyproject.toml
--- old/mashumaro-3.18/pyproject.toml 2026-01-30 19:30:35.000000000 +0100
+++ new/mashumaro-3.19/pyproject.toml 2026-02-03 20:07:21.000000000 +0100
@@ -4,7 +4,7 @@
[project]
name = "mashumaro"
-version = "3.18"
+version = "3.19"
license = "Apache-2.0"
description = "Fast and well tested serialization library"
readme = "README.md"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/mashumaro-3.18/tests/test_jsonschema/test_jsonschema_pep_695.py
new/mashumaro-3.19/tests/test_jsonschema/test_jsonschema_pep_695.py
--- old/mashumaro-3.18/tests/test_jsonschema/test_jsonschema_pep_695.py
2026-01-30 19:30:35.000000000 +0100
+++ new/mashumaro-3.19/tests/test_jsonschema/test_jsonschema_pep_695.py
2026-02-03 20:07:21.000000000 +0100
@@ -1,9 +1,137 @@
-type MyTypeAliasType = int | str
+from mashumaro.core.meta.types.common import clean_id
from mashumaro.jsonschema import build_json_schema
+from mashumaro.jsonschema.models import Context
+from mashumaro.jsonschema.schema import _type_alias_definition_name
+
+type JSON = int | str | float | bool | None | list[JSON] | dict[str, JSON]
+type X = int | str
+type A = int | list[B]
+type B = str | list[A]
def test_type_alias_type_with_jsonschema():
- schema = build_json_schema(MyTypeAliasType)
+ schema = build_json_schema(X)
assert schema.to_dict() == {
"anyOf": [{"type": "integer"}, {"type": "string"}]
}
+
+
+def test_jsonschema_for_recursive_union() -> None:
+ schema = build_json_schema(JSON)
+ assert schema.to_dict() == {
+ "$ref": "#/$defs/JSON",
+ "$defs": {
+ "JSON": {
+ "anyOf": [
+ {"type": "integer"},
+ {"type": "string"},
+ {"type": "number"},
+ {"type": "boolean"},
+ {"type": "null"},
+ {"type": "array", "items": {"$ref": "#/$defs/JSON"}},
+ {
+ "type": "object",
+ "additionalProperties": {"$ref": "#/$defs/JSON"},
+ "propertyNames": {"type": "string"},
+ },
+ ]
+ }
+ },
+ }
+
+
+def test_jsonschema_for_mutual_recursive_type_aliases_without_refs() -> None:
+ schema = build_json_schema(A)
+ assert schema.to_dict() == {
+ "$ref": "#/$defs/A",
+ "$defs": {
+ "A": {
+ "anyOf": [
+ {"type": "integer"},
+ {
+ "type": "array",
+ "items": {
+ "anyOf": [
+ {"type": "string"},
+ {
+ "type": "array",
+ "items": {"$ref": "#/$defs/A"},
+ },
+ ]
+ },
+ },
+ ]
+ }
+ },
+ }
+
+
+def test_jsonschema_for_mutual_recursive_type_aliases_with_refs() -> None:
+ schema = build_json_schema(A, all_refs=True)
+ assert schema.to_dict() == {
+ "$ref": "#/$defs/A",
+ "$defs": {
+ "A": {
+ "anyOf": [
+ {"type": "integer"},
+ {"type": "array", "items": {"$ref": "#/$defs/B"}},
+ ]
+ },
+ "B": {
+ "anyOf": [
+ {"type": "string"},
+ {"type": "array", "items": {"$ref": "#/$defs/A"}},
+ ]
+ },
+ },
+ }
+
+
+def test_type_alias_non_recursive_inlines_when_all_refs_false() -> None:
+ schema = build_json_schema(X, all_refs=False)
+ assert schema.to_dict() == {
+ "anyOf": [
+ {"type": "integer"},
+ {"type": "string"},
+ ]
+ }
+
+
+def test_type_alias_non_recursive_uses_defs_when_all_refs_true() -> None:
+ schema = build_json_schema(X, all_refs=True)
+ assert schema.to_dict() == {
+ "$ref": "#/$defs/X",
+ "$defs": {
+ "X": {
+ "anyOf": [
+ {"type": "integer"},
+ {"type": "string"},
+ ]
+ }
+ },
+ }
+
+
+def test_type_alias_placeholder_not_leaking_into_context_defs() -> None:
+ # Ensure that for non-recursive aliases with all_refs=False we don't leave
+ # unused entries in Context.definitions.
+ ctx = Context()
+ schema = build_json_schema(X, context=ctx, all_refs=False)
+ assert schema.to_dict() == {
+ "anyOf": [
+ {"type": "integer"},
+ {"type": "string"},
+ ]
+ }
+ assert ctx.definitions == {}
+
+
+def test_type_alias_definition_name_falls_back_to_clean_id_when_name_empty()
-> (
+ None
+):
+ class NamelessAlias:
+ __name__ = ""
+
+ alias = NamelessAlias()
+
+ assert _type_alias_definition_name(alias) == clean_id(str(id(alias)))