Skip to content

SchemaGenerator — duplicated branches in oneOf unions make valid entries fail strict validation #446

Description

@GamelinAl

Summary

In accelerator.schema.json several classes appear twice in a oneOf union: once directly and once inside a nested union of their base class. JSON Schema oneOf requires exactly one match, so every such entry is rejected with "is valid under each of …" / "Matches multiple schemas when only one must validate" (yaml-language-server), even though it is correct.

Affected:

  • properties.devices.items.oneOf: HCorrector, VCorrector, Quadrupole, SkewQuad, Sextupole, Octupole, SkewSext, SkewOctu, CombinedFunctionMagnet are listed directly and inside the nested MagnetConfigurationSchema oneOf (item 4); same pattern for MeasurementToolConfigurationSchema / TuningToolConfigurationSchema (items 21, 26).
  • StaticCatalogEntry.properties.device.oneOf: tango.pyaml.attribute_read_only.AttributeReadOnly and the pyaml_cs_oa.epics* classes appear directly and in a nested oneOf.

Reproduction

import json, jsonschema
s = json.load(open("schemas/accelerator.schema.json"))
branches = s["properties"]["devices"]["anyOf"][0]["items"]["oneOf"]
q = {"class": "pyaml.magnet.quadrupole.Quadrupole", "name": "Q1",
     "model": {"class": "pyaml.magnet.linear_model.LinearMagnetModel", "unit": "1/m", "hardware_unit": "A"}}
print(sum(jsonschema.Draft202012Validator(b).is_valid(q) for b in branches))   # 2  -> oneOf fails

On a real configuration (SOLEIL storage ring, 569 devices / 698 catalog entries): 429 devices and 257 catalog entries are rejected for this reason only; with oneOf rewritten to anyOf the configuration validates with 0 errors.

Cause

model_schema builds the union of all registry entries that are subclasses of the model (issubclass(schema_cls, model_cls)), including intermediate base classes (MagnetConfigurationSchema, …) whose own schema is again expanded into a union of the same leaves — so leaves are emitted twice. The TODO: get the schemas to work when using oneOf instead comment at generator.py:232 seems related.

Expected

Either flatten unions (emit each concrete class once, skip intermediate bases that expand to a union), or emit anyOf — as the docstring of model_schema (lines 184-187) actually recommends.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions