#
# This file was autogenerated using schema-salad-tool --codegen=python
# The code itself is released under the Apache 2.0 license and the help text is
# subject to the license of the original schema.

import copy
import logging
import os
import pathlib
import tempfile
import uuid as _uuid__  # pylint: disable=unused-import # noqa: F401
import xml.sax  # nosec
from abc import ABC, abstractmethod
from collections.abc import MutableMapping, MutableSequence, Sequence
from io import StringIO
from itertools import chain
from typing import Any, Optional, Union, cast
from urllib.parse import quote, urldefrag, urlparse, urlsplit, urlunsplit
from urllib.request import pathname2url

from rdflib import Graph
from rdflib.plugins.parsers.notation3 import BadSyntax
from ruamel.yaml.comments import CommentedMap

from schema_salad.exceptions import SchemaSaladException, ValidationException
from schema_salad.fetcher import DefaultFetcher, Fetcher, MemoryCachingFetcher
from schema_salad.sourceline import SourceLine, add_lc_filename
from schema_salad.utils import CacheType, yaml_no_ts  # requires schema-salad v8.2+

_vocab: dict[str, str] = {}
_rvocab: dict[str, str] = {}

_logger = logging.getLogger("salad")


IdxType = MutableMapping[str, tuple[Any, "LoadingOptions"]]


class LoadingOptions:
    idx: IdxType
    fileuri: Optional[str]
    baseuri: str
    namespaces: MutableMapping[str, str]
    schemas: MutableSequence[str]
    original_doc: Optional[Any]
    addl_metadata: MutableMapping[str, Any]
    fetcher: Fetcher
    vocab: dict[str, str]
    rvocab: dict[str, str]
    cache: CacheType
    imports: list[str]
    includes: list[str]
    no_link_check: Optional[bool]
    container: Optional[str]

    def __init__(
        self,
        fetcher: Optional[Fetcher] = None,
        namespaces: Optional[dict[str, str]] = None,
        schemas: Optional[list[str]] = None,
        fileuri: Optional[str] = None,
        copyfrom: Optional["LoadingOptions"] = None,
        original_doc: Optional[Any] = None,
        addl_metadata: Optional[dict[str, str]] = None,
        baseuri: Optional[str] = None,
        idx: Optional[IdxType] = None,
        imports: Optional[list[str]] = None,
        includes: Optional[list[str]] = None,
        no_link_check: Optional[bool] = None,
        container: Optional[str] = None,
    ) -> None:
        """Create a LoadingOptions object."""
        self.original_doc = original_doc

        if idx is not None:
            self.idx = idx
        else:
            self.idx = copyfrom.idx if copyfrom is not None else {}

        if fileuri is not None:
            self.fileuri = fileuri
        else:
            self.fileuri = copyfrom.fileuri if copyfrom is not None else None

        if baseuri is not None:
            self.baseuri = baseuri
        else:
            self.baseuri = copyfrom.baseuri if copyfrom is not None else ""

        if namespaces is not None:
            self.namespaces = namespaces
        else:
            self.namespaces = copyfrom.namespaces if copyfrom is not None else {}

        if schemas is not None:
            self.schemas = schemas
        else:
            self.schemas = copyfrom.schemas if copyfrom is not None else []

        if addl_metadata is not None:
            self.addl_metadata = addl_metadata
        else:
            self.addl_metadata = copyfrom.addl_metadata if copyfrom is not None else {}

        if imports is not None:
            self.imports = imports
        else:
            self.imports = copyfrom.imports if copyfrom is not None else []

        if includes is not None:
            self.includes = includes
        else:
            self.includes = copyfrom.includes if copyfrom is not None else []

        if no_link_check is not None:
            self.no_link_check = no_link_check
        else:
            self.no_link_check = copyfrom.no_link_check if copyfrom is not None else False

        if container is not None:
            self.container = container
        else:
            self.container = copyfrom.container if copyfrom is not None else None

        if fetcher is not None:
            self.fetcher = fetcher
        elif copyfrom is not None:
            self.fetcher = copyfrom.fetcher
        else:
            import requests
            from cachecontrol.caches import SeparateBodyFileCache
            from cachecontrol.wrapper import CacheControl

            root = pathlib.Path(os.environ.get("HOME", tempfile.gettempdir()))
            session = CacheControl(
                requests.Session(),
                cache=SeparateBodyFileCache(root / ".cache" / "salad"),
            )
            self.fetcher: Fetcher = DefaultFetcher({}, session)

        self.cache = self.fetcher.cache if isinstance(self.fetcher, MemoryCachingFetcher) else {}

        self.vocab = _vocab
        self.rvocab = _rvocab

        if self.namespaces is not None:
            self.vocab = self.vocab.copy()
            self.rvocab = self.rvocab.copy()
            for k, v in self.namespaces.items():
                self.vocab[k] = v
                self.rvocab[v] = k

    @property
    def graph(self) -> Graph:
        """Generate a merged rdflib.Graph from all entries in self.schemas."""
        graph = Graph()
        if not self.schemas:
            return graph
        key = str(hash(tuple(self.schemas)))
        if key in self.cache:
            return cast(Graph, self.cache[key])
        for schema in self.schemas:
            fetchurl = (
                self.fetcher.urljoin(self.fileuri, schema)
                if self.fileuri is not None
                else pathlib.Path(schema).resolve().as_uri()
            )
            if fetchurl not in self.cache or self.cache[fetchurl] is True:
                _logger.debug("Getting external schema %s", fetchurl)
                try:
                    content = self.fetcher.fetch_text(fetchurl)
                except Exception as e:
                    _logger.warning("Could not load extension schema %s: %s", fetchurl, str(e))
                    continue
                newGraph = Graph()
                err_msg = "unknown error"
                for fmt in ["xml", "turtle"]:
                    try:
                        newGraph.parse(data=content, format=fmt, publicID=str(fetchurl))
                        self.cache[fetchurl] = newGraph
                        graph += newGraph
                        break
                    except (xml.sax.SAXParseException, TypeError, BadSyntax) as e:
                        err_msg = str(e)
                else:
                    _logger.warning("Could not load extension schema %s: %s", fetchurl, err_msg)
        self.cache[key] = graph
        return graph


class Saveable(ABC):
    """Mark classes than have a save() and fromDoc() function."""

    @classmethod
    @abstractmethod
    def fromDoc(
        cls,
        _doc: Any,
        baseuri: str,
        loadingOptions: LoadingOptions,
        docRoot: Optional[str] = None,
    ) -> "Saveable":
        """Construct this object from the result of yaml.load()."""

    @abstractmethod
    def save(
        self, top: bool = False, base_url: str = "", relative_uris: bool = True
    ) -> dict[str, Any]:
        """Convert this object to a JSON/YAML friendly dictionary."""


def load_field(
    val: Union[str, dict[str, str]],
    fieldtype: "_Loader",
    baseuri: str,
    loadingOptions: LoadingOptions,
    lc: Optional[list[Any]] = None,
) -> Any:
    """Load field."""
    if isinstance(val, MutableMapping):
        if "$import" in val:
            if loadingOptions.fileuri is None:
                raise SchemaSaladException("Cannot load $import without fileuri")
            url = loadingOptions.fetcher.urljoin(loadingOptions.fileuri, val["$import"])
            result, metadata = _document_load_by_url(
                fieldtype,
                url,
                loadingOptions,
            )
            loadingOptions.imports.append(url)
            return result
        if "$include" in val:
            if loadingOptions.fileuri is None:
                raise SchemaSaladException("Cannot load $import without fileuri")
            url = loadingOptions.fetcher.urljoin(loadingOptions.fileuri, val["$include"])
            val = loadingOptions.fetcher.fetch_text(url)
            loadingOptions.includes.append(url)
    return fieldtype.load(val, baseuri, loadingOptions, lc=lc)


save_type = Optional[Union[MutableMapping[str, Any], MutableSequence[Any], int, float, bool, str]]


def extract_type(val_type: type[Any]) -> str:
    """Take a type of value, and extracts the value as a string."""
    val_str = str(val_type)
    return val_str.split("'")[1]


def convert_typing(val_type: str) -> str:
    """Normalize type names to schema-salad types."""
    if "None" in val_type:
        return "null"
    if "CommentedSeq" in val_type or "list" in val_type:
        return "array"
    if "CommentedMap" in val_type or "dict" in val_type:
        return "object"
    if "False" in val_type or "True" in val_type:
        return "boolean"
    return val_type


def parse_errors(error_message: str) -> tuple[str, str, str]:
    """Parse error messages from several loaders into one error message."""
    if not error_message.startswith("Expected"):
        return error_message, "", ""
    vals = error_message.split("\n")
    if len(vals) == 1:
        return error_message, "", ""
    types = set()
    for val in vals:
        individual_vals = val.split(" ")
        if val == "":
            continue
        if individual_vals[1] == "one":
            individual_vals = val.split("(")[1].split(",")
            for t in individual_vals:
                types.add(t.strip(" ").strip(")\n"))
        elif individual_vals[2] == "<class":
            types.add(individual_vals[3].strip(">").replace("'", ""))
        elif individual_vals[0] == "Value":
            types.add(individual_vals[-1].strip("."))
        else:
            types.add(individual_vals[1].replace(",", ""))
    types = {val for val in types if val != "NoneType"}
    if "str" in types:
        types = {convert_typing(val) for val in types if "'" not in val}
    to_print = ""
    for val in types:
        if "'" in val:
            to_print = "value" if len(types) == 1 else "values"

    if to_print == "":
        to_print = "type" if len(types) == 1 else "types"

    verb_tensage = "is" if len(types) == 1 else "are"

    return str(types).replace("{", "(").replace("}", ")").replace("'", ""), to_print, verb_tensage


def save(
    val: Any,
    top: bool = True,
    base_url: str = "",
    relative_uris: bool = True,
) -> save_type:
    if isinstance(val, Saveable):
        return val.save(top=top, base_url=base_url, relative_uris=relative_uris)
    if isinstance(val, MutableSequence):
        return [save(v, top=False, base_url=base_url, relative_uris=relative_uris) for v in val]
    if isinstance(val, MutableMapping):
        newdict = {}
        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)):
        return val
    raise Exception("Not Saveable: %s" % type(val))


def save_with_metadata(
    val: Any,
    valLoadingOpts: LoadingOptions,
    top: bool = True,
    base_url: str = "",
    relative_uris: bool = True,
) -> save_type:
    """Save and set $namespaces, $schemas, $base and any other metadata fields at the top level."""
    saved_val = save(val, top, base_url, relative_uris)
    newdict: MutableMapping[str, Any] = {}
    if isinstance(saved_val, MutableSequence):
        newdict = {"$graph": saved_val}
    elif isinstance(saved_val, MutableMapping):
        newdict = saved_val

    if valLoadingOpts.namespaces:
        newdict["$namespaces"] = valLoadingOpts.namespaces
    if valLoadingOpts.schemas:
        newdict["$schemas"] = valLoadingOpts.schemas
    if valLoadingOpts.baseuri:
        newdict["$base"] = valLoadingOpts.baseuri
    for k, v in valLoadingOpts.addl_metadata.items():
        if k not in newdict:
            newdict[k] = v

    return newdict


def expand_url(
    url: str,
    base_url: str,
    loadingOptions: LoadingOptions,
    scoped_id: bool = False,
    vocab_term: bool = False,
    scoped_ref: Optional[int] = None,
) -> str:
    if url in ("@id", "@type"):
        return url

    if vocab_term and url in loadingOptions.vocab:
        return url

    if bool(loadingOptions.vocab) and ":" in url:
        prefix = url.split(":")[0]
        if prefix in loadingOptions.vocab:
            url = loadingOptions.vocab[prefix] + url[len(prefix) + 1 :]

    split = urlsplit(url)

    if (
        (bool(split.scheme) and split.scheme in loadingOptions.fetcher.supported_schemes())
        or url.startswith("$(")
        or url.startswith("${")
    ):
        pass
    elif scoped_id and not bool(split.fragment):
        splitbase = urlsplit(base_url)
        frg = ""
        if bool(splitbase.fragment):
            frg = splitbase.fragment + "/" + split.path
        else:
            frg = split.path
        pt = splitbase.path if splitbase.path != "" else "/"
        url = urlunsplit((splitbase.scheme, splitbase.netloc, pt, splitbase.query, frg))
    elif scoped_ref is not None and not bool(split.fragment):
        splitbase = urlsplit(base_url)
        sp = splitbase.fragment.split("/")
        n = scoped_ref
        while n > 0 and len(sp) > 0:
            sp.pop()
            n -= 1
        sp.append(url)
        url = urlunsplit(
            (
                splitbase.scheme,
                splitbase.netloc,
                splitbase.path,
                splitbase.query,
                "/".join(sp),
            )
        )
    else:
        url = loadingOptions.fetcher.urljoin(base_url, url)

    if vocab_term:
        split = urlsplit(url)
        if bool(split.scheme):
            if url in loadingOptions.rvocab:
                return loadingOptions.rvocab[url]
        else:
            raise ValidationException(f"Term {url!r} not in vocabulary")

    return url


class _Loader:
    def load(
        self,
        doc: Any,
        baseuri: str,
        loadingOptions: LoadingOptions,
        docRoot: Optional[str] = None,
        lc: Optional[list[Any]] = None,
    ) -> Any:
        pass


class _AnyLoader(_Loader):
    def load(
        self,
        doc: Any,
        baseuri: str,
        loadingOptions: LoadingOptions,
        docRoot: Optional[str] = None,
        lc: Optional[list[Any]] = None,
    ) -> Any:
        if doc is not None:
            return doc
        raise ValidationException("Expected non-null")


class _PrimitiveLoader(_Loader):
    def __init__(self, tp: Union[type, tuple[type[str], type[str]]]) -> None:
        self.tp = tp

    def load(
        self,
        doc: Any,
        baseuri: str,
        loadingOptions: LoadingOptions,
        docRoot: Optional[str] = None,
        lc: Optional[list[Any]] = None,
    ) -> Any:
        if not isinstance(doc, self.tp):
            raise ValidationException(f"Expected a {self.tp} but got {doc.__class__.__name__}")
        return doc

    def __repr__(self) -> str:
        return str(self.tp)


class _ArrayLoader(_Loader):
    def __init__(self, items: _Loader) -> None:
        self.items = items

    def load(
        self,
        doc: Any,
        baseuri: str,
        loadingOptions: LoadingOptions,
        docRoot: Optional[str] = None,
        lc: Optional[list[Any]] = None,
    ) -> Any:
        if not isinstance(doc, MutableSequence):
            raise ValidationException(
                f"Value is a {convert_typing(extract_type(type(doc)))}, "
                f"but valid type for this field is an array."
            )
        r: list[Any] = []
        errors: list[SchemaSaladException] = []
        fields: list[str] = []
        for i in range(0, len(doc)):
            try:
                lf = load_field(
                    doc[i], _UnionLoader([self, self.items]), baseuri, loadingOptions, lc=lc
                )
                flatten = loadingOptions.container != "@list"
                if flatten and isinstance(lf, MutableSequence):
                    r.extend(lf)
                else:
                    r.append(lf)

                if isinstance(doc[i], CommentedMap):
                    if doc[i].get("id") is not None:
                        if doc[i].get("id") in fields:
                            errors.append(
                                ValidationException(
                                    f"Duplicate field {doc[i].get('id')!r}",
                                    SourceLine(doc[i], "id", str),
                                    [],
                                )
                            )
                        else:
                            fields.append(doc[i].get("id"))

            except ValidationException as e:
                e = ValidationException(
                    "array item is invalid because", SourceLine(doc, i, str), [e]
                )
                errors.append(e)
        if errors:
            raise ValidationException("", None, errors)
        return r

    def __repr__(self) -> str:
        return f"array<{self.items}>"


class _MapLoader(_Loader):
    def __init__(
        self,
        values: _Loader,
        name: Optional[str] = None,
        container: Optional[str] = None,
        no_link_check: Optional[bool] = None,
    ) -> None:
        self.values = values
        self.name = name
        self.container = container
        self.no_link_check = no_link_check

    def load(
        self,
        doc: Any,
        baseuri: str,
        loadingOptions: LoadingOptions,
        docRoot: Optional[str] = None,
        lc: Optional[list[Any]] = None,
    ) -> Any:
        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:
            loadingOptions = LoadingOptions(
                copyfrom=loadingOptions, container=self.container, no_link_check=self.no_link_check
            )
        r: dict[str, Any] = {}
        errors: list[SchemaSaladException] = []
        for k, v in doc.items():
            try:
                lf = load_field(v, self.values, baseuri, loadingOptions, lc)
                r[k] = lf
            except ValidationException as e:
                errors.append(e.with_sourceline(SourceLine(doc, k, str)))
        if errors:
            raise ValidationException("", None, errors)
        return r

    def __repr__(self) -> str:
        return self.name if self.name is not None else f"map<string, {self.values}>"


class _EnumLoader(_Loader):
    def __init__(self, symbols: Sequence[str], name: str) -> None:
        self.symbols = symbols
        self.name = name

    def load(
        self,
        doc: Any,
        baseuri: str,
        loadingOptions: LoadingOptions,
        docRoot: Optional[str] = None,
        lc: Optional[list[Any]] = None,
    ) -> Any:
        if doc in self.symbols:
            return 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:
        self.inner = inner

    def load(
        self,
        doc: Any,
        baseuri: str,
        loadingOptions: LoadingOptions,
        docRoot: Optional[str] = None,
        lc: Optional[list[Any]] = None,
    ) -> Any:
        r: list[dict[str, Any]] = []
        if isinstance(doc, MutableSequence):
            for d in doc:
                if isinstance(d, str):
                    if d.endswith("?"):
                        r.append({"pattern": d[:-1], "required": False})
                    else:
                        r.append({"pattern": d})
                elif isinstance(d, dict):
                    new_dict: dict[str, Any] = {}
                    dict_copy = copy.deepcopy(d)
                    if "pattern" in dict_copy:
                        new_dict["pattern"] = dict_copy.pop("pattern")
                    else:
                        raise ValidationException(
                            f"Missing pattern in secondaryFiles specification entry: {d}"
                        )
                    new_dict["required"] = (
                        dict_copy.pop("required") if "required" in dict_copy else None
                    )

                    if len(dict_copy):
                        raise ValidationException(
                            "Unallowed values in secondaryFiles specification entry: {}".format(
                                dict_copy
                            )
                        )
                    r.append(new_dict)

                else:
                    raise ValidationException(
                        "Expected a string or sequence of (strings or mappings)."
                    )
        elif isinstance(doc, MutableMapping):
            new_dict = {}
            doc_copy = copy.deepcopy(doc)
            if "pattern" in doc_copy:
                new_dict["pattern"] = doc_copy.pop("pattern")
            else:
                raise ValidationException(
                    f"Missing pattern in secondaryFiles specification entry: {doc}"
                )
            new_dict["required"] = doc_copy.pop("required") if "required" in doc_copy else None

            if len(doc_copy):
                raise ValidationException(
                    f"Unallowed values in secondaryFiles specification entry: {doc_copy}"
                )
            r.append(new_dict)

        elif isinstance(doc, str):
            if doc.endswith("?"):
                r.append({"pattern": doc[:-1], "required": False})
            else:
                r.append({"pattern": doc})
        else:
            raise ValidationException("Expected str or sequence of str")
        return self.inner.load(r, baseuri, loadingOptions, docRoot, lc=lc)


class _RecordLoader(_Loader):
    def __init__(
        self,
        classtype: type[Saveable],
        container: Optional[str] = None,
        no_link_check: Optional[bool] = None,
    ) -> None:
        self.classtype = classtype
        self.container = container
        self.no_link_check = no_link_check

    def load(
        self,
        doc: Any,
        baseuri: str,
        loadingOptions: LoadingOptions,
        docRoot: Optional[str] = None,
        lc: Optional[list[Any]] = None,
    ) -> Any:
        if not isinstance(doc, MutableMapping):
            raise ValidationException(
                f"Value is a {convert_typing(extract_type(type(doc)))}, "
                f"but valid type for this field is an object."
            )
        if self.container is not None or self.no_link_check is not None:
            loadingOptions = LoadingOptions(
                copyfrom=loadingOptions, container=self.container, no_link_check=self.no_link_check
            )
        return self.classtype.fromDoc(doc, baseuri, loadingOptions, docRoot=docRoot)

    def __repr__(self) -> str:
        return str(self.classtype.__name__)


class _ExpressionLoader(_Loader):
    def __init__(self, items: type[str]) -> None:
        self.items = items

    def load(
        self,
        doc: Any,
        baseuri: str,
        loadingOptions: LoadingOptions,
        docRoot: Optional[str] = None,
        lc: Optional[list[Any]] = None,
    ) -> Any:
        if not isinstance(doc, str):
            raise ValidationException(
                f"Value is a {convert_typing(extract_type(type(doc)))}, "
                f"but valid type for this field is a str."
            )
        return doc


class _UnionLoader(_Loader):
    def __init__(self, alternates: Sequence[_Loader], name: Optional[str] = None) -> None:
        self.alternates = alternates
        self.name = name

    def add_loaders(self, loaders: Sequence[_Loader]) -> None:
        self.alternates = tuple(loader for loader in chain(self.alternates, loaders))

    def load(
        self,
        doc: Any,
        baseuri: str,
        loadingOptions: LoadingOptions,
        docRoot: Optional[str] = None,
        lc: Optional[list[Any]] = None,
    ) -> Any:
        errors = []

        if lc is None:
            lc = []

        for t in self.alternates:
            try:
                return t.load(doc, baseuri, loadingOptions, docRoot=docRoot, lc=lc)
            except ValidationException as e:
                if isinstance(t, _ArrayLoader) and len(self.alternates) > 1:
                    continue
                if isinstance(doc, (CommentedMap, dict)):
                    if "class" in doc:
                        if str(doc.get("class")) == str(t):
                            errors.append(
                                ValidationException(
                                    f"Object `{baseuri.split('/')[-1]}` is not valid because:",
                                    SourceLine(doc, next(iter(doc)), str),
                                    [e],
                                )
                            )
                    else:
                        if "array" in str(t):
                            continue
                        else:
                            if "id" in doc:
                                id = baseuri.split("/")[-1] + "#" + str(doc.get("id"))
                                if "id" in lc:
                                    errors.append(
                                        ValidationException(
                                            f"checking object `{id}` using `{t}`",
                                            SourceLine(lc, "id", str),
                                            [e],
                                        )
                                    )
                                else:
                                    errors.append(
                                        ValidationException(
                                            f"checking object `{id}` using `{t}`",
                                            SourceLine(lc, doc.get("id"), str),
                                            [e],
                                        )
                                    )
                            else:
                                if not isinstance(
                                    t, (_PrimitiveLoader)
                                ):  # avoids 'tried <class "NoneType"> was {x}' errors
                                    errors.append(
                                        ValidationException(f"tried `{t}` but", None, [e])
                                    )
                else:
                    # avoids "tried <class "CWLType"> but x" and instead returns the values for parsing
                    errors.append(ValidationException("", None, [e]))

        if isinstance(doc, (CommentedMap, dict)) and "class" in doc:
            if str(doc.get("class")) not in str(self.alternates):
                errors.append(
                    ValidationException(
                        "Field `class` contains undefined reference to "
                        + "`"
                        + "/".join(baseuri.split("/")[0:-1])
                        + "/"
                        + str(doc.get("class"))
                        + "`",
                        SourceLine(doc, "class", str),
                        [],
                    )
                )
        raise ValidationException("", None, errors, "*")

    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):
    def __init__(
        self,
        inner: _Loader,
        scoped_id: bool,
        vocab_term: bool,
        scoped_ref: Optional[int],
        no_link_check: Optional[bool],
    ) -> None:
        self.inner = inner
        self.scoped_id = scoped_id
        self.vocab_term = vocab_term
        self.scoped_ref = scoped_ref
        self.no_link_check = no_link_check

    def load(
        self,
        doc: Any,
        baseuri: str,
        loadingOptions: LoadingOptions,
        docRoot: Optional[str] = None,
        lc: Optional[list[Any]] = None,
    ) -> Any:
        if self.no_link_check is not None:
            loadingOptions = LoadingOptions(
                copyfrom=loadingOptions, no_link_check=self.no_link_check
            )
        if isinstance(doc, MutableSequence):
            newdoc = []
            for i in doc:
                if isinstance(i, str):
                    newdoc.append(
                        expand_url(
                            i,
                            baseuri,
                            loadingOptions,
                            self.scoped_id,
                            self.vocab_term,
                            self.scoped_ref,
                        )
                    )
                else:
                    newdoc.append(i)
            doc = newdoc
        elif isinstance(doc, str):
            doc = expand_url(
                doc,
                baseuri,
                loadingOptions,
                self.scoped_id,
                self.vocab_term,
                self.scoped_ref,
            )
        if isinstance(doc, str):
            if not loadingOptions.no_link_check:
                errors = []
                try:
                    if not loadingOptions.fetcher.check_exists(doc):
                        errors.append(
                            ValidationException(f"contains undefined reference to `{doc}`")
                        )
                except ValidationException:
                    pass
                if len(errors) > 0:
                    raise ValidationException("", None, errors)
        return self.inner.load(doc, baseuri, loadingOptions, lc=lc)


class _TypeDSLLoader(_Loader):
    def __init__(self, inner: _Loader, refScope: Optional[int], salad_version: str) -> None:
        self.inner = inner
        self.refScope = refScope
        self.salad_version = salad_version

    def resolve(
        self,
        doc: str,
        baseuri: str,
        loadingOptions: LoadingOptions,
    ) -> Union[list[Union[dict[str, Any], str]], dict[str, Any], str]:
        doc_ = doc
        optional = False
        if doc_.endswith("?"):
            optional = True
            doc_ = doc_[0:-1]

        if doc_.endswith("[]"):
            salad_versions = [int(v) for v in self.salad_version[1:].split(".")]
            items: Union[list[Union[dict[str, Any], str]], dict[str, Any], str] = ""
            rest = doc_[0:-2]
            if salad_versions < [1, 3]:
                if rest.endswith("[]"):
                    # To show the error message with the original type
                    return doc
                else:
                    items = expand_url(rest, baseuri, loadingOptions, False, True, self.refScope)
            else:
                items = self.resolve(rest, baseuri, loadingOptions)
                if isinstance(items, str):
                    items = expand_url(items, baseuri, loadingOptions, False, True, self.refScope)
            expanded: Union[dict[str, Any], str] = {"type": "array", "items": items}
        else:
            expanded = expand_url(doc_, baseuri, loadingOptions, False, True, self.refScope)

        if optional:
            return ["null", expanded]
        else:
            return expanded

    def load(
        self,
        doc: Any,
        baseuri: str,
        loadingOptions: LoadingOptions,
        docRoot: Optional[str] = None,
        lc: Optional[list[Any]] = None,
    ) -> Any:
        if isinstance(doc, MutableSequence):
            r: list[Any] = []
            for d in doc:
                if isinstance(d, str):
                    resolved = self.resolve(d, baseuri, loadingOptions)
                    if isinstance(resolved, MutableSequence):
                        for i in resolved:
                            if i not in r:
                                r.append(i)
                    else:
                        if resolved not in r:
                            r.append(resolved)
                else:
                    r.append(d)
            doc = r
        elif isinstance(doc, str):
            doc = self.resolve(doc, baseuri, loadingOptions)

        return self.inner.load(doc, baseuri, loadingOptions, lc=lc)


class _IdMapLoader(_Loader):
    def __init__(self, inner: _Loader, mapSubject: str, mapPredicate: Optional[str]) -> None:
        self.inner = inner
        self.mapSubject = mapSubject
        self.mapPredicate = mapPredicate

    def load(
        self,
        doc: Any,
        baseuri: str,
        loadingOptions: LoadingOptions,
        docRoot: Optional[str] = None,
        lc: Optional[list[Any]] = None,
    ) -> Any:
        if isinstance(doc, MutableMapping):
            r: list[Any] = []
            for k in doc.keys():
                val = doc[k]
                if isinstance(val, CommentedMap):
                    v = copy.copy(val)
                    v.lc.data = val.lc.data
                    v.lc.filename = val.lc.filename
                    v[self.mapSubject] = k
                    r.append(v)
                elif isinstance(val, MutableMapping):
                    v2 = copy.copy(val)
                    v2[self.mapSubject] = k
                    r.append(v2)
                else:
                    if self.mapPredicate:
                        v3 = {self.mapPredicate: val}
                        v3[self.mapSubject] = k
                        r.append(v3)
                    else:
                        raise ValidationException("No mapPredicate")
            doc = r
        return self.inner.load(doc, baseuri, loadingOptions, lc=lc)


def _document_load(
    loader: _Loader,
    doc: Union[str, MutableMapping[str, Any], MutableSequence[Any]],
    baseuri: str,
    loadingOptions: LoadingOptions,
    addl_metadata_fields: Optional[MutableSequence[str]] = None,
) -> tuple[Any, LoadingOptions]:
    if isinstance(doc, str):
        return _document_load_by_url(
            loader,
            loadingOptions.fetcher.urljoin(baseuri, doc),
            loadingOptions,
            addl_metadata_fields=addl_metadata_fields,
        )

    if isinstance(doc, MutableMapping):
        addl_metadata = {}
        if addl_metadata_fields is not None:
            for mf in addl_metadata_fields:
                if mf in doc:
                    addl_metadata[mf] = doc[mf]

        docuri = baseuri
        if "$base" in doc:
            baseuri = doc["$base"]

        loadingOptions = LoadingOptions(
            copyfrom=loadingOptions,
            namespaces=doc.get("$namespaces", None),
            schemas=doc.get("$schemas", None),
            baseuri=doc.get("$base", None),
            addl_metadata=addl_metadata,
        )

        doc = copy.copy(doc)
        if "$namespaces" in doc:
            doc.pop("$namespaces")
        if "$schemas" in doc:
            doc.pop("$schemas")
        if "$base" in doc:
            doc.pop("$base")

        if "$graph" in doc:
            loadingOptions.idx[baseuri] = (
                loader.load(doc["$graph"], baseuri, loadingOptions),
                loadingOptions,
            )
        else:
            loadingOptions.idx[baseuri] = (
                loader.load(doc, baseuri, loadingOptions, docRoot=baseuri),
                loadingOptions,
            )

        if docuri != baseuri:
            loadingOptions.idx[docuri] = loadingOptions.idx[baseuri]

        return loadingOptions.idx[baseuri]

    if isinstance(doc, MutableSequence):
        loadingOptions.idx[baseuri] = (
            loader.load(doc, baseuri, loadingOptions),
            loadingOptions,
        )
        return loadingOptions.idx[baseuri]

    raise ValidationException(
        "Expected URI string, MutableMapping or MutableSequence, got %s" % type(doc)
    )


def _document_load_by_url(
    loader: _Loader,
    url: str,
    loadingOptions: LoadingOptions,
    addl_metadata_fields: Optional[MutableSequence[str]] = None,
) -> tuple[Any, LoadingOptions]:
    if url in loadingOptions.idx:
        return loadingOptions.idx[url]

    doc_url, frg = urldefrag(url)

    text = loadingOptions.fetcher.fetch_text(doc_url)
    textIO = StringIO(text)
    textIO.name = str(doc_url)
    yaml = yaml_no_ts()
    result = yaml.load(textIO)
    add_lc_filename(result, doc_url)

    loadingOptions = LoadingOptions(copyfrom=loadingOptions, fileuri=doc_url)

    _document_load(
        loader,
        result,
        doc_url,
        loadingOptions,
        addl_metadata_fields=addl_metadata_fields,
    )

    return loadingOptions.idx[url]


def file_uri(path: str, split_frag: bool = False) -> str:
    """Transform a file path into a URL with file scheme."""
    if path.startswith("file://"):
        return path
    if split_frag:
        pathsp = path.split("#", 2)
        frag = "#" + quote(str(pathsp[1])) if len(pathsp) == 2 else ""
        urlpath = pathname2url(str(pathsp[0]))
    else:
        urlpath = pathname2url(path)
        frag = ""
    if urlpath.startswith("//"):
        return f"file:{urlpath}{frag}"
    return f"file://{urlpath}{frag}"


def prefix_url(url: str, namespaces: dict[str, str]) -> str:
    """Expand short forms into full URLs using the given namespace dictionary."""
    for k, v in namespaces.items():
        if url.startswith(v):
            return k + ":" + url[len(v) :]
    return url


def save_relative_uri(
    uri: Any,
    base_url: str,
    scoped_id: bool,
    ref_scope: Optional[int],
    relative_uris: bool,
) -> Any:
    """Convert any URI to a relative one, obeying the scoping rules."""
    if isinstance(uri, MutableSequence):
        return [save_relative_uri(u, base_url, scoped_id, ref_scope, relative_uris) for u in uri]
    elif isinstance(uri, str):
        if not relative_uris or uri == base_url:
            return uri
        urisplit = urlsplit(uri)
        basesplit = urlsplit(base_url)
        if urisplit.scheme == basesplit.scheme and urisplit.netloc == basesplit.netloc:
            if urisplit.path != basesplit.path:
                p = os.path.relpath(urisplit.path, os.path.dirname(basesplit.path))
                if urisplit.fragment:
                    p = p + "#" + urisplit.fragment
                return p

            basefrag = basesplit.fragment + "/"
            if ref_scope:
                sp = basefrag.split("/")
                i = 0
                while i < ref_scope:
                    sp.pop()
                    i += 1
                basefrag = "/".join(sp)

            if urisplit.fragment.startswith(basefrag):
                return urisplit.fragment[len(basefrag) :]
            return urisplit.fragment
        return uri
    else:
        return save(uri, top=False, base_url=base_url, relative_uris=relative_uris)


def shortname(inputid: str) -> str:
    """
    Compute the shortname of a fully qualified identifier.

    See https://w3id.org/cwl/v1.2/SchemaSalad.html#Short_names.
    """
    parsed_id = urlparse(inputid)
    if parsed_id.fragment:
        return parsed_id.fragment.split("/")[-1]
    return parsed_id.path.split("/")[-1]


def parser_info() -> str:
    return "org.galaxyproject.gxformat2.v19_09"


class Documented(Saveable):
    pass


class RecordField(Documented):
    """
    A field of a record.
    """

    name: str

    def __init__(
        self,
        name: Any,
        type_: Any,
        doc: Optional[Any] = None,
        extension_fields: Optional[dict[str, Any]] = None,
        loadingOptions: Optional[LoadingOptions] = 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(
                self.doc == other.doc
                and self.name == other.name
                and self.type_ == other.type_
            )
        return False

    def __hash__(self) -> int:
        return hash((self.doc, self.name, self.type_))

    @classmethod
    def fromDoc(
        cls,
        doc: Any,
        baseuri: str,
        loadingOptions: LoadingOptions,
        docRoot: Optional[str] = None
    ) -> "RecordField":
        _doc = copy.copy(doc)

        if hasattr(doc, "lc"):
            _doc.lc.data = doc.lc.data
            _doc.lc.filename = doc.lc.filename
        _errors__ = []
        name = None
        if "name" in _doc:
            try:
                name = load_field(
                    _doc.get("name"),
                    uri_strtype_True_False_None_None,
                    baseuri,
                    loadingOptions,
                    lc=_doc.get("name")
                )

            except ValidationException as e:
                error_message, to_print, verb_tensage = parse_errors(str(e))

                if str(e) == "missing required field `name`":
                    _errors__.append(
                        ValidationException(
                            str(e),
                            None
                        )
                    )
                else:
                    val = _doc.get("name")
                    if error_message != str(e):
                        val_type = convert_typing(extract_type(type(val)))
                        _errors__.append(
                            ValidationException(
                                "the `name` field is not valid because:",
                                SourceLine(_doc, "name", str),
                                [ValidationException(f"Value is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}",
                                                     detailed_message=f"Value `{val}` is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}")],
                            )
                        )
                    else:
                        _errors__.append(
                            ValidationException(
                                "the `name` field is not valid because:",
                                SourceLine(_doc, "name", str),
                                [e],
                                detailed_message=f"the `name` field with value `{val}` "
                                "is not valid because:",
                            )
                        )

        __original_name_is_none = name is None
        if name is None:
            if docRoot is not None:
                name = docRoot
            else:
                _errors__.append(ValidationException("missing name"))
        if not __original_name_is_none:
            baseuri = cast(str, name)
        doc = None
        if "doc" in _doc:
            try:
                doc = load_field(
                    _doc.get("doc"),
                    union_of_None_type_or_strtype_or_array_of_strtype,
                    baseuri,
                    loadingOptions,
                    lc=_doc.get("doc")
                )

            except ValidationException as e:
                error_message, to_print, verb_tensage = parse_errors(str(e))

                if str(e) == "missing required field `doc`":
                    _errors__.append(
                        ValidationException(
                            str(e),
                            None
                        )
                    )
                else:
                    val = _doc.get("doc")
                    if error_message != str(e):
                        val_type = convert_typing(extract_type(type(val)))
                        _errors__.append(
                            ValidationException(
                                "the `doc` field is not valid because:",
                                SourceLine(_doc, "doc", str),
                                [ValidationException(f"Value is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}",
                                                     detailed_message=f"Value `{val}` is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}")],
                            )
                        )
                    else:
                        _errors__.append(
                            ValidationException(
                                "the `doc` field is not valid because:",
                                SourceLine(_doc, "doc", str),
                                [e],
                                detailed_message=f"the `doc` field with value `{val}` "
                                "is not valid because:",
                            )
                        )
        try:
            if _doc.get("type") is None:
                raise ValidationException("missing required field `type`", None, [])

            type_ = load_field(
                _doc.get("type"),
                typedsl_union_of_PrimitiveTypeLoader_or_RecordSchemaLoader_or_EnumSchemaLoader_or_ArraySchemaLoader_or_strtype_or_array_of_union_of_PrimitiveTypeLoader_or_RecordSchemaLoader_or_EnumSchemaLoader_or_ArraySchemaLoader_or_strtype_2,
                baseuri,
                loadingOptions,
                lc=_doc.get("type")
            )

        except ValidationException as e:
            error_message, to_print, verb_tensage = parse_errors(str(e))

            if str(e) == "missing required field `type`":
                _errors__.append(
                    ValidationException(
                        str(e),
                        None
                    )
                )
            else:
                val = _doc.get("type")
                if error_message != str(e):
                    val_type = convert_typing(extract_type(type(val)))
                    _errors__.append(
                        ValidationException(
                            "the `type` field is not valid because:",
                            SourceLine(_doc, "type", str),
                            [ValidationException(f"Value is a {val_type}, "
                                                 f"but valid {to_print} for this field "
                                                 f"{verb_tensage} {error_message}",
                                                 detailed_message=f"Value `{val}` is a {val_type}, "
                                                 f"but valid {to_print} for this field "
                                                 f"{verb_tensage} {error_message}")],
                        )
                    )
                else:
                    _errors__.append(
                        ValidationException(
                            "the `type` field is not valid because:",
                            SourceLine(_doc, "type", str),
                            [e],
                            detailed_message=f"the `type` field with value `{val}` "
                            "is not valid because:",
                        )
                    )
        extension_fields: dict[str, Any] = {}
        for k in _doc.keys():
            if k not in cls.attrs:
                if not k:
                    _errors__.append(
                        ValidationException("mapping with implicit null key")
                    )
                elif ":" in k:
                    ex = expand_url(
                        k, "", loadingOptions, scoped_id=False, vocab_term=False
                    )
                    extension_fields[ex] = _doc[k]
                else:
                    _errors__.append(
                        ValidationException(
                            "invalid field `{}`, expected one of: `doc`, `name`, `type`".format(
                                k
                            ),
                            SourceLine(_doc, k, str),
                        )
                    )

        if _errors__:
            raise ValidationException("", None, _errors__, "*")
        _constructed = cls(
            doc=doc,
            name=name,
            type_=type_,
            extension_fields=extension_fields,
            loadingOptions=loadingOptions,
        )
        loadingOptions.idx[cast(str, name)] = (_constructed, loadingOptions)
        return _constructed

    def save(
        self, top: bool = False, base_url: str = "", relative_uris: bool = True
    ) -> dict[str, Any]:
        r: dict[str, Any] = {}

        if relative_uris:
            for ef in self.extension_fields:
                r[prefix_url(ef, self.loadingOptions.vocab)] = self.extension_fields[ef]
        else:
            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)
            r["name"] = u
        if self.doc is not None:
            r["doc"] = save(
                self.doc, top=False, base_url=self.name, relative_uris=relative_uris
            )
        if self.type_ is not None:
            r["type"] = save(
                self.type_, top=False, base_url=self.name, relative_uris=relative_uris
            )

        # top refers to the directory level
        if top:
            if self.loadingOptions.namespaces:
                r["$namespaces"] = self.loadingOptions.namespaces
            if self.loadingOptions.schemas:
                r["$schemas"] = self.loadingOptions.schemas
        return r

    attrs = frozenset(["doc", "name", "type"])


class RecordSchema(Saveable):
    def __init__(
        self,
        type_: Any,
        fields: Optional[Any] = None,
        extension_fields: Optional[dict[str, Any]] = None,
        loadingOptions: Optional[LoadingOptions] = 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.fields = fields
        self.type_ = type_

    def __eq__(self, other: Any) -> bool:
        if isinstance(other, RecordSchema):
            return bool(self.fields == other.fields and self.type_ == other.type_)
        return False

    def __hash__(self) -> int:
        return hash((self.fields, self.type_))

    @classmethod
    def fromDoc(
        cls,
        doc: Any,
        baseuri: str,
        loadingOptions: LoadingOptions,
        docRoot: Optional[str] = None
    ) -> "RecordSchema":
        _doc = copy.copy(doc)

        if hasattr(doc, "lc"):
            _doc.lc.data = doc.lc.data
            _doc.lc.filename = doc.lc.filename
        _errors__ = []
        fields = None
        if "fields" in _doc:
            try:
                fields = load_field(
                    _doc.get("fields"),
                    idmap_fields_union_of_None_type_or_array_of_RecordFieldLoader,
                    baseuri,
                    loadingOptions,
                    lc=_doc.get("fields")
                )

            except ValidationException as e:
                error_message, to_print, verb_tensage = parse_errors(str(e))

                if str(e) == "missing required field `fields`":
                    _errors__.append(
                        ValidationException(
                            str(e),
                            None
                        )
                    )
                else:
                    val = _doc.get("fields")
                    if error_message != str(e):
                        val_type = convert_typing(extract_type(type(val)))
                        _errors__.append(
                            ValidationException(
                                "the `fields` field is not valid because:",
                                SourceLine(_doc, "fields", str),
                                [ValidationException(f"Value is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}",
                                                     detailed_message=f"Value `{val}` is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}")],
                            )
                        )
                    else:
                        _errors__.append(
                            ValidationException(
                                "the `fields` field is not valid because:",
                                SourceLine(_doc, "fields", str),
                                [e],
                                detailed_message=f"the `fields` field with value `{val}` "
                                "is not valid because:",
                            )
                        )
        try:
            if _doc.get("type") is None:
                raise ValidationException("missing required field `type`", None, [])

            type_ = load_field(
                _doc.get("type"),
                typedsl_enum_d9cba076fca539106791a4f46d198c7fcfbdb779Loader_2,
                baseuri,
                loadingOptions,
                lc=_doc.get("type")
            )

        except ValidationException as e:
            error_message, to_print, verb_tensage = parse_errors(str(e))

            if str(e) == "missing required field `type`":
                _errors__.append(
                    ValidationException(
                        str(e),
                        None
                    )
                )
            else:
                val = _doc.get("type")
                if error_message != str(e):
                    val_type = convert_typing(extract_type(type(val)))
                    _errors__.append(
                        ValidationException(
                            "the `type` field is not valid because:",
                            SourceLine(_doc, "type", str),
                            [ValidationException(f"Value is a {val_type}, "
                                                 f"but valid {to_print} for this field "
                                                 f"{verb_tensage} {error_message}",
                                                 detailed_message=f"Value `{val}` is a {val_type}, "
                                                 f"but valid {to_print} for this field "
                                                 f"{verb_tensage} {error_message}")],
                        )
                    )
                else:
                    _errors__.append(
                        ValidationException(
                            "the `type` field is not valid because:",
                            SourceLine(_doc, "type", str),
                            [e],
                            detailed_message=f"the `type` field with value `{val}` "
                            "is not valid because:",
                        )
                    )
        extension_fields: dict[str, Any] = {}
        for k in _doc.keys():
            if k not in cls.attrs:
                if not k:
                    _errors__.append(
                        ValidationException("mapping with implicit null key")
                    )
                elif ":" in k:
                    ex = expand_url(
                        k, "", loadingOptions, scoped_id=False, vocab_term=False
                    )
                    extension_fields[ex] = _doc[k]
                else:
                    _errors__.append(
                        ValidationException(
                            "invalid field `{}`, expected one of: `fields`, `type`".format(
                                k
                            ),
                            SourceLine(_doc, k, str),
                        )
                    )

        if _errors__:
            raise ValidationException("", None, _errors__, "*")
        _constructed = cls(
            fields=fields,
            type_=type_,
            extension_fields=extension_fields,
            loadingOptions=loadingOptions,
        )
        return _constructed

    def save(
        self, top: bool = False, base_url: str = "", relative_uris: bool = True
    ) -> dict[str, Any]:
        r: dict[str, Any] = {}

        if relative_uris:
            for ef in self.extension_fields:
                r[prefix_url(ef, self.loadingOptions.vocab)] = self.extension_fields[ef]
        else:
            for ef in self.extension_fields:
                r[ef] = self.extension_fields[ef]
        if self.fields is not None:
            r["fields"] = save(
                self.fields, top=False, base_url=base_url, relative_uris=relative_uris
            )
        if self.type_ is not None:
            r["type"] = save(
                self.type_, top=False, base_url=base_url, relative_uris=relative_uris
            )

        # top refers to the directory level
        if top:
            if self.loadingOptions.namespaces:
                r["$namespaces"] = self.loadingOptions.namespaces
            if self.loadingOptions.schemas:
                r["$schemas"] = self.loadingOptions.schemas
        return r

    attrs = frozenset(["fields", "type"])


class EnumSchema(Saveable):
    """
    Define an enumerated type.

    """

    def __init__(
        self,
        symbols: Any,
        type_: Any,
        extension_fields: Optional[dict[str, Any]] = None,
        loadingOptions: Optional[LoadingOptions] = 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.symbols = symbols
        self.type_ = type_

    def __eq__(self, other: Any) -> bool:
        if isinstance(other, EnumSchema):
            return bool(self.symbols == other.symbols and self.type_ == other.type_)
        return False

    def __hash__(self) -> int:
        return hash((self.symbols, self.type_))

    @classmethod
    def fromDoc(
        cls,
        doc: Any,
        baseuri: str,
        loadingOptions: LoadingOptions,
        docRoot: Optional[str] = None
    ) -> "EnumSchema":
        _doc = copy.copy(doc)

        if hasattr(doc, "lc"):
            _doc.lc.data = doc.lc.data
            _doc.lc.filename = doc.lc.filename
        _errors__ = []
        try:
            if _doc.get("symbols") is None:
                raise ValidationException("missing required field `symbols`", None, [])

            symbols = load_field(
                _doc.get("symbols"),
                uri_array_of_strtype_True_False_None_None,
                baseuri,
                loadingOptions,
                lc=_doc.get("symbols")
            )

        except ValidationException as e:
            error_message, to_print, verb_tensage = parse_errors(str(e))

            if str(e) == "missing required field `symbols`":
                _errors__.append(
                    ValidationException(
                        str(e),
                        None
                    )
                )
            else:
                val = _doc.get("symbols")
                if error_message != str(e):
                    val_type = convert_typing(extract_type(type(val)))
                    _errors__.append(
                        ValidationException(
                            "the `symbols` field is not valid because:",
                            SourceLine(_doc, "symbols", str),
                            [ValidationException(f"Value is a {val_type}, "
                                                 f"but valid {to_print} for this field "
                                                 f"{verb_tensage} {error_message}",
                                                 detailed_message=f"Value `{val}` is a {val_type}, "
                                                 f"but valid {to_print} for this field "
                                                 f"{verb_tensage} {error_message}")],
                        )
                    )
                else:
                    _errors__.append(
                        ValidationException(
                            "the `symbols` field is not valid because:",
                            SourceLine(_doc, "symbols", str),
                            [e],
                            detailed_message=f"the `symbols` field with value `{val}` "
                            "is not valid because:",
                        )
                    )
        try:
            if _doc.get("type") is None:
                raise ValidationException("missing required field `type`", None, [])

            type_ = load_field(
                _doc.get("type"),
                typedsl_enum_d961d79c225752b9fadb617367615ab176b47d77Loader_2,
                baseuri,
                loadingOptions,
                lc=_doc.get("type")
            )

        except ValidationException as e:
            error_message, to_print, verb_tensage = parse_errors(str(e))

            if str(e) == "missing required field `type`":
                _errors__.append(
                    ValidationException(
                        str(e),
                        None
                    )
                )
            else:
                val = _doc.get("type")
                if error_message != str(e):
                    val_type = convert_typing(extract_type(type(val)))
                    _errors__.append(
                        ValidationException(
                            "the `type` field is not valid because:",
                            SourceLine(_doc, "type", str),
                            [ValidationException(f"Value is a {val_type}, "
                                                 f"but valid {to_print} for this field "
                                                 f"{verb_tensage} {error_message}",
                                                 detailed_message=f"Value `{val}` is a {val_type}, "
                                                 f"but valid {to_print} for this field "
                                                 f"{verb_tensage} {error_message}")],
                        )
                    )
                else:
                    _errors__.append(
                        ValidationException(
                            "the `type` field is not valid because:",
                            SourceLine(_doc, "type", str),
                            [e],
                            detailed_message=f"the `type` field with value `{val}` "
                            "is not valid because:",
                        )
                    )
        extension_fields: dict[str, Any] = {}
        for k in _doc.keys():
            if k not in cls.attrs:
                if not k:
                    _errors__.append(
                        ValidationException("mapping with implicit null key")
                    )
                elif ":" in k:
                    ex = expand_url(
                        k, "", loadingOptions, scoped_id=False, vocab_term=False
                    )
                    extension_fields[ex] = _doc[k]
                else:
                    _errors__.append(
                        ValidationException(
                            "invalid field `{}`, expected one of: `symbols`, `type`".format(
                                k
                            ),
                            SourceLine(_doc, k, str),
                        )
                    )

        if _errors__:
            raise ValidationException("", None, _errors__, "*")
        _constructed = cls(
            symbols=symbols,
            type_=type_,
            extension_fields=extension_fields,
            loadingOptions=loadingOptions,
        )
        return _constructed

    def save(
        self, top: bool = False, base_url: str = "", relative_uris: bool = True
    ) -> dict[str, Any]:
        r: dict[str, Any] = {}

        if relative_uris:
            for ef in self.extension_fields:
                r[prefix_url(ef, self.loadingOptions.vocab)] = self.extension_fields[ef]
        else:
            for ef in self.extension_fields:
                r[ef] = self.extension_fields[ef]
        if self.symbols is not None:
            u = save_relative_uri(self.symbols, base_url, True, None, relative_uris)
            r["symbols"] = u
        if self.type_ is not None:
            r["type"] = save(
                self.type_, top=False, base_url=base_url, relative_uris=relative_uris
            )

        # top refers to the directory level
        if top:
            if self.loadingOptions.namespaces:
                r["$namespaces"] = self.loadingOptions.namespaces
            if self.loadingOptions.schemas:
                r["$schemas"] = self.loadingOptions.schemas
        return r

    attrs = frozenset(["symbols", "type"])


class ArraySchema(Saveable):
    def __init__(
        self,
        items: Any,
        type_: Any,
        extension_fields: Optional[dict[str, Any]] = None,
        loadingOptions: Optional[LoadingOptions] = 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.items = items
        self.type_ = type_

    def __eq__(self, other: Any) -> bool:
        if isinstance(other, ArraySchema):
            return bool(self.items == other.items and self.type_ == other.type_)
        return False

    def __hash__(self) -> int:
        return hash((self.items, self.type_))

    @classmethod
    def fromDoc(
        cls,
        doc: Any,
        baseuri: str,
        loadingOptions: LoadingOptions,
        docRoot: Optional[str] = None
    ) -> "ArraySchema":
        _doc = copy.copy(doc)

        if hasattr(doc, "lc"):
            _doc.lc.data = doc.lc.data
            _doc.lc.filename = doc.lc.filename
        _errors__ = []
        try:
            if _doc.get("items") is None:
                raise ValidationException("missing required field `items`", None, [])

            items = load_field(
                _doc.get("items"),
                uri_union_of_PrimitiveTypeLoader_or_RecordSchemaLoader_or_EnumSchemaLoader_or_ArraySchemaLoader_or_strtype_or_array_of_union_of_PrimitiveTypeLoader_or_RecordSchemaLoader_or_EnumSchemaLoader_or_ArraySchemaLoader_or_strtype_False_True_2_None,
                baseuri,
                loadingOptions,
                lc=_doc.get("items")
            )

        except ValidationException as e:
            error_message, to_print, verb_tensage = parse_errors(str(e))

            if str(e) == "missing required field `items`":
                _errors__.append(
                    ValidationException(
                        str(e),
                        None
                    )
                )
            else:
                val = _doc.get("items")
                if error_message != str(e):
                    val_type = convert_typing(extract_type(type(val)))
                    _errors__.append(
                        ValidationException(
                            "the `items` field is not valid because:",
                            SourceLine(_doc, "items", str),
                            [ValidationException(f"Value is a {val_type}, "
                                                 f"but valid {to_print} for this field "
                                                 f"{verb_tensage} {error_message}",
                                                 detailed_message=f"Value `{val}` is a {val_type}, "
                                                 f"but valid {to_print} for this field "
                                                 f"{verb_tensage} {error_message}")],
                        )
                    )
                else:
                    _errors__.append(
                        ValidationException(
                            "the `items` field is not valid because:",
                            SourceLine(_doc, "items", str),
                            [e],
                            detailed_message=f"the `items` field with value `{val}` "
                            "is not valid because:",
                        )
                    )
        try:
            if _doc.get("type") is None:
                raise ValidationException("missing required field `type`", None, [])

            type_ = load_field(
                _doc.get("type"),
                typedsl_enum_d062602be0b4b8fd33e69e29a841317b6ab665bcLoader_2,
                baseuri,
                loadingOptions,
                lc=_doc.get("type")
            )

        except ValidationException as e:
            error_message, to_print, verb_tensage = parse_errors(str(e))

            if str(e) == "missing required field `type`":
                _errors__.append(
                    ValidationException(
                        str(e),
                        None
                    )
                )
            else:
                val = _doc.get("type")
                if error_message != str(e):
                    val_type = convert_typing(extract_type(type(val)))
                    _errors__.append(
                        ValidationException(
                            "the `type` field is not valid because:",
                            SourceLine(_doc, "type", str),
                            [ValidationException(f"Value is a {val_type}, "
                                                 f"but valid {to_print} for this field "
                                                 f"{verb_tensage} {error_message}",
                                                 detailed_message=f"Value `{val}` is a {val_type}, "
                                                 f"but valid {to_print} for this field "
                                                 f"{verb_tensage} {error_message}")],
                        )
                    )
                else:
                    _errors__.append(
                        ValidationException(
                            "the `type` field is not valid because:",
                            SourceLine(_doc, "type", str),
                            [e],
                            detailed_message=f"the `type` field with value `{val}` "
                            "is not valid because:",
                        )
                    )
        extension_fields: dict[str, Any] = {}
        for k in _doc.keys():
            if k not in cls.attrs:
                if not k:
                    _errors__.append(
                        ValidationException("mapping with implicit null key")
                    )
                elif ":" in k:
                    ex = expand_url(
                        k, "", loadingOptions, scoped_id=False, vocab_term=False
                    )
                    extension_fields[ex] = _doc[k]
                else:
                    _errors__.append(
                        ValidationException(
                            "invalid field `{}`, expected one of: `items`, `type`".format(
                                k
                            ),
                            SourceLine(_doc, k, str),
                        )
                    )

        if _errors__:
            raise ValidationException("", None, _errors__, "*")
        _constructed = cls(
            items=items,
            type_=type_,
            extension_fields=extension_fields,
            loadingOptions=loadingOptions,
        )
        return _constructed

    def save(
        self, top: bool = False, base_url: str = "", relative_uris: bool = True
    ) -> dict[str, Any]:
        r: dict[str, Any] = {}

        if relative_uris:
            for ef in self.extension_fields:
                r[prefix_url(ef, self.loadingOptions.vocab)] = self.extension_fields[ef]
        else:
            for ef in self.extension_fields:
                r[ef] = self.extension_fields[ef]
        if self.items is not None:
            u = save_relative_uri(self.items, base_url, False, 2, relative_uris)
            r["items"] = u
        if self.type_ is not None:
            r["type"] = save(
                self.type_, top=False, base_url=base_url, relative_uris=relative_uris
            )

        # top refers to the directory level
        if top:
            if self.loadingOptions.namespaces:
                r["$namespaces"] = self.loadingOptions.namespaces
            if self.loadingOptions.schemas:
                r["$schemas"] = self.loadingOptions.schemas
        return r

    attrs = frozenset(["items", "type"])


class Labeled(Saveable):
    pass


class Identified(Saveable):
    pass


class Parameter(Labeled, Documented, Identified):
    """
    Define an input or output parameter to a process.

    """

    pass


class InputParameter(Parameter):
    pass


class OutputParameter(Parameter):
    pass


class Process(Identified, Labeled, Documented):
    """

    The base executable type in CWL is the `Process` object defined by the
    document.  Note that the `Process` object is abstract and cannot be
    directly executed.

    """

    pass


class HasUUID(Saveable):
    pass


class HasStepErrors(Saveable):
    pass


class HasStepPosition(Saveable):
    pass


class StepPosition(Saveable):
    """
    This field specifies the location of the step's node when rendered in the workflow editor.
    """

    def __init__(
        self,
        top: Any,
        left: Any,
        extension_fields: Optional[dict[str, Any]] = None,
        loadingOptions: Optional[LoadingOptions] = 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.top = top
        self.left = left

    def __eq__(self, other: Any) -> bool:
        if isinstance(other, StepPosition):
            return bool(self.top == other.top and self.left == other.left)
        return False

    def __hash__(self) -> int:
        return hash((self.top, self.left))

    @classmethod
    def fromDoc(
        cls,
        doc: Any,
        baseuri: str,
        loadingOptions: LoadingOptions,
        docRoot: Optional[str] = None
    ) -> "StepPosition":
        _doc = copy.copy(doc)

        if hasattr(doc, "lc"):
            _doc.lc.data = doc.lc.data
            _doc.lc.filename = doc.lc.filename
        _errors__ = []
        try:
            if _doc.get("top") is None:
                raise ValidationException("missing required field `top`", None, [])

            top = load_field(
                _doc.get("top"),
                union_of_floattype_or_inttype,
                baseuri,
                loadingOptions,
                lc=_doc.get("top")
            )

        except ValidationException as e:
            error_message, to_print, verb_tensage = parse_errors(str(e))

            if str(e) == "missing required field `top`":
                _errors__.append(
                    ValidationException(
                        str(e),
                        None
                    )
                )
            else:
                val = _doc.get("top")
                if error_message != str(e):
                    val_type = convert_typing(extract_type(type(val)))
                    _errors__.append(
                        ValidationException(
                            "the `top` field is not valid because:",
                            SourceLine(_doc, "top", str),
                            [ValidationException(f"Value is a {val_type}, "
                                                 f"but valid {to_print} for this field "
                                                 f"{verb_tensage} {error_message}",
                                                 detailed_message=f"Value `{val}` is a {val_type}, "
                                                 f"but valid {to_print} for this field "
                                                 f"{verb_tensage} {error_message}")],
                        )
                    )
                else:
                    _errors__.append(
                        ValidationException(
                            "the `top` field is not valid because:",
                            SourceLine(_doc, "top", str),
                            [e],
                            detailed_message=f"the `top` field with value `{val}` "
                            "is not valid because:",
                        )
                    )
        try:
            if _doc.get("left") is None:
                raise ValidationException("missing required field `left`", None, [])

            left = load_field(
                _doc.get("left"),
                union_of_floattype_or_inttype,
                baseuri,
                loadingOptions,
                lc=_doc.get("left")
            )

        except ValidationException as e:
            error_message, to_print, verb_tensage = parse_errors(str(e))

            if str(e) == "missing required field `left`":
                _errors__.append(
                    ValidationException(
                        str(e),
                        None
                    )
                )
            else:
                val = _doc.get("left")
                if error_message != str(e):
                    val_type = convert_typing(extract_type(type(val)))
                    _errors__.append(
                        ValidationException(
                            "the `left` field is not valid because:",
                            SourceLine(_doc, "left", str),
                            [ValidationException(f"Value is a {val_type}, "
                                                 f"but valid {to_print} for this field "
                                                 f"{verb_tensage} {error_message}",
                                                 detailed_message=f"Value `{val}` is a {val_type}, "
                                                 f"but valid {to_print} for this field "
                                                 f"{verb_tensage} {error_message}")],
                        )
                    )
                else:
                    _errors__.append(
                        ValidationException(
                            "the `left` field is not valid because:",
                            SourceLine(_doc, "left", str),
                            [e],
                            detailed_message=f"the `left` field with value `{val}` "
                            "is not valid because:",
                        )
                    )
        extension_fields: dict[str, Any] = {}
        for k in _doc.keys():
            if k not in cls.attrs:
                if not k:
                    _errors__.append(
                        ValidationException("mapping with implicit null key")
                    )
                elif ":" in k:
                    ex = expand_url(
                        k, "", loadingOptions, scoped_id=False, vocab_term=False
                    )
                    extension_fields[ex] = _doc[k]
                else:
                    _errors__.append(
                        ValidationException(
                            "invalid field `{}`, expected one of: `top`, `left`".format(
                                k
                            ),
                            SourceLine(_doc, k, str),
                        )
                    )

        if _errors__:
            raise ValidationException("", None, _errors__, "*")
        _constructed = cls(
            top=top,
            left=left,
            extension_fields=extension_fields,
            loadingOptions=loadingOptions,
        )
        return _constructed

    def save(
        self, top: bool = False, base_url: str = "", relative_uris: bool = True
    ) -> dict[str, Any]:
        r: dict[str, Any] = {}

        if relative_uris:
            for ef in self.extension_fields:
                r[prefix_url(ef, self.loadingOptions.vocab)] = self.extension_fields[ef]
        else:
            for ef in self.extension_fields:
                r[ef] = self.extension_fields[ef]
        if self.top is not None:
            r["top"] = save(
                self.top, top=False, base_url=base_url, relative_uris=relative_uris
            )
        if self.left is not None:
            r["left"] = save(
                self.left, top=False, base_url=base_url, relative_uris=relative_uris
            )

        # top refers to the directory level
        if top:
            if self.loadingOptions.namespaces:
                r["$namespaces"] = self.loadingOptions.namespaces
            if self.loadingOptions.schemas:
                r["$schemas"] = self.loadingOptions.schemas
        return r

    attrs = frozenset(["top", "left"])


class ReferencesTool(Saveable):
    pass


class ToolShedRepository(Saveable):
    name: str

    def __init__(
        self,
        changeset_revision: Any,
        name: Any,
        owner: Any,
        tool_shed: Any,
        extension_fields: Optional[dict[str, Any]] = None,
        loadingOptions: Optional[LoadingOptions] = 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.changeset_revision = changeset_revision
        self.name = name if name is not None else "_:" + str(_uuid__.uuid4())
        self.owner = owner
        self.tool_shed = tool_shed

    def __eq__(self, other: Any) -> bool:
        if isinstance(other, ToolShedRepository):
            return bool(
                self.changeset_revision == other.changeset_revision
                and self.name == other.name
                and self.owner == other.owner
                and self.tool_shed == other.tool_shed
            )
        return False

    def __hash__(self) -> int:
        return hash((self.changeset_revision, self.name, self.owner, self.tool_shed))

    @classmethod
    def fromDoc(
        cls,
        doc: Any,
        baseuri: str,
        loadingOptions: LoadingOptions,
        docRoot: Optional[str] = None
    ) -> "ToolShedRepository":
        _doc = copy.copy(doc)

        if hasattr(doc, "lc"):
            _doc.lc.data = doc.lc.data
            _doc.lc.filename = doc.lc.filename
        _errors__ = []
        name = None
        if "name" in _doc:
            try:
                name = load_field(
                    _doc.get("name"),
                    uri_strtype_True_False_None_None,
                    baseuri,
                    loadingOptions,
                    lc=_doc.get("name")
                )

            except ValidationException as e:
                error_message, to_print, verb_tensage = parse_errors(str(e))

                if str(e) == "missing required field `name`":
                    _errors__.append(
                        ValidationException(
                            str(e),
                            None
                        )
                    )
                else:
                    val = _doc.get("name")
                    if error_message != str(e):
                        val_type = convert_typing(extract_type(type(val)))
                        _errors__.append(
                            ValidationException(
                                "the `name` field is not valid because:",
                                SourceLine(_doc, "name", str),
                                [ValidationException(f"Value is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}",
                                                     detailed_message=f"Value `{val}` is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}")],
                            )
                        )
                    else:
                        _errors__.append(
                            ValidationException(
                                "the `name` field is not valid because:",
                                SourceLine(_doc, "name", str),
                                [e],
                                detailed_message=f"the `name` field with value `{val}` "
                                "is not valid because:",
                            )
                        )

        __original_name_is_none = name is None
        if name is None:
            if docRoot is not None:
                name = docRoot
            else:
                _errors__.append(ValidationException("missing name"))
        if not __original_name_is_none:
            baseuri = cast(str, name)
        try:
            if _doc.get("changeset_revision") is None:
                raise ValidationException("missing required field `changeset_revision`", None, [])

            changeset_revision = load_field(
                _doc.get("changeset_revision"),
                strtype,
                baseuri,
                loadingOptions,
                lc=_doc.get("changeset_revision")
            )

        except ValidationException as e:
            error_message, to_print, verb_tensage = parse_errors(str(e))

            if str(e) == "missing required field `changeset_revision`":
                _errors__.append(
                    ValidationException(
                        str(e),
                        None
                    )
                )
            else:
                val = _doc.get("changeset_revision")
                if error_message != str(e):
                    val_type = convert_typing(extract_type(type(val)))
                    _errors__.append(
                        ValidationException(
                            "the `changeset_revision` field is not valid because:",
                            SourceLine(_doc, "changeset_revision", str),
                            [ValidationException(f"Value is a {val_type}, "
                                                 f"but valid {to_print} for this field "
                                                 f"{verb_tensage} {error_message}",
                                                 detailed_message=f"Value `{val}` is a {val_type}, "
                                                 f"but valid {to_print} for this field "
                                                 f"{verb_tensage} {error_message}")],
                        )
                    )
                else:
                    _errors__.append(
                        ValidationException(
                            "the `changeset_revision` field is not valid because:",
                            SourceLine(_doc, "changeset_revision", str),
                            [e],
                            detailed_message=f"the `changeset_revision` field with value `{val}` "
                            "is not valid because:",
                        )
                    )
        try:
            if _doc.get("owner") is None:
                raise ValidationException("missing required field `owner`", None, [])

            owner = load_field(
                _doc.get("owner"),
                strtype,
                baseuri,
                loadingOptions,
                lc=_doc.get("owner")
            )

        except ValidationException as e:
            error_message, to_print, verb_tensage = parse_errors(str(e))

            if str(e) == "missing required field `owner`":
                _errors__.append(
                    ValidationException(
                        str(e),
                        None
                    )
                )
            else:
                val = _doc.get("owner")
                if error_message != str(e):
                    val_type = convert_typing(extract_type(type(val)))
                    _errors__.append(
                        ValidationException(
                            "the `owner` field is not valid because:",
                            SourceLine(_doc, "owner", str),
                            [ValidationException(f"Value is a {val_type}, "
                                                 f"but valid {to_print} for this field "
                                                 f"{verb_tensage} {error_message}",
                                                 detailed_message=f"Value `{val}` is a {val_type}, "
                                                 f"but valid {to_print} for this field "
                                                 f"{verb_tensage} {error_message}")],
                        )
                    )
                else:
                    _errors__.append(
                        ValidationException(
                            "the `owner` field is not valid because:",
                            SourceLine(_doc, "owner", str),
                            [e],
                            detailed_message=f"the `owner` field with value `{val}` "
                            "is not valid because:",
                        )
                    )
        try:
            if _doc.get("tool_shed") is None:
                raise ValidationException("missing required field `tool_shed`", None, [])

            tool_shed = load_field(
                _doc.get("tool_shed"),
                strtype,
                baseuri,
                loadingOptions,
                lc=_doc.get("tool_shed")
            )

        except ValidationException as e:
            error_message, to_print, verb_tensage = parse_errors(str(e))

            if str(e) == "missing required field `tool_shed`":
                _errors__.append(
                    ValidationException(
                        str(e),
                        None
                    )
                )
            else:
                val = _doc.get("tool_shed")
                if error_message != str(e):
                    val_type = convert_typing(extract_type(type(val)))
                    _errors__.append(
                        ValidationException(
                            "the `tool_shed` field is not valid because:",
                            SourceLine(_doc, "tool_shed", str),
                            [ValidationException(f"Value is a {val_type}, "
                                                 f"but valid {to_print} for this field "
                                                 f"{verb_tensage} {error_message}",
                                                 detailed_message=f"Value `{val}` is a {val_type}, "
                                                 f"but valid {to_print} for this field "
                                                 f"{verb_tensage} {error_message}")],
                        )
                    )
                else:
                    _errors__.append(
                        ValidationException(
                            "the `tool_shed` field is not valid because:",
                            SourceLine(_doc, "tool_shed", str),
                            [e],
                            detailed_message=f"the `tool_shed` field with value `{val}` "
                            "is not valid because:",
                        )
                    )
        extension_fields: dict[str, Any] = {}
        for k in _doc.keys():
            if k not in cls.attrs:
                if not k:
                    _errors__.append(
                        ValidationException("mapping with implicit null key")
                    )
                elif ":" in k:
                    ex = expand_url(
                        k, "", loadingOptions, scoped_id=False, vocab_term=False
                    )
                    extension_fields[ex] = _doc[k]
                else:
                    _errors__.append(
                        ValidationException(
                            "invalid field `{}`, expected one of: `changeset_revision`, `name`, `owner`, `tool_shed`".format(
                                k
                            ),
                            SourceLine(_doc, k, str),
                        )
                    )

        if _errors__:
            raise ValidationException("", None, _errors__, "*")
        _constructed = cls(
            changeset_revision=changeset_revision,
            name=name,
            owner=owner,
            tool_shed=tool_shed,
            extension_fields=extension_fields,
            loadingOptions=loadingOptions,
        )
        loadingOptions.idx[cast(str, name)] = (_constructed, loadingOptions)
        return _constructed

    def save(
        self, top: bool = False, base_url: str = "", relative_uris: bool = True
    ) -> dict[str, Any]:
        r: dict[str, Any] = {}

        if relative_uris:
            for ef in self.extension_fields:
                r[prefix_url(ef, self.loadingOptions.vocab)] = self.extension_fields[ef]
        else:
            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)
            r["name"] = u
        if self.changeset_revision is not None:
            r["changeset_revision"] = save(
                self.changeset_revision,
                top=False,
                base_url=self.name,
                relative_uris=relative_uris,
            )
        if self.owner is not None:
            r["owner"] = save(
                self.owner, top=False, base_url=self.name, relative_uris=relative_uris
            )
        if self.tool_shed is not None:
            r["tool_shed"] = save(
                self.tool_shed,
                top=False,
                base_url=self.name,
                relative_uris=relative_uris,
            )

        # top refers to the directory level
        if top:
            if self.loadingOptions.namespaces:
                r["$namespaces"] = self.loadingOptions.namespaces
            if self.loadingOptions.schemas:
                r["$schemas"] = self.loadingOptions.schemas
        return r

    attrs = frozenset(["changeset_revision", "name", "owner", "tool_shed"])


class WorkflowInputParameter(InputParameter, HasStepPosition):
    id: str

    def __init__(
        self,
        type_: Any,
        optional: Any,
        label: Optional[Any] = None,
        doc: Optional[Any] = None,
        id: Optional[Any] = None,
        default: Optional[Any] = None,
        position: Optional[Any] = None,
        format: Optional[Any] = None,
        collection_type: Optional[Any] = None,
        extension_fields: Optional[dict[str, Any]] = None,
        loadingOptions: Optional[LoadingOptions] = 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.label = label
        self.doc = doc
        self.id = id if id is not None else "_:" + str(_uuid__.uuid4())
        self.default = default
        self.position = position
        self.type_ = type_
        self.optional = optional
        self.format = format
        self.collection_type = collection_type

    def __eq__(self, other: Any) -> bool:
        if isinstance(other, WorkflowInputParameter):
            return bool(
                self.label == other.label
                and self.doc == other.doc
                and self.id == other.id
                and self.default == other.default
                and self.position == other.position
                and self.type_ == other.type_
                and self.optional == other.optional
                and self.format == other.format
                and self.collection_type == other.collection_type
            )
        return False

    def __hash__(self) -> int:
        return hash(
            (
                self.label,
                self.doc,
                self.id,
                self.default,
                self.position,
                self.type_,
                self.optional,
                self.format,
                self.collection_type,
            )
        )

    @classmethod
    def fromDoc(
        cls,
        doc: Any,
        baseuri: str,
        loadingOptions: LoadingOptions,
        docRoot: Optional[str] = None
    ) -> "WorkflowInputParameter":
        _doc = copy.copy(doc)

        if hasattr(doc, "lc"):
            _doc.lc.data = doc.lc.data
            _doc.lc.filename = doc.lc.filename
        _errors__ = []
        id = None
        if "id" in _doc:
            try:
                id = load_field(
                    _doc.get("id"),
                    uri_union_of_None_type_or_strtype_True_False_None_None,
                    baseuri,
                    loadingOptions,
                    lc=_doc.get("id")
                )

            except ValidationException as e:
                error_message, to_print, verb_tensage = parse_errors(str(e))

                if str(e) == "missing required field `id`":
                    _errors__.append(
                        ValidationException(
                            str(e),
                            None
                        )
                    )
                else:
                    val = _doc.get("id")
                    if error_message != str(e):
                        val_type = convert_typing(extract_type(type(val)))
                        _errors__.append(
                            ValidationException(
                                "the `id` field is not valid because:",
                                SourceLine(_doc, "id", str),
                                [ValidationException(f"Value is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}",
                                                     detailed_message=f"Value `{val}` is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}")],
                            )
                        )
                    else:
                        _errors__.append(
                            ValidationException(
                                "the `id` field is not valid because:",
                                SourceLine(_doc, "id", str),
                                [e],
                                detailed_message=f"the `id` field with value `{val}` "
                                "is not valid because:",
                            )
                        )

        __original_id_is_none = id is None
        if id is None:
            if docRoot is not None:
                id = docRoot
            else:
                id = "_:" + str(_uuid__.uuid4())
        if not __original_id_is_none:
            baseuri = cast(str, id)
        label = None
        if "label" in _doc:
            try:
                label = load_field(
                    _doc.get("label"),
                    union_of_None_type_or_strtype,
                    baseuri,
                    loadingOptions,
                    lc=_doc.get("label")
                )

            except ValidationException as e:
                error_message, to_print, verb_tensage = parse_errors(str(e))

                if str(e) == "missing required field `label`":
                    _errors__.append(
                        ValidationException(
                            str(e),
                            None
                        )
                    )
                else:
                    val = _doc.get("label")
                    if error_message != str(e):
                        val_type = convert_typing(extract_type(type(val)))
                        _errors__.append(
                            ValidationException(
                                "the `label` field is not valid because:",
                                SourceLine(_doc, "label", str),
                                [ValidationException(f"Value is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}",
                                                     detailed_message=f"Value `{val}` is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}")],
                            )
                        )
                    else:
                        _errors__.append(
                            ValidationException(
                                "the `label` field is not valid because:",
                                SourceLine(_doc, "label", str),
                                [e],
                                detailed_message=f"the `label` field with value `{val}` "
                                "is not valid because:",
                            )
                        )
        doc = None
        if "doc" in _doc:
            try:
                doc = load_field(
                    _doc.get("doc"),
                    union_of_None_type_or_strtype_or_array_of_strtype,
                    baseuri,
                    loadingOptions,
                    lc=_doc.get("doc")
                )

            except ValidationException as e:
                error_message, to_print, verb_tensage = parse_errors(str(e))

                if str(e) == "missing required field `doc`":
                    _errors__.append(
                        ValidationException(
                            str(e),
                            None
                        )
                    )
                else:
                    val = _doc.get("doc")
                    if error_message != str(e):
                        val_type = convert_typing(extract_type(type(val)))
                        _errors__.append(
                            ValidationException(
                                "the `doc` field is not valid because:",
                                SourceLine(_doc, "doc", str),
                                [ValidationException(f"Value is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}",
                                                     detailed_message=f"Value `{val}` is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}")],
                            )
                        )
                    else:
                        _errors__.append(
                            ValidationException(
                                "the `doc` field is not valid because:",
                                SourceLine(_doc, "doc", str),
                                [e],
                                detailed_message=f"the `doc` field with value `{val}` "
                                "is not valid because:",
                            )
                        )
        default = None
        if "default" in _doc:
            try:
                default = load_field(
                    _doc.get("default"),
                    union_of_None_type_or_Any_type,
                    baseuri,
                    loadingOptions,
                    lc=_doc.get("default")
                )

            except ValidationException as e:
                error_message, to_print, verb_tensage = parse_errors(str(e))

                if str(e) == "missing required field `default`":
                    _errors__.append(
                        ValidationException(
                            str(e),
                            None
                        )
                    )
                else:
                    val = _doc.get("default")
                    if error_message != str(e):
                        val_type = convert_typing(extract_type(type(val)))
                        _errors__.append(
                            ValidationException(
                                "the `default` field is not valid because:",
                                SourceLine(_doc, "default", str),
                                [ValidationException(f"Value is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}",
                                                     detailed_message=f"Value `{val}` is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}")],
                            )
                        )
                    else:
                        _errors__.append(
                            ValidationException(
                                "the `default` field is not valid because:",
                                SourceLine(_doc, "default", str),
                                [e],
                                detailed_message=f"the `default` field with value `{val}` "
                                "is not valid because:",
                            )
                        )
        position = None
        if "position" in _doc:
            try:
                position = load_field(
                    _doc.get("position"),
                    union_of_None_type_or_StepPositionLoader,
                    baseuri,
                    loadingOptions,
                    lc=_doc.get("position")
                )

            except ValidationException as e:
                error_message, to_print, verb_tensage = parse_errors(str(e))

                if str(e) == "missing required field `position`":
                    _errors__.append(
                        ValidationException(
                            str(e),
                            None
                        )
                    )
                else:
                    val = _doc.get("position")
                    if error_message != str(e):
                        val_type = convert_typing(extract_type(type(val)))
                        _errors__.append(
                            ValidationException(
                                "the `position` field is not valid because:",
                                SourceLine(_doc, "position", str),
                                [ValidationException(f"Value is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}",
                                                     detailed_message=f"Value `{val}` is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}")],
                            )
                        )
                    else:
                        _errors__.append(
                            ValidationException(
                                "the `position` field is not valid because:",
                                SourceLine(_doc, "position", str),
                                [e],
                                detailed_message=f"the `position` field with value `{val}` "
                                "is not valid because:",
                            )
                        )
        type_ = None
        if "type" in _doc:
            try:
                type_ = load_field(
                    _doc.get("type"),
                    typedsl_union_of_GalaxyTypeLoader_or_None_type_or_array_of_union_of_GalaxyTypeLoader_2,
                    baseuri,
                    loadingOptions,
                    lc=_doc.get("type")
                )

            except ValidationException as e:
                error_message, to_print, verb_tensage = parse_errors(str(e))

                if str(e) == "missing required field `type`":
                    _errors__.append(
                        ValidationException(
                            str(e),
                            None
                        )
                    )
                else:
                    val = _doc.get("type")
                    if error_message != str(e):
                        val_type = convert_typing(extract_type(type(val)))
                        _errors__.append(
                            ValidationException(
                                "the `type` field is not valid because:",
                                SourceLine(_doc, "type", str),
                                [ValidationException(f"Value is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}",
                                                     detailed_message=f"Value `{val}` is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}")],
                            )
                        )
                    else:
                        _errors__.append(
                            ValidationException(
                                "the `type` field is not valid because:",
                                SourceLine(_doc, "type", str),
                                [e],
                                detailed_message=f"the `type` field with value `{val}` "
                                "is not valid because:",
                            )
                        )
        optional = None
        if "optional" in _doc:
            try:
                optional = load_field(
                    _doc.get("optional"),
                    union_of_booltype_or_None_type,
                    baseuri,
                    loadingOptions,
                    lc=_doc.get("optional")
                )

            except ValidationException as e:
                error_message, to_print, verb_tensage = parse_errors(str(e))

                if str(e) == "missing required field `optional`":
                    _errors__.append(
                        ValidationException(
                            str(e),
                            None
                        )
                    )
                else:
                    val = _doc.get("optional")
                    if error_message != str(e):
                        val_type = convert_typing(extract_type(type(val)))
                        _errors__.append(
                            ValidationException(
                                "the `optional` field is not valid because:",
                                SourceLine(_doc, "optional", str),
                                [ValidationException(f"Value is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}",
                                                     detailed_message=f"Value `{val}` is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}")],
                            )
                        )
                    else:
                        _errors__.append(
                            ValidationException(
                                "the `optional` field is not valid because:",
                                SourceLine(_doc, "optional", str),
                                [e],
                                detailed_message=f"the `optional` field with value `{val}` "
                                "is not valid because:",
                            )
                        )
        format = None
        if "format" in _doc:
            try:
                format = load_field(
                    _doc.get("format"),
                    union_of_None_type_or_array_of_strtype,
                    baseuri,
                    loadingOptions,
                    lc=_doc.get("format")
                )

            except ValidationException as e:
                error_message, to_print, verb_tensage = parse_errors(str(e))

                if str(e) == "missing required field `format`":
                    _errors__.append(
                        ValidationException(
                            str(e),
                            None
                        )
                    )
                else:
                    val = _doc.get("format")
                    if error_message != str(e):
                        val_type = convert_typing(extract_type(type(val)))
                        _errors__.append(
                            ValidationException(
                                "the `format` field is not valid because:",
                                SourceLine(_doc, "format", str),
                                [ValidationException(f"Value is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}",
                                                     detailed_message=f"Value `{val}` is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}")],
                            )
                        )
                    else:
                        _errors__.append(
                            ValidationException(
                                "the `format` field is not valid because:",
                                SourceLine(_doc, "format", str),
                                [e],
                                detailed_message=f"the `format` field with value `{val}` "
                                "is not valid because:",
                            )
                        )
        collection_type = None
        if "collection_type" in _doc:
            try:
                collection_type = load_field(
                    _doc.get("collection_type"),
                    union_of_None_type_or_strtype,
                    baseuri,
                    loadingOptions,
                    lc=_doc.get("collection_type")
                )

            except ValidationException as e:
                error_message, to_print, verb_tensage = parse_errors(str(e))

                if str(e) == "missing required field `collection_type`":
                    _errors__.append(
                        ValidationException(
                            str(e),
                            None
                        )
                    )
                else:
                    val = _doc.get("collection_type")
                    if error_message != str(e):
                        val_type = convert_typing(extract_type(type(val)))
                        _errors__.append(
                            ValidationException(
                                "the `collection_type` field is not valid because:",
                                SourceLine(_doc, "collection_type", str),
                                [ValidationException(f"Value is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}",
                                                     detailed_message=f"Value `{val}` is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}")],
                            )
                        )
                    else:
                        _errors__.append(
                            ValidationException(
                                "the `collection_type` field is not valid because:",
                                SourceLine(_doc, "collection_type", str),
                                [e],
                                detailed_message=f"the `collection_type` field with value `{val}` "
                                "is not valid because:",
                            )
                        )
        extension_fields: dict[str, Any] = {}
        for k in _doc.keys():
            if k not in cls.attrs:
                if not k:
                    _errors__.append(
                        ValidationException("mapping with implicit null key")
                    )
                elif ":" in k:
                    ex = expand_url(
                        k, "", loadingOptions, scoped_id=False, vocab_term=False
                    )
                    extension_fields[ex] = _doc[k]
                else:
                    _errors__.append(
                        ValidationException(
                            "invalid field `{}`, expected one of: `label`, `doc`, `id`, `default`, `position`, `type`, `optional`, `format`, `collection_type`".format(
                                k
                            ),
                            SourceLine(_doc, k, str),
                        )
                    )

        if _errors__:
            raise ValidationException("", None, _errors__, "*")
        _constructed = cls(
            label=label,
            doc=doc,
            id=id,
            default=default,
            position=position,
            type_=type_,
            optional=optional,
            format=format,
            collection_type=collection_type,
            extension_fields=extension_fields,
            loadingOptions=loadingOptions,
        )
        loadingOptions.idx[cast(str, id)] = (_constructed, loadingOptions)
        return _constructed

    def save(
        self, top: bool = False, base_url: str = "", relative_uris: bool = True
    ) -> dict[str, Any]:
        r: dict[str, Any] = {}

        if relative_uris:
            for ef in self.extension_fields:
                r[prefix_url(ef, self.loadingOptions.vocab)] = self.extension_fields[ef]
        else:
            for ef in self.extension_fields:
                r[ef] = self.extension_fields[ef]
        if self.id is not None:
            u = save_relative_uri(self.id, base_url, True, None, relative_uris)
            r["id"] = u
        if self.label is not None:
            r["label"] = save(
                self.label, top=False, base_url=self.id, relative_uris=relative_uris
            )
        if self.doc is not None:
            r["doc"] = save(
                self.doc, top=False, base_url=self.id, relative_uris=relative_uris
            )
        if self.default is not None:
            r["default"] = save(
                self.default, top=False, base_url=self.id, relative_uris=relative_uris
            )
        if self.position is not None:
            r["position"] = save(
                self.position, top=False, base_url=self.id, relative_uris=relative_uris
            )
        if self.type_ is not None:
            r["type"] = save(
                self.type_, top=False, base_url=self.id, relative_uris=relative_uris
            )
        if self.optional is not None:
            r["optional"] = save(
                self.optional, top=False, base_url=self.id, relative_uris=relative_uris
            )
        if self.format is not None:
            r["format"] = save(
                self.format, top=False, base_url=self.id, relative_uris=relative_uris
            )
        if self.collection_type is not None:
            r["collection_type"] = save(
                self.collection_type,
                top=False,
                base_url=self.id,
                relative_uris=relative_uris,
            )

        # top refers to the directory level
        if top:
            if self.loadingOptions.namespaces:
                r["$namespaces"] = self.loadingOptions.namespaces
            if self.loadingOptions.schemas:
                r["$schemas"] = self.loadingOptions.schemas
        return r

    attrs = frozenset(
        [
            "label",
            "doc",
            "id",
            "default",
            "position",
            "type",
            "optional",
            "format",
            "collection_type",
        ]
    )


class WorkflowOutputParameter(OutputParameter):
    """
    Describe an output parameter of a workflow.  The parameter must be
    connected to one parameter defined in the workflow that
    will provide the value of the output parameter. It is legal to
    connect a WorkflowInputParameter to a WorkflowOutputParameter.

    """

    id: str

    def __init__(
        self,
        label: Optional[Any] = None,
        doc: Optional[Any] = None,
        id: Optional[Any] = None,
        outputSource: Optional[Any] = None,
        type_: Optional[Any] = None,
        extension_fields: Optional[dict[str, Any]] = None,
        loadingOptions: Optional[LoadingOptions] = 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.label = label
        self.doc = doc
        self.id = id if id is not None else "_:" + str(_uuid__.uuid4())
        self.outputSource = outputSource
        self.type_ = type_

    def __eq__(self, other: Any) -> bool:
        if isinstance(other, WorkflowOutputParameter):
            return bool(
                self.label == other.label
                and self.doc == other.doc
                and self.id == other.id
                and self.outputSource == other.outputSource
                and self.type_ == other.type_
            )
        return False

    def __hash__(self) -> int:
        return hash((self.label, self.doc, self.id, self.outputSource, self.type_))

    @classmethod
    def fromDoc(
        cls,
        doc: Any,
        baseuri: str,
        loadingOptions: LoadingOptions,
        docRoot: Optional[str] = None
    ) -> "WorkflowOutputParameter":
        _doc = copy.copy(doc)

        if hasattr(doc, "lc"):
            _doc.lc.data = doc.lc.data
            _doc.lc.filename = doc.lc.filename
        _errors__ = []
        id = None
        if "id" in _doc:
            try:
                id = load_field(
                    _doc.get("id"),
                    uri_union_of_None_type_or_strtype_True_False_None_None,
                    baseuri,
                    loadingOptions,
                    lc=_doc.get("id")
                )

            except ValidationException as e:
                error_message, to_print, verb_tensage = parse_errors(str(e))

                if str(e) == "missing required field `id`":
                    _errors__.append(
                        ValidationException(
                            str(e),
                            None
                        )
                    )
                else:
                    val = _doc.get("id")
                    if error_message != str(e):
                        val_type = convert_typing(extract_type(type(val)))
                        _errors__.append(
                            ValidationException(
                                "the `id` field is not valid because:",
                                SourceLine(_doc, "id", str),
                                [ValidationException(f"Value is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}",
                                                     detailed_message=f"Value `{val}` is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}")],
                            )
                        )
                    else:
                        _errors__.append(
                            ValidationException(
                                "the `id` field is not valid because:",
                                SourceLine(_doc, "id", str),
                                [e],
                                detailed_message=f"the `id` field with value `{val}` "
                                "is not valid because:",
                            )
                        )

        __original_id_is_none = id is None
        if id is None:
            if docRoot is not None:
                id = docRoot
            else:
                id = "_:" + str(_uuid__.uuid4())
        if not __original_id_is_none:
            baseuri = cast(str, id)
        label = None
        if "label" in _doc:
            try:
                label = load_field(
                    _doc.get("label"),
                    union_of_None_type_or_strtype,
                    baseuri,
                    loadingOptions,
                    lc=_doc.get("label")
                )

            except ValidationException as e:
                error_message, to_print, verb_tensage = parse_errors(str(e))

                if str(e) == "missing required field `label`":
                    _errors__.append(
                        ValidationException(
                            str(e),
                            None
                        )
                    )
                else:
                    val = _doc.get("label")
                    if error_message != str(e):
                        val_type = convert_typing(extract_type(type(val)))
                        _errors__.append(
                            ValidationException(
                                "the `label` field is not valid because:",
                                SourceLine(_doc, "label", str),
                                [ValidationException(f"Value is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}",
                                                     detailed_message=f"Value `{val}` is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}")],
                            )
                        )
                    else:
                        _errors__.append(
                            ValidationException(
                                "the `label` field is not valid because:",
                                SourceLine(_doc, "label", str),
                                [e],
                                detailed_message=f"the `label` field with value `{val}` "
                                "is not valid because:",
                            )
                        )
        doc = None
        if "doc" in _doc:
            try:
                doc = load_field(
                    _doc.get("doc"),
                    union_of_None_type_or_strtype_or_array_of_strtype,
                    baseuri,
                    loadingOptions,
                    lc=_doc.get("doc")
                )

            except ValidationException as e:
                error_message, to_print, verb_tensage = parse_errors(str(e))

                if str(e) == "missing required field `doc`":
                    _errors__.append(
                        ValidationException(
                            str(e),
                            None
                        )
                    )
                else:
                    val = _doc.get("doc")
                    if error_message != str(e):
                        val_type = convert_typing(extract_type(type(val)))
                        _errors__.append(
                            ValidationException(
                                "the `doc` field is not valid because:",
                                SourceLine(_doc, "doc", str),
                                [ValidationException(f"Value is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}",
                                                     detailed_message=f"Value `{val}` is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}")],
                            )
                        )
                    else:
                        _errors__.append(
                            ValidationException(
                                "the `doc` field is not valid because:",
                                SourceLine(_doc, "doc", str),
                                [e],
                                detailed_message=f"the `doc` field with value `{val}` "
                                "is not valid because:",
                            )
                        )
        outputSource = None
        if "outputSource" in _doc:
            try:
                outputSource = load_field(
                    _doc.get("outputSource"),
                    union_of_None_type_or_strtype,
                    baseuri,
                    loadingOptions,
                    lc=_doc.get("outputSource")
                )

            except ValidationException as e:
                error_message, to_print, verb_tensage = parse_errors(str(e))

                if str(e) == "missing required field `outputSource`":
                    _errors__.append(
                        ValidationException(
                            str(e),
                            None
                        )
                    )
                else:
                    val = _doc.get("outputSource")
                    if error_message != str(e):
                        val_type = convert_typing(extract_type(type(val)))
                        _errors__.append(
                            ValidationException(
                                "the `outputSource` field is not valid because:",
                                SourceLine(_doc, "outputSource", str),
                                [ValidationException(f"Value is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}",
                                                     detailed_message=f"Value `{val}` is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}")],
                            )
                        )
                    else:
                        _errors__.append(
                            ValidationException(
                                "the `outputSource` field is not valid because:",
                                SourceLine(_doc, "outputSource", str),
                                [e],
                                detailed_message=f"the `outputSource` field with value `{val}` "
                                "is not valid because:",
                            )
                        )
        type_ = None
        if "type" in _doc:
            try:
                type_ = load_field(
                    _doc.get("type"),
                    typedsl_union_of_None_type_or_GalaxyTypeLoader_2,
                    baseuri,
                    loadingOptions,
                    lc=_doc.get("type")
                )

            except ValidationException as e:
                error_message, to_print, verb_tensage = parse_errors(str(e))

                if str(e) == "missing required field `type`":
                    _errors__.append(
                        ValidationException(
                            str(e),
                            None
                        )
                    )
                else:
                    val = _doc.get("type")
                    if error_message != str(e):
                        val_type = convert_typing(extract_type(type(val)))
                        _errors__.append(
                            ValidationException(
                                "the `type` field is not valid because:",
                                SourceLine(_doc, "type", str),
                                [ValidationException(f"Value is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}",
                                                     detailed_message=f"Value `{val}` is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}")],
                            )
                        )
                    else:
                        _errors__.append(
                            ValidationException(
                                "the `type` field is not valid because:",
                                SourceLine(_doc, "type", str),
                                [e],
                                detailed_message=f"the `type` field with value `{val}` "
                                "is not valid because:",
                            )
                        )
        extension_fields: dict[str, Any] = {}
        for k in _doc.keys():
            if k not in cls.attrs:
                if not k:
                    _errors__.append(
                        ValidationException("mapping with implicit null key")
                    )
                elif ":" in k:
                    ex = expand_url(
                        k, "", loadingOptions, scoped_id=False, vocab_term=False
                    )
                    extension_fields[ex] = _doc[k]
                else:
                    _errors__.append(
                        ValidationException(
                            "invalid field `{}`, expected one of: `label`, `doc`, `id`, `outputSource`, `type`".format(
                                k
                            ),
                            SourceLine(_doc, k, str),
                        )
                    )

        if _errors__:
            raise ValidationException("", None, _errors__, "*")
        _constructed = cls(
            label=label,
            doc=doc,
            id=id,
            outputSource=outputSource,
            type_=type_,
            extension_fields=extension_fields,
            loadingOptions=loadingOptions,
        )
        loadingOptions.idx[cast(str, id)] = (_constructed, loadingOptions)
        return _constructed

    def save(
        self, top: bool = False, base_url: str = "", relative_uris: bool = True
    ) -> dict[str, Any]:
        r: dict[str, Any] = {}

        if relative_uris:
            for ef in self.extension_fields:
                r[prefix_url(ef, self.loadingOptions.vocab)] = self.extension_fields[ef]
        else:
            for ef in self.extension_fields:
                r[ef] = self.extension_fields[ef]
        if self.id is not None:
            u = save_relative_uri(self.id, base_url, True, None, relative_uris)
            r["id"] = u
        if self.label is not None:
            r["label"] = save(
                self.label, top=False, base_url=self.id, relative_uris=relative_uris
            )
        if self.doc is not None:
            r["doc"] = save(
                self.doc, top=False, base_url=self.id, relative_uris=relative_uris
            )
        if self.outputSource is not None:
            r["outputSource"] = save(
                self.outputSource,
                top=False,
                base_url=self.id,
                relative_uris=relative_uris,
            )
        if self.type_ is not None:
            r["type"] = save(
                self.type_, top=False, base_url=self.id, relative_uris=relative_uris
            )

        # top refers to the directory level
        if top:
            if self.loadingOptions.namespaces:
                r["$namespaces"] = self.loadingOptions.namespaces
            if self.loadingOptions.schemas:
                r["$schemas"] = self.loadingOptions.schemas
        return r

    attrs = frozenset(["label", "doc", "id", "outputSource", "type"])


class WorkflowStep(
    Identified,
    Labeled,
    Documented,
    HasStepPosition,
    ReferencesTool,
    HasStepErrors,
    HasUUID,
):
    """
    This represents a non-input step a Galaxy Workflow.

    # A note about `state` and `tool_state` fields.

    Only one or the other should be specified. These are two ways to represent the "state"
    of a tool at this workflow step. Both are essentially maps from parameter names to
    parameter values.

    `tool_state` is much more low-level and expects a flat dictionary with each value a JSON
    dump. Nested tool structures such as conditionals and repeats should have all their values
    in the JSON dumped string. In general `tool_state` may be present in workflows exported from
    Galaxy but shouldn't be written by humans.

    `state` can contained a typed map. Repeat values can be represented as YAML arrays. An alternative
    to representing `state` this way is defining inputs with default values.

    """

    id: str

    def __init__(
        self,
        out: Any,
        id: Optional[Any] = None,
        label: Optional[Any] = None,
        doc: Optional[Any] = None,
        position: Optional[Any] = None,
        tool_id: Optional[Any] = None,
        tool_shed_repository: Optional[Any] = None,
        tool_version: Optional[Any] = None,
        errors: Optional[Any] = None,
        uuid: Optional[Any] = None,
        in_: Optional[Any] = None,
        state: Optional[Any] = None,
        tool_state: Optional[Any] = None,
        type_: Optional[Any] = None,
        run: Optional[Any] = None,
        runtime_inputs: Optional[Any] = None,
        when: Optional[Any] = None,
        extension_fields: Optional[dict[str, Any]] = None,
        loadingOptions: Optional[LoadingOptions] = 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 if id is not None else "_:" + str(_uuid__.uuid4())
        self.label = label
        self.doc = doc
        self.position = position
        self.tool_id = tool_id
        self.tool_shed_repository = tool_shed_repository
        self.tool_version = tool_version
        self.errors = errors
        self.uuid = uuid
        self.in_ = in_
        self.out = out
        self.state = state
        self.tool_state = tool_state
        self.type_ = type_
        self.run = run
        self.runtime_inputs = runtime_inputs
        self.when = when

    def __eq__(self, other: Any) -> bool:
        if isinstance(other, WorkflowStep):
            return bool(
                self.id == other.id
                and self.label == other.label
                and self.doc == other.doc
                and self.position == other.position
                and self.tool_id == other.tool_id
                and self.tool_shed_repository == other.tool_shed_repository
                and self.tool_version == other.tool_version
                and self.errors == other.errors
                and self.uuid == other.uuid
                and self.in_ == other.in_
                and self.out == other.out
                and self.state == other.state
                and self.tool_state == other.tool_state
                and self.type_ == other.type_
                and self.run == other.run
                and self.runtime_inputs == other.runtime_inputs
                and self.when == other.when
            )
        return False

    def __hash__(self) -> int:
        return hash(
            (
                self.id,
                self.label,
                self.doc,
                self.position,
                self.tool_id,
                self.tool_shed_repository,
                self.tool_version,
                self.errors,
                self.uuid,
                self.in_,
                self.out,
                self.state,
                self.tool_state,
                self.type_,
                self.run,
                self.runtime_inputs,
                self.when,
            )
        )

    @classmethod
    def fromDoc(
        cls,
        doc: Any,
        baseuri: str,
        loadingOptions: LoadingOptions,
        docRoot: Optional[str] = None
    ) -> "WorkflowStep":
        _doc = copy.copy(doc)

        if hasattr(doc, "lc"):
            _doc.lc.data = doc.lc.data
            _doc.lc.filename = doc.lc.filename
        _errors__ = []
        id = None
        if "id" in _doc:
            try:
                id = load_field(
                    _doc.get("id"),
                    uri_union_of_None_type_or_strtype_True_False_None_None,
                    baseuri,
                    loadingOptions,
                    lc=_doc.get("id")
                )

            except ValidationException as e:
                error_message, to_print, verb_tensage = parse_errors(str(e))

                if str(e) == "missing required field `id`":
                    _errors__.append(
                        ValidationException(
                            str(e),
                            None
                        )
                    )
                else:
                    val = _doc.get("id")
                    if error_message != str(e):
                        val_type = convert_typing(extract_type(type(val)))
                        _errors__.append(
                            ValidationException(
                                "the `id` field is not valid because:",
                                SourceLine(_doc, "id", str),
                                [ValidationException(f"Value is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}",
                                                     detailed_message=f"Value `{val}` is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}")],
                            )
                        )
                    else:
                        _errors__.append(
                            ValidationException(
                                "the `id` field is not valid because:",
                                SourceLine(_doc, "id", str),
                                [e],
                                detailed_message=f"the `id` field with value `{val}` "
                                "is not valid because:",
                            )
                        )

        __original_id_is_none = id is None
        if id is None:
            if docRoot is not None:
                id = docRoot
            else:
                id = "_:" + str(_uuid__.uuid4())
        if not __original_id_is_none:
            baseuri = cast(str, id)
        label = None
        if "label" in _doc:
            try:
                label = load_field(
                    _doc.get("label"),
                    union_of_None_type_or_strtype,
                    baseuri,
                    loadingOptions,
                    lc=_doc.get("label")
                )

            except ValidationException as e:
                error_message, to_print, verb_tensage = parse_errors(str(e))

                if str(e) == "missing required field `label`":
                    _errors__.append(
                        ValidationException(
                            str(e),
                            None
                        )
                    )
                else:
                    val = _doc.get("label")
                    if error_message != str(e):
                        val_type = convert_typing(extract_type(type(val)))
                        _errors__.append(
                            ValidationException(
                                "the `label` field is not valid because:",
                                SourceLine(_doc, "label", str),
                                [ValidationException(f"Value is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}",
                                                     detailed_message=f"Value `{val}` is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}")],
                            )
                        )
                    else:
                        _errors__.append(
                            ValidationException(
                                "the `label` field is not valid because:",
                                SourceLine(_doc, "label", str),
                                [e],
                                detailed_message=f"the `label` field with value `{val}` "
                                "is not valid because:",
                            )
                        )
        doc = None
        if "doc" in _doc:
            try:
                doc = load_field(
                    _doc.get("doc"),
                    union_of_None_type_or_strtype_or_array_of_strtype,
                    baseuri,
                    loadingOptions,
                    lc=_doc.get("doc")
                )

            except ValidationException as e:
                error_message, to_print, verb_tensage = parse_errors(str(e))

                if str(e) == "missing required field `doc`":
                    _errors__.append(
                        ValidationException(
                            str(e),
                            None
                        )
                    )
                else:
                    val = _doc.get("doc")
                    if error_message != str(e):
                        val_type = convert_typing(extract_type(type(val)))
                        _errors__.append(
                            ValidationException(
                                "the `doc` field is not valid because:",
                                SourceLine(_doc, "doc", str),
                                [ValidationException(f"Value is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}",
                                                     detailed_message=f"Value `{val}` is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}")],
                            )
                        )
                    else:
                        _errors__.append(
                            ValidationException(
                                "the `doc` field is not valid because:",
                                SourceLine(_doc, "doc", str),
                                [e],
                                detailed_message=f"the `doc` field with value `{val}` "
                                "is not valid because:",
                            )
                        )
        position = None
        if "position" in _doc:
            try:
                position = load_field(
                    _doc.get("position"),
                    union_of_None_type_or_StepPositionLoader,
                    baseuri,
                    loadingOptions,
                    lc=_doc.get("position")
                )

            except ValidationException as e:
                error_message, to_print, verb_tensage = parse_errors(str(e))

                if str(e) == "missing required field `position`":
                    _errors__.append(
                        ValidationException(
                            str(e),
                            None
                        )
                    )
                else:
                    val = _doc.get("position")
                    if error_message != str(e):
                        val_type = convert_typing(extract_type(type(val)))
                        _errors__.append(
                            ValidationException(
                                "the `position` field is not valid because:",
                                SourceLine(_doc, "position", str),
                                [ValidationException(f"Value is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}",
                                                     detailed_message=f"Value `{val}` is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}")],
                            )
                        )
                    else:
                        _errors__.append(
                            ValidationException(
                                "the `position` field is not valid because:",
                                SourceLine(_doc, "position", str),
                                [e],
                                detailed_message=f"the `position` field with value `{val}` "
                                "is not valid because:",
                            )
                        )
        tool_id = None
        if "tool_id" in _doc:
            try:
                tool_id = load_field(
                    _doc.get("tool_id"),
                    union_of_None_type_or_strtype,
                    baseuri,
                    loadingOptions,
                    lc=_doc.get("tool_id")
                )

            except ValidationException as e:
                error_message, to_print, verb_tensage = parse_errors(str(e))

                if str(e) == "missing required field `tool_id`":
                    _errors__.append(
                        ValidationException(
                            str(e),
                            None
                        )
                    )
                else:
                    val = _doc.get("tool_id")
                    if error_message != str(e):
                        val_type = convert_typing(extract_type(type(val)))
                        _errors__.append(
                            ValidationException(
                                "the `tool_id` field is not valid because:",
                                SourceLine(_doc, "tool_id", str),
                                [ValidationException(f"Value is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}",
                                                     detailed_message=f"Value `{val}` is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}")],
                            )
                        )
                    else:
                        _errors__.append(
                            ValidationException(
                                "the `tool_id` field is not valid because:",
                                SourceLine(_doc, "tool_id", str),
                                [e],
                                detailed_message=f"the `tool_id` field with value `{val}` "
                                "is not valid because:",
                            )
                        )
        tool_shed_repository = None
        if "tool_shed_repository" in _doc:
            try:
                tool_shed_repository = load_field(
                    _doc.get("tool_shed_repository"),
                    union_of_None_type_or_ToolShedRepositoryLoader,
                    baseuri,
                    loadingOptions,
                    lc=_doc.get("tool_shed_repository")
                )

            except ValidationException as e:
                error_message, to_print, verb_tensage = parse_errors(str(e))

                if str(e) == "missing required field `tool_shed_repository`":
                    _errors__.append(
                        ValidationException(
                            str(e),
                            None
                        )
                    )
                else:
                    val = _doc.get("tool_shed_repository")
                    if error_message != str(e):
                        val_type = convert_typing(extract_type(type(val)))
                        _errors__.append(
                            ValidationException(
                                "the `tool_shed_repository` field is not valid because:",
                                SourceLine(_doc, "tool_shed_repository", str),
                                [ValidationException(f"Value is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}",
                                                     detailed_message=f"Value `{val}` is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}")],
                            )
                        )
                    else:
                        _errors__.append(
                            ValidationException(
                                "the `tool_shed_repository` field is not valid because:",
                                SourceLine(_doc, "tool_shed_repository", str),
                                [e],
                                detailed_message=f"the `tool_shed_repository` field with value `{val}` "
                                "is not valid because:",
                            )
                        )
        tool_version = None
        if "tool_version" in _doc:
            try:
                tool_version = load_field(
                    _doc.get("tool_version"),
                    union_of_None_type_or_strtype,
                    baseuri,
                    loadingOptions,
                    lc=_doc.get("tool_version")
                )

            except ValidationException as e:
                error_message, to_print, verb_tensage = parse_errors(str(e))

                if str(e) == "missing required field `tool_version`":
                    _errors__.append(
                        ValidationException(
                            str(e),
                            None
                        )
                    )
                else:
                    val = _doc.get("tool_version")
                    if error_message != str(e):
                        val_type = convert_typing(extract_type(type(val)))
                        _errors__.append(
                            ValidationException(
                                "the `tool_version` field is not valid because:",
                                SourceLine(_doc, "tool_version", str),
                                [ValidationException(f"Value is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}",
                                                     detailed_message=f"Value `{val}` is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}")],
                            )
                        )
                    else:
                        _errors__.append(
                            ValidationException(
                                "the `tool_version` field is not valid because:",
                                SourceLine(_doc, "tool_version", str),
                                [e],
                                detailed_message=f"the `tool_version` field with value `{val}` "
                                "is not valid because:",
                            )
                        )
        errors = None
        if "errors" in _doc:
            try:
                errors = load_field(
                    _doc.get("errors"),
                    union_of_None_type_or_strtype,
                    baseuri,
                    loadingOptions,
                    lc=_doc.get("errors")
                )

            except ValidationException as e:
                error_message, to_print, verb_tensage = parse_errors(str(e))

                if str(e) == "missing required field `errors`":
                    _errors__.append(
                        ValidationException(
                            str(e),
                            None
                        )
                    )
                else:
                    val = _doc.get("errors")
                    if error_message != str(e):
                        val_type = convert_typing(extract_type(type(val)))
                        _errors__.append(
                            ValidationException(
                                "the `errors` field is not valid because:",
                                SourceLine(_doc, "errors", str),
                                [ValidationException(f"Value is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}",
                                                     detailed_message=f"Value `{val}` is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}")],
                            )
                        )
                    else:
                        _errors__.append(
                            ValidationException(
                                "the `errors` field is not valid because:",
                                SourceLine(_doc, "errors", str),
                                [e],
                                detailed_message=f"the `errors` field with value `{val}` "
                                "is not valid because:",
                            )
                        )
        uuid = None
        if "uuid" in _doc:
            try:
                uuid = load_field(
                    _doc.get("uuid"),
                    union_of_None_type_or_strtype,
                    baseuri,
                    loadingOptions,
                    lc=_doc.get("uuid")
                )

            except ValidationException as e:
                error_message, to_print, verb_tensage = parse_errors(str(e))

                if str(e) == "missing required field `uuid`":
                    _errors__.append(
                        ValidationException(
                            str(e),
                            None
                        )
                    )
                else:
                    val = _doc.get("uuid")
                    if error_message != str(e):
                        val_type = convert_typing(extract_type(type(val)))
                        _errors__.append(
                            ValidationException(
                                "the `uuid` field is not valid because:",
                                SourceLine(_doc, "uuid", str),
                                [ValidationException(f"Value is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}",
                                                     detailed_message=f"Value `{val}` is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}")],
                            )
                        )
                    else:
                        _errors__.append(
                            ValidationException(
                                "the `uuid` field is not valid because:",
                                SourceLine(_doc, "uuid", str),
                                [e],
                                detailed_message=f"the `uuid` field with value `{val}` "
                                "is not valid because:",
                            )
                        )
        in_ = None
        if "in" in _doc:
            try:
                in_ = load_field(
                    _doc.get("in"),
                    idmap_in__union_of_None_type_or_array_of_WorkflowStepInputLoader,
                    baseuri,
                    loadingOptions,
                    lc=_doc.get("in")
                )

            except ValidationException as e:
                error_message, to_print, verb_tensage = parse_errors(str(e))

                if str(e) == "missing required field `in`":
                    _errors__.append(
                        ValidationException(
                            str(e),
                            None
                        )
                    )
                else:
                    val = _doc.get("in")
                    if error_message != str(e):
                        val_type = convert_typing(extract_type(type(val)))
                        _errors__.append(
                            ValidationException(
                                "the `in` field is not valid because:",
                                SourceLine(_doc, "in", str),
                                [ValidationException(f"Value is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}",
                                                     detailed_message=f"Value `{val}` is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}")],
                            )
                        )
                    else:
                        _errors__.append(
                            ValidationException(
                                "the `in` field is not valid because:",
                                SourceLine(_doc, "in", str),
                                [e],
                                detailed_message=f"the `in` field with value `{val}` "
                                "is not valid because:",
                            )
                        )
        out = None
        if "out" in _doc:
            try:
                out = load_field(
                    _doc.get("out"),
                    idmap_out_union_of_array_of_union_of_strtype_or_WorkflowStepOutputLoader_or_None_type,
                    baseuri,
                    loadingOptions,
                    lc=_doc.get("out")
                )

            except ValidationException as e:
                error_message, to_print, verb_tensage = parse_errors(str(e))

                if str(e) == "missing required field `out`":
                    _errors__.append(
                        ValidationException(
                            str(e),
                            None
                        )
                    )
                else:
                    val = _doc.get("out")
                    if error_message != str(e):
                        val_type = convert_typing(extract_type(type(val)))
                        _errors__.append(
                            ValidationException(
                                "the `out` field is not valid because:",
                                SourceLine(_doc, "out", str),
                                [ValidationException(f"Value is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}",
                                                     detailed_message=f"Value `{val}` is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}")],
                            )
                        )
                    else:
                        _errors__.append(
                            ValidationException(
                                "the `out` field is not valid because:",
                                SourceLine(_doc, "out", str),
                                [e],
                                detailed_message=f"the `out` field with value `{val}` "
                                "is not valid because:",
                            )
                        )
        state = None
        if "state" in _doc:
            try:
                state = load_field(
                    _doc.get("state"),
                    union_of_None_type_or_Any_type,
                    baseuri,
                    loadingOptions,
                    lc=_doc.get("state")
                )

            except ValidationException as e:
                error_message, to_print, verb_tensage = parse_errors(str(e))

                if str(e) == "missing required field `state`":
                    _errors__.append(
                        ValidationException(
                            str(e),
                            None
                        )
                    )
                else:
                    val = _doc.get("state")
                    if error_message != str(e):
                        val_type = convert_typing(extract_type(type(val)))
                        _errors__.append(
                            ValidationException(
                                "the `state` field is not valid because:",
                                SourceLine(_doc, "state", str),
                                [ValidationException(f"Value is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}",
                                                     detailed_message=f"Value `{val}` is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}")],
                            )
                        )
                    else:
                        _errors__.append(
                            ValidationException(
                                "the `state` field is not valid because:",
                                SourceLine(_doc, "state", str),
                                [e],
                                detailed_message=f"the `state` field with value `{val}` "
                                "is not valid because:",
                            )
                        )
        tool_state = None
        if "tool_state" in _doc:
            try:
                tool_state = load_field(
                    _doc.get("tool_state"),
                    union_of_None_type_or_Any_type,
                    baseuri,
                    loadingOptions,
                    lc=_doc.get("tool_state")
                )

            except ValidationException as e:
                error_message, to_print, verb_tensage = parse_errors(str(e))

                if str(e) == "missing required field `tool_state`":
                    _errors__.append(
                        ValidationException(
                            str(e),
                            None
                        )
                    )
                else:
                    val = _doc.get("tool_state")
                    if error_message != str(e):
                        val_type = convert_typing(extract_type(type(val)))
                        _errors__.append(
                            ValidationException(
                                "the `tool_state` field is not valid because:",
                                SourceLine(_doc, "tool_state", str),
                                [ValidationException(f"Value is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}",
                                                     detailed_message=f"Value `{val}` is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}")],
                            )
                        )
                    else:
                        _errors__.append(
                            ValidationException(
                                "the `tool_state` field is not valid because:",
                                SourceLine(_doc, "tool_state", str),
                                [e],
                                detailed_message=f"the `tool_state` field with value `{val}` "
                                "is not valid because:",
                            )
                        )
        type_ = None
        if "type" in _doc:
            try:
                type_ = load_field(
                    _doc.get("type"),
                    typedsl_union_of_None_type_or_WorkflowStepTypeLoader_2,
                    baseuri,
                    loadingOptions,
                    lc=_doc.get("type")
                )

            except ValidationException as e:
                error_message, to_print, verb_tensage = parse_errors(str(e))

                if str(e) == "missing required field `type`":
                    _errors__.append(
                        ValidationException(
                            str(e),
                            None
                        )
                    )
                else:
                    val = _doc.get("type")
                    if error_message != str(e):
                        val_type = convert_typing(extract_type(type(val)))
                        _errors__.append(
                            ValidationException(
                                "the `type` field is not valid because:",
                                SourceLine(_doc, "type", str),
                                [ValidationException(f"Value is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}",
                                                     detailed_message=f"Value `{val}` is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}")],
                            )
                        )
                    else:
                        _errors__.append(
                            ValidationException(
                                "the `type` field is not valid because:",
                                SourceLine(_doc, "type", str),
                                [e],
                                detailed_message=f"the `type` field with value `{val}` "
                                "is not valid because:",
                            )
                        )
        run = None
        if "run" in _doc:

            subscope_baseuri = expand_url('run', baseuri, loadingOptions, True)
            try:
                run = load_field(
                    _doc.get("run"),
                    uri_union_of_None_type_or_GalaxyWorkflowLoader_False_False_None_None,
                    subscope_baseuri,
                    loadingOptions,
                    lc=_doc.get("run")
                )

            except ValidationException as e:
                error_message, to_print, verb_tensage = parse_errors(str(e))

                if str(e) == "missing required field `run`":
                    _errors__.append(
                        ValidationException(
                            str(e),
                            None
                        )
                    )
                else:
                    val = _doc.get("run")
                    if error_message != str(e):
                        val_type = convert_typing(extract_type(type(val)))
                        _errors__.append(
                            ValidationException(
                                "the `run` field is not valid because:",
                                SourceLine(_doc, "run", str),
                                [ValidationException(f"Value is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}",
                                                     detailed_message=f"Value `{val}` is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}")],
                            )
                        )
                    else:
                        _errors__.append(
                            ValidationException(
                                "the `run` field is not valid because:",
                                SourceLine(_doc, "run", str),
                                [e],
                                detailed_message=f"the `run` field with value `{val}` "
                                "is not valid because:",
                            )
                        )
        runtime_inputs = None
        if "runtime_inputs" in _doc:
            try:
                runtime_inputs = load_field(
                    _doc.get("runtime_inputs"),
                    union_of_None_type_or_array_of_strtype,
                    baseuri,
                    loadingOptions,
                    lc=_doc.get("runtime_inputs")
                )

            except ValidationException as e:
                error_message, to_print, verb_tensage = parse_errors(str(e))

                if str(e) == "missing required field `runtime_inputs`":
                    _errors__.append(
                        ValidationException(
                            str(e),
                            None
                        )
                    )
                else:
                    val = _doc.get("runtime_inputs")
                    if error_message != str(e):
                        val_type = convert_typing(extract_type(type(val)))
                        _errors__.append(
                            ValidationException(
                                "the `runtime_inputs` field is not valid because:",
                                SourceLine(_doc, "runtime_inputs", str),
                                [ValidationException(f"Value is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}",
                                                     detailed_message=f"Value `{val}` is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}")],
                            )
                        )
                    else:
                        _errors__.append(
                            ValidationException(
                                "the `runtime_inputs` field is not valid because:",
                                SourceLine(_doc, "runtime_inputs", str),
                                [e],
                                detailed_message=f"the `runtime_inputs` field with value `{val}` "
                                "is not valid because:",
                            )
                        )
        when = None
        if "when" in _doc:
            try:
                when = load_field(
                    _doc.get("when"),
                    union_of_None_type_or_strtype,
                    baseuri,
                    loadingOptions,
                    lc=_doc.get("when")
                )

            except ValidationException as e:
                error_message, to_print, verb_tensage = parse_errors(str(e))

                if str(e) == "missing required field `when`":
                    _errors__.append(
                        ValidationException(
                            str(e),
                            None
                        )
                    )
                else:
                    val = _doc.get("when")
                    if error_message != str(e):
                        val_type = convert_typing(extract_type(type(val)))
                        _errors__.append(
                            ValidationException(
                                "the `when` field is not valid because:",
                                SourceLine(_doc, "when", str),
                                [ValidationException(f"Value is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}",
                                                     detailed_message=f"Value `{val}` is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}")],
                            )
                        )
                    else:
                        _errors__.append(
                            ValidationException(
                                "the `when` field is not valid because:",
                                SourceLine(_doc, "when", str),
                                [e],
                                detailed_message=f"the `when` field with value `{val}` "
                                "is not valid because:",
                            )
                        )
        extension_fields: dict[str, Any] = {}
        for k in _doc.keys():
            if k not in cls.attrs:
                if not k:
                    _errors__.append(
                        ValidationException("mapping with implicit null key")
                    )
                elif ":" in k:
                    ex = expand_url(
                        k, "", loadingOptions, scoped_id=False, vocab_term=False
                    )
                    extension_fields[ex] = _doc[k]
                else:
                    _errors__.append(
                        ValidationException(
                            "invalid field `{}`, expected one of: `id`, `label`, `doc`, `position`, `tool_id`, `tool_shed_repository`, `tool_version`, `errors`, `uuid`, `in`, `out`, `state`, `tool_state`, `type`, `run`, `runtime_inputs`, `when`".format(
                                k
                            ),
                            SourceLine(_doc, k, str),
                        )
                    )

        if _errors__:
            raise ValidationException("", None, _errors__, "*")
        _constructed = cls(
            id=id,
            label=label,
            doc=doc,
            position=position,
            tool_id=tool_id,
            tool_shed_repository=tool_shed_repository,
            tool_version=tool_version,
            errors=errors,
            uuid=uuid,
            in_=in_,
            out=out,
            state=state,
            tool_state=tool_state,
            type_=type_,
            run=run,
            runtime_inputs=runtime_inputs,
            when=when,
            extension_fields=extension_fields,
            loadingOptions=loadingOptions,
        )
        loadingOptions.idx[cast(str, id)] = (_constructed, loadingOptions)
        return _constructed

    def save(
        self, top: bool = False, base_url: str = "", relative_uris: bool = True
    ) -> dict[str, Any]:
        r: dict[str, Any] = {}

        if relative_uris:
            for ef in self.extension_fields:
                r[prefix_url(ef, self.loadingOptions.vocab)] = self.extension_fields[ef]
        else:
            for ef in self.extension_fields:
                r[ef] = self.extension_fields[ef]
        if self.id is not None:
            u = save_relative_uri(self.id, base_url, True, None, relative_uris)
            r["id"] = u
        if self.label is not None:
            r["label"] = save(
                self.label, top=False, base_url=self.id, relative_uris=relative_uris
            )
        if self.doc is not None:
            r["doc"] = save(
                self.doc, top=False, base_url=self.id, relative_uris=relative_uris
            )
        if self.position is not None:
            r["position"] = save(
                self.position, top=False, base_url=self.id, relative_uris=relative_uris
            )
        if self.tool_id is not None:
            r["tool_id"] = save(
                self.tool_id, top=False, base_url=self.id, relative_uris=relative_uris
            )
        if self.tool_shed_repository is not None:
            r["tool_shed_repository"] = save(
                self.tool_shed_repository,
                top=False,
                base_url=self.id,
                relative_uris=relative_uris,
            )
        if self.tool_version is not None:
            r["tool_version"] = save(
                self.tool_version,
                top=False,
                base_url=self.id,
                relative_uris=relative_uris,
            )
        if self.errors is not None:
            r["errors"] = save(
                self.errors, top=False, base_url=self.id, relative_uris=relative_uris
            )
        if self.uuid is not None:
            r["uuid"] = save(
                self.uuid, top=False, base_url=self.id, relative_uris=relative_uris
            )
        if self.in_ is not None:
            r["in"] = save(
                self.in_, top=False, base_url=self.id, relative_uris=relative_uris
            )
        if self.out is not None:
            r["out"] = save(
                self.out, top=False, base_url=self.id, relative_uris=relative_uris
            )
        if self.state is not None:
            r["state"] = save(
                self.state, top=False, base_url=self.id, relative_uris=relative_uris
            )
        if self.tool_state is not None:
            r["tool_state"] = save(
                self.tool_state,
                top=False,
                base_url=self.id,
                relative_uris=relative_uris,
            )
        if self.type_ is not None:
            r["type"] = save(
                self.type_, top=False, base_url=self.id, relative_uris=relative_uris
            )
        if self.run is not None:
            u = save_relative_uri(self.run, self.id, False, None, relative_uris)
            r["run"] = u
        if self.runtime_inputs is not None:
            r["runtime_inputs"] = save(
                self.runtime_inputs,
                top=False,
                base_url=self.id,
                relative_uris=relative_uris,
            )
        if self.when is not None:
            r["when"] = save(
                self.when, top=False, base_url=self.id, relative_uris=relative_uris
            )

        # top refers to the directory level
        if top:
            if self.loadingOptions.namespaces:
                r["$namespaces"] = self.loadingOptions.namespaces
            if self.loadingOptions.schemas:
                r["$schemas"] = self.loadingOptions.schemas
        return r

    attrs = frozenset(
        [
            "id",
            "label",
            "doc",
            "position",
            "tool_id",
            "tool_shed_repository",
            "tool_version",
            "errors",
            "uuid",
            "in",
            "out",
            "state",
            "tool_state",
            "type",
            "run",
            "runtime_inputs",
            "when",
        ]
    )


class Sink(Saveable):
    pass


class WorkflowStepInput(Identified, Sink, Labeled):
    """
    TODO:

    """

    id: str

    def __init__(
        self,
        id: Optional[Any] = None,
        source: Optional[Any] = None,
        label: Optional[Any] = None,
        default: Optional[Any] = None,
        extension_fields: Optional[dict[str, Any]] = None,
        loadingOptions: Optional[LoadingOptions] = 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 if id is not None else "_:" + str(_uuid__.uuid4())
        self.source = source
        self.label = label
        self.default = default

    def __eq__(self, other: Any) -> bool:
        if isinstance(other, WorkflowStepInput):
            return bool(
                self.id == other.id
                and self.source == other.source
                and self.label == other.label
                and self.default == other.default
            )
        return False

    def __hash__(self) -> int:
        return hash((self.id, self.source, self.label, self.default))

    @classmethod
    def fromDoc(
        cls,
        doc: Any,
        baseuri: str,
        loadingOptions: LoadingOptions,
        docRoot: Optional[str] = None
    ) -> "WorkflowStepInput":
        _doc = copy.copy(doc)

        if hasattr(doc, "lc"):
            _doc.lc.data = doc.lc.data
            _doc.lc.filename = doc.lc.filename
        _errors__ = []
        id = None
        if "id" in _doc:
            try:
                id = load_field(
                    _doc.get("id"),
                    uri_union_of_None_type_or_strtype_True_False_None_None,
                    baseuri,
                    loadingOptions,
                    lc=_doc.get("id")
                )

            except ValidationException as e:
                error_message, to_print, verb_tensage = parse_errors(str(e))

                if str(e) == "missing required field `id`":
                    _errors__.append(
                        ValidationException(
                            str(e),
                            None
                        )
                    )
                else:
                    val = _doc.get("id")
                    if error_message != str(e):
                        val_type = convert_typing(extract_type(type(val)))
                        _errors__.append(
                            ValidationException(
                                "the `id` field is not valid because:",
                                SourceLine(_doc, "id", str),
                                [ValidationException(f"Value is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}",
                                                     detailed_message=f"Value `{val}` is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}")],
                            )
                        )
                    else:
                        _errors__.append(
                            ValidationException(
                                "the `id` field is not valid because:",
                                SourceLine(_doc, "id", str),
                                [e],
                                detailed_message=f"the `id` field with value `{val}` "
                                "is not valid because:",
                            )
                        )

        __original_id_is_none = id is None
        if id is None:
            if docRoot is not None:
                id = docRoot
            else:
                id = "_:" + str(_uuid__.uuid4())
        if not __original_id_is_none:
            baseuri = cast(str, id)
        source = None
        if "source" in _doc:
            try:
                source = load_field(
                    _doc.get("source"),
                    uri_union_of_None_type_or_strtype_or_array_of_strtype_False_False_2_None,
                    baseuri,
                    loadingOptions,
                    lc=_doc.get("source")
                )

            except ValidationException as e:
                error_message, to_print, verb_tensage = parse_errors(str(e))

                if str(e) == "missing required field `source`":
                    _errors__.append(
                        ValidationException(
                            str(e),
                            None
                        )
                    )
                else:
                    val = _doc.get("source")
                    if error_message != str(e):
                        val_type = convert_typing(extract_type(type(val)))
                        _errors__.append(
                            ValidationException(
                                "the `source` field is not valid because:",
                                SourceLine(_doc, "source", str),
                                [ValidationException(f"Value is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}",
                                                     detailed_message=f"Value `{val}` is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}")],
                            )
                        )
                    else:
                        _errors__.append(
                            ValidationException(
                                "the `source` field is not valid because:",
                                SourceLine(_doc, "source", str),
                                [e],
                                detailed_message=f"the `source` field with value `{val}` "
                                "is not valid because:",
                            )
                        )
        label = None
        if "label" in _doc:
            try:
                label = load_field(
                    _doc.get("label"),
                    union_of_None_type_or_strtype,
                    baseuri,
                    loadingOptions,
                    lc=_doc.get("label")
                )

            except ValidationException as e:
                error_message, to_print, verb_tensage = parse_errors(str(e))

                if str(e) == "missing required field `label`":
                    _errors__.append(
                        ValidationException(
                            str(e),
                            None
                        )
                    )
                else:
                    val = _doc.get("label")
                    if error_message != str(e):
                        val_type = convert_typing(extract_type(type(val)))
                        _errors__.append(
                            ValidationException(
                                "the `label` field is not valid because:",
                                SourceLine(_doc, "label", str),
                                [ValidationException(f"Value is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}",
                                                     detailed_message=f"Value `{val}` is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}")],
                            )
                        )
                    else:
                        _errors__.append(
                            ValidationException(
                                "the `label` field is not valid because:",
                                SourceLine(_doc, "label", str),
                                [e],
                                detailed_message=f"the `label` field with value `{val}` "
                                "is not valid because:",
                            )
                        )
        default = None
        if "default" in _doc:
            try:
                default = load_field(
                    _doc.get("default"),
                    union_of_None_type_or_Any_type,
                    baseuri,
                    loadingOptions,
                    lc=_doc.get("default")
                )

            except ValidationException as e:
                error_message, to_print, verb_tensage = parse_errors(str(e))

                if str(e) == "missing required field `default`":
                    _errors__.append(
                        ValidationException(
                            str(e),
                            None
                        )
                    )
                else:
                    val = _doc.get("default")
                    if error_message != str(e):
                        val_type = convert_typing(extract_type(type(val)))
                        _errors__.append(
                            ValidationException(
                                "the `default` field is not valid because:",
                                SourceLine(_doc, "default", str),
                                [ValidationException(f"Value is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}",
                                                     detailed_message=f"Value `{val}` is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}")],
                            )
                        )
                    else:
                        _errors__.append(
                            ValidationException(
                                "the `default` field is not valid because:",
                                SourceLine(_doc, "default", str),
                                [e],
                                detailed_message=f"the `default` field with value `{val}` "
                                "is not valid because:",
                            )
                        )
        extension_fields: dict[str, Any] = {}
        for k in _doc.keys():
            if k not in cls.attrs:
                if not k:
                    _errors__.append(
                        ValidationException("mapping with implicit null key")
                    )
                elif ":" in k:
                    ex = expand_url(
                        k, "", loadingOptions, scoped_id=False, vocab_term=False
                    )
                    extension_fields[ex] = _doc[k]
                else:
                    _errors__.append(
                        ValidationException(
                            "invalid field `{}`, expected one of: `id`, `source`, `label`, `default`".format(
                                k
                            ),
                            SourceLine(_doc, k, str),
                        )
                    )

        if _errors__:
            raise ValidationException("", None, _errors__, "*")
        _constructed = cls(
            id=id,
            source=source,
            label=label,
            default=default,
            extension_fields=extension_fields,
            loadingOptions=loadingOptions,
        )
        loadingOptions.idx[cast(str, id)] = (_constructed, loadingOptions)
        return _constructed

    def save(
        self, top: bool = False, base_url: str = "", relative_uris: bool = True
    ) -> dict[str, Any]:
        r: dict[str, Any] = {}

        if relative_uris:
            for ef in self.extension_fields:
                r[prefix_url(ef, self.loadingOptions.vocab)] = self.extension_fields[ef]
        else:
            for ef in self.extension_fields:
                r[ef] = self.extension_fields[ef]
        if self.id is not None:
            u = save_relative_uri(self.id, base_url, True, None, relative_uris)
            r["id"] = u
        if self.source is not None:
            u = save_relative_uri(self.source, self.id, False, 2, relative_uris)
            r["source"] = u
        if self.label is not None:
            r["label"] = save(
                self.label, top=False, base_url=self.id, relative_uris=relative_uris
            )
        if self.default is not None:
            r["default"] = save(
                self.default, top=False, base_url=self.id, relative_uris=relative_uris
            )

        # top refers to the directory level
        if top:
            if self.loadingOptions.namespaces:
                r["$namespaces"] = self.loadingOptions.namespaces
            if self.loadingOptions.schemas:
                r["$schemas"] = self.loadingOptions.schemas
        return r

    attrs = frozenset(["id", "source", "label", "default"])


class Report(Saveable):
    """
    Definition of an invocation report for this workflow. Currently the only
    field is 'markdown'.

    """

    def __init__(
        self,
        markdown: Any,
        extension_fields: Optional[dict[str, Any]] = None,
        loadingOptions: Optional[LoadingOptions] = 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.markdown = markdown

    def __eq__(self, other: Any) -> bool:
        if isinstance(other, Report):
            return bool(self.markdown == other.markdown)
        return False

    def __hash__(self) -> int:
        return hash((self.markdown))

    @classmethod
    def fromDoc(
        cls,
        doc: Any,
        baseuri: str,
        loadingOptions: LoadingOptions,
        docRoot: Optional[str] = None
    ) -> "Report":
        _doc = copy.copy(doc)

        if hasattr(doc, "lc"):
            _doc.lc.data = doc.lc.data
            _doc.lc.filename = doc.lc.filename
        _errors__ = []
        try:
            if _doc.get("markdown") is None:
                raise ValidationException("missing required field `markdown`", None, [])

            markdown = load_field(
                _doc.get("markdown"),
                strtype,
                baseuri,
                loadingOptions,
                lc=_doc.get("markdown")
            )

        except ValidationException as e:
            error_message, to_print, verb_tensage = parse_errors(str(e))

            if str(e) == "missing required field `markdown`":
                _errors__.append(
                    ValidationException(
                        str(e),
                        None
                    )
                )
            else:
                val = _doc.get("markdown")
                if error_message != str(e):
                    val_type = convert_typing(extract_type(type(val)))
                    _errors__.append(
                        ValidationException(
                            "the `markdown` field is not valid because:",
                            SourceLine(_doc, "markdown", str),
                            [ValidationException(f"Value is a {val_type}, "
                                                 f"but valid {to_print} for this field "
                                                 f"{verb_tensage} {error_message}",
                                                 detailed_message=f"Value `{val}` is a {val_type}, "
                                                 f"but valid {to_print} for this field "
                                                 f"{verb_tensage} {error_message}")],
                        )
                    )
                else:
                    _errors__.append(
                        ValidationException(
                            "the `markdown` field is not valid because:",
                            SourceLine(_doc, "markdown", str),
                            [e],
                            detailed_message=f"the `markdown` field with value `{val}` "
                            "is not valid because:",
                        )
                    )
        extension_fields: dict[str, Any] = {}
        for k in _doc.keys():
            if k not in cls.attrs:
                if not k:
                    _errors__.append(
                        ValidationException("mapping with implicit null key")
                    )
                elif ":" in k:
                    ex = expand_url(
                        k, "", loadingOptions, scoped_id=False, vocab_term=False
                    )
                    extension_fields[ex] = _doc[k]
                else:
                    _errors__.append(
                        ValidationException(
                            "invalid field `{}`, expected one of: `markdown`".format(k),
                            SourceLine(_doc, k, str),
                        )
                    )

        if _errors__:
            raise ValidationException("", None, _errors__, "*")
        _constructed = cls(
            markdown=markdown,
            extension_fields=extension_fields,
            loadingOptions=loadingOptions,
        )
        return _constructed

    def save(
        self, top: bool = False, base_url: str = "", relative_uris: bool = True
    ) -> dict[str, Any]:
        r: dict[str, Any] = {}

        if relative_uris:
            for ef in self.extension_fields:
                r[prefix_url(ef, self.loadingOptions.vocab)] = self.extension_fields[ef]
        else:
            for ef in self.extension_fields:
                r[ef] = self.extension_fields[ef]
        if self.markdown is not None:
            r["markdown"] = save(
                self.markdown, top=False, base_url=base_url, relative_uris=relative_uris
            )

        # top refers to the directory level
        if top:
            if self.loadingOptions.namespaces:
                r["$namespaces"] = self.loadingOptions.namespaces
            if self.loadingOptions.schemas:
                r["$schemas"] = self.loadingOptions.schemas
        return r

    attrs = frozenset(["markdown"])


class WorkflowStepOutput(Identified):
    """
    Associate an output parameter of the underlying process with a workflow
    parameter.  The workflow parameter (given in the `id` field) be may be used
    as a `source` to connect with input parameters of other workflow steps, or
    with an output parameter of the process.

    A unique identifier for this workflow output parameter.  This is
    the identifier to use in the `source` field of `WorkflowStepInput`
    to connect the output value to downstream parameters.

    """

    id: str

    def __init__(
        self,
        id: Optional[Any] = None,
        add_tags: Optional[Any] = None,
        change_datatype: Optional[Any] = None,
        delete_intermediate_datasets: Optional[Any] = None,
        hide: Optional[Any] = None,
        remove_tags: Optional[Any] = None,
        rename: Optional[Any] = None,
        set_columns: Optional[Any] = None,
        extension_fields: Optional[dict[str, Any]] = None,
        loadingOptions: Optional[LoadingOptions] = 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 if id is not None else "_:" + str(_uuid__.uuid4())
        self.add_tags = add_tags
        self.change_datatype = change_datatype
        self.delete_intermediate_datasets = delete_intermediate_datasets
        self.hide = hide
        self.remove_tags = remove_tags
        self.rename = rename
        self.set_columns = set_columns

    def __eq__(self, other: Any) -> bool:
        if isinstance(other, WorkflowStepOutput):
            return bool(
                self.id == other.id
                and self.add_tags == other.add_tags
                and self.change_datatype == other.change_datatype
                and self.delete_intermediate_datasets
                == other.delete_intermediate_datasets
                and self.hide == other.hide
                and self.remove_tags == other.remove_tags
                and self.rename == other.rename
                and self.set_columns == other.set_columns
            )
        return False

    def __hash__(self) -> int:
        return hash(
            (
                self.id,
                self.add_tags,
                self.change_datatype,
                self.delete_intermediate_datasets,
                self.hide,
                self.remove_tags,
                self.rename,
                self.set_columns,
            )
        )

    @classmethod
    def fromDoc(
        cls,
        doc: Any,
        baseuri: str,
        loadingOptions: LoadingOptions,
        docRoot: Optional[str] = None
    ) -> "WorkflowStepOutput":
        _doc = copy.copy(doc)

        if hasattr(doc, "lc"):
            _doc.lc.data = doc.lc.data
            _doc.lc.filename = doc.lc.filename
        _errors__ = []
        id = None
        if "id" in _doc:
            try:
                id = load_field(
                    _doc.get("id"),
                    uri_union_of_None_type_or_strtype_True_False_None_None,
                    baseuri,
                    loadingOptions,
                    lc=_doc.get("id")
                )

            except ValidationException as e:
                error_message, to_print, verb_tensage = parse_errors(str(e))

                if str(e) == "missing required field `id`":
                    _errors__.append(
                        ValidationException(
                            str(e),
                            None
                        )
                    )
                else:
                    val = _doc.get("id")
                    if error_message != str(e):
                        val_type = convert_typing(extract_type(type(val)))
                        _errors__.append(
                            ValidationException(
                                "the `id` field is not valid because:",
                                SourceLine(_doc, "id", str),
                                [ValidationException(f"Value is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}",
                                                     detailed_message=f"Value `{val}` is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}")],
                            )
                        )
                    else:
                        _errors__.append(
                            ValidationException(
                                "the `id` field is not valid because:",
                                SourceLine(_doc, "id", str),
                                [e],
                                detailed_message=f"the `id` field with value `{val}` "
                                "is not valid because:",
                            )
                        )

        __original_id_is_none = id is None
        if id is None:
            if docRoot is not None:
                id = docRoot
            else:
                id = "_:" + str(_uuid__.uuid4())
        if not __original_id_is_none:
            baseuri = cast(str, id)
        add_tags = None
        if "add_tags" in _doc:
            try:
                add_tags = load_field(
                    _doc.get("add_tags"),
                    union_of_None_type_or_array_of_strtype,
                    baseuri,
                    loadingOptions,
                    lc=_doc.get("add_tags")
                )

            except ValidationException as e:
                error_message, to_print, verb_tensage = parse_errors(str(e))

                if str(e) == "missing required field `add_tags`":
                    _errors__.append(
                        ValidationException(
                            str(e),
                            None
                        )
                    )
                else:
                    val = _doc.get("add_tags")
                    if error_message != str(e):
                        val_type = convert_typing(extract_type(type(val)))
                        _errors__.append(
                            ValidationException(
                                "the `add_tags` field is not valid because:",
                                SourceLine(_doc, "add_tags", str),
                                [ValidationException(f"Value is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}",
                                                     detailed_message=f"Value `{val}` is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}")],
                            )
                        )
                    else:
                        _errors__.append(
                            ValidationException(
                                "the `add_tags` field is not valid because:",
                                SourceLine(_doc, "add_tags", str),
                                [e],
                                detailed_message=f"the `add_tags` field with value `{val}` "
                                "is not valid because:",
                            )
                        )
        change_datatype = None
        if "change_datatype" in _doc:
            try:
                change_datatype = load_field(
                    _doc.get("change_datatype"),
                    union_of_None_type_or_strtype,
                    baseuri,
                    loadingOptions,
                    lc=_doc.get("change_datatype")
                )

            except ValidationException as e:
                error_message, to_print, verb_tensage = parse_errors(str(e))

                if str(e) == "missing required field `change_datatype`":
                    _errors__.append(
                        ValidationException(
                            str(e),
                            None
                        )
                    )
                else:
                    val = _doc.get("change_datatype")
                    if error_message != str(e):
                        val_type = convert_typing(extract_type(type(val)))
                        _errors__.append(
                            ValidationException(
                                "the `change_datatype` field is not valid because:",
                                SourceLine(_doc, "change_datatype", str),
                                [ValidationException(f"Value is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}",
                                                     detailed_message=f"Value `{val}` is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}")],
                            )
                        )
                    else:
                        _errors__.append(
                            ValidationException(
                                "the `change_datatype` field is not valid because:",
                                SourceLine(_doc, "change_datatype", str),
                                [e],
                                detailed_message=f"the `change_datatype` field with value `{val}` "
                                "is not valid because:",
                            )
                        )
        delete_intermediate_datasets = None
        if "delete_intermediate_datasets" in _doc:
            try:
                delete_intermediate_datasets = load_field(
                    _doc.get("delete_intermediate_datasets"),
                    union_of_None_type_or_booltype,
                    baseuri,
                    loadingOptions,
                    lc=_doc.get("delete_intermediate_datasets")
                )

            except ValidationException as e:
                error_message, to_print, verb_tensage = parse_errors(str(e))

                if str(e) == "missing required field `delete_intermediate_datasets`":
                    _errors__.append(
                        ValidationException(
                            str(e),
                            None
                        )
                    )
                else:
                    val = _doc.get("delete_intermediate_datasets")
                    if error_message != str(e):
                        val_type = convert_typing(extract_type(type(val)))
                        _errors__.append(
                            ValidationException(
                                "the `delete_intermediate_datasets` field is not valid because:",
                                SourceLine(_doc, "delete_intermediate_datasets", str),
                                [ValidationException(f"Value is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}",
                                                     detailed_message=f"Value `{val}` is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}")],
                            )
                        )
                    else:
                        _errors__.append(
                            ValidationException(
                                "the `delete_intermediate_datasets` field is not valid because:",
                                SourceLine(_doc, "delete_intermediate_datasets", str),
                                [e],
                                detailed_message=f"the `delete_intermediate_datasets` field with value `{val}` "
                                "is not valid because:",
                            )
                        )
        hide = None
        if "hide" in _doc:
            try:
                hide = load_field(
                    _doc.get("hide"),
                    union_of_None_type_or_booltype,
                    baseuri,
                    loadingOptions,
                    lc=_doc.get("hide")
                )

            except ValidationException as e:
                error_message, to_print, verb_tensage = parse_errors(str(e))

                if str(e) == "missing required field `hide`":
                    _errors__.append(
                        ValidationException(
                            str(e),
                            None
                        )
                    )
                else:
                    val = _doc.get("hide")
                    if error_message != str(e):
                        val_type = convert_typing(extract_type(type(val)))
                        _errors__.append(
                            ValidationException(
                                "the `hide` field is not valid because:",
                                SourceLine(_doc, "hide", str),
                                [ValidationException(f"Value is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}",
                                                     detailed_message=f"Value `{val}` is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}")],
                            )
                        )
                    else:
                        _errors__.append(
                            ValidationException(
                                "the `hide` field is not valid because:",
                                SourceLine(_doc, "hide", str),
                                [e],
                                detailed_message=f"the `hide` field with value `{val}` "
                                "is not valid because:",
                            )
                        )
        remove_tags = None
        if "remove_tags" in _doc:
            try:
                remove_tags = load_field(
                    _doc.get("remove_tags"),
                    union_of_None_type_or_array_of_strtype,
                    baseuri,
                    loadingOptions,
                    lc=_doc.get("remove_tags")
                )

            except ValidationException as e:
                error_message, to_print, verb_tensage = parse_errors(str(e))

                if str(e) == "missing required field `remove_tags`":
                    _errors__.append(
                        ValidationException(
                            str(e),
                            None
                        )
                    )
                else:
                    val = _doc.get("remove_tags")
                    if error_message != str(e):
                        val_type = convert_typing(extract_type(type(val)))
                        _errors__.append(
                            ValidationException(
                                "the `remove_tags` field is not valid because:",
                                SourceLine(_doc, "remove_tags", str),
                                [ValidationException(f"Value is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}",
                                                     detailed_message=f"Value `{val}` is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}")],
                            )
                        )
                    else:
                        _errors__.append(
                            ValidationException(
                                "the `remove_tags` field is not valid because:",
                                SourceLine(_doc, "remove_tags", str),
                                [e],
                                detailed_message=f"the `remove_tags` field with value `{val}` "
                                "is not valid because:",
                            )
                        )
        rename = None
        if "rename" in _doc:
            try:
                rename = load_field(
                    _doc.get("rename"),
                    union_of_None_type_or_strtype,
                    baseuri,
                    loadingOptions,
                    lc=_doc.get("rename")
                )

            except ValidationException as e:
                error_message, to_print, verb_tensage = parse_errors(str(e))

                if str(e) == "missing required field `rename`":
                    _errors__.append(
                        ValidationException(
                            str(e),
                            None
                        )
                    )
                else:
                    val = _doc.get("rename")
                    if error_message != str(e):
                        val_type = convert_typing(extract_type(type(val)))
                        _errors__.append(
                            ValidationException(
                                "the `rename` field is not valid because:",
                                SourceLine(_doc, "rename", str),
                                [ValidationException(f"Value is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}",
                                                     detailed_message=f"Value `{val}` is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}")],
                            )
                        )
                    else:
                        _errors__.append(
                            ValidationException(
                                "the `rename` field is not valid because:",
                                SourceLine(_doc, "rename", str),
                                [e],
                                detailed_message=f"the `rename` field with value `{val}` "
                                "is not valid because:",
                            )
                        )
        set_columns = None
        if "set_columns" in _doc:
            try:
                set_columns = load_field(
                    _doc.get("set_columns"),
                    union_of_None_type_or_array_of_strtype,
                    baseuri,
                    loadingOptions,
                    lc=_doc.get("set_columns")
                )

            except ValidationException as e:
                error_message, to_print, verb_tensage = parse_errors(str(e))

                if str(e) == "missing required field `set_columns`":
                    _errors__.append(
                        ValidationException(
                            str(e),
                            None
                        )
                    )
                else:
                    val = _doc.get("set_columns")
                    if error_message != str(e):
                        val_type = convert_typing(extract_type(type(val)))
                        _errors__.append(
                            ValidationException(
                                "the `set_columns` field is not valid because:",
                                SourceLine(_doc, "set_columns", str),
                                [ValidationException(f"Value is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}",
                                                     detailed_message=f"Value `{val}` is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}")],
                            )
                        )
                    else:
                        _errors__.append(
                            ValidationException(
                                "the `set_columns` field is not valid because:",
                                SourceLine(_doc, "set_columns", str),
                                [e],
                                detailed_message=f"the `set_columns` field with value `{val}` "
                                "is not valid because:",
                            )
                        )
        extension_fields: dict[str, Any] = {}
        for k in _doc.keys():
            if k not in cls.attrs:
                if not k:
                    _errors__.append(
                        ValidationException("mapping with implicit null key")
                    )
                elif ":" in k:
                    ex = expand_url(
                        k, "", loadingOptions, scoped_id=False, vocab_term=False
                    )
                    extension_fields[ex] = _doc[k]
                else:
                    _errors__.append(
                        ValidationException(
                            "invalid field `{}`, expected one of: `id`, `add_tags`, `change_datatype`, `delete_intermediate_datasets`, `hide`, `remove_tags`, `rename`, `set_columns`".format(
                                k
                            ),
                            SourceLine(_doc, k, str),
                        )
                    )

        if _errors__:
            raise ValidationException("", None, _errors__, "*")
        _constructed = cls(
            id=id,
            add_tags=add_tags,
            change_datatype=change_datatype,
            delete_intermediate_datasets=delete_intermediate_datasets,
            hide=hide,
            remove_tags=remove_tags,
            rename=rename,
            set_columns=set_columns,
            extension_fields=extension_fields,
            loadingOptions=loadingOptions,
        )
        loadingOptions.idx[cast(str, id)] = (_constructed, loadingOptions)
        return _constructed

    def save(
        self, top: bool = False, base_url: str = "", relative_uris: bool = True
    ) -> dict[str, Any]:
        r: dict[str, Any] = {}

        if relative_uris:
            for ef in self.extension_fields:
                r[prefix_url(ef, self.loadingOptions.vocab)] = self.extension_fields[ef]
        else:
            for ef in self.extension_fields:
                r[ef] = self.extension_fields[ef]
        if self.id is not None:
            u = save_relative_uri(self.id, base_url, True, None, relative_uris)
            r["id"] = u
        if self.add_tags is not None:
            r["add_tags"] = save(
                self.add_tags, top=False, base_url=self.id, relative_uris=relative_uris
            )
        if self.change_datatype is not None:
            r["change_datatype"] = save(
                self.change_datatype,
                top=False,
                base_url=self.id,
                relative_uris=relative_uris,
            )
        if self.delete_intermediate_datasets is not None:
            r["delete_intermediate_datasets"] = save(
                self.delete_intermediate_datasets,
                top=False,
                base_url=self.id,
                relative_uris=relative_uris,
            )
        if self.hide is not None:
            r["hide"] = save(
                self.hide, top=False, base_url=self.id, relative_uris=relative_uris
            )
        if self.remove_tags is not None:
            r["remove_tags"] = save(
                self.remove_tags,
                top=False,
                base_url=self.id,
                relative_uris=relative_uris,
            )
        if self.rename is not None:
            r["rename"] = save(
                self.rename, top=False, base_url=self.id, relative_uris=relative_uris
            )
        if self.set_columns is not None:
            r["set_columns"] = save(
                self.set_columns,
                top=False,
                base_url=self.id,
                relative_uris=relative_uris,
            )

        # top refers to the directory level
        if top:
            if self.loadingOptions.namespaces:
                r["$namespaces"] = self.loadingOptions.namespaces
            if self.loadingOptions.schemas:
                r["$schemas"] = self.loadingOptions.schemas
        return r

    attrs = frozenset(
        [
            "id",
            "add_tags",
            "change_datatype",
            "delete_intermediate_datasets",
            "hide",
            "remove_tags",
            "rename",
            "set_columns",
        ]
    )


class GalaxyWorkflow(Process, HasUUID):
    """
    A Galaxy workflow description. This record corresponds to the description of a workflow that should be executable
    on a Galaxy server that includes the contained tool definitions.

    The workflows API or the user interface of Galaxy instances that are of version 19.09 or newer should be able to
    import a document defining this record.

    ## A note about `label` field.

    This is the name of the workflow in the Galaxy user interface. This is the mechanism that
    users will primarily identify the workflow using. Legacy support - this may also be called 'name' and Galaxy will
    consume the workflow document fine and treat this attribute correctly - however in order to validate against this
    workflow definition schema the attribute should be called `label`.

    """

    id: str

    def __init__(
        self,
        inputs: Any,
        outputs: Any,
        steps: Any,
        tags: Any,
        id: Optional[Any] = None,
        label: Optional[Any] = None,
        doc: Optional[Any] = None,
        uuid: Optional[Any] = None,
        report: Optional[Any] = None,
        creator: Optional[Any] = None,
        license: Optional[Any] = None,
        release: Optional[Any] = None,
        extension_fields: Optional[dict[str, Any]] = None,
        loadingOptions: Optional[LoadingOptions] = 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 if id is not None else "_:" + str(_uuid__.uuid4())
        self.label = label
        self.doc = doc
        self.inputs = inputs
        self.outputs = outputs
        self.uuid = uuid
        self.class_ = "GalaxyWorkflow"
        self.steps = steps
        self.report = report
        self.tags = tags
        self.creator = creator
        self.license = license
        self.release = release

    def __eq__(self, other: Any) -> bool:
        if isinstance(other, GalaxyWorkflow):
            return bool(
                self.id == other.id
                and self.label == other.label
                and self.doc == other.doc
                and self.inputs == other.inputs
                and self.outputs == other.outputs
                and self.uuid == other.uuid
                and self.class_ == other.class_
                and self.steps == other.steps
                and self.report == other.report
                and self.tags == other.tags
                and self.creator == other.creator
                and self.license == other.license
                and self.release == other.release
            )
        return False

    def __hash__(self) -> int:
        return hash(
            (
                self.id,
                self.label,
                self.doc,
                self.inputs,
                self.outputs,
                self.uuid,
                self.class_,
                self.steps,
                self.report,
                self.tags,
                self.creator,
                self.license,
                self.release,
            )
        )

    @classmethod
    def fromDoc(
        cls,
        doc: Any,
        baseuri: str,
        loadingOptions: LoadingOptions,
        docRoot: Optional[str] = None
    ) -> "GalaxyWorkflow":
        _doc = copy.copy(doc)

        if hasattr(doc, "lc"):
            _doc.lc.data = doc.lc.data
            _doc.lc.filename = doc.lc.filename
        _errors__ = []
        id = None
        if "id" in _doc:
            try:
                id = load_field(
                    _doc.get("id"),
                    uri_union_of_None_type_or_strtype_True_False_None_None,
                    baseuri,
                    loadingOptions,
                    lc=_doc.get("id")
                )

            except ValidationException as e:
                error_message, to_print, verb_tensage = parse_errors(str(e))

                if str(e) == "missing required field `id`":
                    _errors__.append(
                        ValidationException(
                            str(e),
                            None
                        )
                    )
                else:
                    val = _doc.get("id")
                    if error_message != str(e):
                        val_type = convert_typing(extract_type(type(val)))
                        _errors__.append(
                            ValidationException(
                                "the `id` field is not valid because:",
                                SourceLine(_doc, "id", str),
                                [ValidationException(f"Value is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}",
                                                     detailed_message=f"Value `{val}` is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}")],
                            )
                        )
                    else:
                        _errors__.append(
                            ValidationException(
                                "the `id` field is not valid because:",
                                SourceLine(_doc, "id", str),
                                [e],
                                detailed_message=f"the `id` field with value `{val}` "
                                "is not valid because:",
                            )
                        )

        __original_id_is_none = id is None
        if id is None:
            if docRoot is not None:
                id = docRoot
            else:
                id = "_:" + str(_uuid__.uuid4())
        if not __original_id_is_none:
            baseuri = cast(str, id)
        try:
            if _doc.get("class") is None:
                raise ValidationException("missing required field `class`", None, [])

            class_ = load_field(
                _doc.get("class"),
                uri_GalaxyWorkflow_classLoader_False_True_None_None,
                baseuri,
                loadingOptions,
                lc=_doc.get("class")
            )

            if class_ not in (cls.__name__, loadingOptions.vocab.get(cls.__name__)):
               raise ValidationException(f"tried `{cls.__name__}` but")
        except ValidationException as e:
               raise e
        label = None
        if "label" in _doc:
            try:
                label = load_field(
                    _doc.get("label"),
                    union_of_None_type_or_strtype,
                    baseuri,
                    loadingOptions,
                    lc=_doc.get("label")
                )

            except ValidationException as e:
                error_message, to_print, verb_tensage = parse_errors(str(e))

                if str(e) == "missing required field `label`":
                    _errors__.append(
                        ValidationException(
                            str(e),
                            None
                        )
                    )
                else:
                    val = _doc.get("label")
                    if error_message != str(e):
                        val_type = convert_typing(extract_type(type(val)))
                        _errors__.append(
                            ValidationException(
                                "the `label` field is not valid because:",
                                SourceLine(_doc, "label", str),
                                [ValidationException(f"Value is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}",
                                                     detailed_message=f"Value `{val}` is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}")],
                            )
                        )
                    else:
                        _errors__.append(
                            ValidationException(
                                "the `label` field is not valid because:",
                                SourceLine(_doc, "label", str),
                                [e],
                                detailed_message=f"the `label` field with value `{val}` "
                                "is not valid because:",
                            )
                        )
        doc = None
        if "doc" in _doc:
            try:
                doc = load_field(
                    _doc.get("doc"),
                    union_of_None_type_or_strtype_or_array_of_strtype,
                    baseuri,
                    loadingOptions,
                    lc=_doc.get("doc")
                )

            except ValidationException as e:
                error_message, to_print, verb_tensage = parse_errors(str(e))

                if str(e) == "missing required field `doc`":
                    _errors__.append(
                        ValidationException(
                            str(e),
                            None
                        )
                    )
                else:
                    val = _doc.get("doc")
                    if error_message != str(e):
                        val_type = convert_typing(extract_type(type(val)))
                        _errors__.append(
                            ValidationException(
                                "the `doc` field is not valid because:",
                                SourceLine(_doc, "doc", str),
                                [ValidationException(f"Value is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}",
                                                     detailed_message=f"Value `{val}` is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}")],
                            )
                        )
                    else:
                        _errors__.append(
                            ValidationException(
                                "the `doc` field is not valid because:",
                                SourceLine(_doc, "doc", str),
                                [e],
                                detailed_message=f"the `doc` field with value `{val}` "
                                "is not valid because:",
                            )
                        )
        try:
            if _doc.get("inputs") is None:
                raise ValidationException("missing required field `inputs`", None, [])

            inputs = load_field(
                _doc.get("inputs"),
                idmap_inputs_array_of_WorkflowInputParameterLoader,
                baseuri,
                loadingOptions,
                lc=_doc.get("inputs")
            )

        except ValidationException as e:
            error_message, to_print, verb_tensage = parse_errors(str(e))

            if str(e) == "missing required field `inputs`":
                _errors__.append(
                    ValidationException(
                        str(e),
                        None
                    )
                )
            else:
                val = _doc.get("inputs")
                if error_message != str(e):
                    val_type = convert_typing(extract_type(type(val)))
                    _errors__.append(
                        ValidationException(
                            "the `inputs` field is not valid because:",
                            SourceLine(_doc, "inputs", str),
                            [ValidationException(f"Value is a {val_type}, "
                                                 f"but valid {to_print} for this field "
                                                 f"{verb_tensage} {error_message}",
                                                 detailed_message=f"Value `{val}` is a {val_type}, "
                                                 f"but valid {to_print} for this field "
                                                 f"{verb_tensage} {error_message}")],
                        )
                    )
                else:
                    _errors__.append(
                        ValidationException(
                            "the `inputs` field is not valid because:",
                            SourceLine(_doc, "inputs", str),
                            [e],
                            detailed_message=f"the `inputs` field with value `{val}` "
                            "is not valid because:",
                        )
                    )
        try:
            if _doc.get("outputs") is None:
                raise ValidationException("missing required field `outputs`", None, [])

            outputs = load_field(
                _doc.get("outputs"),
                idmap_outputs_array_of_WorkflowOutputParameterLoader,
                baseuri,
                loadingOptions,
                lc=_doc.get("outputs")
            )

        except ValidationException as e:
            error_message, to_print, verb_tensage = parse_errors(str(e))

            if str(e) == "missing required field `outputs`":
                _errors__.append(
                    ValidationException(
                        str(e),
                        None
                    )
                )
            else:
                val = _doc.get("outputs")
                if error_message != str(e):
                    val_type = convert_typing(extract_type(type(val)))
                    _errors__.append(
                        ValidationException(
                            "the `outputs` field is not valid because:",
                            SourceLine(_doc, "outputs", str),
                            [ValidationException(f"Value is a {val_type}, "
                                                 f"but valid {to_print} for this field "
                                                 f"{verb_tensage} {error_message}",
                                                 detailed_message=f"Value `{val}` is a {val_type}, "
                                                 f"but valid {to_print} for this field "
                                                 f"{verb_tensage} {error_message}")],
                        )
                    )
                else:
                    _errors__.append(
                        ValidationException(
                            "the `outputs` field is not valid because:",
                            SourceLine(_doc, "outputs", str),
                            [e],
                            detailed_message=f"the `outputs` field with value `{val}` "
                            "is not valid because:",
                        )
                    )
        uuid = None
        if "uuid" in _doc:
            try:
                uuid = load_field(
                    _doc.get("uuid"),
                    union_of_None_type_or_strtype,
                    baseuri,
                    loadingOptions,
                    lc=_doc.get("uuid")
                )

            except ValidationException as e:
                error_message, to_print, verb_tensage = parse_errors(str(e))

                if str(e) == "missing required field `uuid`":
                    _errors__.append(
                        ValidationException(
                            str(e),
                            None
                        )
                    )
                else:
                    val = _doc.get("uuid")
                    if error_message != str(e):
                        val_type = convert_typing(extract_type(type(val)))
                        _errors__.append(
                            ValidationException(
                                "the `uuid` field is not valid because:",
                                SourceLine(_doc, "uuid", str),
                                [ValidationException(f"Value is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}",
                                                     detailed_message=f"Value `{val}` is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}")],
                            )
                        )
                    else:
                        _errors__.append(
                            ValidationException(
                                "the `uuid` field is not valid because:",
                                SourceLine(_doc, "uuid", str),
                                [e],
                                detailed_message=f"the `uuid` field with value `{val}` "
                                "is not valid because:",
                            )
                        )
        try:
            if _doc.get("steps") is None:
                raise ValidationException("missing required field `steps`", None, [])

            steps = load_field(
                _doc.get("steps"),
                idmap_steps_union_of_array_of_WorkflowStepLoader,
                baseuri,
                loadingOptions,
                lc=_doc.get("steps")
            )

        except ValidationException as e:
            error_message, to_print, verb_tensage = parse_errors(str(e))

            if str(e) == "missing required field `steps`":
                _errors__.append(
                    ValidationException(
                        str(e),
                        None
                    )
                )
            else:
                val = _doc.get("steps")
                if error_message != str(e):
                    val_type = convert_typing(extract_type(type(val)))
                    _errors__.append(
                        ValidationException(
                            "the `steps` field is not valid because:",
                            SourceLine(_doc, "steps", str),
                            [ValidationException(f"Value is a {val_type}, "
                                                 f"but valid {to_print} for this field "
                                                 f"{verb_tensage} {error_message}",
                                                 detailed_message=f"Value `{val}` is a {val_type}, "
                                                 f"but valid {to_print} for this field "
                                                 f"{verb_tensage} {error_message}")],
                        )
                    )
                else:
                    _errors__.append(
                        ValidationException(
                            "the `steps` field is not valid because:",
                            SourceLine(_doc, "steps", str),
                            [e],
                            detailed_message=f"the `steps` field with value `{val}` "
                            "is not valid because:",
                        )
                    )
        report = None
        if "report" in _doc:
            try:
                report = load_field(
                    _doc.get("report"),
                    union_of_None_type_or_ReportLoader,
                    baseuri,
                    loadingOptions,
                    lc=_doc.get("report")
                )

            except ValidationException as e:
                error_message, to_print, verb_tensage = parse_errors(str(e))

                if str(e) == "missing required field `report`":
                    _errors__.append(
                        ValidationException(
                            str(e),
                            None
                        )
                    )
                else:
                    val = _doc.get("report")
                    if error_message != str(e):
                        val_type = convert_typing(extract_type(type(val)))
                        _errors__.append(
                            ValidationException(
                                "the `report` field is not valid because:",
                                SourceLine(_doc, "report", str),
                                [ValidationException(f"Value is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}",
                                                     detailed_message=f"Value `{val}` is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}")],
                            )
                        )
                    else:
                        _errors__.append(
                            ValidationException(
                                "the `report` field is not valid because:",
                                SourceLine(_doc, "report", str),
                                [e],
                                detailed_message=f"the `report` field with value `{val}` "
                                "is not valid because:",
                            )
                        )
        tags = None
        if "tags" in _doc:
            try:
                tags = load_field(
                    _doc.get("tags"),
                    union_of_array_of_strtype_or_None_type,
                    baseuri,
                    loadingOptions,
                    lc=_doc.get("tags")
                )

            except ValidationException as e:
                error_message, to_print, verb_tensage = parse_errors(str(e))

                if str(e) == "missing required field `tags`":
                    _errors__.append(
                        ValidationException(
                            str(e),
                            None
                        )
                    )
                else:
                    val = _doc.get("tags")
                    if error_message != str(e):
                        val_type = convert_typing(extract_type(type(val)))
                        _errors__.append(
                            ValidationException(
                                "the `tags` field is not valid because:",
                                SourceLine(_doc, "tags", str),
                                [ValidationException(f"Value is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}",
                                                     detailed_message=f"Value `{val}` is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}")],
                            )
                        )
                    else:
                        _errors__.append(
                            ValidationException(
                                "the `tags` field is not valid because:",
                                SourceLine(_doc, "tags", str),
                                [e],
                                detailed_message=f"the `tags` field with value `{val}` "
                                "is not valid because:",
                            )
                        )
        creator = None
        if "creator" in _doc:
            try:
                creator = load_field(
                    _doc.get("creator"),
                    union_of_None_type_or_Any_type,
                    baseuri,
                    loadingOptions,
                    lc=_doc.get("creator")
                )

            except ValidationException as e:
                error_message, to_print, verb_tensage = parse_errors(str(e))

                if str(e) == "missing required field `creator`":
                    _errors__.append(
                        ValidationException(
                            str(e),
                            None
                        )
                    )
                else:
                    val = _doc.get("creator")
                    if error_message != str(e):
                        val_type = convert_typing(extract_type(type(val)))
                        _errors__.append(
                            ValidationException(
                                "the `creator` field is not valid because:",
                                SourceLine(_doc, "creator", str),
                                [ValidationException(f"Value is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}",
                                                     detailed_message=f"Value `{val}` is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}")],
                            )
                        )
                    else:
                        _errors__.append(
                            ValidationException(
                                "the `creator` field is not valid because:",
                                SourceLine(_doc, "creator", str),
                                [e],
                                detailed_message=f"the `creator` field with value `{val}` "
                                "is not valid because:",
                            )
                        )
        license = None
        if "license" in _doc:
            try:
                license = load_field(
                    _doc.get("license"),
                    union_of_None_type_or_strtype,
                    baseuri,
                    loadingOptions,
                    lc=_doc.get("license")
                )

            except ValidationException as e:
                error_message, to_print, verb_tensage = parse_errors(str(e))

                if str(e) == "missing required field `license`":
                    _errors__.append(
                        ValidationException(
                            str(e),
                            None
                        )
                    )
                else:
                    val = _doc.get("license")
                    if error_message != str(e):
                        val_type = convert_typing(extract_type(type(val)))
                        _errors__.append(
                            ValidationException(
                                "the `license` field is not valid because:",
                                SourceLine(_doc, "license", str),
                                [ValidationException(f"Value is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}",
                                                     detailed_message=f"Value `{val}` is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}")],
                            )
                        )
                    else:
                        _errors__.append(
                            ValidationException(
                                "the `license` field is not valid because:",
                                SourceLine(_doc, "license", str),
                                [e],
                                detailed_message=f"the `license` field with value `{val}` "
                                "is not valid because:",
                            )
                        )
        release = None
        if "release" in _doc:
            try:
                release = load_field(
                    _doc.get("release"),
                    union_of_None_type_or_strtype,
                    baseuri,
                    loadingOptions,
                    lc=_doc.get("release")
                )

            except ValidationException as e:
                error_message, to_print, verb_tensage = parse_errors(str(e))

                if str(e) == "missing required field `release`":
                    _errors__.append(
                        ValidationException(
                            str(e),
                            None
                        )
                    )
                else:
                    val = _doc.get("release")
                    if error_message != str(e):
                        val_type = convert_typing(extract_type(type(val)))
                        _errors__.append(
                            ValidationException(
                                "the `release` field is not valid because:",
                                SourceLine(_doc, "release", str),
                                [ValidationException(f"Value is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}",
                                                     detailed_message=f"Value `{val}` is a {val_type}, "
                                                     f"but valid {to_print} for this field "
                                                     f"{verb_tensage} {error_message}")],
                            )
                        )
                    else:
                        _errors__.append(
                            ValidationException(
                                "the `release` field is not valid because:",
                                SourceLine(_doc, "release", str),
                                [e],
                                detailed_message=f"the `release` field with value `{val}` "
                                "is not valid because:",
                            )
                        )
        extension_fields: dict[str, Any] = {}
        for k in _doc.keys():
            if k not in cls.attrs:
                if not k:
                    _errors__.append(
                        ValidationException("mapping with implicit null key")
                    )
                elif ":" in k:
                    ex = expand_url(
                        k, "", loadingOptions, scoped_id=False, vocab_term=False
                    )
                    extension_fields[ex] = _doc[k]
                else:
                    _errors__.append(
                        ValidationException(
                            "invalid field `{}`, expected one of: `id`, `label`, `doc`, `inputs`, `outputs`, `uuid`, `class`, `steps`, `report`, `tags`, `creator`, `license`, `release`".format(
                                k
                            ),
                            SourceLine(_doc, k, str),
                        )
                    )

        if _errors__:
            raise ValidationException("", None, _errors__, "*")
        _constructed = cls(
            id=id,
            label=label,
            doc=doc,
            inputs=inputs,
            outputs=outputs,
            uuid=uuid,
            steps=steps,
            report=report,
            tags=tags,
            creator=creator,
            license=license,
            release=release,
            extension_fields=extension_fields,
            loadingOptions=loadingOptions,
        )
        loadingOptions.idx[cast(str, id)] = (_constructed, loadingOptions)
        return _constructed

    def save(
        self, top: bool = False, base_url: str = "", relative_uris: bool = True
    ) -> dict[str, Any]:
        r: dict[str, Any] = {}

        if relative_uris:
            for ef in self.extension_fields:
                r[prefix_url(ef, self.loadingOptions.vocab)] = self.extension_fields[ef]
        else:
            for ef in self.extension_fields:
                r[ef] = self.extension_fields[ef]
        if self.id is not None:
            u = save_relative_uri(self.id, base_url, True, None, relative_uris)
            r["id"] = u
        if self.class_ is not None:
            uri = self.loadingOptions.vocab[self.class_]
            if p := self.loadingOptions.rvocab.get(uri[: -len(self.class_)]):
                uri = f"{p}:{self.class_}"
            else:
                uri = self.class_
            u = save_relative_uri(uri, self.id, False, None, relative_uris)
            r["class"] = u
        if self.label is not None:
            r["label"] = save(
                self.label, top=False, base_url=self.id, relative_uris=relative_uris
            )
        if self.doc is not None:
            r["doc"] = save(
                self.doc, top=False, base_url=self.id, relative_uris=relative_uris
            )
        if self.inputs is not None:
            r["inputs"] = save(
                self.inputs, top=False, base_url=self.id, relative_uris=relative_uris
            )
        if self.outputs is not None:
            r["outputs"] = save(
                self.outputs, top=False, base_url=self.id, relative_uris=relative_uris
            )
        if self.uuid is not None:
            r["uuid"] = save(
                self.uuid, top=False, base_url=self.id, relative_uris=relative_uris
            )
        if self.steps is not None:
            r["steps"] = save(
                self.steps, top=False, base_url=self.id, relative_uris=relative_uris
            )
        if self.report is not None:
            r["report"] = save(
                self.report, top=False, base_url=self.id, relative_uris=relative_uris
            )
        if self.tags is not None:
            r["tags"] = save(
                self.tags, top=False, base_url=self.id, relative_uris=relative_uris
            )
        if self.creator is not None:
            r["creator"] = save(
                self.creator, top=False, base_url=self.id, relative_uris=relative_uris
            )
        if self.license is not None:
            r["license"] = save(
                self.license, top=False, base_url=self.id, relative_uris=relative_uris
            )
        if self.release is not None:
            r["release"] = save(
                self.release, top=False, base_url=self.id, relative_uris=relative_uris
            )

        # top refers to the directory level
        if top:
            if self.loadingOptions.namespaces:
                r["$namespaces"] = self.loadingOptions.namespaces
            if self.loadingOptions.schemas:
                r["$schemas"] = self.loadingOptions.schemas
        return r

    attrs = frozenset(
        [
            "id",
            "label",
            "doc",
            "inputs",
            "outputs",
            "uuid",
            "class",
            "steps",
            "report",
            "tags",
            "creator",
            "license",
            "release",
        ]
    )


_vocab = {
    "Any": "https://w3id.org/cwl/salad#Any",
    "ArraySchema": "https://w3id.org/cwl/salad#ArraySchema",
    "Documented": "https://w3id.org/cwl/salad#Documented",
    "EnumSchema": "https://w3id.org/cwl/salad#EnumSchema",
    "File": "https://galaxyproject.org/gxformat2/v19_09#GalaxyType/File",
    "GalaxyType": "https://galaxyproject.org/gxformat2/v19_09#GalaxyType",
    "GalaxyWorkflow": "https://galaxyproject.org/gxformat2/v19_09#GalaxyWorkflow",
    "HasStepErrors": "https://galaxyproject.org/gxformat2/gxformat2common#HasStepErrors",
    "HasStepPosition": "https://galaxyproject.org/gxformat2/gxformat2common#HasStepPosition",
    "HasUUID": "https://galaxyproject.org/gxformat2/gxformat2common#HasUUID",
    "Identified": "https://w3id.org/cwl/cwl#Identified",
    "InputParameter": "https://w3id.org/cwl/cwl#InputParameter",
    "Labeled": "https://w3id.org/cwl/cwl#Labeled",
    "OutputParameter": "https://w3id.org/cwl/cwl#OutputParameter",
    "Parameter": "https://w3id.org/cwl/cwl#Parameter",
    "PrimitiveType": "https://w3id.org/cwl/salad#PrimitiveType",
    "Process": "https://w3id.org/cwl/cwl#Process",
    "RecordField": "https://w3id.org/cwl/salad#RecordField",
    "RecordSchema": "https://w3id.org/cwl/salad#RecordSchema",
    "ReferencesTool": "https://galaxyproject.org/gxformat2/gxformat2common#ReferencesTool",
    "Report": "https://galaxyproject.org/gxformat2/v19_09#Report",
    "Sink": "https://galaxyproject.org/gxformat2/v19_09#Sink",
    "StepPosition": "https://galaxyproject.org/gxformat2/gxformat2common#StepPosition",
    "ToolShedRepository": "https://galaxyproject.org/gxformat2/gxformat2common#ToolShedRepository",
    "WorkflowInputParameter": "https://galaxyproject.org/gxformat2/v19_09#WorkflowInputParameter",
    "WorkflowOutputParameter": "https://galaxyproject.org/gxformat2/v19_09#WorkflowOutputParameter",
    "WorkflowStep": "https://galaxyproject.org/gxformat2/v19_09#WorkflowStep",
    "WorkflowStepInput": "https://galaxyproject.org/gxformat2/v19_09#WorkflowStepInput",
    "WorkflowStepOutput": "https://galaxyproject.org/gxformat2/v19_09#WorkflowStepOutput",
    "WorkflowStepType": "https://galaxyproject.org/gxformat2/v19_09#WorkflowStepType",
    "array": "https://w3id.org/cwl/salad#array",
    "boolean": "http://www.w3.org/2001/XMLSchema#boolean",
    "collection": "https://galaxyproject.org/gxformat2/v19_09#GalaxyType/collection",
    "data": "https://galaxyproject.org/gxformat2/v19_09#GalaxyType/data",
    "double": "http://www.w3.org/2001/XMLSchema#double",
    "enum": "https://w3id.org/cwl/salad#enum",
    "float": "http://www.w3.org/2001/XMLSchema#float",
    "int": "http://www.w3.org/2001/XMLSchema#int",
    "integer": "https://galaxyproject.org/gxformat2/v19_09#GalaxyType/integer",
    "long": "http://www.w3.org/2001/XMLSchema#long",
    "null": "https://w3id.org/cwl/salad#null",
    "pause": "https://galaxyproject.org/gxformat2/v19_09#WorkflowStepType/pause",
    "record": "https://w3id.org/cwl/salad#record",
    "string": "http://www.w3.org/2001/XMLSchema#string",
    "subworkflow": "https://galaxyproject.org/gxformat2/v19_09#WorkflowStepType/subworkflow",
    "text": "https://galaxyproject.org/gxformat2/v19_09#GalaxyType/text",
    "tool": "https://galaxyproject.org/gxformat2/v19_09#WorkflowStepType/tool",
}
_rvocab = {
    "https://w3id.org/cwl/salad#Any": "Any",
    "https://w3id.org/cwl/salad#ArraySchema": "ArraySchema",
    "https://w3id.org/cwl/salad#Documented": "Documented",
    "https://w3id.org/cwl/salad#EnumSchema": "EnumSchema",
    "https://galaxyproject.org/gxformat2/v19_09#GalaxyType/File": "File",
    "https://galaxyproject.org/gxformat2/v19_09#GalaxyType": "GalaxyType",
    "https://galaxyproject.org/gxformat2/v19_09#GalaxyWorkflow": "GalaxyWorkflow",
    "https://galaxyproject.org/gxformat2/gxformat2common#HasStepErrors": "HasStepErrors",
    "https://galaxyproject.org/gxformat2/gxformat2common#HasStepPosition": "HasStepPosition",
    "https://galaxyproject.org/gxformat2/gxformat2common#HasUUID": "HasUUID",
    "https://w3id.org/cwl/cwl#Identified": "Identified",
    "https://w3id.org/cwl/cwl#InputParameter": "InputParameter",
    "https://w3id.org/cwl/cwl#Labeled": "Labeled",
    "https://w3id.org/cwl/cwl#OutputParameter": "OutputParameter",
    "https://w3id.org/cwl/cwl#Parameter": "Parameter",
    "https://w3id.org/cwl/salad#PrimitiveType": "PrimitiveType",
    "https://w3id.org/cwl/cwl#Process": "Process",
    "https://w3id.org/cwl/salad#RecordField": "RecordField",
    "https://w3id.org/cwl/salad#RecordSchema": "RecordSchema",
    "https://galaxyproject.org/gxformat2/gxformat2common#ReferencesTool": "ReferencesTool",
    "https://galaxyproject.org/gxformat2/v19_09#Report": "Report",
    "https://galaxyproject.org/gxformat2/v19_09#Sink": "Sink",
    "https://galaxyproject.org/gxformat2/gxformat2common#StepPosition": "StepPosition",
    "https://galaxyproject.org/gxformat2/gxformat2common#ToolShedRepository": "ToolShedRepository",
    "https://galaxyproject.org/gxformat2/v19_09#WorkflowInputParameter": "WorkflowInputParameter",
    "https://galaxyproject.org/gxformat2/v19_09#WorkflowOutputParameter": "WorkflowOutputParameter",
    "https://galaxyproject.org/gxformat2/v19_09#WorkflowStep": "WorkflowStep",
    "https://galaxyproject.org/gxformat2/v19_09#WorkflowStepInput": "WorkflowStepInput",
    "https://galaxyproject.org/gxformat2/v19_09#WorkflowStepOutput": "WorkflowStepOutput",
    "https://galaxyproject.org/gxformat2/v19_09#WorkflowStepType": "WorkflowStepType",
    "https://w3id.org/cwl/salad#array": "array",
    "http://www.w3.org/2001/XMLSchema#boolean": "boolean",
    "https://galaxyproject.org/gxformat2/v19_09#GalaxyType/collection": "collection",
    "https://galaxyproject.org/gxformat2/v19_09#GalaxyType/data": "data",
    "http://www.w3.org/2001/XMLSchema#double": "double",
    "https://w3id.org/cwl/salad#enum": "enum",
    "http://www.w3.org/2001/XMLSchema#float": "float",
    "http://www.w3.org/2001/XMLSchema#int": "int",
    "https://galaxyproject.org/gxformat2/v19_09#GalaxyType/integer": "integer",
    "http://www.w3.org/2001/XMLSchema#long": "long",
    "https://w3id.org/cwl/salad#null": "null",
    "https://galaxyproject.org/gxformat2/v19_09#WorkflowStepType/pause": "pause",
    "https://w3id.org/cwl/salad#record": "record",
    "http://www.w3.org/2001/XMLSchema#string": "string",
    "https://galaxyproject.org/gxformat2/v19_09#WorkflowStepType/subworkflow": "subworkflow",
    "https://galaxyproject.org/gxformat2/v19_09#GalaxyType/text": "text",
    "https://galaxyproject.org/gxformat2/v19_09#WorkflowStepType/tool": "tool",
}

strtype = _PrimitiveLoader(str)
inttype = _PrimitiveLoader(int)
floattype = _PrimitiveLoader(float)
booltype = _PrimitiveLoader(bool)
None_type = _PrimitiveLoader(type(None))
Any_type = _AnyLoader()
PrimitiveTypeLoader = _EnumLoader(
    (
        "null",
        "boolean",
        "int",
        "long",
        "float",
        "double",
        "string",
    ),
    "PrimitiveType",
)
"""
Salad data types are based on Avro schema declarations.  Refer to the
[Avro schema declaration documentation](https://avro.apache.org/docs/current/spec.html#schemas) for
detailed information.

null: no value
boolean: a binary value
int: 32-bit signed integer
long: 64-bit signed integer
float: single precision (32-bit) IEEE 754 floating-point number
double: double precision (64-bit) IEEE 754 floating-point number
string: Unicode character sequence
"""
AnyLoader = _EnumLoader(("Any",), "Any")
"""
The **Any** type validates for any non-null value.
"""
RecordFieldLoader = _RecordLoader(RecordField, None, None)
RecordSchemaLoader = _RecordLoader(RecordSchema, None, None)
EnumSchemaLoader = _RecordLoader(EnumSchema, None, None)
ArraySchemaLoader = _RecordLoader(ArraySchema, None, None)
StepPositionLoader = _RecordLoader(StepPosition, None, None)
ToolShedRepositoryLoader = _RecordLoader(ToolShedRepository, None, None)
GalaxyTypeLoader = _EnumLoader(
    (
        "null",
        "boolean",
        "int",
        "long",
        "float",
        "double",
        "string",
        "integer",
        "text",
        "File",
        "data",
        "collection",
    ),
    "GalaxyType",
)
"""
Extends primitive types with the native Galaxy concepts such datasets and collections.
integer: an alias for int type - matches syntax used by Galaxy tools
text: an alias for string type - matches syntax used by Galaxy tools
File: an alias for data - there are subtle differences between a plain file, the CWL concept of 'File', and the Galaxy concept of a dataset - this may have subtly difference semantics in the future
data: a Galaxy dataset
collection: a Galaxy dataset collection
"""
WorkflowStepTypeLoader = _EnumLoader(
    (
        "tool",
        "subworkflow",
        "pause",
    ),
    "WorkflowStepType",
)
"""
Module types used by Galaxy steps. Galaxy's native format allows additional types such as data_input, data_input_collection, and parameter_type
but these should be represented as ``inputs`` in Format2.

tool: Run a tool.
subworkflow: Run a subworkflow.
pause: Pause computation on this branch of workflow until user allows it to continue.
"""
WorkflowInputParameterLoader = _RecordLoader(WorkflowInputParameter, None, None)
WorkflowOutputParameterLoader = _RecordLoader(WorkflowOutputParameter, None, None)
WorkflowStepLoader = _RecordLoader(WorkflowStep, None, None)
WorkflowStepInputLoader = _RecordLoader(WorkflowStepInput, None, None)
ReportLoader = _RecordLoader(Report, None, None)
WorkflowStepOutputLoader = _RecordLoader(WorkflowStepOutput, None, None)
GalaxyWorkflowLoader = _RecordLoader(GalaxyWorkflow, None, None)
array_of_strtype = _ArrayLoader(strtype)
union_of_None_type_or_strtype_or_array_of_strtype = _UnionLoader(
    (
        None_type,
        strtype,
        array_of_strtype,
    )
)
uri_strtype_True_False_None_None = _URILoader(strtype, True, False, None, None)
union_of_PrimitiveTypeLoader_or_RecordSchemaLoader_or_EnumSchemaLoader_or_ArraySchemaLoader_or_strtype = _UnionLoader(
    (
        PrimitiveTypeLoader,
        RecordSchemaLoader,
        EnumSchemaLoader,
        ArraySchemaLoader,
        strtype,
    )
)
array_of_union_of_PrimitiveTypeLoader_or_RecordSchemaLoader_or_EnumSchemaLoader_or_ArraySchemaLoader_or_strtype = _ArrayLoader(
    union_of_PrimitiveTypeLoader_or_RecordSchemaLoader_or_EnumSchemaLoader_or_ArraySchemaLoader_or_strtype
)
union_of_PrimitiveTypeLoader_or_RecordSchemaLoader_or_EnumSchemaLoader_or_ArraySchemaLoader_or_strtype_or_array_of_union_of_PrimitiveTypeLoader_or_RecordSchemaLoader_or_EnumSchemaLoader_or_ArraySchemaLoader_or_strtype = _UnionLoader(
    (
        PrimitiveTypeLoader,
        RecordSchemaLoader,
        EnumSchemaLoader,
        ArraySchemaLoader,
        strtype,
        array_of_union_of_PrimitiveTypeLoader_or_RecordSchemaLoader_or_EnumSchemaLoader_or_ArraySchemaLoader_or_strtype,
    )
)
typedsl_union_of_PrimitiveTypeLoader_or_RecordSchemaLoader_or_EnumSchemaLoader_or_ArraySchemaLoader_or_strtype_or_array_of_union_of_PrimitiveTypeLoader_or_RecordSchemaLoader_or_EnumSchemaLoader_or_ArraySchemaLoader_or_strtype_2 = _TypeDSLLoader(
    union_of_PrimitiveTypeLoader_or_RecordSchemaLoader_or_EnumSchemaLoader_or_ArraySchemaLoader_or_strtype_or_array_of_union_of_PrimitiveTypeLoader_or_RecordSchemaLoader_or_EnumSchemaLoader_or_ArraySchemaLoader_or_strtype,
    2,
    "v1.1",
)
array_of_RecordFieldLoader = _ArrayLoader(RecordFieldLoader)
union_of_None_type_or_array_of_RecordFieldLoader = _UnionLoader(
    (
        None_type,
        array_of_RecordFieldLoader,
    )
)
idmap_fields_union_of_None_type_or_array_of_RecordFieldLoader = _IdMapLoader(
    union_of_None_type_or_array_of_RecordFieldLoader, "name", "type"
)
enum_d9cba076fca539106791a4f46d198c7fcfbdb779Loader = _EnumLoader(
    ("record",), "enum_d9cba076fca539106791a4f46d198c7fcfbdb779"
)
typedsl_enum_d9cba076fca539106791a4f46d198c7fcfbdb779Loader_2 = _TypeDSLLoader(
    enum_d9cba076fca539106791a4f46d198c7fcfbdb779Loader, 2, "v1.1"
)
uri_array_of_strtype_True_False_None_None = _URILoader(
    array_of_strtype, True, False, None, None
)
enum_d961d79c225752b9fadb617367615ab176b47d77Loader = _EnumLoader(
    ("enum",), "enum_d961d79c225752b9fadb617367615ab176b47d77"
)
typedsl_enum_d961d79c225752b9fadb617367615ab176b47d77Loader_2 = _TypeDSLLoader(
    enum_d961d79c225752b9fadb617367615ab176b47d77Loader, 2, "v1.1"
)
uri_union_of_PrimitiveTypeLoader_or_RecordSchemaLoader_or_EnumSchemaLoader_or_ArraySchemaLoader_or_strtype_or_array_of_union_of_PrimitiveTypeLoader_or_RecordSchemaLoader_or_EnumSchemaLoader_or_ArraySchemaLoader_or_strtype_False_True_2_None = _URILoader(
    union_of_PrimitiveTypeLoader_or_RecordSchemaLoader_or_EnumSchemaLoader_or_ArraySchemaLoader_or_strtype_or_array_of_union_of_PrimitiveTypeLoader_or_RecordSchemaLoader_or_EnumSchemaLoader_or_ArraySchemaLoader_or_strtype,
    False,
    True,
    2,
    None,
)
enum_d062602be0b4b8fd33e69e29a841317b6ab665bcLoader = _EnumLoader(
    ("array",), "enum_d062602be0b4b8fd33e69e29a841317b6ab665bc"
)
typedsl_enum_d062602be0b4b8fd33e69e29a841317b6ab665bcLoader_2 = _TypeDSLLoader(
    enum_d062602be0b4b8fd33e69e29a841317b6ab665bcLoader, 2, "v1.1"
)
union_of_None_type_or_strtype = _UnionLoader(
    (
        None_type,
        strtype,
    )
)
uri_union_of_None_type_or_strtype_True_False_None_None = _URILoader(
    union_of_None_type_or_strtype, True, False, None, None
)
union_of_None_type_or_Any_type = _UnionLoader(
    (
        None_type,
        Any_type,
    )
)
union_of_WorkflowInputParameterLoader = _UnionLoader((WorkflowInputParameterLoader,))
array_of_union_of_WorkflowInputParameterLoader = _ArrayLoader(
    union_of_WorkflowInputParameterLoader
)
idmap_inputs_array_of_union_of_WorkflowInputParameterLoader = _IdMapLoader(
    array_of_union_of_WorkflowInputParameterLoader, "id", "type"
)
union_of_WorkflowOutputParameterLoader = _UnionLoader((WorkflowOutputParameterLoader,))
array_of_union_of_WorkflowOutputParameterLoader = _ArrayLoader(
    union_of_WorkflowOutputParameterLoader
)
idmap_outputs_array_of_union_of_WorkflowOutputParameterLoader = _IdMapLoader(
    array_of_union_of_WorkflowOutputParameterLoader, "id", "type"
)
union_of_None_type_or_StepPositionLoader = _UnionLoader(
    (
        None_type,
        StepPositionLoader,
    )
)
union_of_floattype_or_inttype = _UnionLoader(
    (
        floattype,
        inttype,
    )
)
union_of_None_type_or_ToolShedRepositoryLoader = _UnionLoader(
    (
        None_type,
        ToolShedRepositoryLoader,
    )
)
union_of_GalaxyTypeLoader = _UnionLoader((GalaxyTypeLoader,))
array_of_union_of_GalaxyTypeLoader = _ArrayLoader(union_of_GalaxyTypeLoader)
union_of_GalaxyTypeLoader_or_None_type_or_array_of_union_of_GalaxyTypeLoader = (
    _UnionLoader(
        (
            GalaxyTypeLoader,
            None_type,
            array_of_union_of_GalaxyTypeLoader,
        )
    )
)
typedsl_union_of_GalaxyTypeLoader_or_None_type_or_array_of_union_of_GalaxyTypeLoader_2 = _TypeDSLLoader(
    union_of_GalaxyTypeLoader_or_None_type_or_array_of_union_of_GalaxyTypeLoader,
    2,
    "v1.1",
)
union_of_booltype_or_None_type = _UnionLoader(
    (
        booltype,
        None_type,
    )
)
union_of_None_type_or_array_of_strtype = _UnionLoader(
    (
        None_type,
        array_of_strtype,
    )
)
union_of_None_type_or_GalaxyTypeLoader = _UnionLoader(
    (
        None_type,
        GalaxyTypeLoader,
    )
)
typedsl_union_of_None_type_or_GalaxyTypeLoader_2 = _TypeDSLLoader(
    union_of_None_type_or_GalaxyTypeLoader, 2, "v1.1"
)
array_of_WorkflowStepInputLoader = _ArrayLoader(WorkflowStepInputLoader)
union_of_None_type_or_array_of_WorkflowStepInputLoader = _UnionLoader(
    (
        None_type,
        array_of_WorkflowStepInputLoader,
    )
)
idmap_in__union_of_None_type_or_array_of_WorkflowStepInputLoader = _IdMapLoader(
    union_of_None_type_or_array_of_WorkflowStepInputLoader, "id", "source"
)
union_of_strtype_or_WorkflowStepOutputLoader = _UnionLoader(
    (
        strtype,
        WorkflowStepOutputLoader,
    )
)
array_of_union_of_strtype_or_WorkflowStepOutputLoader = _ArrayLoader(
    union_of_strtype_or_WorkflowStepOutputLoader
)
union_of_array_of_union_of_strtype_or_WorkflowStepOutputLoader_or_None_type = (
    _UnionLoader(
        (
            array_of_union_of_strtype_or_WorkflowStepOutputLoader,
            None_type,
        )
    )
)
idmap_out_union_of_array_of_union_of_strtype_or_WorkflowStepOutputLoader_or_None_type = _IdMapLoader(
    union_of_array_of_union_of_strtype_or_WorkflowStepOutputLoader_or_None_type,
    "id",
    "source",
)
union_of_None_type_or_WorkflowStepTypeLoader = _UnionLoader(
    (
        None_type,
        WorkflowStepTypeLoader,
    )
)
typedsl_union_of_None_type_or_WorkflowStepTypeLoader_2 = _TypeDSLLoader(
    union_of_None_type_or_WorkflowStepTypeLoader, 2, "v1.1"
)
union_of_None_type_or_GalaxyWorkflowLoader = _UnionLoader(
    (
        None_type,
        GalaxyWorkflowLoader,
    )
)
uri_union_of_None_type_or_GalaxyWorkflowLoader_False_False_None_None = _URILoader(
    union_of_None_type_or_GalaxyWorkflowLoader, False, False, None, None
)
uri_union_of_None_type_or_strtype_or_array_of_strtype_False_False_2_None = _URILoader(
    union_of_None_type_or_strtype_or_array_of_strtype, False, False, 2, None
)
union_of_None_type_or_booltype = _UnionLoader(
    (
        None_type,
        booltype,
    )
)
GalaxyWorkflow_classLoader = _EnumLoader(("GalaxyWorkflow",), "GalaxyWorkflow_class")
uri_GalaxyWorkflow_classLoader_False_True_None_None = _URILoader(
    GalaxyWorkflow_classLoader, False, True, None, None
)
array_of_WorkflowInputParameterLoader = _ArrayLoader(WorkflowInputParameterLoader)
idmap_inputs_array_of_WorkflowInputParameterLoader = _IdMapLoader(
    array_of_WorkflowInputParameterLoader, "id", "type"
)
array_of_WorkflowOutputParameterLoader = _ArrayLoader(WorkflowOutputParameterLoader)
idmap_outputs_array_of_WorkflowOutputParameterLoader = _IdMapLoader(
    array_of_WorkflowOutputParameterLoader, "id", "type"
)
array_of_WorkflowStepLoader = _ArrayLoader(WorkflowStepLoader)
union_of_array_of_WorkflowStepLoader = _UnionLoader((array_of_WorkflowStepLoader,))
idmap_steps_union_of_array_of_WorkflowStepLoader = _IdMapLoader(
    union_of_array_of_WorkflowStepLoader, "id", "None"
)
union_of_None_type_or_ReportLoader = _UnionLoader(
    (
        None_type,
        ReportLoader,
    )
)
union_of_array_of_strtype_or_None_type = _UnionLoader(
    (
        array_of_strtype,
        None_type,
    )
)
union_of_GalaxyWorkflowLoader = _UnionLoader((GalaxyWorkflowLoader,))
array_of_union_of_GalaxyWorkflowLoader = _ArrayLoader(union_of_GalaxyWorkflowLoader)
union_of_GalaxyWorkflowLoader_or_array_of_union_of_GalaxyWorkflowLoader = _UnionLoader(
    (
        GalaxyWorkflowLoader,
        array_of_union_of_GalaxyWorkflowLoader,
    )
)


def load_document(
    doc: Any,
    baseuri: Optional[str] = None,
    loadingOptions: Optional[LoadingOptions] = None,
) -> Any:
    if baseuri is None:
        baseuri = file_uri(os.getcwd()) + "/"
    if loadingOptions is None:
        loadingOptions = LoadingOptions()
    result, metadata = _document_load(
        union_of_GalaxyWorkflowLoader_or_array_of_union_of_GalaxyWorkflowLoader,
        doc,
        baseuri,
        loadingOptions,
    )
    return result


def load_document_with_metadata(
    doc: Any,
    baseuri: Optional[str] = None,
    loadingOptions: Optional[LoadingOptions] = None,
    addl_metadata_fields: Optional[MutableSequence[str]] = None,
) -> Any:
    if baseuri is None:
        baseuri = file_uri(os.getcwd()) + "/"
    if loadingOptions is None:
        loadingOptions = LoadingOptions(fileuri=baseuri)
    return _document_load(
        union_of_GalaxyWorkflowLoader_or_array_of_union_of_GalaxyWorkflowLoader,
        doc,
        baseuri,
        loadingOptions,
        addl_metadata_fields=addl_metadata_fields,
    )


def load_document_by_string(
    string: Any,
    uri: str,
    loadingOptions: Optional[LoadingOptions] = None,
) -> Any:
    yaml = yaml_no_ts()
    result = yaml.load(string)
    add_lc_filename(result, uri)

    if loadingOptions is None:
        loadingOptions = LoadingOptions(fileuri=uri)

    result, metadata = _document_load(
        union_of_GalaxyWorkflowLoader_or_array_of_union_of_GalaxyWorkflowLoader,
        result,
        uri,
        loadingOptions,
    )
    return result


def load_document_by_yaml(
    yaml: Any,
    uri: str,
    loadingOptions: Optional[LoadingOptions] = None,
) -> Any:
    """
    Shortcut to load via a YAML object.
    yaml: must be from ruamel.yaml.main.YAML.load with preserve_quotes=True
    """
    add_lc_filename(yaml, uri)

    if loadingOptions is None:
        loadingOptions = LoadingOptions(fileuri=uri)

    result, metadata = _document_load(
        union_of_GalaxyWorkflowLoader_or_array_of_union_of_GalaxyWorkflowLoader,
        yaml,
        uri,
        loadingOptions,
    )
    return result
