diff --git a/src/schema_salad/codegen_base.py b/src/schema_salad/codegen_base.py index 2f285c52..870616e1 100644 --- a/src/schema_salad/codegen_base.py +++ b/src/schema_salad/codegen_base.py @@ -23,6 +23,7 @@ class LazyInitDef(NamedTuple): name: str init: str + instance_type: str | None = None class CodeGenBase: diff --git a/src/schema_salad/metaschema.py b/src/schema_salad/metaschema.py index 811937a9..139dd362 100644 --- a/src/schema_salad/metaschema.py +++ b/src/schema_salad/metaschema.py @@ -25,12 +25,18 @@ from typing_extensions import Self import copy +from abc import ABCMeta, abstractmethod from collections.abc import MutableSequence, Sequence, MutableMapping from io import StringIO from itertools import chain +from typing import Literal, TypeVar # pylint: disable=unused-import # noqa: F401 +from collections.abc import Mapping +from typing import TypeAlias # pylint: disable=unused-import # noqa: F401 from typing import Any, Final, cast, Generic from urllib.parse import urldefrag, urlsplit, urlunsplit +from mypy_extensions import i32, i64 # pylint: disable=unused-import # noqa: F401 +from mypy_extensions import mypyc_attr from ruamel.yaml.comments import CommentedMap from schema_salad.exceptions import ValidationException, SchemaSaladException @@ -39,6 +45,8 @@ convert_typing, extract_type, SaveableType, + FieldType, + EnumFieldType, ) from schema_salad.sourceline import SourceLine, add_lc_filename from schema_salad.utils import yaml_no_ts # requires schema-salad v8.2+ @@ -47,7 +55,9 @@ _rvocab: Final[dict[str, str]] = {} -class _Loader: +@mypyc_attr(native_class=True) +class _Loader(Generic[FieldType], metaclass=ABCMeta): + @abstractmethod def load( self, doc: Any, @@ -55,11 +65,11 @@ def load( loadingOptions: LoadingOptions, docRoot: str | None = None, lc: Any | None = None, - ) -> Any | None: - pass + ) -> FieldType: ... -class _AnyLoader(_Loader): +@mypyc_attr(native_class=True) +class _AnyLoader(_Loader[Any]): def load( self, doc: Any, @@ -73,8 +83,9 @@ def load( raise ValidationException("Expected non-null") -class _PrimitiveLoader(_Loader): - def __init__(self, tp: type | tuple[type[str], type[str]]) -> None: +@mypyc_attr(native_class=True) +class _PrimitiveLoader(_Loader[FieldType]): + def __init__(self, tp: type[FieldType]) -> None: self.tp: Final = tp def load( @@ -84,7 +95,7 @@ def load( loadingOptions: LoadingOptions, docRoot: str | None = None, lc: Any | None = None, - ) -> Any: + ) -> FieldType: if not isinstance(doc, self.tp): raise ValidationException(f"Expected a {self.tp} but got {doc.__class__.__name__}") return doc @@ -93,8 +104,9 @@ def __repr__(self) -> str: return str(self.tp) -class _ArrayLoader(_Loader): - def __init__(self, items: _Loader) -> None: +@mypyc_attr(native_class=True) +class _ArrayLoader(_Loader[Sequence[FieldType]]): + def __init__(self, items: _Loader[FieldType]) -> None: self.items: Final = items def load( @@ -104,7 +116,7 @@ def load( loadingOptions: LoadingOptions, docRoot: str | None = None, lc: Any | None = None, - ) -> list[Any]: + ) -> list[FieldType]: if not isinstance(doc, MutableSequence): raise ValidationException( f"Value is a {convert_typing(extract_type(type(doc)))}, " @@ -150,10 +162,11 @@ def __repr__(self) -> str: return f"array<{self.items}>" -class _MapLoader(_Loader): +@mypyc_attr(native_class=True) +class _MapLoader(_Loader[Mapping[str, FieldType]]): def __init__( self, - values: _Loader, + values: _Loader[FieldType], name: str | None = None, container: str | None = None, no_link_check: bool | None = None, @@ -170,7 +183,7 @@ def load( loadingOptions: LoadingOptions, docRoot: str | None = None, lc: Any | None = None, - ) -> dict[str, Any]: + ) -> dict[str, FieldType]: if not isinstance(doc, MutableMapping): raise ValidationException(f"Expected a map, was {type(doc)}") if self.container is not None or self.no_link_check is not None: @@ -193,7 +206,8 @@ def __repr__(self) -> str: return self.name if self.name is not None else f"map" -class _EnumLoader(_Loader): +@mypyc_attr(native_class=True) +class _EnumLoader(_Loader[EnumFieldType]): def __init__(self, symbols: Sequence[str], name: str) -> None: self.symbols: Final = symbols self.name: Final = name @@ -205,17 +219,18 @@ def load( loadingOptions: LoadingOptions, docRoot: str | None = None, lc: Any | None = None, - ) -> str: + ) -> EnumFieldType: if doc in self.symbols: - return cast(str, doc) + return cast(EnumFieldType, doc) raise ValidationException(f"Expected one of {self.symbols}") def __repr__(self) -> str: return self.name -class _SecondaryDSLLoader(_Loader): - def __init__(self, inner: _Loader) -> None: +@mypyc_attr(native_class=True) +class _SecondaryDSLLoader(_Loader[FieldType]): + def __init__(self, inner: _Loader[FieldType]) -> None: self.inner: Final = inner def load( @@ -225,7 +240,7 @@ def load( loadingOptions: LoadingOptions, docRoot: str | None = None, lc: Any | None = None, - ) -> Any: + ) -> FieldType: r: Final[list[dict[str, Any]]] = [] match doc: case MutableSequence() as dlist: @@ -287,7 +302,8 @@ def load( return self.inner.load(r, baseuri, loadingOptions, docRoot, lc=lc) -class _RecordLoader(_Loader, Generic[SaveableType]): +@mypyc_attr(native_class=True) +class _RecordLoader(_Loader[SaveableType]): def __init__( self, classtype: type[SaveableType], @@ -321,7 +337,8 @@ def __repr__(self) -> str: return str(self.classtype.__name__) -class _ExpressionLoader(_Loader): +@mypyc_attr(native_class=True) +class _ExpressionLoader(_Loader[str]): def __init__(self, items: type[str]) -> None: self.items: Final = items @@ -342,12 +359,13 @@ def load( return doc -class _UnionLoader(_Loader): - def __init__(self, alternates: Sequence[_Loader], name: str | None = None) -> None: +@mypyc_attr(native_class=True) +class _UnionLoader(_Loader[FieldType]): + def __init__(self, alternates: Sequence[_Loader[FieldType]], name: str | None = None) -> None: self.alternates = alternates self.name: Final = name - def add_loaders(self, loaders: Sequence[_Loader]) -> None: + def add_loaders(self, loaders: Sequence[_Loader[FieldType]]) -> None: self.alternates = tuple(loader for loader in chain(self.alternates, loaders)) def load( @@ -357,7 +375,7 @@ def load( loadingOptions: LoadingOptions, docRoot: str | None = None, lc: Any | None = None, - ) -> Any: + ) -> FieldType: errors: Final = [] if lc is None: @@ -432,10 +450,11 @@ def __repr__(self) -> str: return self.name if self.name is not None else " | ".join(str(a) for a in self.alternates) -class _URILoader(_Loader): +@mypyc_attr(native_class=True) +class _URILoader(_Loader[FieldType]): def __init__( self, - inner: _Loader, + inner: _Loader[FieldType], scoped_id: bool, vocab_term: bool, scoped_ref: int | None, @@ -454,7 +473,7 @@ def load( loadingOptions: LoadingOptions, docRoot: str | None = None, lc: Any | None = None, - ) -> Any: + ) -> FieldType: if self.no_link_check is not None: loadingOptions = LoadingOptions( copyfrom=loadingOptions, no_link_check=self.no_link_check @@ -501,10 +520,11 @@ def load( return self.inner.load(doc, baseuri, loadingOptions, lc=lc) -class _TypeDSLLoader(_Loader): +@mypyc_attr(native_class=True) +class _TypeDSLLoader(_Loader[FieldType]): def __init__( self, - inner: _Loader, + inner: _Loader[FieldType], refScope: int | None, salad_version: str, ) -> None: @@ -575,7 +595,7 @@ def load( loadingOptions: LoadingOptions, docRoot: str | None = None, lc: Any | None = None, - ) -> Any: + ) -> FieldType: if isinstance(doc, MutableSequence): r: Final[list[Any]] = [] for d in doc: @@ -597,8 +617,10 @@ def load( return self.inner.load(doc, baseuri, loadingOptions, lc=lc) -class _IdMapLoader(_Loader): - def __init__(self, inner: _Loader, mapSubject: str, mapPredicate: str | None) -> None: +class _IdMapLoader(_Loader[FieldType]): + def __init__( + self, inner: _Loader[FieldType], mapSubject: str, mapPredicate: str | None + ) -> None: self.inner: Final = inner self.mapSubject: Final = mapSubject self.mapPredicate: Final = mapPredicate @@ -610,7 +632,7 @@ def load( loadingOptions: LoadingOptions, docRoot: str | None = None, lc: Any | None = None, - ) -> Any: + ) -> FieldType: if isinstance(doc, MutableMapping): r: Final[list[Any]] = [] for k in doc.keys(): @@ -637,12 +659,12 @@ def load( def _document_load( - loader: _Loader, + loader: _Loader[FieldType], doc: str | MutableMapping[str, Any] | MutableSequence[Any], baseuri: str, loadingOptions: LoadingOptions, addl_metadata_fields: MutableSequence[str] | None = None, -) -> tuple[Any, LoadingOptions]: +) -> tuple[FieldType, LoadingOptions]: if isinstance(doc, str): return _document_load_by_url( loader, @@ -707,11 +729,11 @@ def _document_load( def _document_load_by_url( - loader: _Loader, + loader: _Loader[FieldType], url: str, loadingOptions: LoadingOptions, addl_metadata_fields: MutableSequence[str] | None = None, -) -> tuple[Any, LoadingOptions]: +) -> tuple[FieldType, LoadingOptions]: if url in loadingOptions.idx: return loadingOptions.idx[url] @@ -807,11 +829,11 @@ def _expand_url( def _load_field( val: Any | None, - fieldtype: "_Loader", + fieldtype: _Loader[FieldType], baseuri: str, loadingOptions: LoadingOptions, lc: Any | None = None, -) -> Any: +) -> FieldType: """Load field.""" if isinstance(val, MutableMapping): if "$import" in val: @@ -838,11 +860,8 @@ def parser_info() -> str: return "org.w3id.cwl.salad" -class Documented(Saveable): - pass - - -class RecordField(Documented): +@mypyc_attr(native_class=True) +class RecordField(Saveable): """ A field of a record. @@ -850,26 +869,6 @@ class RecordField(Documented): name: str - def __init__( - self, - name: Any, - type_: Any, - doc: Any | None = None, - extension_fields: MutableMapping[str, Any] | None = None, - loadingOptions: LoadingOptions | None = None, - ) -> None: - if extension_fields: - self.extension_fields = extension_fields - else: - self.extension_fields = CommentedMap() - if loadingOptions: - self.loadingOptions = loadingOptions - else: - self.loadingOptions = LoadingOptions() - self.doc = doc - self.name = name if name is not None else "_:" + str(_uuid__.uuid4()) - self.type_ = type_ - def __eq__(self, other: Any) -> bool: if isinstance(other, RecordField): return bool( @@ -944,14 +943,14 @@ def fromDoc( ) ) - __original_name_is_none = name is None if name is None: if docRoot is not None: name = docRoot else: + name = "" _errors__.append(ValidationException("missing name")) - if not __original_name_is_none: - baseuri = cast(str, name) + else: + baseuri = name doc = None if "doc" in _doc: try: @@ -1072,13 +1071,13 @@ def fromDoc( if _errors__: raise ValidationException("", None, _errors__, "*") _constructed = cls( - doc=doc, name=name, + doc=doc, type_=type_, extension_fields=extension_fields, loadingOptions=loadingOptions, ) - loadingOptions.idx[cast(str, name)] = (_constructed, loadingOptions) + loadingOptions.idx[name] = (_constructed, loadingOptions) return _constructed def save( @@ -1093,7 +1092,7 @@ def save( for ef in self.extension_fields: r[ef] = self.extension_fields[ef] if self.name is not None: - u = save_relative_uri(self.name, base_url, True, None, relative_uris) + u = save_relative_uri(self.name, self.name, True, None, relative_uris) r["name"] = u if self.doc is not None: r["doc"] = save( @@ -1112,14 +1111,11 @@ def save( r["$schemas"] = self.loadingOptions.schemas return r - attrs: ClassVar[Collection[str]] = frozenset(["doc", "name", "type"]) - - -class RecordSchema(Saveable): def __init__( self, - type_: Any, - fields: Any | None = None, + name: str, + type_: ArraySchema | EnumSchema | MapSchema | PrimitiveType | RecordSchema | Sequence[ArraySchema | EnumSchema | MapSchema | PrimitiveType | RecordSchema | UnionSchema | str] | UnionSchema | str, + doc: None | Sequence[str] | str = None, extension_fields: MutableMapping[str, Any] | None = None, loadingOptions: LoadingOptions | None = None, ) -> None: @@ -1131,9 +1127,15 @@ def __init__( self.loadingOptions = loadingOptions else: self.loadingOptions = LoadingOptions() - self.fields = fields + self.doc = doc + self.name = name self.type_ = type_ + attrs: ClassVar[Collection[str]] = frozenset(["doc", "name", "type"]) + + +@mypyc_attr(native_class=True) +class RecordSchema(Saveable): def __eq__(self, other: Any) -> bool: if isinstance(other, RecordSchema): return bool(self.fields == other.fields and self.type_ == other.type_) @@ -1311,22 +1313,10 @@ def save( r["$schemas"] = self.loadingOptions.schemas return r - attrs: ClassVar[Collection[str]] = frozenset(["fields", "type"]) - - -class EnumSchema(Saveable): - """ - Define an enumerated type. - - """ - - name: str - def __init__( self, - symbols: Any, - type_: Any, - name: Any | None = None, + type_: Record_name, + fields: None | Sequence[RecordField] = None, extension_fields: MutableMapping[str, Any] | None = None, loadingOptions: LoadingOptions | None = None, ) -> None: @@ -1338,10 +1328,21 @@ def __init__( self.loadingOptions = loadingOptions else: self.loadingOptions = LoadingOptions() - self.name = name if name is not None else "_:" + str(_uuid__.uuid4()) - self.symbols = symbols + self.fields = fields self.type_ = type_ + attrs: ClassVar[Collection[str]] = frozenset(["fields", "type"]) + + +@mypyc_attr(native_class=True) +class EnumSchema(Saveable): + """ + Define an enumerated type. + + """ + + name: str + def __eq__(self, other: Any) -> bool: if isinstance(other, EnumSchema): return bool( @@ -1416,14 +1417,13 @@ def fromDoc( ) ) - __original_name_is_none = name is None if name is None: if docRoot is not None: name = docRoot else: name = "_:" + str(_uuid__.uuid4()) - if not __original_name_is_none: - baseuri = cast(str, name) + else: + baseuri = name try: if _doc.get("symbols") is None: raise ValidationException("missing required field `symbols`", None, []) @@ -1551,7 +1551,7 @@ def fromDoc( extension_fields=extension_fields, loadingOptions=loadingOptions, ) - loadingOptions.idx[cast(str, name)] = (_constructed, loadingOptions) + loadingOptions.idx[name] = (_constructed, loadingOptions) return _constructed def save( @@ -1566,7 +1566,7 @@ def save( for ef in self.extension_fields: r[ef] = self.extension_fields[ef] if self.name is not None: - u = save_relative_uri(self.name, base_url, True, None, relative_uris) + u = save_relative_uri(self.name, self.name, True, None, relative_uris) r["name"] = u if self.symbols is not None: u = save_relative_uri(self.symbols, self.name, True, None, relative_uris) @@ -1584,14 +1584,11 @@ def save( r["$schemas"] = self.loadingOptions.schemas return r - attrs: ClassVar[Collection[str]] = frozenset(["name", "symbols", "type"]) - - -class ArraySchema(Saveable): def __init__( self, - items: Any, - type_: Any, + symbols: Sequence[str], + type_: Enum_name, + name: None | str = None, extension_fields: MutableMapping[str, Any] | None = None, loadingOptions: LoadingOptions | None = None, ) -> None: @@ -1603,9 +1600,15 @@ def __init__( self.loadingOptions = loadingOptions else: self.loadingOptions = LoadingOptions() - self.items = items + self.name = name if name is not None else "_:" + str(_uuid__.uuid4()) + self.symbols = symbols self.type_ = type_ + attrs: ClassVar[Collection[str]] = frozenset(["name", "symbols", "type"]) + + +@mypyc_attr(native_class=True) +class ArraySchema(Saveable): def __eq__(self, other: Any) -> bool: if isinstance(other, ArraySchema): return bool(self.items == other.items and self.type_ == other.type_) @@ -1783,14 +1786,10 @@ def save( r["$schemas"] = self.loadingOptions.schemas return r - attrs: ClassVar[Collection[str]] = frozenset(["items", "type"]) - - -class MapSchema(Saveable): def __init__( self, - type_: Any, - values: Any, + items: ArraySchema | EnumSchema | MapSchema | PrimitiveType | RecordSchema | Sequence[ArraySchema | EnumSchema | MapSchema | PrimitiveType | RecordSchema | UnionSchema | str] | UnionSchema | str, + type_: Array_name, extension_fields: MutableMapping[str, Any] | None = None, loadingOptions: LoadingOptions | None = None, ) -> None: @@ -1802,9 +1801,14 @@ def __init__( self.loadingOptions = loadingOptions else: self.loadingOptions = LoadingOptions() + self.items = items self.type_ = type_ - self.values = values + attrs: ClassVar[Collection[str]] = frozenset(["items", "type"]) + + +@mypyc_attr(native_class=True) +class MapSchema(Saveable): def __eq__(self, other: Any) -> bool: if isinstance(other, MapSchema): return bool(self.type_ == other.type_ and self.values == other.values) @@ -1982,14 +1986,10 @@ def save( r["$schemas"] = self.loadingOptions.schemas return r - attrs: ClassVar[Collection[str]] = frozenset(["type", "values"]) - - -class UnionSchema(Saveable): def __init__( self, - names: Any, - type_: Any, + type_: Map_name, + values: ArraySchema | EnumSchema | MapSchema | PrimitiveType | RecordSchema | Sequence[ArraySchema | EnumSchema | MapSchema | PrimitiveType | RecordSchema | UnionSchema | str] | UnionSchema | str, extension_fields: MutableMapping[str, Any] | None = None, loadingOptions: LoadingOptions | None = None, ) -> None: @@ -2001,9 +2001,14 @@ def __init__( self.loadingOptions = loadingOptions else: self.loadingOptions = LoadingOptions() - self.names = names self.type_ = type_ + self.values = values + + attrs: ClassVar[Collection[str]] = frozenset(["type", "values"]) + +@mypyc_attr(native_class=True) +class UnionSchema(Saveable): def __eq__(self, other: Any) -> bool: if isinstance(other, UnionSchema): return bool(self.names == other.names and self.type_ == other.type_) @@ -2181,28 +2186,10 @@ def save( r["$schemas"] = self.loadingOptions.schemas return r - attrs: ClassVar[Collection[str]] = frozenset(["names", "type"]) - - -class JsonldPredicate(Saveable): - """ - Attached to a record field to define how the parent record field is handled for URI resolution and JSON-LD context generation. - - """ - def __init__( self, - _id: Any | None = None, - _type: Any | None = None, - _container: Any | None = None, - identity: Any | None = None, - noLinkCheck: Any | None = None, - mapSubject: Any | None = None, - mapPredicate: Any | None = None, - refScope: Any | None = None, - typeDSL: Any | None = None, - secondaryFilesDSL: Any | None = None, - subscope: Any | None = None, + names: ArraySchema | EnumSchema | MapSchema | PrimitiveType | RecordSchema | Sequence[ArraySchema | EnumSchema | MapSchema | PrimitiveType | RecordSchema | UnionSchema | str] | UnionSchema | str, + type_: Union_name, extension_fields: MutableMapping[str, Any] | None = None, loadingOptions: LoadingOptions | None = None, ) -> None: @@ -2214,17 +2201,18 @@ def __init__( self.loadingOptions = loadingOptions else: self.loadingOptions = LoadingOptions() - self._id = _id - self._type = _type - self._container = _container - self.identity = identity - self.noLinkCheck = noLinkCheck - self.mapSubject = mapSubject - self.mapPredicate = mapPredicate - self.refScope = refScope - self.typeDSL = typeDSL - self.secondaryFilesDSL = secondaryFilesDSL - self.subscope = subscope + self.names = names + self.type_ = type_ + + attrs: ClassVar[Collection[str]] = frozenset(["names", "type"]) + + +@mypyc_attr(native_class=True) +class JsonldPredicate(Saveable): + """ + Attached to a record field to define how the parent record field is handled for URI resolution and JSON-LD context generation. + + """ def __eq__(self, other: Any) -> bool: if isinstance(other, JsonldPredicate): @@ -2910,6 +2898,42 @@ def save( r["$schemas"] = self.loadingOptions.schemas return r + def __init__( + self, + _id: None | str = None, + _type: None | str = None, + _container: None | str = None, + identity: None | bool = None, + noLinkCheck: None | bool = None, + mapSubject: None | str = None, + mapPredicate: None | str = None, + refScope: None | i32 = None, + typeDSL: None | bool = None, + secondaryFilesDSL: None | bool = None, + subscope: None | str = None, + extension_fields: MutableMapping[str, Any] | None = None, + loadingOptions: LoadingOptions | None = None, + ) -> None: + if extension_fields: + self.extension_fields = extension_fields + else: + self.extension_fields = CommentedMap() + if loadingOptions: + self.loadingOptions = loadingOptions + else: + self.loadingOptions = LoadingOptions() + self._id = _id + self._type = _type + self._container = _container + self.identity = identity + self.noLinkCheck = noLinkCheck + self.mapSubject = mapSubject + self.mapPredicate = mapPredicate + self.refScope = refScope + self.typeDSL = typeDSL + self.secondaryFilesDSL = secondaryFilesDSL + self.subscope = subscope + attrs: ClassVar[Collection[str]] = frozenset( [ "_id", @@ -2927,25 +2951,8 @@ def save( ) +@mypyc_attr(native_class=True) class SpecializeDef(Saveable): - def __init__( - self, - specializeFrom: Any, - specializeTo: Any, - extension_fields: MutableMapping[str, Any] | None = None, - loadingOptions: LoadingOptions | None = None, - ) -> None: - if extension_fields: - self.extension_fields = extension_fields - else: - self.extension_fields = CommentedMap() - if loadingOptions: - self.loadingOptions = loadingOptions - else: - self.loadingOptions = LoadingOptions() - self.specializeFrom = specializeFrom - self.specializeTo = specializeTo - def __eq__(self, other: Any) -> bool: if isinstance(other, SpecializeDef): return bool( @@ -3127,41 +3134,10 @@ def save( r["$schemas"] = self.loadingOptions.schemas return r - attrs: ClassVar[Collection[str]] = frozenset(["specializeFrom", "specializeTo"]) - - -class NamedType(Saveable): - pass - - -class DocType(Documented): - pass - - -class SchemaDefinedType(DocType): - """ - Abstract base for schema-defined types. - - """ - - pass - - -class SaladRecordField(RecordField): - """ - A field of a record. - - """ - - name: str - def __init__( self, - name: Any, - type_: Any, - doc: Any | None = None, - jsonldPredicate: Any | None = None, - default: Any | None = None, + specializeFrom: str, + specializeTo: str, extension_fields: MutableMapping[str, Any] | None = None, loadingOptions: LoadingOptions | None = None, ) -> None: @@ -3173,11 +3149,20 @@ def __init__( self.loadingOptions = loadingOptions else: self.loadingOptions = LoadingOptions() - self.doc = doc - self.name = name if name is not None else "_:" + str(_uuid__.uuid4()) - self.type_ = type_ - self.jsonldPredicate = jsonldPredicate - self.default = default + self.specializeFrom = specializeFrom + self.specializeTo = specializeTo + + attrs: ClassVar[Collection[str]] = frozenset(["specializeFrom", "specializeTo"]) + + +@mypyc_attr(native_class=True) +class SaladRecordField(RecordField): + """ + A field of a record. + + """ + + name: str def __eq__(self, other: Any) -> bool: if isinstance(other, SaladRecordField): @@ -3257,14 +3242,14 @@ def fromDoc( ) ) - __original_name_is_none = name is None if name is None: if docRoot is not None: name = docRoot else: + name = "" _errors__.append(ValidationException("missing name")) - if not __original_name_is_none: - baseuri = cast(str, name) + else: + baseuri = name doc = None if "doc" in _doc: try: @@ -3479,15 +3464,15 @@ def fromDoc( if _errors__: raise ValidationException("", None, _errors__, "*") _constructed = cls( - doc=doc, name=name, + doc=doc, type_=type_, jsonldPredicate=jsonldPredicate, default=default, extension_fields=extension_fields, loadingOptions=loadingOptions, ) - loadingOptions.idx[cast(str, name)] = (_constructed, loadingOptions) + loadingOptions.idx[name] = (_constructed, loadingOptions) return _constructed def save( @@ -3502,7 +3487,7 @@ def save( for ef in self.extension_fields: r[ef] = self.extension_fields[ef] if self.name is not None: - u = save_relative_uri(self.name, base_url, True, None, relative_uris) + u = save_relative_uri(self.name, self.name, True, None, relative_uris) r["name"] = u if self.doc is not None: r["doc"] = save( @@ -3532,29 +3517,13 @@ def save( r["$schemas"] = self.loadingOptions.schemas return r - attrs: ClassVar[Collection[str]] = frozenset( - ["doc", "name", "type", "jsonldPredicate", "default"] - ) - - -class SaladRecordSchema(NamedType, RecordSchema, SchemaDefinedType): - name: str - def __init__( self, - name: Any, - type_: Any, - inVocab: Any | None = None, - fields: Any | None = None, - doc: Any | None = None, - docParent: Any | None = None, - docChild: Any | None = None, - docAfter: Any | None = None, - jsonldPredicate: Any | None = None, - documentRoot: Any | None = None, - abstract: Any | None = None, - extends: Any | None = None, - specialize: Any | None = None, + name: str, + type_: ArraySchema | EnumSchema | MapSchema | PrimitiveType | RecordSchema | Sequence[ArraySchema | EnumSchema | MapSchema | PrimitiveType | RecordSchema | UnionSchema | str] | UnionSchema | str, + doc: None | Sequence[str] | str = None, + jsonldPredicate: JsonldPredicate | None | str = None, + default: Any | None = None, extension_fields: MutableMapping[str, Any] | None = None, loadingOptions: LoadingOptions | None = None, ) -> None: @@ -3566,19 +3535,20 @@ def __init__( self.loadingOptions = loadingOptions else: self.loadingOptions = LoadingOptions() - self.name = name if name is not None else "_:" + str(_uuid__.uuid4()) - self.inVocab = inVocab - self.fields = fields - self.type_ = type_ self.doc = doc - self.docParent = docParent - self.docChild = docChild - self.docAfter = docAfter + self.name = name + self.type_ = type_ self.jsonldPredicate = jsonldPredicate - self.documentRoot = documentRoot - self.abstract = abstract - self.extends = extends - self.specialize = specialize + self.default = default + + attrs: ClassVar[Collection[str]] = frozenset( + ["doc", "name", "type", "jsonldPredicate", "default"] + ) + + +@mypyc_attr(native_class=True) +class SaladRecordSchema(RecordSchema): + name: str def __eq__(self, other: Any) -> bool: if isinstance(other, SaladRecordSchema): @@ -3680,14 +3650,14 @@ def fromDoc( ) ) - __original_name_is_none = name is None if name is None: if docRoot is not None: name = docRoot else: + name = "" _errors__.append(ValidationException("missing name")) - if not __original_name_is_none: - baseuri = cast(str, name) + else: + baseuri = name inVocab = None if "inVocab" in _doc: try: @@ -4294,7 +4264,7 @@ def fromDoc( extension_fields=extension_fields, loadingOptions=loadingOptions, ) - loadingOptions.idx[cast(str, name)] = (_constructed, loadingOptions) + loadingOptions.idx[name] = (_constructed, loadingOptions) return _constructed def save( @@ -4309,7 +4279,7 @@ def save( for ef in self.extension_fields: r[ef] = self.extension_fields[ef] if self.name is not None: - u = save_relative_uri(self.name, base_url, True, None, relative_uris) + u = save_relative_uri(self.name, self.name, True, None, relative_uris) r["name"] = u if self.inVocab is not None: r["inVocab"] = save( @@ -4376,6 +4346,46 @@ def save( r["$schemas"] = self.loadingOptions.schemas return r + def __init__( + self, + name: str, + type_: Record_name, + inVocab: None | bool = None, + fields: None | Sequence[SaladRecordField] = None, + doc: None | Sequence[str] | str = None, + docParent: None | str = None, + docChild: None | Sequence[str] | str = None, + docAfter: None | str = None, + jsonldPredicate: JsonldPredicate | None | str = None, + documentRoot: None | bool = None, + abstract: None | bool = None, + extends: None | Sequence[str] | str = None, + specialize: None | Sequence[SpecializeDef] = None, + extension_fields: MutableMapping[str, Any] | None = None, + loadingOptions: LoadingOptions | None = None, + ) -> None: + if extension_fields: + self.extension_fields = extension_fields + else: + self.extension_fields = CommentedMap() + if loadingOptions: + self.loadingOptions = loadingOptions + else: + self.loadingOptions = LoadingOptions() + self.name = name + self.inVocab = inVocab + self.fields = fields + self.type_ = type_ + self.doc = doc + self.docParent = docParent + self.docChild = docChild + self.docAfter = docAfter + self.jsonldPredicate = jsonldPredicate + self.documentRoot = documentRoot + self.abstract = abstract + self.extends = extends + self.specialize = specialize + attrs: ClassVar[Collection[str]] = frozenset( [ "name", @@ -4395,7 +4405,8 @@ def save( ) -class SaladEnumSchema(NamedType, EnumSchema, SchemaDefinedType): +@mypyc_attr(native_class=True) +class SaladEnumSchema(EnumSchema): """ Define an enumerated type. @@ -4403,42 +4414,6 @@ class SaladEnumSchema(NamedType, EnumSchema, SchemaDefinedType): name: str - def __init__( - self, - symbols: Any, - type_: Any, - name: Any | None = None, - inVocab: Any | None = None, - doc: Any | None = None, - docParent: Any | None = None, - docChild: Any | None = None, - docAfter: Any | None = None, - jsonldPredicate: Any | None = None, - documentRoot: Any | None = None, - extends: Any | None = None, - extension_fields: MutableMapping[str, Any] | None = None, - loadingOptions: LoadingOptions | None = None, - ) -> None: - if extension_fields: - self.extension_fields = extension_fields - else: - self.extension_fields = CommentedMap() - if loadingOptions: - self.loadingOptions = loadingOptions - else: - self.loadingOptions = LoadingOptions() - self.name = name if name is not None else "_:" + str(_uuid__.uuid4()) - self.inVocab = inVocab - self.symbols = symbols - self.type_ = type_ - self.doc = doc - self.docParent = docParent - self.docChild = docChild - self.docAfter = docAfter - self.jsonldPredicate = jsonldPredicate - self.documentRoot = documentRoot - self.extends = extends - def __eq__(self, other: Any) -> bool: if isinstance(other, SaladEnumSchema): return bool( @@ -4535,14 +4510,13 @@ def fromDoc( ) ) - __original_name_is_none = name is None if name is None: if docRoot is not None: name = docRoot else: name = "_:" + str(_uuid__.uuid4()) - if not __original_name_is_none: - baseuri = cast(str, name) + else: + baseuri = name inVocab = None if "inVocab" in _doc: try: @@ -5054,7 +5028,7 @@ def fromDoc( extension_fields=extension_fields, loadingOptions=loadingOptions, ) - loadingOptions.idx[cast(str, name)] = (_constructed, loadingOptions) + loadingOptions.idx[name] = (_constructed, loadingOptions) return _constructed def save( @@ -5069,7 +5043,7 @@ def save( for ef in self.extension_fields: r[ef] = self.extension_fields[ef] if self.name is not None: - u = save_relative_uri(self.name, base_url, True, None, relative_uris) + u = save_relative_uri(self.name, self.name, True, None, relative_uris) r["name"] = u if self.inVocab is not None: r["inVocab"] = save( @@ -5121,6 +5095,42 @@ def save( r["$schemas"] = self.loadingOptions.schemas return r + def __init__( + self, + symbols: Sequence[str], + type_: Enum_name, + name: None | str = None, + inVocab: None | bool = None, + doc: None | Sequence[str] | str = None, + docParent: None | str = None, + docChild: None | Sequence[str] | str = None, + docAfter: None | str = None, + jsonldPredicate: JsonldPredicate | None | str = None, + documentRoot: None | bool = None, + extends: None | Sequence[str] | str = None, + extension_fields: MutableMapping[str, Any] | None = None, + loadingOptions: LoadingOptions | None = None, + ) -> None: + if extension_fields: + self.extension_fields = extension_fields + else: + self.extension_fields = CommentedMap() + if loadingOptions: + self.loadingOptions = loadingOptions + else: + self.loadingOptions = LoadingOptions() + self.name = name if name is not None else "_:" + str(_uuid__.uuid4()) + self.inVocab = inVocab + self.symbols = symbols + self.type_ = type_ + self.doc = doc + self.docParent = docParent + self.docChild = docChild + self.docAfter = docAfter + self.jsonldPredicate = jsonldPredicate + self.documentRoot = documentRoot + self.extends = extends + attrs: ClassVar[Collection[str]] = frozenset( [ "name", @@ -5138,7 +5148,8 @@ def save( ) -class SaladMapSchema(NamedType, MapSchema, SchemaDefinedType): +@mypyc_attr(native_class=True) +class SaladMapSchema(MapSchema): """ Define a map type. @@ -5146,40 +5157,6 @@ class SaladMapSchema(NamedType, MapSchema, SchemaDefinedType): name: str - def __init__( - self, - name: Any, - type_: Any, - values: Any, - inVocab: Any | None = None, - doc: Any | None = None, - docParent: Any | None = None, - docChild: Any | None = None, - docAfter: Any | None = None, - jsonldPredicate: Any | None = None, - documentRoot: Any | None = None, - extension_fields: MutableMapping[str, Any] | None = None, - loadingOptions: LoadingOptions | None = None, - ) -> None: - if extension_fields: - self.extension_fields = extension_fields - else: - self.extension_fields = CommentedMap() - if loadingOptions: - self.loadingOptions = loadingOptions - else: - self.loadingOptions = LoadingOptions() - self.name = name if name is not None else "_:" + str(_uuid__.uuid4()) - self.inVocab = inVocab - self.type_ = type_ - self.values = values - self.doc = doc - self.docParent = docParent - self.docChild = docChild - self.docAfter = docAfter - self.jsonldPredicate = jsonldPredicate - self.documentRoot = documentRoot - def __eq__(self, other: Any) -> bool: if isinstance(other, SaladMapSchema): return bool( @@ -5274,14 +5251,14 @@ def fromDoc( ) ) - __original_name_is_none = name is None if name is None: if docRoot is not None: name = docRoot else: + name = "" _errors__.append(ValidationException("missing name")) - if not __original_name_is_none: - baseuri = cast(str, name) + else: + baseuri = name inVocab = None if "inVocab" in _doc: try: @@ -5745,7 +5722,7 @@ def fromDoc( extension_fields=extension_fields, loadingOptions=loadingOptions, ) - loadingOptions.idx[cast(str, name)] = (_constructed, loadingOptions) + loadingOptions.idx[name] = (_constructed, loadingOptions) return _constructed def save( @@ -5760,7 +5737,7 @@ def save( for ef in self.extension_fields: r[ef] = self.extension_fields[ef] if self.name is not None: - u = save_relative_uri(self.name, base_url, True, None, relative_uris) + u = save_relative_uri(self.name, self.name, True, None, relative_uris) r["name"] = u if self.inVocab is not None: r["inVocab"] = save( @@ -5809,6 +5786,40 @@ def save( r["$schemas"] = self.loadingOptions.schemas return r + def __init__( + self, + name: str, + type_: Map_name, + values: ArraySchema | EnumSchema | MapSchema | PrimitiveType | RecordSchema | Sequence[ArraySchema | EnumSchema | MapSchema | PrimitiveType | RecordSchema | UnionSchema | str] | UnionSchema | str, + inVocab: None | bool = None, + doc: None | Sequence[str] | str = None, + docParent: None | str = None, + docChild: None | Sequence[str] | str = None, + docAfter: None | str = None, + jsonldPredicate: JsonldPredicate | None | str = None, + documentRoot: None | bool = None, + extension_fields: MutableMapping[str, Any] | None = None, + loadingOptions: LoadingOptions | None = None, + ) -> None: + if extension_fields: + self.extension_fields = extension_fields + else: + self.extension_fields = CommentedMap() + if loadingOptions: + self.loadingOptions = loadingOptions + else: + self.loadingOptions = LoadingOptions() + self.name = name + self.inVocab = inVocab + self.type_ = type_ + self.values = values + self.doc = doc + self.docParent = docParent + self.docChild = docChild + self.docAfter = docAfter + self.jsonldPredicate = jsonldPredicate + self.documentRoot = documentRoot + attrs: ClassVar[Collection[str]] = frozenset( [ "name", @@ -5825,7 +5836,8 @@ def save( ) -class SaladUnionSchema(NamedType, UnionSchema, DocType): +@mypyc_attr(native_class=True) +class SaladUnionSchema(UnionSchema): """ Define a union type. @@ -5833,38 +5845,6 @@ class SaladUnionSchema(NamedType, UnionSchema, DocType): name: str - def __init__( - self, - name: Any, - names: Any, - type_: Any, - inVocab: Any | None = None, - doc: Any | None = None, - docParent: Any | None = None, - docChild: Any | None = None, - docAfter: Any | None = None, - documentRoot: Any | None = None, - extension_fields: MutableMapping[str, Any] | None = None, - loadingOptions: LoadingOptions | None = None, - ) -> None: - if extension_fields: - self.extension_fields = extension_fields - else: - self.extension_fields = CommentedMap() - if loadingOptions: - self.loadingOptions = loadingOptions - else: - self.loadingOptions = LoadingOptions() - self.name = name if name is not None else "_:" + str(_uuid__.uuid4()) - self.inVocab = inVocab - self.names = names - self.type_ = type_ - self.doc = doc - self.docParent = docParent - self.docChild = docChild - self.docAfter = docAfter - self.documentRoot = documentRoot - def __eq__(self, other: Any) -> bool: if isinstance(other, SaladUnionSchema): return bool( @@ -5957,14 +5937,14 @@ def fromDoc( ) ) - __original_name_is_none = name is None if name is None: if docRoot is not None: name = docRoot else: + name = "" _errors__.append(ValidationException("missing name")) - if not __original_name_is_none: - baseuri = cast(str, name) + else: + baseuri = name inVocab = None if "inVocab" in _doc: try: @@ -6380,7 +6360,7 @@ def fromDoc( extension_fields=extension_fields, loadingOptions=loadingOptions, ) - loadingOptions.idx[cast(str, name)] = (_constructed, loadingOptions) + loadingOptions.idx[name] = (_constructed, loadingOptions) return _constructed def save( @@ -6395,7 +6375,7 @@ def save( for ef in self.extension_fields: r[ef] = self.extension_fields[ef] if self.name is not None: - u = save_relative_uri(self.name, base_url, True, None, relative_uris) + u = save_relative_uri(self.name, self.name, True, None, relative_uris) r["name"] = u if self.inVocab is not None: r["inVocab"] = save( @@ -6437,6 +6417,38 @@ def save( r["$schemas"] = self.loadingOptions.schemas return r + def __init__( + self, + name: str, + names: ArraySchema | EnumSchema | MapSchema | PrimitiveType | RecordSchema | Sequence[ArraySchema | EnumSchema | MapSchema | PrimitiveType | RecordSchema | UnionSchema | str] | UnionSchema | str, + type_: Union_name, + inVocab: None | bool = None, + doc: None | Sequence[str] | str = None, + docParent: None | str = None, + docChild: None | Sequence[str] | str = None, + docAfter: None | str = None, + documentRoot: None | bool = None, + extension_fields: MutableMapping[str, Any] | None = None, + loadingOptions: LoadingOptions | None = None, + ) -> None: + if extension_fields: + self.extension_fields = extension_fields + else: + self.extension_fields = CommentedMap() + if loadingOptions: + self.loadingOptions = loadingOptions + else: + self.loadingOptions = LoadingOptions() + self.name = name + self.inVocab = inVocab + self.names = names + self.type_ = type_ + self.doc = doc + self.docParent = docParent + self.docChild = docChild + self.docAfter = docAfter + self.documentRoot = documentRoot + attrs: ClassVar[Collection[str]] = frozenset( [ "name", @@ -6452,7 +6464,8 @@ def save( ) -class Documentation(NamedType, DocType): +@mypyc_attr(native_class=True) +class Documentation(Saveable): """ A documentation section. This type exists to facilitate self-documenting schemas but has no role in formal validation. @@ -6460,34 +6473,6 @@ class Documentation(NamedType, DocType): name: str - def __init__( - self, - name: Any, - type_: Any, - inVocab: Any | None = None, - doc: Any | None = None, - docParent: Any | None = None, - docChild: Any | None = None, - docAfter: Any | None = None, - extension_fields: MutableMapping[str, Any] | None = None, - loadingOptions: LoadingOptions | None = None, - ) -> None: - if extension_fields: - self.extension_fields = extension_fields - else: - self.extension_fields = CommentedMap() - if loadingOptions: - self.loadingOptions = loadingOptions - else: - self.loadingOptions = LoadingOptions() - self.name = name if name is not None else "_:" + str(_uuid__.uuid4()) - self.inVocab = inVocab - self.doc = doc - self.docParent = docParent - self.docChild = docChild - self.docAfter = docAfter - self.type_ = type_ - def __eq__(self, other: Any) -> bool: if isinstance(other, Documentation): return bool( @@ -6576,14 +6561,14 @@ def fromDoc( ) ) - __original_name_is_none = name is None if name is None: if docRoot is not None: name = docRoot else: + name = "" _errors__.append(ValidationException("missing name")) - if not __original_name_is_none: - baseuri = cast(str, name) + else: + baseuri = name inVocab = None if "inVocab" in _doc: try: @@ -6902,7 +6887,7 @@ def fromDoc( extension_fields=extension_fields, loadingOptions=loadingOptions, ) - loadingOptions.idx[cast(str, name)] = (_constructed, loadingOptions) + loadingOptions.idx[name] = (_constructed, loadingOptions) return _constructed def save( @@ -6917,7 +6902,7 @@ def save( for ef in self.extension_fields: r[ef] = self.extension_fields[ef] if self.name is not None: - u = save_relative_uri(self.name, base_url, True, None, relative_uris) + u = save_relative_uri(self.name, self.name, True, None, relative_uris) r["name"] = u if self.inVocab is not None: r["inVocab"] = save( @@ -6949,6 +6934,34 @@ def save( r["$schemas"] = self.loadingOptions.schemas return r + def __init__( + self, + name: str, + type_: Documentation_name, + inVocab: None | bool = None, + doc: None | Sequence[str] | str = None, + docParent: None | str = None, + docChild: None | Sequence[str] | str = None, + docAfter: None | str = None, + extension_fields: MutableMapping[str, Any] | None = None, + loadingOptions: LoadingOptions | None = None, + ) -> None: + if extension_fields: + self.extension_fields = extension_fields + else: + self.extension_fields = CommentedMap() + if loadingOptions: + self.loadingOptions = loadingOptions + else: + self.loadingOptions = LoadingOptions() + self.name = name + self.inVocab = inVocab + self.doc = doc + self.docParent = docParent + self.docChild = docChild + self.docAfter = docAfter + self.type_ = type_ + attrs: ClassVar[Collection[str]] = frozenset( ["name", "inVocab", "doc", "docParent", "docChild", "docAfter", "type"] ) @@ -7025,13 +7038,17 @@ def save( "https://w3id.org/cwl/salad#union": "union", }) -strtype: Final = _PrimitiveLoader(str) -inttype: Final = _PrimitiveLoader(int) -floattype: Final = _PrimitiveLoader(float) -booltype: Final = _PrimitiveLoader(bool) -None_type: Final = _PrimitiveLoader(type(None)) -Any_type: Final = _AnyLoader() -PrimitiveTypeLoader: Final = _EnumLoader( +strtype: Final[_Loader[str]] = _PrimitiveLoader(str) +inttype: Final[_Loader[i32]] = _PrimitiveLoader(i32) +longtype: Final[_Loader[i64]] = _PrimitiveLoader(i64) +floattype: Final[_Loader[float]] = _PrimitiveLoader(float) +booltype: Final[_Loader[bool]] = _PrimitiveLoader(bool) +None_type: Final[_Loader[None]] = _PrimitiveLoader(type(None)) +Any_type: Final[_Loader[Any]] = _AnyLoader() +PrimitiveType: TypeAlias = Literal[ + "null", "boolean", "int", "long", "float", "double", "string" +] +PrimitiveTypeLoader: Final[_Loader[PrimitiveType]] = _EnumLoader( ( "null", "boolean", @@ -7062,36 +7079,67 @@ def save( string: Unicode character sequence """ -AnyLoader: Final = _EnumLoader(("Any",), "Any") +Any_: TypeAlias = Literal["Any"] +Any_Loader: Final[_Loader[Any_]] = _EnumLoader(("Any",), "Any_") """ The **Any** type validates for any non-null value. """ -RecordFieldLoader: Final = _RecordLoader(RecordField, None, None) -RecordSchemaLoader: Final = _RecordLoader(RecordSchema, None, None) -EnumSchemaLoader: Final = _RecordLoader(EnumSchema, None, None) -ArraySchemaLoader: Final = _RecordLoader(ArraySchema, None, None) -MapSchemaLoader: Final = _RecordLoader(MapSchema, None, None) -UnionSchemaLoader: Final = _RecordLoader(UnionSchema, None, None) -JsonldPredicateLoader: Final = _RecordLoader(JsonldPredicate, None, None) -SpecializeDefLoader: Final = _RecordLoader(SpecializeDef, None, None) -SaladRecordFieldLoader: Final = _RecordLoader(SaladRecordField, None, None) -SaladRecordSchemaLoader: Final = _RecordLoader(SaladRecordSchema, None, None) -SaladEnumSchemaLoader: Final = _RecordLoader(SaladEnumSchema, None, None) -SaladMapSchemaLoader: Final = _RecordLoader(SaladMapSchema, None, None) -SaladUnionSchemaLoader: Final = _RecordLoader(SaladUnionSchema, None, None) -DocumentationLoader: Final = _RecordLoader(Documentation, None, None) -array_of_strtype: Final = _ArrayLoader(strtype) -union_of_None_type_or_strtype_or_array_of_strtype: Final = _UnionLoader( +RecordFieldLoader: Final[_Loader[RecordField]] = _RecordLoader(RecordField, None, None) +RecordSchemaLoader: Final[_Loader[RecordSchema]] = _RecordLoader( + RecordSchema, None, None +) +EnumSchemaLoader: Final[_Loader[EnumSchema]] = _RecordLoader(EnumSchema, None, None) +ArraySchemaLoader: Final[_Loader[ArraySchema]] = _RecordLoader(ArraySchema, None, None) +MapSchemaLoader: Final[_Loader[MapSchema]] = _RecordLoader(MapSchema, None, None) +UnionSchemaLoader: Final[_Loader[UnionSchema]] = _RecordLoader(UnionSchema, None, None) +JsonldPredicateLoader: Final[_Loader[JsonldPredicate]] = _RecordLoader( + JsonldPredicate, None, None +) +SpecializeDefLoader: Final[_Loader[SpecializeDef]] = _RecordLoader( + SpecializeDef, None, None +) +SaladRecordFieldLoader: Final[_Loader[SaladRecordField]] = _RecordLoader( + SaladRecordField, None, None +) +SaladRecordSchemaLoader: Final[_Loader[SaladRecordSchema]] = _RecordLoader( + SaladRecordSchema, None, None +) +SaladEnumSchemaLoader: Final[_Loader[SaladEnumSchema]] = _RecordLoader( + SaladEnumSchema, None, None +) +SaladMapSchemaLoader: Final[_Loader[SaladMapSchema]] = _RecordLoader( + SaladMapSchema, None, None +) +SaladUnionSchemaLoader: Final[_Loader[SaladUnionSchema]] = _RecordLoader( + SaladUnionSchema, None, None +) +DocumentationLoader: Final[_Loader[Documentation]] = _RecordLoader( + Documentation, None, None +) +array_of_strtype: Final[_Loader[Sequence[str]]] = _ArrayLoader(strtype) +union_of_None_type_or_strtype_or_array_of_strtype: Final[ + _Loader[None | Sequence[str] | str] +] = _UnionLoader( ( None_type, strtype, array_of_strtype, ) ) -uri_strtype_True_False_None_None: Final = _URILoader(strtype, True, False, None, None) -union_of_PrimitiveTypeLoader_or_RecordSchemaLoader_or_EnumSchemaLoader_or_ArraySchemaLoader_or_MapSchemaLoader_or_UnionSchemaLoader_or_strtype: ( - Final -) = _UnionLoader( +uri_strtype_True_False_None_None: Final[_Loader[str]] = _URILoader( + strtype, True, False, None, None +) +union_of_PrimitiveTypeLoader_or_RecordSchemaLoader_or_EnumSchemaLoader_or_ArraySchemaLoader_or_MapSchemaLoader_or_UnionSchemaLoader_or_strtype: Final[ + _Loader[ + ArraySchema + | EnumSchema + | MapSchema + | PrimitiveType + | RecordSchema + | UnionSchema + | str + ] +] = _UnionLoader( ( PrimitiveTypeLoader, RecordSchemaLoader, @@ -7102,14 +7150,41 @@ def save( strtype, ) ) -array_of_union_of_PrimitiveTypeLoader_or_RecordSchemaLoader_or_EnumSchemaLoader_or_ArraySchemaLoader_or_MapSchemaLoader_or_UnionSchemaLoader_or_strtype: ( - Final -) = _ArrayLoader( +array_of_union_of_PrimitiveTypeLoader_or_RecordSchemaLoader_or_EnumSchemaLoader_or_ArraySchemaLoader_or_MapSchemaLoader_or_UnionSchemaLoader_or_strtype: Final[ + _Loader[ + Sequence[ + ArraySchema + | EnumSchema + | MapSchema + | PrimitiveType + | RecordSchema + | UnionSchema + | str + ] + ] +] = _ArrayLoader( union_of_PrimitiveTypeLoader_or_RecordSchemaLoader_or_EnumSchemaLoader_or_ArraySchemaLoader_or_MapSchemaLoader_or_UnionSchemaLoader_or_strtype ) -union_of_PrimitiveTypeLoader_or_RecordSchemaLoader_or_EnumSchemaLoader_or_ArraySchemaLoader_or_MapSchemaLoader_or_UnionSchemaLoader_or_strtype_or_array_of_union_of_PrimitiveTypeLoader_or_RecordSchemaLoader_or_EnumSchemaLoader_or_ArraySchemaLoader_or_MapSchemaLoader_or_UnionSchemaLoader_or_strtype: ( - Final -) = _UnionLoader( +union_of_PrimitiveTypeLoader_or_RecordSchemaLoader_or_EnumSchemaLoader_or_ArraySchemaLoader_or_MapSchemaLoader_or_UnionSchemaLoader_or_strtype_or_array_of_union_of_PrimitiveTypeLoader_or_RecordSchemaLoader_or_EnumSchemaLoader_or_ArraySchemaLoader_or_MapSchemaLoader_or_UnionSchemaLoader_or_strtype: Final[ + _Loader[ + ArraySchema + | EnumSchema + | MapSchema + | PrimitiveType + | RecordSchema + | Sequence[ + ArraySchema + | EnumSchema + | MapSchema + | PrimitiveType + | RecordSchema + | UnionSchema + | str + ] + | UnionSchema + | str + ] +] = _UnionLoader( ( PrimitiveTypeLoader, RecordSchemaLoader, @@ -7121,122 +7196,194 @@ def save( array_of_union_of_PrimitiveTypeLoader_or_RecordSchemaLoader_or_EnumSchemaLoader_or_ArraySchemaLoader_or_MapSchemaLoader_or_UnionSchemaLoader_or_strtype, ) ) -typedsl_union_of_PrimitiveTypeLoader_or_RecordSchemaLoader_or_EnumSchemaLoader_or_ArraySchemaLoader_or_MapSchemaLoader_or_UnionSchemaLoader_or_strtype_or_array_of_union_of_PrimitiveTypeLoader_or_RecordSchemaLoader_or_EnumSchemaLoader_or_ArraySchemaLoader_or_MapSchemaLoader_or_UnionSchemaLoader_or_strtype_2: ( - Final -) = _TypeDSLLoader( +typedsl_union_of_PrimitiveTypeLoader_or_RecordSchemaLoader_or_EnumSchemaLoader_or_ArraySchemaLoader_or_MapSchemaLoader_or_UnionSchemaLoader_or_strtype_or_array_of_union_of_PrimitiveTypeLoader_or_RecordSchemaLoader_or_EnumSchemaLoader_or_ArraySchemaLoader_or_MapSchemaLoader_or_UnionSchemaLoader_or_strtype_2: Final[ + _Loader[ + ArraySchema + | EnumSchema + | MapSchema + | PrimitiveType + | RecordSchema + | Sequence[ + ArraySchema + | EnumSchema + | MapSchema + | PrimitiveType + | RecordSchema + | UnionSchema + | str + ] + | UnionSchema + | str + ] +] = _TypeDSLLoader( union_of_PrimitiveTypeLoader_or_RecordSchemaLoader_or_EnumSchemaLoader_or_ArraySchemaLoader_or_MapSchemaLoader_or_UnionSchemaLoader_or_strtype_or_array_of_union_of_PrimitiveTypeLoader_or_RecordSchemaLoader_or_EnumSchemaLoader_or_ArraySchemaLoader_or_MapSchemaLoader_or_UnionSchemaLoader_or_strtype, 2, "v1.1", ) -array_of_RecordFieldLoader: Final = _ArrayLoader(RecordFieldLoader) -union_of_None_type_or_array_of_RecordFieldLoader: Final = _UnionLoader( +array_of_RecordFieldLoader: Final[_Loader[Sequence[RecordField]]] = _ArrayLoader( + RecordFieldLoader +) +union_of_None_type_or_array_of_RecordFieldLoader: Final[ + _Loader[None | Sequence[RecordField]] +] = _UnionLoader( ( None_type, array_of_RecordFieldLoader, ) ) -idmap_fields_union_of_None_type_or_array_of_RecordFieldLoader: Final = _IdMapLoader( - union_of_None_type_or_array_of_RecordFieldLoader, "name", "type" +idmap_fields_union_of_None_type_or_array_of_RecordFieldLoader: Final[ + _Loader[None | Sequence[RecordField]] +] = _IdMapLoader(union_of_None_type_or_array_of_RecordFieldLoader, "name", "type") +Record_name: TypeAlias = Literal["record"] +Record_nameLoader: Final[_Loader[Record_name]] = _EnumLoader(("record",), "Record_name") +typedsl_Record_nameLoader_2: Final[_Loader[Record_name]] = _TypeDSLLoader( + Record_nameLoader, 2, "v1.1" ) -Record_nameLoader: Final = _EnumLoader(("record",), "Record_name") -typedsl_Record_nameLoader_2: Final = _TypeDSLLoader(Record_nameLoader, 2, "v1.1") -union_of_None_type_or_strtype: Final = _UnionLoader( +union_of_None_type_or_strtype: Final[_Loader[None | str]] = _UnionLoader( ( None_type, strtype, ) ) -uri_union_of_None_type_or_strtype_True_False_None_None: Final = _URILoader( - union_of_None_type_or_strtype, True, False, None, None +uri_union_of_None_type_or_strtype_True_False_None_None: Final[_Loader[None | str]] = ( + _URILoader(union_of_None_type_or_strtype, True, False, None, None) ) -uri_array_of_strtype_True_False_None_None: Final = _URILoader( +uri_array_of_strtype_True_False_None_None: Final[_Loader[Sequence[str]]] = _URILoader( array_of_strtype, True, False, None, None ) -Enum_nameLoader: Final = _EnumLoader(("enum",), "Enum_name") -typedsl_Enum_nameLoader_2: Final = _TypeDSLLoader(Enum_nameLoader, 2, "v1.1") -uri_union_of_PrimitiveTypeLoader_or_RecordSchemaLoader_or_EnumSchemaLoader_or_ArraySchemaLoader_or_MapSchemaLoader_or_UnionSchemaLoader_or_strtype_or_array_of_union_of_PrimitiveTypeLoader_or_RecordSchemaLoader_or_EnumSchemaLoader_or_ArraySchemaLoader_or_MapSchemaLoader_or_UnionSchemaLoader_or_strtype_False_True_2_None: ( - Final -) = _URILoader( +Enum_name: TypeAlias = Literal["enum"] +Enum_nameLoader: Final[_Loader[Enum_name]] = _EnumLoader(("enum",), "Enum_name") +typedsl_Enum_nameLoader_2: Final[_Loader[Enum_name]] = _TypeDSLLoader( + Enum_nameLoader, 2, "v1.1" +) +uri_union_of_PrimitiveTypeLoader_or_RecordSchemaLoader_or_EnumSchemaLoader_or_ArraySchemaLoader_or_MapSchemaLoader_or_UnionSchemaLoader_or_strtype_or_array_of_union_of_PrimitiveTypeLoader_or_RecordSchemaLoader_or_EnumSchemaLoader_or_ArraySchemaLoader_or_MapSchemaLoader_or_UnionSchemaLoader_or_strtype_False_True_2_None: Final[ + _Loader[ + ArraySchema + | EnumSchema + | MapSchema + | PrimitiveType + | RecordSchema + | Sequence[ + ArraySchema + | EnumSchema + | MapSchema + | PrimitiveType + | RecordSchema + | UnionSchema + | str + ] + | UnionSchema + | str + ] +] = _URILoader( union_of_PrimitiveTypeLoader_or_RecordSchemaLoader_or_EnumSchemaLoader_or_ArraySchemaLoader_or_MapSchemaLoader_or_UnionSchemaLoader_or_strtype_or_array_of_union_of_PrimitiveTypeLoader_or_RecordSchemaLoader_or_EnumSchemaLoader_or_ArraySchemaLoader_or_MapSchemaLoader_or_UnionSchemaLoader_or_strtype, False, True, 2, None, ) -Array_nameLoader: Final = _EnumLoader(("array",), "Array_name") -typedsl_Array_nameLoader_2: Final = _TypeDSLLoader(Array_nameLoader, 2, "v1.1") -Map_nameLoader: Final = _EnumLoader(("map",), "Map_name") -typedsl_Map_nameLoader_2: Final = _TypeDSLLoader(Map_nameLoader, 2, "v1.1") -Union_nameLoader: Final = _EnumLoader(("union",), "Union_name") -typedsl_Union_nameLoader_2: Final = _TypeDSLLoader(Union_nameLoader, 2, "v1.1") -union_of_None_type_or_booltype: Final = _UnionLoader( +Array_name: TypeAlias = Literal["array"] +Array_nameLoader: Final[_Loader[Array_name]] = _EnumLoader(("array",), "Array_name") +typedsl_Array_nameLoader_2: Final[_Loader[Array_name]] = _TypeDSLLoader( + Array_nameLoader, 2, "v1.1" +) +Map_name: TypeAlias = Literal["map"] +Map_nameLoader: Final[_Loader[Map_name]] = _EnumLoader(("map",), "Map_name") +typedsl_Map_nameLoader_2: Final[_Loader[Map_name]] = _TypeDSLLoader( + Map_nameLoader, 2, "v1.1" +) +Union_name: TypeAlias = Literal["union"] +Union_nameLoader: Final[_Loader[Union_name]] = _EnumLoader(("union",), "Union_name") +typedsl_Union_nameLoader_2: Final[_Loader[Union_name]] = _TypeDSLLoader( + Union_nameLoader, 2, "v1.1" +) +union_of_None_type_or_booltype: Final[_Loader[None | bool]] = _UnionLoader( ( None_type, booltype, ) ) -union_of_None_type_or_inttype: Final = _UnionLoader( +union_of_None_type_or_inttype: Final[_Loader[None | i32]] = _UnionLoader( ( None_type, inttype, ) ) -uri_strtype_False_False_1_None: Final = _URILoader(strtype, False, False, 1, None) -uri_union_of_None_type_or_strtype_False_False_None_None: Final = _URILoader( - union_of_None_type_or_strtype, False, False, None, None +uri_strtype_False_False_1_None: Final[_Loader[str]] = _URILoader( + strtype, False, False, 1, None ) -uri_union_of_None_type_or_strtype_or_array_of_strtype_False_False_None_None: Final = ( - _URILoader( - union_of_None_type_or_strtype_or_array_of_strtype, False, False, None, None - ) +uri_union_of_None_type_or_strtype_False_False_None_None: Final[_Loader[None | str]] = ( + _URILoader(union_of_None_type_or_strtype, False, False, None, None) ) -union_of_None_type_or_strtype_or_JsonldPredicateLoader: Final = _UnionLoader( +uri_union_of_None_type_or_strtype_or_array_of_strtype_False_False_None_None: Final[ + _Loader[None | Sequence[str] | str] +] = _URILoader( + union_of_None_type_or_strtype_or_array_of_strtype, False, False, None, None +) +union_of_None_type_or_strtype_or_JsonldPredicateLoader: Final[ + _Loader[JsonldPredicate | None | str] +] = _UnionLoader( ( None_type, strtype, JsonldPredicateLoader, ) ) -union_of_None_type_or_Any_type: Final = _UnionLoader( +union_of_None_type_or_Any_type: Final[_Loader[Any | None]] = _UnionLoader( ( None_type, Any_type, ) ) -array_of_SaladRecordFieldLoader: Final = _ArrayLoader(SaladRecordFieldLoader) -union_of_None_type_or_array_of_SaladRecordFieldLoader: Final = _UnionLoader( +array_of_SaladRecordFieldLoader: Final[_Loader[Sequence[SaladRecordField]]] = ( + _ArrayLoader(SaladRecordFieldLoader) +) +union_of_None_type_or_array_of_SaladRecordFieldLoader: Final[ + _Loader[None | Sequence[SaladRecordField]] +] = _UnionLoader( ( None_type, array_of_SaladRecordFieldLoader, ) ) -idmap_fields_union_of_None_type_or_array_of_SaladRecordFieldLoader: Final = ( - _IdMapLoader(union_of_None_type_or_array_of_SaladRecordFieldLoader, "name", "type") +idmap_fields_union_of_None_type_or_array_of_SaladRecordFieldLoader: Final[ + _Loader[None | Sequence[SaladRecordField]] +] = _IdMapLoader(union_of_None_type_or_array_of_SaladRecordFieldLoader, "name", "type") +uri_union_of_None_type_or_strtype_or_array_of_strtype_False_False_1_None: Final[ + _Loader[None | Sequence[str] | str] +] = _URILoader(union_of_None_type_or_strtype_or_array_of_strtype, False, False, 1, None) +array_of_SpecializeDefLoader: Final[_Loader[Sequence[SpecializeDef]]] = _ArrayLoader( + SpecializeDefLoader ) -uri_union_of_None_type_or_strtype_or_array_of_strtype_False_False_1_None: Final = ( - _URILoader(union_of_None_type_or_strtype_or_array_of_strtype, False, False, 1, None) -) -array_of_SpecializeDefLoader: Final = _ArrayLoader(SpecializeDefLoader) -union_of_None_type_or_array_of_SpecializeDefLoader: Final = _UnionLoader( +union_of_None_type_or_array_of_SpecializeDefLoader: Final[ + _Loader[None | Sequence[SpecializeDef]] +] = _UnionLoader( ( None_type, array_of_SpecializeDefLoader, ) ) -idmap_specialize_union_of_None_type_or_array_of_SpecializeDefLoader: Final = ( - _IdMapLoader( - union_of_None_type_or_array_of_SpecializeDefLoader, - "specializeFrom", - "specializeTo", - ) +idmap_specialize_union_of_None_type_or_array_of_SpecializeDefLoader: Final[ + _Loader[None | Sequence[SpecializeDef]] +] = _IdMapLoader( + union_of_None_type_or_array_of_SpecializeDefLoader, "specializeFrom", "specializeTo" ) -Documentation_nameLoader: Final = _EnumLoader(("documentation",), "Documentation_name") -typedsl_Documentation_nameLoader_2: Final = _TypeDSLLoader( +Documentation_name: TypeAlias = Literal["documentation"] +Documentation_nameLoader: Final[_Loader[Documentation_name]] = _EnumLoader( + ("documentation",), "Documentation_name" +) +typedsl_Documentation_nameLoader_2: Final[_Loader[Documentation_name]] = _TypeDSLLoader( Documentation_nameLoader, 2, "v1.1" ) -union_of_SaladRecordSchemaLoader_or_SaladEnumSchemaLoader_or_SaladMapSchemaLoader_or_SaladUnionSchemaLoader_or_DocumentationLoader: ( - Final -) = _UnionLoader( +union_of_SaladRecordSchemaLoader_or_SaladEnumSchemaLoader_or_SaladMapSchemaLoader_or_SaladUnionSchemaLoader_or_DocumentationLoader: Final[ + _Loader[ + Documentation + | SaladEnumSchema + | SaladMapSchema + | SaladRecordSchema + | SaladUnionSchema + ] +] = _UnionLoader( ( SaladRecordSchemaLoader, SaladEnumSchemaLoader, @@ -7245,14 +7392,35 @@ def save( DocumentationLoader, ) ) -array_of_union_of_SaladRecordSchemaLoader_or_SaladEnumSchemaLoader_or_SaladMapSchemaLoader_or_SaladUnionSchemaLoader_or_DocumentationLoader: ( - Final -) = _ArrayLoader( +array_of_union_of_SaladRecordSchemaLoader_or_SaladEnumSchemaLoader_or_SaladMapSchemaLoader_or_SaladUnionSchemaLoader_or_DocumentationLoader: Final[ + _Loader[ + Sequence[ + Documentation + | SaladEnumSchema + | SaladMapSchema + | SaladRecordSchema + | SaladUnionSchema + ] + ] +] = _ArrayLoader( union_of_SaladRecordSchemaLoader_or_SaladEnumSchemaLoader_or_SaladMapSchemaLoader_or_SaladUnionSchemaLoader_or_DocumentationLoader ) -union_of_SaladRecordSchemaLoader_or_SaladEnumSchemaLoader_or_SaladMapSchemaLoader_or_SaladUnionSchemaLoader_or_DocumentationLoader_or_array_of_union_of_SaladRecordSchemaLoader_or_SaladEnumSchemaLoader_or_SaladMapSchemaLoader_or_SaladUnionSchemaLoader_or_DocumentationLoader: ( - Final -) = _UnionLoader( +union_of_SaladRecordSchemaLoader_or_SaladEnumSchemaLoader_or_SaladMapSchemaLoader_or_SaladUnionSchemaLoader_or_DocumentationLoader_or_array_of_union_of_SaladRecordSchemaLoader_or_SaladEnumSchemaLoader_or_SaladMapSchemaLoader_or_SaladUnionSchemaLoader_or_DocumentationLoader: Final[ + _Loader[ + Documentation + | SaladEnumSchema + | SaladMapSchema + | SaladRecordSchema + | SaladUnionSchema + | Sequence[ + Documentation + | SaladEnumSchema + | SaladMapSchema + | SaladRecordSchema + | SaladUnionSchema + ] + ] +] = _UnionLoader( ( SaladRecordSchemaLoader, SaladEnumSchemaLoader, diff --git a/src/schema_salad/python_codegen.py b/src/schema_salad/python_codegen.py index ce4454a0..cbaa12a8 100644 --- a/src/schema_salad/python_codegen.py +++ b/src/schema_salad/python_codegen.py @@ -2,6 +2,7 @@ import textwrap from collections.abc import MutableSequence +from graphlib import TopologicalSorter from importlib.resources import files from io import StringIO from types import ModuleType @@ -23,17 +24,41 @@ from .makedoc import markdown_plugins from .schema import shortname -_string_type_def: Final = TypeDef("strtype", "_PrimitiveLoader(str)") -_int_type_def: Final = TypeDef("inttype", "_PrimitiveLoader(int)") -_float_type_def: Final = TypeDef("floattype", "_PrimitiveLoader(float)") -_bool_type_def: Final = TypeDef("booltype", "_PrimitiveLoader(bool)") -_null_type_def: Final = TypeDef("None_type", "_PrimitiveLoader(type(None))") -_any_type_def: Final = TypeDef("Any_type", "_AnyLoader()") +_string_type_def: Final = TypeDef( + name="strtype", init="_PrimitiveLoader(str)", instance_type="str", loader_type="_Loader[str]" +) +_int_type_def: Final = TypeDef( + name="inttype", init="_PrimitiveLoader(i32)", instance_type="i32", loader_type="_Loader[i32]" +) +_long_type_def: Final = TypeDef( + name="longtype", init="_PrimitiveLoader(i64)", instance_type="i64", loader_type="_Loader[i64]" +) +_float_type_def: Final = TypeDef( + name="floattype", + init="_PrimitiveLoader(float)", + instance_type="float", + loader_type="_Loader[float]", +) +_bool_type_def: Final = TypeDef( + name="booltype", + init="_PrimitiveLoader(bool)", + instance_type="bool", + loader_type="_Loader[bool]", +) +_null_type_def: Final = TypeDef( + name="None_type", + init="_PrimitiveLoader(type(None))", + instance_type="None", + loader_type="_Loader[None]", +) +_any_type_def: Final = TypeDef( + name="Any_type", init="_AnyLoader()", instance_type="Any", loader_type="_Loader[Any]" +) prims: Final = { "http://www.w3.org/2001/XMLSchema#string": _string_type_def, "http://www.w3.org/2001/XMLSchema#int": _int_type_def, - "http://www.w3.org/2001/XMLSchema#long": _int_type_def, + "http://www.w3.org/2001/XMLSchema#long": _long_type_def, "http://www.w3.org/2001/XMLSchema#float": _float_type_def, "http://www.w3.org/2001/XMLSchema#double": _float_type_def, "http://www.w3.org/2001/XMLSchema#boolean": _bool_type_def, @@ -96,12 +121,13 @@ def __init__( self.out: Final = out self.current_class_is_abstract = False self.serializer = StringIO() - self.idfield = "" + self.idfield: str | None = "" self.copyright: Final = copyright self.parents_map: Final = parents_map or {} self.parser_info: Final = parser_info self.salad_version: Final = salad_version self.inherited_classes: dict[str, str] = {} + self.subclasses: dict[str, list[str]] = {} @staticmethod def safe_name(name: str) -> str: @@ -111,7 +137,7 @@ def safe_name(name: str) -> str: avn = avn[5:] elif avn[0].isdigit(): avn = f"_{avn}" - elif avn in ("class", "in", "type"): + elif avn in ("class", "in", "type", "Any"): # reserved words avn = f"{avn}_" return avn.replace(".", "_") @@ -187,19 +213,29 @@ def begin_class( idfield: str, optional_fields: set[str], ) -> None: - if (classname := self.safe_name(classname)) in self.inherited_classes: - self.current_class_is_abstract = True - return - self.current_class_is_abstract = abstract + classname = self.safe_name(classname) + self.current_optional_fields = optional_fields + self.current_fieldtypes: dict[str, TypeDef] = {} + self.current_class_is_abstract = abstract or (classname in self.inherited_classes) - if extends: - ext = ", ".join( - self.inherited_classes.get(self.safe_name(e), self.safe_name(e)) for e in extends - ) - else: - ext = "Saveable" + if self.current_class_is_abstract: + self.subclasses[classname] = [] - self.out.write(fmt(f"class {classname}({ext}):\n pass", 0)[:-9]) + parents = [] + for ext in extends: + safe_ext = self.inherited_classes.get(self.safe_name(ext), self.safe_name(ext)) + if safe_ext in self.subclasses: + self.subclasses[safe_ext].append(classname) + else: + parents.append(safe_ext) + + if self.current_class_is_abstract: + return + + ext = ", ".join(parents) if parents else "Saveable" + self.out.write( + fmt(f"@mypyc_attr(native_class=True)\nclass {classname}({ext}):\n pass", 0)[:-9] + ) # make a valid class for Black, but then trim off the "pass" if doc: @@ -207,57 +243,9 @@ def begin_class( self.serializer = StringIO() - if self.current_class_is_abstract: - self.out.write(" pass\n\n\n") - return - - idfield_safe_name: Final = self.safe_name(idfield) if idfield != "" else None - if idfield_safe_name is not None: - self.out.write(f" {idfield_safe_name}: str\n\n") - - required_field_names: Final = [f for f in field_names if f not in optional_fields] - optional_field_names: Final = [f for f in field_names if f in optional_fields] - - safe_inits: Final[list[str]] = [" self,"] - safe_inits.extend( - [f" {self.safe_name(f)}: Any," for f in required_field_names if f != "class"] - ) - safe_inits.extend( - [ - f" {self.safe_name(f)}: Any | None = None," - for f in optional_field_names - if f != "class" - ] - ) - self.out.write( - " def __init__(\n" - + "\n".join(safe_inits) - + "\n extension_fields: MutableMapping[str, Any] | None = None," - + "\n loadingOptions: LoadingOptions | None = None," - + "\n ) -> None:\n" - + """ if extension_fields: - self.extension_fields = extension_fields - else: - self.extension_fields = CommentedMap() - if loadingOptions: - self.loadingOptions = loadingOptions - else: - self.loadingOptions = LoadingOptions() -""" - ) - field_inits = "" - for name in field_names: - if name == "class": - field_inits += """ self.class_: Final[str] = "{}" -""".format(classname) - elif name == idfield_safe_name: - field_inits += """ self.{0} = {0} if {0} is not None else "_:" + str(_uuid__.uuid4()) -""".format( - self.safe_name(name) - ) - else: - field_inits += """ self.{0} = {0} -""".format(self.safe_name(name)) + self.idfield = self.safe_name(idfield) if idfield != "" else None + if self.idfield is not None: + self.out.write(f" {self.idfield}: str\n\n") field_eqs: Final = [] field_hashes: Final = [] for name in field_names: @@ -265,10 +253,8 @@ def begin_class( field_hashes.append(f"self.{self.safe_name(name)}") field_eq: Final = " and\n ".join(field_eqs) field_hash: Final = ",\n ".join(field_hashes) - self.out.write(field_inits) self.out.write( - "\n" - + fmt( + fmt( f"""def __eq__( self, other: Any @@ -309,8 +295,6 @@ def fromDoc( _errors__ = [] """) # noqa: B907 - self.idfield = idfield - self.serializer.write(""" def save( self, top: bool = False, base_url: str = "", relative_uris: bool = True @@ -373,7 +357,61 @@ def end_class(self, classname: str, field_names: list[str]) -> None: r["$schemas"] = self.loadingOptions.schemas """) - self.serializer.write(" return r\n\n") + self.serializer.write(" return r\n") + + required_field_names: Final = [ + f for f in field_names if f not in self.current_optional_fields + ] + optional_field_names: Final = [f for f in field_names if f in self.current_optional_fields] + + safe_inits: Final[list[str]] = [" self,"] + safe_inits.extend( + [ + f" {self.safe_name(f)}: {self.current_fieldtypes[self.safe_name(f)].instance_type}," + for f in required_field_names + if f != "class" + ] + ) + safe_inits.extend( + [ + f" {self.safe_name(f)}: " + f"{self.current_fieldtypes[self.safe_name(f)].instance_type} = None," + for f in optional_field_names + if f != "class" + ] + ) + self.serializer.write( + "\n def __init__(\n" + + "\n".join(safe_inits) + + "\n extension_fields: MutableMapping[str, Any] | None = None," + + "\n loadingOptions: LoadingOptions | None = None," + + "\n ) -> None:\n" + + """ if extension_fields: + self.extension_fields = extension_fields + else: + self.extension_fields = CommentedMap() + if loadingOptions: + self.loadingOptions = loadingOptions + else: + self.loadingOptions = LoadingOptions() +""" + ) + field_inits = "" + for name in field_names: + if name == "class": + field_inits += """ self.class_: Final[str] = "{}" +""".format(self.safe_name(classname)) + elif name == self.idfield and name in optional_field_names: + field_inits += ( + " self.{0} = {0} if {0} is not None else " + '"_:" + str(_uuid__.uuid4())\n'.format(self.safe_name(name)) + ) + else: + field_inits += """ self.{0} = {0} +""".format( + self.safe_name(name), + ) + self.serializer.write(f"{field_inits}\n") self.serializer.write( fmt( @@ -382,22 +420,29 @@ def end_class(self, classname: str, field_names: list[str]) -> None: ) ) - safe_init_fields: Final[list[str]] = [ - self.safe_name(f) for f in field_names if f != "class" - ] + safe_inits2: Final = [] - safe_inits: Final = [f + "=" + f for f in safe_init_fields] + if self.idfield is not None: + safe_inits2.append(f"{self.idfield}={self.idfield}") - safe_inits.extend(["extension_fields=extension_fields", "loadingOptions=loadingOptions"]) + safe_inits2.extend( + [ + f"{f}={f}" + for f in ( + self.safe_name(f) for f in field_names if f not in ("class", self.idfield) + ) + ] + ) + safe_inits2.extend(["extension_fields=extension_fields", "loadingOptions=loadingOptions"]) self.out.write( " _constructed = cls(\n " - + ",\n ".join(safe_inits) + + ",\n ".join(safe_inits2) + ",\n )\n" ) - if self.idfield: + if self.idfield is not None: self.out.write( - f" loadingOptions.idx[cast(str, {self.safe_name(self.idfield)})] " + f" loadingOptions.idx[{self.safe_name(self.idfield)}] " "= (_constructed, loadingOptions)\n" ) @@ -416,21 +461,27 @@ def type_loader( """Parse the given type declaration and declare its components.""" match type_declaration: case MutableSequence(): - sub_names1: Final = list( - dict.fromkeys([self.type_loader(i).name for i in type_declaration]) + sub_types1: Final = [self.type_loader(i) for i in type_declaration] + sub_names1: Final = [t.name for t in sub_types1] + instance_type: Final = " | ".join( + sorted({t.instance_type or "" for t in sub_types1}) ) return self.declare_type( TypeDef( - "union_of_{}".format("_or_".join(sub_names1)), - "_UnionLoader(({},))".format(", ".join(sub_names1)), + name="union_of_{}".format("_or_".join(sub_names1)), + init="_UnionLoader(({},))".format(", ".join(sub_names1)), + instance_type=instance_type, + loader_type=f"_Loader[{instance_type}]", ) ) case {"type": "array" | "https://w3id.org/cwl/salad#array", "items": items}: i1: Final = self.type_loader(items) return self.declare_type( TypeDef( - f"array_of_{i1.name}", - f"_ArrayLoader({i1.name})", + name=f"array_of_{i1.name}", + init=f"_ArrayLoader({i1.name})", + instance_type=f"Sequence[{i1.instance_type}]", + loader_type=f"_Loader[Sequence[{i1.instance_type}]]", ) ) case {"type": "map" | "https://w3id.org/cwl/salad#map", "values": values, **rest}: @@ -438,18 +489,25 @@ def type_loader( name = self.safe_name(str(rest["name"])) if "name" in rest else None anon_type = self.declare_type( TypeDef( - f"map_of_{i2.name}", - "_MapLoader({}, {}, {}, {})".format( + name=f"map_of_{i2.name}", + init="_MapLoader({}, {}, {}, {})".format( i2.name, f"'{name}'", # noqa: B907 f"'{container}'" if container is not None else None, # noqa: B907 no_link_check, ), + instance_type=f"Mapping[str, {i2.instance_type}]", + loader_type=f"_Loader[Mapping[str, {i2.instance_type}]]", ) ) if "name" in rest: return self.declare_type( - TypeDef(self.safe_name(str(rest["name"])) + "Loader", anon_type.name) + TypeDef( + name=self.safe_name(str(rest["name"])) + "Loader", + init=anon_type.name, + instance_type=anon_type.instance_type, + loader_type=anon_type.loader_type, + ) ) else: return anon_type @@ -470,14 +528,26 @@ def type_loader( docstring = f'\n"""\n{formated_doc}\n"""' else: docstring = "" + sym_names: Final = [schema.avro_field_name(sym) for sym in symbols] + sym_literals: Final = [f'"{s}"' for s in sym_names] + instance_type2: Final = f"Literal[{', '.join(sym_literals)}]" + self.declare_type( + TypeDef( + name=self.safe_name(name), + init=instance_type2, + instance_type="TypeAlias", + ) + ) return self.declare_type( TypeDef( - self.safe_name(name) + "Loader", - '_EnumLoader(("{}",), "{}"){}'.format( - '", "'.join(schema.avro_field_name(sym) for sym in symbols), + name=self.safe_name(name) + "Loader", + init='_EnumLoader(("{}",), "{}"){}'.format( + '", "'.join(sym_names), self.safe_name(name), docstring, ), + instance_type=self.safe_name(name), + loader_type=f"_Loader[{self.safe_name(name)}]", ) ) @@ -487,12 +557,14 @@ def type_loader( self.inherited_classes[classname] = f"{self.parents_map[prefix]}.{classname}" return self.declare_type( TypeDef( - classname + "Loader", - "_RecordLoader({}, {}, {})".format( + name=classname + "Loader", + init="_RecordLoader({}, {}, {})".format( self.inherited_classes.get(classname, classname), f"'{container}'" if container is not None else None, # noqa: B907 no_link_check, ), + instance_type=self.inherited_classes.get(classname, classname), + loader_type=f"_Loader[{self.inherited_classes.get(classname, classname)}]", abstract=bool(rest.get("abstract", False)), ) ) @@ -504,15 +576,28 @@ def type_loader( }: # Declare the named loader to handle recursive union definitions loader_name = self.safe_name(name) + "Loader" - loader_type = TypeDef(loader_name, f"_UnionLoader((), '{loader_name}')") + loader_type = TypeDef( + name=loader_name, + init=f"_UnionLoader((), '{loader_name}')", + instance_type=self.safe_name(name), + loader_type="_UnionLoader[Any]", + ) self.declare_type(loader_type) # Parse inner types - sub_names2: Final = list(dict.fromkeys([self.type_loader(i).name for i in names])) + sub_types2: Final = [self.type_loader(i) for i in names] + sub_names2: Final = list(dict.fromkeys(t.name for t in sub_types2)) # Register lazy initialization for the loader self.add_lazy_init( LazyInitDef( - loader_name, - "{}.add_loaders(({},))".format(loader_name, ", ".join(sub_names2)), + name=loader_name, + init="{}.add_loaders(({},))".format(loader_name, ", ".join(sub_names2)), + instance_type=f'{self.safe_name(name)}: TypeAlias = "' + + " | ".join( + sorted( + {t.instance_type for t in sub_types2 if t.instance_type is not None} + ) + ) + + '"', ) ) return loader_type @@ -525,8 +610,10 @@ def type_loader( case "Expression" | "https://w3id.org/cwl/cwl#Expression" as decl: return self.declare_type( TypeDef( - self.safe_name(decl) + "Loader", - "_ExpressionLoader(str)", + name=self.safe_name(decl) + "Loader", + init="_ExpressionLoader(str)", + instance_type="str", + loader_type="_Loader[str]", ) ) case str(decl): @@ -541,29 +628,29 @@ def declare_id_field( doc: str | None, optional: bool, ) -> None: + self.declare_field(name, fieldtype, doc, True, "") + if self.current_class_is_abstract: return - self.declare_field(name, fieldtype, doc, True, "") - if optional: opt = """{safename} = "_:" + str(_uuid__.uuid4())""".format( safename=self.safe_name(name) ) else: - opt = """_errors__.append(ValidationException("missing {fieldname}"))""".format( - fieldname=shortname(name) + opt = """{safename} = \"\" + _errors__.append(ValidationException("missing {fieldname}"))""".format( + safename=self.safe_name(name), fieldname=shortname(name) ) self.out.write(""" - __original_{safename}_is_none = {safename} is None if {safename} is None: if docRoot is not None: {safename} = docRoot else: {opt} - if not __original_{safename}_is_none: - baseuri = cast(str, {safename}) + else: + baseuri = {safename} """.format(safename=self.safe_name(name), opt=opt)) def declare_field( @@ -574,6 +661,8 @@ def declare_field( optional: bool, subscope: str | None, ) -> None: + self.current_fieldtypes[self.safe_name(name)] = fieldtype + if self.current_class_is_abstract: return @@ -756,11 +845,13 @@ def uri_loader( """Construct the TypeDef for the given URI loader.""" return self.declare_type( TypeDef( - f"uri_{inner.name}_{scoped_id}_{vocab_term}_{ref_scope}_{no_link_check}", - f"_URILoader({inner.name}, {scoped_id}, {vocab_term}, {ref_scope}, {no_link_check})", + name=f"uri_{inner.name}_{scoped_id}_{vocab_term}_{ref_scope}_{no_link_check}", + init=f"_URILoader({inner.name}, {scoped_id}, {vocab_term}, {ref_scope}, {no_link_check})", is_uri=True, scoped_id=scoped_id, ref_scope=ref_scope, + instance_type=inner.instance_type, + loader_type=inner.loader_type, ) ) @@ -770,8 +861,10 @@ def idmap_loader( """Construct the TypeDef for the given mapped ID loader.""" return self.declare_type( TypeDef( - f"idmap_{self.safe_name(field)}_{inner.name}", - f"_IdMapLoader({inner.name}, '{map_subject}', '{map_predicate}')", # noqa: B907 + name=f"idmap_{self.safe_name(field)}_{inner.name}", + init=f"_IdMapLoader({inner.name}, '{map_subject}', '{map_predicate}')", # noqa: B907 + instance_type=inner.instance_type, + loader_type=inner.loader_type, ) ) @@ -779,9 +872,11 @@ def typedsl_loader(self, inner: TypeDef, ref_scope: int | None) -> TypeDef: """Construct the TypeDef for the given DSL loader.""" return self.declare_type( TypeDef( - f"typedsl_{self.safe_name(inner.name)}_{ref_scope}", - f"_TypeDSLLoader({self.safe_name(inner.name)}, {ref_scope}, " # noqa: B907 + name=f"typedsl_{self.safe_name(inner.name)}_{ref_scope}", + init=f"_TypeDSLLoader({self.safe_name(inner.name)}, {ref_scope}, " # noqa: B907 f"'{self.salad_version}')", # noqa: B907 + instance_type=inner.instance_type, + loader_type=inner.loader_type, ) ) @@ -789,8 +884,10 @@ def secondaryfilesdsl_loader(self, inner: TypeDef) -> TypeDef: """Construct the TypeDef for secondary files.""" return self.declare_type( TypeDef( - f"secondaryfilesdsl_{inner.name}", - f"_UnionLoader((_SecondaryDSLLoader({inner.name}), {inner.name},))", + name=f"secondaryfilesdsl_{inner.name}", + init=f"_UnionLoader((_SecondaryDSLLoader({inner.name}), {inner.name},))", + instance_type=inner.instance_type, + loader_type=inner.loader_type, ) ) @@ -809,12 +906,39 @@ def epilogue(self, root_loader: TypeDef) -> None: for _, collected_type in self.collected_types.items(): if not collected_type.abstract: - self.out.write(fmt(f"{collected_type.name}: Final = {collected_type.init}\n", 0)) + self.out.write( + fmt( + "{}: {} = {}\n".format( + collected_type.name, + ( + f"Final[{collected_type.loader_type}]" + if collected_type.loader_type is not None + else collected_type.instance_type + ), + collected_type.init, + ), + 0, + ) + ) self.out.write("\n") if self.lazy_inits: for lazy_init in self.lazy_inits.values(): self.out.write(fmt(f"{lazy_init.init}\n", 0)) + self.out.write(fmt(f"{lazy_init.instance_type}", 0)) + self.out.write("\n") + + if abstract_classes := [ + e for e in TopologicalSorter(self.subclasses).static_order() if e in self.subclasses + ]: + for class_ in abstract_classes: + if self.subclasses[class_]: + self.out.write( + fmt( + f"{class_}: TypeAlias = {' | '.join(sorted(self.subclasses[class_]))}", + 0, + ) + ) self.out.write("\n") self.out.write( diff --git a/src/schema_salad/python_codegen_support.py b/src/schema_salad/python_codegen_support.py index d59cf811..270c6cf4 100644 --- a/src/schema_salad/python_codegen_support.py +++ b/src/schema_salad/python_codegen_support.py @@ -3,12 +3,18 @@ from __future__ import annotations import copy +from abc import ABCMeta, abstractmethod from collections.abc import MutableSequence, Sequence, MutableMapping from io import StringIO from itertools import chain +from typing import Literal, TypeVar # pylint: disable=unused-import # noqa: F401 +from collections.abc import Mapping +from typing import TypeAlias # pylint: disable=unused-import # noqa: F401 from typing import Any, Final, cast, Generic from urllib.parse import urldefrag, urlsplit, urlunsplit +from mypy_extensions import i32, i64 # pylint: disable=unused-import # noqa: F401 +from mypy_extensions import mypyc_attr from ruamel.yaml.comments import CommentedMap from schema_salad.exceptions import ValidationException, SchemaSaladException @@ -17,6 +23,8 @@ convert_typing, extract_type, SaveableType, + FieldType, + EnumFieldType, ) from schema_salad.sourceline import SourceLine, add_lc_filename from schema_salad.utils import yaml_no_ts # requires schema-salad v8.2+ @@ -25,7 +33,9 @@ _rvocab: Final[dict[str, str]] = {} -class _Loader: +@mypyc_attr(native_class=True) +class _Loader(Generic[FieldType], metaclass=ABCMeta): + @abstractmethod def load( self, doc: Any, @@ -33,11 +43,11 @@ def load( loadingOptions: LoadingOptions, docRoot: str | None = None, lc: Any | None = None, - ) -> Any | None: - pass + ) -> FieldType: ... -class _AnyLoader(_Loader): +@mypyc_attr(native_class=True) +class _AnyLoader(_Loader[Any]): def load( self, doc: Any, @@ -51,8 +61,9 @@ def load( raise ValidationException("Expected non-null") -class _PrimitiveLoader(_Loader): - def __init__(self, tp: type | tuple[type[str], type[str]]) -> None: +@mypyc_attr(native_class=True) +class _PrimitiveLoader(_Loader[FieldType]): + def __init__(self, tp: type[FieldType]) -> None: self.tp: Final = tp def load( @@ -62,7 +73,7 @@ def load( loadingOptions: LoadingOptions, docRoot: str | None = None, lc: Any | None = None, - ) -> Any: + ) -> FieldType: if not isinstance(doc, self.tp): raise ValidationException(f"Expected a {self.tp} but got {doc.__class__.__name__}") return doc @@ -71,8 +82,9 @@ def __repr__(self) -> str: return str(self.tp) -class _ArrayLoader(_Loader): - def __init__(self, items: _Loader) -> None: +@mypyc_attr(native_class=True) +class _ArrayLoader(_Loader[Sequence[FieldType]]): + def __init__(self, items: _Loader[FieldType]) -> None: self.items: Final = items def load( @@ -82,7 +94,7 @@ def load( loadingOptions: LoadingOptions, docRoot: str | None = None, lc: Any | None = None, - ) -> list[Any]: + ) -> list[FieldType]: if not isinstance(doc, MutableSequence): raise ValidationException( f"Value is a {convert_typing(extract_type(type(doc)))}, " @@ -128,10 +140,11 @@ def __repr__(self) -> str: return f"array<{self.items}>" -class _MapLoader(_Loader): +@mypyc_attr(native_class=True) +class _MapLoader(_Loader[Mapping[str, FieldType]]): def __init__( self, - values: _Loader, + values: _Loader[FieldType], name: str | None = None, container: str | None = None, no_link_check: bool | None = None, @@ -148,7 +161,7 @@ def load( loadingOptions: LoadingOptions, docRoot: str | None = None, lc: Any | None = None, - ) -> dict[str, Any]: + ) -> dict[str, FieldType]: if not isinstance(doc, MutableMapping): raise ValidationException(f"Expected a map, was {type(doc)}") if self.container is not None or self.no_link_check is not None: @@ -171,7 +184,8 @@ def __repr__(self) -> str: return self.name if self.name is not None else f"map" -class _EnumLoader(_Loader): +@mypyc_attr(native_class=True) +class _EnumLoader(_Loader[EnumFieldType]): def __init__(self, symbols: Sequence[str], name: str) -> None: self.symbols: Final = symbols self.name: Final = name @@ -183,17 +197,18 @@ def load( loadingOptions: LoadingOptions, docRoot: str | None = None, lc: Any | None = None, - ) -> str: + ) -> EnumFieldType: if doc in self.symbols: - return cast(str, doc) + return cast(EnumFieldType, doc) raise ValidationException(f"Expected one of {self.symbols}") def __repr__(self) -> str: return self.name -class _SecondaryDSLLoader(_Loader): - def __init__(self, inner: _Loader) -> None: +@mypyc_attr(native_class=True) +class _SecondaryDSLLoader(_Loader[FieldType]): + def __init__(self, inner: _Loader[FieldType]) -> None: self.inner: Final = inner def load( @@ -203,7 +218,7 @@ def load( loadingOptions: LoadingOptions, docRoot: str | None = None, lc: Any | None = None, - ) -> Any: + ) -> FieldType: r: Final[list[dict[str, Any]]] = [] match doc: case MutableSequence() as dlist: @@ -265,7 +280,8 @@ def load( return self.inner.load(r, baseuri, loadingOptions, docRoot, lc=lc) -class _RecordLoader(_Loader, Generic[SaveableType]): +@mypyc_attr(native_class=True) +class _RecordLoader(_Loader[SaveableType]): def __init__( self, classtype: type[SaveableType], @@ -299,7 +315,8 @@ def __repr__(self) -> str: return str(self.classtype.__name__) -class _ExpressionLoader(_Loader): +@mypyc_attr(native_class=True) +class _ExpressionLoader(_Loader[str]): def __init__(self, items: type[str]) -> None: self.items: Final = items @@ -320,12 +337,13 @@ def load( return doc -class _UnionLoader(_Loader): - def __init__(self, alternates: Sequence[_Loader], name: str | None = None) -> None: +@mypyc_attr(native_class=True) +class _UnionLoader(_Loader[FieldType]): + def __init__(self, alternates: Sequence[_Loader[FieldType]], name: str | None = None) -> None: self.alternates = alternates self.name: Final = name - def add_loaders(self, loaders: Sequence[_Loader]) -> None: + def add_loaders(self, loaders: Sequence[_Loader[FieldType]]) -> None: self.alternates = tuple(loader for loader in chain(self.alternates, loaders)) def load( @@ -335,7 +353,7 @@ def load( loadingOptions: LoadingOptions, docRoot: str | None = None, lc: Any | None = None, - ) -> Any: + ) -> FieldType: errors: Final = [] if lc is None: @@ -410,10 +428,11 @@ def __repr__(self) -> str: return self.name if self.name is not None else " | ".join(str(a) for a in self.alternates) -class _URILoader(_Loader): +@mypyc_attr(native_class=True) +class _URILoader(_Loader[FieldType]): def __init__( self, - inner: _Loader, + inner: _Loader[FieldType], scoped_id: bool, vocab_term: bool, scoped_ref: int | None, @@ -432,7 +451,7 @@ def load( loadingOptions: LoadingOptions, docRoot: str | None = None, lc: Any | None = None, - ) -> Any: + ) -> FieldType: if self.no_link_check is not None: loadingOptions = LoadingOptions( copyfrom=loadingOptions, no_link_check=self.no_link_check @@ -479,10 +498,11 @@ def load( return self.inner.load(doc, baseuri, loadingOptions, lc=lc) -class _TypeDSLLoader(_Loader): +@mypyc_attr(native_class=True) +class _TypeDSLLoader(_Loader[FieldType]): def __init__( self, - inner: _Loader, + inner: _Loader[FieldType], refScope: int | None, salad_version: str, ) -> None: @@ -553,7 +573,7 @@ def load( loadingOptions: LoadingOptions, docRoot: str | None = None, lc: Any | None = None, - ) -> Any: + ) -> FieldType: if isinstance(doc, MutableSequence): r: Final[list[Any]] = [] for d in doc: @@ -575,8 +595,10 @@ def load( return self.inner.load(doc, baseuri, loadingOptions, lc=lc) -class _IdMapLoader(_Loader): - def __init__(self, inner: _Loader, mapSubject: str, mapPredicate: str | None) -> None: +class _IdMapLoader(_Loader[FieldType]): + def __init__( + self, inner: _Loader[FieldType], mapSubject: str, mapPredicate: str | None + ) -> None: self.inner: Final = inner self.mapSubject: Final = mapSubject self.mapPredicate: Final = mapPredicate @@ -588,7 +610,7 @@ def load( loadingOptions: LoadingOptions, docRoot: str | None = None, lc: Any | None = None, - ) -> Any: + ) -> FieldType: if isinstance(doc, MutableMapping): r: Final[list[Any]] = [] for k in doc.keys(): @@ -615,12 +637,12 @@ def load( def _document_load( - loader: _Loader, + loader: _Loader[FieldType], doc: str | MutableMapping[str, Any] | MutableSequence[Any], baseuri: str, loadingOptions: LoadingOptions, addl_metadata_fields: MutableSequence[str] | None = None, -) -> tuple[Any, LoadingOptions]: +) -> tuple[FieldType, LoadingOptions]: if isinstance(doc, str): return _document_load_by_url( loader, @@ -685,11 +707,11 @@ def _document_load( def _document_load_by_url( - loader: _Loader, + loader: _Loader[FieldType], url: str, loadingOptions: LoadingOptions, addl_metadata_fields: MutableSequence[str] | None = None, -) -> tuple[Any, LoadingOptions]: +) -> tuple[FieldType, LoadingOptions]: if url in loadingOptions.idx: return loadingOptions.idx[url] @@ -785,11 +807,11 @@ def _expand_url( def _load_field( val: Any | None, - fieldtype: "_Loader", + fieldtype: _Loader[FieldType], baseuri: str, loadingOptions: LoadingOptions, lc: Any | None = None, -) -> Any: +) -> FieldType: """Load field.""" if isinstance(val, MutableMapping): if "$import" in val: diff --git a/src/schema_salad/runtime.py b/src/schema_salad/runtime.py index a0a06084..a2fb7814 100644 --- a/src/schema_salad/runtime.py +++ b/src/schema_salad/runtime.py @@ -18,6 +18,7 @@ from urllib.parse import quote, urlparse, urlsplit from urllib.request import pathname2url +from mypy_extensions import mypyc_attr, i32, i64 from rdflib import Graph from rdflib.plugins.parsers.notation3 import BadSyntax @@ -31,6 +32,8 @@ _logger: Final = logging.getLogger("salad") +EnumFieldType = TypeVar("EnumFieldType", bound=str) +FieldType = TypeVar("FieldType", covariant=True) IdxType: TypeAlias = MutableMapping[str, tuple[Any, "LoadingOptions"]] @@ -191,6 +194,7 @@ def graph(self) -> Graph: return graph +@mypyc_attr(native_class=True) class Saveable(metaclass=ABCMeta): """Mark classes than have a save() and fromDoc() function.""" @@ -213,8 +217,9 @@ def save( SaveableType = TypeVar("SaveableType", bound="Saveable") + save_type: TypeAlias = ( - None | MutableMapping[str, Any] | MutableSequence[Any] | int | float | bool | str + None | MutableMapping[str, Any] | MutableSequence[Any] | i32 | i64 | float | bool | str ) @@ -293,7 +298,7 @@ def save( for key in val: newdict[key] = save(val[key], top=False, base_url=base_url, relative_uris=relative_uris) return newdict - if val is None or isinstance(val, (int, float, bool, str)): + if val is None or isinstance(val, (i32, i64, float, bool, str)): return val raise Exception("Not Saveable: %s" % type(val)) diff --git a/src/schema_salad/tests/test_examples.py b/src/schema_salad/tests/test_examples.py index 5e41414c..caa6ee93 100644 --- a/src/schema_salad/tests/test_examples.py +++ b/src/schema_salad/tests/test_examples.py @@ -608,11 +608,10 @@ def test_python_codegen_parent(tmp_path: Path) -> None: ) with open(src_target) as f: content = f.read() - assert "class ArraySchema(Saveable)" not in content assert "class CWLArraySchema(schema_salad.metaschema.ArraySchema)" in content - assert "class Workflow(Process)" in content + assert "class Workflow(Saveable)" in content assert "EnumSchemaLoader: Final = _RecordLoader(EnumSchema, None, None)" not in content assert ( - "EnumSchemaLoader: Final = _RecordLoader(schema_salad.metaschema.EnumSchema, None, None)" + "EnumSchemaLoader: Final[_Loader[schema_salad.metaschema.EnumSchema]] = _RecordLoader(" in content ) diff --git a/src/schema_salad/tests/test_python_codegen.py b/src/schema_salad/tests/test_python_codegen.py index e962a698..93e9d1c6 100644 --- a/src/schema_salad/tests/test_python_codegen.py +++ b/src/schema_salad/tests/test_python_codegen.py @@ -32,8 +32,11 @@ def test_cwl_gen(tmp_path: Path) -> None: content = f.read() assert "class ArraySchema(Saveable)" in content assert "class CWLArraySchema(ArraySchema)" in content - assert "class Workflow(Process)" in content - assert "EnumSchemaLoader: Final = _RecordLoader(EnumSchema, None, None)" in content + assert "class Workflow(Saveable)" in content + assert ( + "EnumSchemaLoader: Final[_Loader[EnumSchema]] = _RecordLoader(EnumSchema, None, None)" + in content + ) def test_cwl_gen_with_inheritance(tmp_path: Path) -> None: @@ -47,12 +50,10 @@ def test_cwl_gen_with_inheritance(tmp_path: Path) -> None: assert os.path.exists(src_target) with open(src_target) as f: content = f.read() - assert "class ArraySchema(Saveable)" not in content assert "class CWLArraySchema(schema_salad.metaschema.ArraySchema)" in content - assert "class Workflow(Process)" in content - assert "EnumSchemaLoader: Final = _RecordLoader(EnumSchema, None, None)" not in content + assert "class Workflow(Saveable)" in content assert ( - "EnumSchemaLoader: Final = _RecordLoader(schema_salad.metaschema.EnumSchema, None, None)" + "EnumSchemaLoader: Final[_Loader[schema_salad.metaschema.EnumSchema]] = _RecordLoader(" in content )