weaver.wps_restapi.colander_extras ================================== .. py:module:: weaver.wps_restapi.colander_extras .. autoapi-nested-parse:: This module offers multiple utility schema definitions to be employed with :mod:`colander` and :mod:`cornice_swagger`. The :class:`colander.SchemaNode` provided here can be used in-place of :mod:`colander` ones, but giving you extended behaviour according to provided keywords. You can therefore do the following and all will be applied without modifying your code base. .. code-block:: python # same applies for Mapping and Sequence schemas from colander_extras import ExtendedSchemaNode as SchemaNode from colander import SchemaNode # instead of this The schemas support extended :mod:`cornice_swagger` type converters so that you can generate OpenAPI-3 specifications. The original package support is limited to Swagger-2. You will also need additional in-place modifications provided `here `_. Since the intended usage is to generate JSON-deserialized data structures, the base :class:`colander.SchemaNode` have some additional patches needed to handle JSON-native type conversion that are not directly offered by :mod:`colander` .. seealso:: - https://github.com/Pylons/colander/issues/80 The main classes extensions are: - :class:`ExtendedSchemaNode` - :class:`ExtendedSequenceSchema` - :class:`ExtendedMappingSchema` Multiple ``SchemaNode`` variants are provided. You can use them as building blocks, gaining each of their respective feature, to make specific schema that meets your desired behaviour. The ``Extended``-prefixed classes combined all available ````. Note that it is preferable to use the full ``Extended``-prefixed classes over individual ones as they add complementary support of one-another features. .. warning:: All node extensions assume that they are used for JSON data. Deserialization of unknown types *could* result in invalid result. Most of the time, Python native iterators such as tuples and generators *could* work and be converted to the corresponding sequence array (ie: list), but this is not guaranteed. .. warning:: When defining schema nodes, **DO NOT** use the ``name`` keyword otherwise most mapping will fail validation as they cannot retrieve the same key-name from the passed dictionary for ``deserialize`` validation. Let the API figure out the name of the field automatically. Instead, use the keyword or field ``title`` for adjusting the displayed name in the Swagger UI. The same value will also be used to generate the ``$ref`` reference names of generated :term:`OpenAPI` model definitions. If not explicitly provided, the value of ``title`` **WILL** default to the name of the schema node class. Module Contents --------------- .. py:data:: DataT .. py:data:: RegexPattern .. py:class:: MetadataTypeConverter(dispatcher) Converter that applies :term:`OpenAPI` schema metadata properties defined in the schema node. .. py:method:: convert_type(schema_node) .. py:class:: ExtendedStringTypeConverter(dispatcher) Converter that applies :term:`OpenAPI` schema metadata properties defined in the schema node. .. py:class:: ExtendedDateTypeConverter(dispatcher) Converter that applies :term:`OpenAPI` schema metadata properties defined in the schema node. .. py:class:: ExtendedTimeTypeConverter(dispatcher) Converter that applies :term:`OpenAPI` schema metadata properties defined in the schema node. .. py:class:: ExtendedDateTimeTypeConverter(dispatcher) Converter that applies :term:`OpenAPI` schema metadata properties defined in the schema node. .. py:class:: ExtendedBooleanTypeConverter(dispatcher) Converter that applies :term:`OpenAPI` schema metadata properties defined in the schema node. .. py:class:: ExtendedIntegerTypeConverter(dispatcher) Converter that applies :term:`OpenAPI` schema metadata properties defined in the schema node. .. py:class:: ExtendedNumberTypeConverter(dispatcher) Converter that applies :term:`OpenAPI` schema metadata properties defined in the schema node. .. py:class:: ExtendedFloatTypeConverter(dispatcher) Converter that applies :term:`OpenAPI` schema metadata properties defined in the schema node. .. py:attribute:: format :value: 'float' .. py:class:: ExtendedDecimalTypeConverter(dispatcher) Converter that applies :term:`OpenAPI` schema metadata properties defined in the schema node. .. py:attribute:: format :value: 'decimal' .. py:class:: ExtendedMoneyTypeConverter(dispatcher) Converter that applies :term:`OpenAPI` schema metadata properties defined in the schema node. .. py:data:: LITERAL_SCHEMA_TYPES .. py:data:: NO_DOUBLE_SLASH_PATTERN :value: '(?!.*//.*$)' .. py:data:: URL_REGEX :value: '' .. py:data:: URL .. py:data:: FILE_URL_REGEX :value: '' .. py:data:: FILE_URI .. py:data:: URI_REGEX :value: '(?:#?|[#?]\\S+)$' .. py:data:: URI .. py:function:: _make_node_instance(schema_node_or_class: Union[colander.SchemaNode, Type[colander.SchemaNode]]) -> colander.SchemaNode Obtains a schema node instance in case it was specified only by type reference. This helps being more permissive of provided definitions while handling situations like presented in the example below: .. code-block:: python class Map(OneOfMappingSchema): # uses types instead of instances like 'SubMap1([...])' and 'SubMap2([...])' _one_of = (SubMap1, SubMap2) .. py:function:: _get_schema_type(schema_node: Union[colander.SchemaNode, Type[colander.SchemaNode]], check: bool = False) -> Optional[colander.SchemaType] Obtains the schema-type from the provided node, supporting various initialization methods. - ``typ`` is set by an instantiated node from specific schema (e.g.: ``colander.SchemaNode(colander.String())``) - ``schema_type`` can also be provided, either by type or instance if using class definition with property :param schema_node: item to analyse :param check: only attempt to retrieve the schema type, and if failing return ``None`` :returns: found schema type :raises ConversionTypeError: if no ``check`` requested and schema type cannot be found (invalid schema node) .. py:function:: _get_node_name(schema_node: colander.SchemaNode, schema_name: bool = False) -> str Obtains the name of the node with the best available value. :param schema_node: node for which to retrieve the name. :param schema_name: - If ``True``, prefer the schema definition (class) name over the instance or field name. - Otherwise, return the field name, the title or as last result the class name. :returns: node name .. py:exception:: SchemaNodeTypeError Generic error indicating that the definition of a SchemaNode is invalid. This usually means the user forgot to specify a required element for schema creation, or that a provided combination of keywords, sub-nodes and/or schema type don't make any sense together, that they are erroneous, or that they cannot be resolved because of some kind of ambiguous definitions leading to multiple conflicting choices. Initialize self. See help(type(self)) for accurate signature. .. py:exception:: ConversionTypeError Conversion error due to invalid type. Initialize self. See help(type(self)) for accurate signature. .. py:exception:: ConversionValueError Conversion error due to invalid value. Initialize self. See help(type(self)) for accurate signature. .. py:class:: OneOfCaseInsensitive(choices: Iterable[str], *args: Any, **kwargs: Any) Validator that ensures the given value matches one of the available choices, but allowing case-insensitive values. .. py:class:: StringOneOf(choices: Iterable[str], delimiter: str = ',', case_sensitive: bool = True, **kwargs: Any) Validator that ensures the given value matches one of the available choices, but defined by string delimited values. .. py:attribute:: delimiter :value: ',' .. py:class:: BoundedRange(min: Optional[Union[float, int]] = None, max: Optional[Union[float, int]] = None, exclusive_min: bool = False, exclusive_max: bool = False, **kwargs: Any) Validator of value within range with added ``exclusive`` bounds support. .. py:attribute:: min_excl :value: False .. py:attribute:: max_excl :value: False .. py:class:: StringRange(min: Optional[Union[float, int, str]] = None, max: Optional[Union[float, int, str]] = None, exclusive_min: bool = False, exclusive_max: bool = False, **kwargs: Any) Validator that provides the same functionalities as :class:`colander.Range` for a numerical string value. .. py:class:: CommaSeparated(allow_chars: str = 'A-Za-z0-9_-', msg: str = _MSG_ERR, flags: re.RegexFlag = re.IGNORECASE) Validator that ensures the given value is a comma-separated string. .. py:attribute:: _MSG_ERR .. py:attribute:: allow_chars :value: 'A-Za-z0-9_-' .. py:class:: SchemeURL(schemes: Optional[Iterable[str]] = None, path_pattern: Union[None, str, RegexPattern] = None, msg: Optional[str] = None, flags: Optional[re.RegexFlag] = re.IGNORECASE) String representation of an URL with extended set of allowed URI schemes. .. seealso:: :class:`colander.url` [remote http(s)/ftp(s)] :class:`colander.file_uri` [local file://] :data:`URL` .. py:class:: SemanticVersion(*args: Any, v_prefix: bool = False, rc_suffix: bool = True, **kwargs: Any) String representation that is valid against Semantic Versioning specification. .. seealso:: https://semver.org/ .. py:class:: ExtendedBoolean(*args: Any, true_choices: Optional[Iterable[str]] = None, false_choices: Optional[Iterable[str]] = None, allow_string: bool = False, **kwargs: Any) A type representing a boolean object. The constructor accepts these keyword arguments: - ``false_choices``: The set of strings representing a ``False`` value on deserialization. - ``true_choices``: The set of strings representing a ``True`` value on deserialization. - ``false_val``: The value returned on serialization of a False value. - ``true_val``: The value returned on serialization of a True value. During deserialization, a value contained in :attr:`false_choices`, will be considered ``False``. The behaviour for values not contained in :attr:`false_choices` depends on :attr:`true_choices`: if it's empty, any value is considered ``True``; otherwise, only values contained in :attr:`true_choices` are considered ``True``, and an Invalid exception would be raised for values outside of both :attr:`false_choices` and :attr:`true_choices`. Serialization will produce :attr:`true_val` or :attr:`false_val` based on the value. If the :attr:`colander.null` value is passed to the serialize method of this class, the :attr:`colander.null` value will be returned. The subnodes of the :class:`colander.SchemaNode` that wraps this type are ignored. Initializes the extended boolean schema node. When arguments :paramref:`true_choices` or :paramref:`false_choices` are provided, the corresponding string values are respectively considered as valid `truthy`/`falsy` values. Otherwise (default), ``strict`` values only of explicit type :class:`bool` will be considered valid. When values are specified :mod:`colander` converts them to string lowercase to compare against `truthy`/`falsy` values it should accept. For real `OpenAPI` typing validation, do **NOT** add other values like ``"1"`` to avoid conflict with :class:`ExtendedInteger` type for schemas that support both variants. If an `OpenAPI` field is expected to support `truthy`/`falsy` values, it is recommended to explicitly define its schema using a ``oneOf`` keyword of all relevant schemas it supports, an any applicable validators for explicit values. This is the safest way to ensure the generated `OpenAPI` schema corresponds to expected type validation. .. py:method:: deserialize(node: colander.SchemaNode, cstruct: Any) -> Union[Type[colander.null, bool]] .. py:class:: ExtendedNumber(*_, allow_string=False, strict=True, **__) Definition of a numeric value, either explicitly or implicit with permissive :class:`str` representation. Behaviour in each case: - ``strict=True`` and ``allow_string=False``: Value can only be explicit numeric type that matches exactly the base ``num`` type (default). All implicit conversion between :class:`float`, :class:`int` or :class:`str` are disallowed. - ``strict=True`` and ``allow_string=True``: Value can be the explicit numeric type (:class:`int` or :class:`float`) or a numeric :class:`str` value representing the corresponding base numeric type. Implicit conversion between :class:`float` and :class:`int` is still disallowed. - ``strict=False`` (``allow_string`` doesn't matter): Value can be anything as long as it can be converted to the expected numeric type (:class:`int` or :class:`float`). Recommended usage: - When making `OpenAPI` schema definitions for JSON body elements within a request or response object, default parameters ``strict=True`` and ``allow_string=False`` should be used to ensure the numeric type is respected. As for other literal data `Extended` schema types, keyword `oneOf` should be used when multiple similar value types are permitted for a field in order to document in `OpenAPI` the specific type definitions of expected data, which is automatically converted by ``json`` properties of request and response classes. - When defining `OpenAPI` query parameters, ``strict=True`` and ``allow_string=True`` should be used. This ensures that documented schemas still indicate only the numeric type as expected data format, although technically the ``path`` of the request will contain a :class:`str` representing the number. Queries are not automatically converted by request objects, but will be converted and validated as the explicit number following deserialization when using those configuration parameters. .. py:method:: number(num) :staticmethod: :abstractmethod: .. py:method:: strict(num) :staticmethod: :abstractmethod: .. py:class:: ExtendedFloat(*_: Any, allow_string: bool = False, strict: bool = True, **__: Any) Float definition with strict typing validation by default. This is to distinguish it from explicit definitions of ``float``-like numbers or strings. By default, values such as ``"1"``, ``1.0``, ``True`` will not be automatically converted to equivalent ``1.0``. .. py:method:: number(num) :staticmethod: .. py:method:: strict(num) :staticmethod: .. py:method:: serialize(node, appstruct) .. py:class:: ExtendedInteger(*_: Any, allow_string: bool = False, strict: bool = True, **__: Any) Integer definition with strict typing validation by default. This is to distinguish it from explicit definitions of ``integer``-like numbers or strings. By default, values such as ``"1"``, ``1.0``, ``True`` will not be automatically converted to equivalent ``1``. .. py:method:: number(num) :staticmethod: .. py:method:: strict(num) :staticmethod: .. py:method:: serialize(node, appstruct) .. py:class:: ExtendedString(encoding=None, allow_empty=False) String with auto-conversion for known :term:`OpenAPI` ``format`` field where no direct :mod:`colander` type exist. Converts :class:`uuid.UUID` to corresponding string when detected in the node if it defined ``format="uuid"``. For ``format="date"`` and ``format="date-time"``, consider instead using :class:`colander.Date` and :class:`colander.DateTime` respectively since more advanced support and features are provided with them. .. py:method:: deserialize(node: colander.SchemaNode, cstruct: Any) -> str .. py:class:: NoneType Type representing an explicit :term:`JSON` ``null`` value. .. py:method:: serialize(node: colander.SchemaNode, appstruct: Any) -> Union[None, colander.null, colander.drop] .. py:method:: deserialize(node: colander.SchemaNode, cstruct: Any) -> Union[None, colander.null, colander.drop] .. py:class:: AnyType Type representing any :term:`JSON` structure. .. py:method:: serialize(node: colander.SchemaNode, appstruct: Any) -> Any .. py:method:: deserialize(node: colander.SchemaNode, cstruct: Any) -> Any .. py:class:: XMLObject Object that provides mapping to known XML extensions for :term:`OpenAPI` schema definition. Name of the schema definition in the :term:`OpenAPI` will use :attr:`prefix` and the schema class name. Prefix can be omitted from the schema definition name by setting it to :class:`colander.drop`. .. seealso:: - https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#xml-object - https://swagger.io/docs/specification/data-models/representing-xml/ .. py:attribute:: attribute :value: None .. py:attribute:: name :value: None .. py:attribute:: namespace :value: None .. py:attribute:: prefix :value: None .. py:attribute:: wrapped :value: None .. py:property:: xml .. py:class:: OAS3Parameter(style: Optional[ParameterStyles] = None, explode: Optional[bool] = None, allow_reserved: Optional[bool] = None, summary: Optional[str] = None, description: Optional[str] = None, example: Optional[weaver.typedefs.JSON] = None, examples: Optional[Dict[str, ParameterExample]] = None, **kwargs) Object that provides mapping to known :term:`OpenAPI` extensions for parameter definition. .. note:: These extensions are mostly for documentation properties not already handled by a specific :class:`cornice_swagger.converters.parameters.ParameterConverter` implementation, but that can be used in combination with any of them when applicable. .. seealso:: - https://swagger.io/docs/specification/v3_0/describing-parameters/#parameter-examples - https://swagger.io/docs/specification/v3_0/describing-parameters/#deprecated-parameters - https://swagger.io/docs/specification/v3_0/serialization/ - https://learn.openapis.org/specification/parameters.html#parameter-serialization-control .. py:attribute:: style :type: Optional[ParameterStyles] :value: None Serialization style of the parameter. .. py:attribute:: explode :type: Optional[bool] :value: None Whether to explode the parameter into separate parameters (e.g.: for arrays and objects). .. py:attribute:: allow_reserved :type: Optional[bool] :value: None Whether reserved characters are allowed in the parameter value. .. py:attribute:: summary :type: Optional[str] :value: None Small description of the parameter. .. py:attribute:: description :type: Optional[str] :value: None Longer description of the parameter. .. py:attribute:: example :type: Optional[weaver.typedefs.JSON] :value: None Single example of the parameter value. .. py:attribute:: examples :type: Optional[Dict[str, ParameterExample]] :value: None Single example of the parameter value. .. py:method:: convert() -> Dict[str, Any] .. py:class:: ExtendedNodeInterface .. py:attribute:: _extension :type: str :value: None .. py:method:: _deserialize_impl(cstruct) :abstractmethod: .. py:class:: ExtendedSchemaMeta(name, bases, clsattrs) .. py:class:: ExtendedSchemaBase(*args, **kwargs) Utility base node definition that initializes additional parameters at creation time of any other extended schema. When no explicit ``title`` is specified by either keyword argument or field definition within container class, default it to the literal name of the class defining the schema node. This title can then be employed by other extended schema implementations to define *cleaner* schema references, notably in the case of :class:`KeywordMapper` derived classes that do not necessarily have any explicit target ``name`` field. When the schema node is a simple field within a container schema (mapping, sequence, etc.), operation is skipped to avoid applying the generic ``SchemaNode`` or ``ExtendedSchemaNode`` name of the basic node class. In this case, converters already employ the target ``name`` of the class attribute of the container schema under which that node gets created. When the schema node is a generic :class:`colander.String` without explicit ``validator``, but that one can be inferred from either ``pattern`` or ``format`` :term:`OpenAPI` definition, the corresponding ``validator`` gets automatically generated. .. py:method:: schema_type() :staticmethod: :abstractmethod: .. py:method:: _validate(node) :staticmethod: .. py:class:: DropableSchemaNode(*args, **kwargs) Schema that can be dropped if the value is missing. Drops the underlying schema node if ``missing=drop`` was specified and that the value representing it represents an *empty* value instead of raising a invalid schema error. In the case of nodes corresponding to literal schema type (i.e.: Integer, String, etc.), the *empty* value looked for is ``None``. This is to make sure that ``0`` or ``""`` are preserved unless explicitly representing *no-data*. In the case of container schema types (i.e.: list, dict, etc.), it is simply considered *empty* if there are no element in it, without any more explicit verification. Original behaviour of schema classes that can have children nodes such as :class:`colander.MappingSchema` and :class:`colander.SequenceSchema` are to drop the sub-node only if its value is resolved as :class:`colander.null` or :class:`colander.drop`. This results in *optional* field definitions replaced by ``None`` in many implementations to raise :py:exc:`colander.Invalid` during deserialization. Inheriting this class in a schema definition will handle this situation automatically. Required schemas (without ``missing=drop``, defaulting to :class:`colander.required`) will still raise for undefined nodes. The following snippet shows the result that can be achieved using this schema class: .. code-block:: python class SchemaA(DropableSchemaNode, MappingSchema): field = SchemaNode(String()) class SchemaB(MappingSchema): s1 = SchemaA(missing=drop) # optional s2 = SchemaA() # required SchemaB().deserialize({"s1": None, "s2": {"field": "ok"}}) # results: {'s2': {'field': 'ok'}} .. seealso:: - https://github.com/Pylons/colander/issues/276 - https://github.com/Pylons/colander/issues/299 .. seealso:: - :class:`DropableMappingSchema` - :class:`DropableSequenceSchema` .. py:attribute:: _extension :value: '_ext_dropable' .. py:method:: schema_type() :staticmethod: :abstractmethod: .. py:method:: deserialize(cstruct) Deserialize the :term:`cstruct` into an :term:`appstruct` based on the schema, run this :term:`appstruct` through the preparer, if one is present, then validate the prepared appstruct. The ``cstruct`` value is deserialized into an ``appstruct`` unconditionally. If ``appstruct`` returned by type deserialization and preparation is the value :attr:`colander.null`, do something special before attempting validation: - If the ``missing`` attribute of this node has been set explicitly, return its value. No validation of this value is performed; it is simply returned. - If the ``missing`` attribute of this node has not been set explicitly, raise a :exc:`colander.Invalid` exception error. If the appstruct is not ``colander.null`` and cannot be validated , a :exc:`colander.Invalid` exception will be raised. If a ``cstruct`` argument is not explicitly provided, it defaults to :attr:`colander.null`. .. py:method:: _deserialize_impl(cstruct) .. py:class:: DefaultSchemaNode(*args, **kwargs) Schema that will return the provided default value when the corresponding value is missing or invalid. If ``default`` keyword is provided during :class:`colander.SchemaNode` creation, overrides the returned value by this default if missing from the structure during :meth:`deserialize` call. Original behaviour was to drop the missing value instead of replacing by ``default``. Executes all other :class:`colander.SchemaNode` operations normally. .. seealso:: - :class:`DefaultMappingSchema` - :class:`DefaultSequenceSchema` .. py:attribute:: _extension :value: '_ext_default' .. py:method:: schema_type() :staticmethod: :abstractmethod: .. py:method:: deserialize(cstruct) Deserialize the :term:`cstruct` into an :term:`appstruct` based on the schema, run this :term:`appstruct` through the preparer, if one is present, then validate the prepared appstruct. The ``cstruct`` value is deserialized into an ``appstruct`` unconditionally. If ``appstruct`` returned by type deserialization and preparation is the value :attr:`colander.null`, do something special before attempting validation: - If the ``missing`` attribute of this node has been set explicitly, return its value. No validation of this value is performed; it is simply returned. - If the ``missing`` attribute of this node has not been set explicitly, raise a :exc:`colander.Invalid` exception error. If the appstruct is not ``colander.null`` and cannot be validated , a :exc:`colander.Invalid` exception will be raised. If a ``cstruct`` argument is not explicitly provided, it defaults to :attr:`colander.null`. .. py:method:: _deserialize_impl(cstruct) .. py:class:: VariableSchemaNode(*args, **kwargs) Object schema that allows defining a field key as *variable* by name supporting deserialization validation. This definition is useful for defining a dictionary where the key name can be any string value but contains an underlying schema that has a very specific structure to be validated, such as in the following example. .. code-block:: json { "": { "name": "required", "value": "something" }, "": { "name": "other required", "value": "same schema" } } This is accomplished using the following definition:: class RequiredDict(ExtendedMappingSchema): name = ExtendedSchemaNode(String()) value = ExtendedSchemaNode(String()) class ContainerAnyKey(ExtendedMappingSchema): var = RequiredDict(variable="{id}") In the above example, the ``var`` node name that would normally be automatically generated and used to define the dictionary key will be replaced by ``{id}`` (any string provided by ``variable`` keyword). The actual attribute name ``var`` could be replaced by anything. .. warning:: Since ``variable`` tells the deserialization converter to try matching any valid children node schema with the provided structure regardless of key name, you should ensure that the variable child node has at least one :class:`colander.required` field (either directly or much deeper in the structure) to ensure it has something to validate against. Otherwise, anything will be matched (ie: drop all for empty structure would be considered as valid). The above statement also applies in case you provide more than one variable schema node under a mapping where both underlying schema are different. Without any required child node to distinguish between them, the sub-structure under each variable node *could* end up interchanged. .. note:: It is recommended to use variable names that include invalid characters for class/attribute names (e.g.: ``{}`` or ``<>``) in order to ensure that any substitution when attempting to find the schema matching the variable doesn't result in overrides. As presented in the following example, ``const`` *could* get overridden if there was a structure to parse that contained both the ``const`` sub-structure and another one with an arbitrary key matched against ````. .. note:: In order to avoid invalid rendering of ``<>`` strings (interpreted as HTML tags by Swagger-UI), it is recommended to employ ``{}`` notation for representing variable names. .. code-block:: python class ContainerAnyKeyWithName(ExtendedMappingSchema): var = RequiredDict(variable="const") # 'const' could clash with other below const = RequiredDict(String()) Using ``{const}`` instead would ensure that no override occurs as it is a syntax error to write ``{const} = RequiredDict(String())`` in the class definition, but this value can still be used to create the internal mapping to evaluate sub-schemas without name clashes. As a plus, it also helps indicating that *any key* is accepted. .. seealso:: - :class:`ExtendedSchemaNode` - :class:`ExtendedMappingSchema` .. py:attribute:: _extension :value: '_ext_variable' .. py:attribute:: _variable :value: 'variable' .. py:attribute:: _variable_map :value: 'variable_map' .. py:method:: is_variable(node: colander.SchemaNode) -> bool :classmethod: If current node is the variable field definition. .. py:method:: has_variables() If the current container schema node has sub-node variables. .. py:method:: schema_type() :staticmethod: :abstractmethod: .. py:method:: _mark_variable_children() Ensures that any immediate children schema with variable key are detected. Verifies if a :class:`colander.MappingSchema` (or any of its extensions) contains children :class:`VariableSchemaNode` schema nodes for adequate :meth:`deserialize` result later on. If children nodes are detected as *variable*, this schema is marked for special processing of the children nodes so they don't get removed from the result (in case of optional field specified by ``missing=drop``) nor raise :class:`colander.Invalid` because they are supposed to be :class:`colander.required`. .. note:: Because mapping schema deserialization is normally processed by validating the content of a sub-node according to its ``name``, it is not possible to use the normal approach (i.e.: get dictionary value under matching key-name and validate it against the sub-schema of same name). We must verify against every *variable* node available in the mapping (also ignoring constants nodes with explicitly named keys), then guess a valid match and finally return it with modified name corresponding to the expected ``variable`` value in the parent mapping schema. Returning this modified ``name`` with ``variable`` makes the value/sub-schema correspondence transparent to the parent mapping when dictionary get-by-key is called during the mapping validation. .. warning:: Because of the above reversed-processing method, all *mapping* nodes must derive from :class:`VariableSchemaNode` to ensure they pre-process potential *variable* candidates. .. py:method:: _get_sub_variable(subnodes: Iterable[colander.SchemaNode]) -> List[VariableSchemaNode] .. py:method:: deserialize(cstruct) Deserialize the :term:`cstruct` into an :term:`appstruct` based on the schema, run this :term:`appstruct` through the preparer, if one is present, then validate the prepared appstruct. The ``cstruct`` value is deserialized into an ``appstruct`` unconditionally. If ``appstruct`` returned by type deserialization and preparation is the value :attr:`colander.null`, do something special before attempting validation: - If the ``missing`` attribute of this node has been set explicitly, return its value. No validation of this value is performed; it is simply returned. - If the ``missing`` attribute of this node has not been set explicitly, raise a :exc:`colander.Invalid` exception error. If the appstruct is not ``colander.null`` and cannot be validated , a :exc:`colander.Invalid` exception will be raised. If a ``cstruct`` argument is not explicitly provided, it defaults to :attr:`colander.null`. .. py:method:: _check_deserialize(node, cstruct) :staticmethod: .. py:method:: _deserialize_remap(node, cstruct, var_map, var_name, has_const_child) :staticmethod: .. py:method:: _deserialize_impl(cstruct) .. py:method:: _validate_cross_variable_mapping(variable_mapping: VariableSchemaNodeMapping) -> None Ensure there are no matches of the same child-property across multiple variable child-schema. In such case, the evaluated variable mapping is ambiguous, and cannot discriminate which property validates the schema. Therefore, the full mapping schema containing the variables would be invalid. There are 2 possible situations where there could be multiple variable child-schema. Either ``additionalProperties`` and ``patternProperties`` capability is supported and employed simultaneously, or the schema class definition is invalid. It is not allowed to have 2 generic ``additionalProperties`` assigned simultaneously to 2 distinct child-schema. A single child-schema using a keyword mapping should be used instead to define such combinations. .. py:method:: _validate_unmatched_variable_mapping(variable_mapping: VariableSchemaNodeMapping, invalid_mapping: Dict[str, colander.Invalid], constant_children_schema_names: List[str], cstruct: weaver.typedefs.JSON) -> None Validate if any additional properties that could not be mapped by variables are permitted in the mapping schema. .. py:class:: SortableMappingSchema(*args, **kwargs) Adds sorting capabilities to mapping schema. Extended schema nodes that inherit from :class:`colander.Mapping` schema-type such that they can request ordering of resulting fields by overriding properties :attr:`_sort_first` and :attr:`_sort_after` within the schema definition with lists of fields names to sort. .. seealso:: - :func:`_order_deserialize` .. py:attribute:: _extension :value: '_ext_sortable' .. py:attribute:: _sort_first :type: Sequence[str] :value: [] .. py:attribute:: _sort_after :type: Sequence[str] :value: [] .. py:method:: deserialize(cstruct) Deserialize the :term:`cstruct` into an :term:`appstruct` based on the schema, run this :term:`appstruct` through the preparer, if one is present, then validate the prepared appstruct. The ``cstruct`` value is deserialized into an ``appstruct`` unconditionally. If ``appstruct`` returned by type deserialization and preparation is the value :attr:`colander.null`, do something special before attempting validation: - If the ``missing`` attribute of this node has been set explicitly, return its value. No validation of this value is performed; it is simply returned. - If the ``missing`` attribute of this node has not been set explicitly, raise a :exc:`colander.Invalid` exception error. If the appstruct is not ``colander.null`` and cannot be validated , a :exc:`colander.Invalid` exception will be raised. If a ``cstruct`` argument is not explicitly provided, it defaults to :attr:`colander.null`. .. py:method:: schema_type() :staticmethod: :abstractmethod: .. py:method:: _deserialize_impl(cstruct) .. py:method:: _order_deserialize(cstruct: Dict[str, Any], sort_first: Optional[Sequence[str]] = None, sort_after: Optional[Sequence[str]] = None) -> Dict[str, Any] :staticmethod: Enforces ordering of expected fields in deserialized result, regardless of specified children/inherited schema. This function takes care of moving back items in a consistent order for better readability from API responses against different loaded definitions field order from remote servers, local database, pre-defined objects, etc. This way, any field insertion order from both the input ``cstruct`` following deserialization operation, the internal mechanics that :mod:`colander` (and extended :term:`OpenAPI` schema definitions) employ to process this deserialization, and the ``result`` dictionary fields order obtained from it all don't matter. Using this, the order of inheritance of schema children classes also doesn't matter, removing the need to worry about placing classes in any specific order when editing and joining the already complicated structures of inherited schemas. :param cstruct: JSON structure to be sorted that has already been processed by a schema's ``deserialize`` call. :param sort_first: ordered list of fields to place first in the result. :param sort_after: ordered list of fields to place last in the result. :returns: results formed from cstruct following order: ( + + ) .. py:class:: SchemaRefMappingSchema(*args, **kwargs) Mapping schema that supports auto-insertion of JSON-schema references provided in the definition. Schema references are resolved under two distinct contexts: 1. When generating the :term:`JSON` schema representation of the current schema node, for :term:`OpenAPI` representation, the ``_schema`` attribute will indicate the ``$id`` value that identifies this schema, while the ``_schema_meta`` will provide the ``$schema`` property that refers to the :term:`JSON` meta-schema used by default to define it. 2. When deserializing :term:`JSON` data that should be validated against the current schema node, the generated :term:`JSON` data will include the ``$schema`` property using the ``_schema`` attribute. In this case, the ``$id`` is omitted as that :term:`JSON` represents an instance of the schema, but not its identity. Alternatively, the parameters ``schema`` and ``schema_meta`` can be passed as keyword arguments when instantiating the schema node. The references injection in the :term:`JSON` schema and data can be disabled with parameters ``schema_include`` and ``schema_meta_include``, or the corresponding class attributes. Furthermore, options ``schema_include_deserialize``, ``schema_include_convert_type`` and ``schema_meta_include_convert_type`` can be used to control individually each schema inclusion during either the type conversion context (:term:`JSON` schema) or the deserialization context (:term:`JSON` data validation). Additionally, the ``_schema_extra`` attribute and the corresponding ``schema_extra`` initialization parameter can be specified to inject further :term:`OpenAPI` schema definitions into the generated schema. Note that duplicate properties specified by this extra definition will override any automatically generated schema properties. .. py:attribute:: _extension :value: '_ext_schema_ref' .. py:attribute:: _ext_schema_options :value: ['_schema_meta', '_schema_meta_include', '_schema_meta_include_convert_type', '_schema',... .. py:attribute:: _ext_schema_fields :value: ['_id', '_schema', '_schema_extra'] .. py:attribute:: _schema_meta :type: str .. py:attribute:: _schema_meta_include :type: bool :value: True .. py:attribute:: _schema_meta_include_convert_type :type: bool :value: True .. py:attribute:: _schema :type: str :value: None .. py:attribute:: _schema_include :type: bool :value: True .. py:attribute:: _schema_include_deserialize :type: bool :value: True .. py:attribute:: _schema_include_convert_type :type: bool :value: True .. py:attribute:: _schema_extra :type: Optional[weaver.typedefs.OpenAPISchema] :value: None .. py:method:: _is_schema_ref(schema_ref: Any) -> bool :staticmethod: .. py:property:: _schema_options .. py:property:: _schema_fields .. py:method:: _schema_deserialize(cstruct: weaver.typedefs.OpenAPISchema, schema_meta: Optional[str] = None, schema_id: Optional[str] = None, schema_extra: Optional[weaver.typedefs.OpenAPISchema] = None) -> weaver.typedefs.OpenAPISchema Applies the relevant schema references and properties depending on :term:`JSON` schema/data conversion context. .. py:method:: _deserialize_impl(cstruct: DataT) -> DataT Converts the data using validation against the :term:`JSON` schema definition. .. py:method:: convert_type(cstruct: weaver.typedefs.OpenAPISchema, dispatcher: Optional[cornice_swagger.converters.schema.TypeConversionDispatcher] = None) -> weaver.typedefs.OpenAPISchema Converts the node to obtain the :term:`JSON` schema definition. .. py:method:: schema_type() :staticmethod: :abstractmethod: .. py:class:: ExtendedSchemaNode(*args, **kwargs) Base schema node with support of extended functionalities. Combines all :class:`colander.SchemaNode` extensions so that ``default`` keyword is used first to resolve a missing field value during :meth:`deserialize` call, and then removes the node completely if no ``default`` was provided, and evaluate variables as needed. .. seealso:: - :class:`ExtendedMappingSchema` - :class:`ExtendedSequenceSchema` - :class:`DefaultSchemaNode` - :class:`DropableSchemaNode` - :class:`VariableSchemaNode` .. py:attribute:: _extension :value: '_ext_combined' .. py:attribute:: _ext_first :type: Iterable[Type[ExtendedNodeInterface]] .. py:attribute:: _ext_after :type: Iterable[Type[ExtendedNodeInterface]] .. py:method:: schema_type() :staticmethod: :abstractmethod: .. py:method:: _deserialize_extensions(cstruct: DataT, extensions: Iterable[Type[ExtendedNodeInterface]]) -> DataT .. py:method:: deserialize(cstruct: DataT) -> DataT Deserialize the :term:`cstruct` into an :term:`appstruct` based on the schema, run this :term:`appstruct` through the preparer, if one is present, then validate the prepared appstruct. The ``cstruct`` value is deserialized into an ``appstruct`` unconditionally. If ``appstruct`` returned by type deserialization and preparation is the value :attr:`colander.null`, do something special before attempting validation: - If the ``missing`` attribute of this node has been set explicitly, return its value. No validation of this value is performed; it is simply returned. - If the ``missing`` attribute of this node has not been set explicitly, raise a :exc:`colander.Invalid` exception error. If the appstruct is not ``colander.null`` and cannot be validated , a :exc:`colander.Invalid` exception will be raised. If a ``cstruct`` argument is not explicitly provided, it defaults to :attr:`colander.null`. .. py:class:: ExpandStringList(*arg, **kw) Utility that will automatically deserialize a string to its list representation using the validator delimiter. .. seealso:: - :class:`CommaSeparated` - :class:`StringOneOf` In order to use this utility, it is important to place it first in the schema node class definition. .. code-block:: class NewNodeSchema(ExpandStringList, ExtendedSchemaNode): schema_type = String validator = CommaSeparated() .. py:attribute:: DEFAULT_DELIMITER :value: ',' .. py:method:: schema_type() :staticmethod: :abstractmethod: .. py:method:: deserialize(cstruct: DataT) -> DataT Deserialize the :term:`cstruct` into an :term:`appstruct` based on the schema, run this :term:`appstruct` through the preparer, if one is present, then validate the prepared appstruct. The ``cstruct`` value is deserialized into an ``appstruct`` unconditionally. If ``appstruct`` returned by type deserialization and preparation is the value :attr:`colander.null`, do something special before attempting validation: - If the ``missing`` attribute of this node has been set explicitly, return its value. No validation of this value is performed; it is simply returned. - If the ``missing`` attribute of this node has not been set explicitly, raise a :exc:`colander.Invalid` exception error. If the appstruct is not ``colander.null`` and cannot be validated , a :exc:`colander.Invalid` exception will be raised. If a ``cstruct`` argument is not explicitly provided, it defaults to :attr:`colander.null`. .. py:class:: DropableSequenceSchema(*args, **kwargs) Sequence schema that supports the dropable functionality. Extends :class:`colander.SequenceSchema` to auto-handle dropping missing entry definitions when its value is either ``None``, :class:`colander.null` or :class:`colander.drop`. .. py:attribute:: schema_type .. py:class:: DefaultSequenceSchema(*args, **kwargs) Sequence schema that supports the default value functionality. Extends :class:`colander.SequenceSchema` to auto-handle replacing the result using the provided ``default`` value when the deserialization results into a sequence that should normally be dropped. .. py:attribute:: schema_type .. py:class:: ExtendedSequenceSchema(*args, **kwargs) Sequence schema that supports all applicable extended schema node functionalities. Combines :class:`DefaultSequenceSchema` and :class:`DefaultSequenceSchema` extensions so that ``default`` keyword is used first to resolve a missing sequence during :meth:`deserialize` call, and then removes the node completely if no ``default`` was provided. .. seealso:: - :class:`ExtendedSchemaNode` - :class:`ExtendedMappingSchema` .. py:attribute:: schema_type .. py:method:: _validate() .. py:class:: DropableMappingSchema(*args, **kwargs) Mapping schema that supports the dropable functionality. Override the default :class:`colander.MappingSchema` to auto-handle dropping missing field definitions when the corresponding value is either ``None``, :class:`colander.null` or :class:`colander.drop`. .. py:attribute:: schema_type .. py:class:: DefaultMappingSchema(*args, **kwargs) Mapping schema that supports the default value functionality. Override the default :class:`colander.MappingSchema` to auto-handle replacing missing entries by their specified ``default`` during deserialization. .. py:attribute:: schema_type .. py:class:: VariableMappingSchema(*args, **kwargs) Mapping schema that supports the variable functionality. Override the default :class:`colander.MappingSchema` to auto-handle replacing missing entries by their specified ``variable`` during deserialization. .. py:attribute:: schema_type .. py:class:: ExtendedMappingSchema(*args, **kwargs) Combines multiple extensions of :class:`colander.MappingSchema` handle their corresponding keywords. Resolution is done so that ``default`` keyword is used first to resolve a missing object during :meth:`deserialize` call, and then removes the node completely if no ``default`` was provided. .. seealso:: - :class:`DefaultSchemaNode` - :class:`DropableSchemaNode` - :class:`VariableSchemaNode` - :class:`ExtendedSchemaNode` - :class:`ExtendedSequenceSchema` - :class:`SchemaRefMappingSchema` - :class:`SortableMappingSchema` - :class:`PermissiveMappingSchema` .. py:attribute:: schema_type .. py:method:: _validate_nodes() .. py:class:: StrictMappingSchema(*args, **kwargs) Object schema that will ``raise`` any unknown field not represented by children schema. This is equivalent to `OpenAPI` object mapping with ``additionalProperties: false``. This type is useful for defining a dictionary that matches *exactly* a specific set of values and children schema. ..note:: When doing schema deserialization to validate it, unknown keys would normally be removed without this class (default behaviour is to ``ignore`` them). With this schema, content under an unknown key is fails validation. .. seealso:: :class:`PermissiveMappingSchema` .. py:class:: EmptyMappingSchema(*args: Any, **kwargs: Any) Mapping that guarantees it is completely empty for validation during deserialization. Any children added to this schema are removed automatically. .. py:attribute:: children :value: [] .. py:class:: PermissiveMappingSchema(*args: Any, **kwargs: Any) Object schema that will ``preserve`` any unknown field to remain present in the resulting deserialization. This type is useful for defining a dictionary where some field names are not known in advance, or when more optional keys that don't need to all be exhaustively provided in the schema are acceptable. ..note:: When doing schema deserialization to validate it, unknown keys would normally be removed without this class (default behaviour is to ``ignore`` them). With this schema, content under an unknown key using ``preserve`` are passed down without any validation. Other fields that are explicitly specified with sub-schema nodes will still be validated as per usual behaviour. .. seealso:: :class:`StrictMappingSchema` Example:: class AnyKeyObject(PermissiveMappingSchema): known_key = SchemaNode(String()) AnyKeyObject().deserialize({"unknown": "kept", "known_key": "requirement"})) # result: dictionary returned as is instead of removing 'unknown' entry # 'known_key' is still validated with its string schema .. note:: This class is only a shorthand definition of ``unknown`` keyword for convenience. All :class:`colander.MappingSchema` support this natively. .. py:class:: PermissiveSequenceSchema(*args, **kwargs) Array schema that allows *any* item type. This is equivalent to the any of the following :term:`JSON` schema definitions. .. code-block:: json { "type": "array", "items": {} } .. code-block:: json { "type": "array", "items": true } .. code-block:: json { "type": "array" } .. py:attribute:: item .. py:class:: KeywordMapper(*args, **kwargs) Generic keyword mapper for any sub-implementers. Allows specifying multiple combinations of schemas variants for an underlying schema definition. Each implementer must provide the corresponding ``keyword`` it defines amongst `OpenAPI` specification keywords. .. py:attribute:: schema_type .. py:attribute:: _keyword_schemas_only_object :value: False .. py:attribute:: _keyword_schemas_same_struct :value: False .. py:attribute:: _keywords .. py:attribute:: _keyword_map .. py:attribute:: _keyword_inv .. py:attribute:: _keyword :type: str :value: None .. py:attribute:: keywords .. py:method:: get_keyword_name() :classmethod: .. py:method:: get_keyword_items() .. py:method:: _validate_keyword_unique() .. py:method:: _validate_keyword_schemas() Validation of children schemas under keyword. Validation of keyword sub-nodes to be only defined as schema *objects* if property ``_keyword_schemas_only_object = True`` (i.e.: any node that defines its schema type as :class:`Mapping`). Validation of keyword sub-nodes to all have matching structure of container if ``_keyword_schemas_same_struct = True`` (i.e.: all :class:`colander.Mapping`, all literal schema-types, etc.). .. py:method:: _bind(kw: Dict[str, Any]) -> None Applies the bindings to the children nodes. Based on :meth:`colander._SchemaNode._bind` except that `children` are obtained from the keyword. .. py:method:: _deserialize_keyword(cstruct) :abstractmethod: Deserialization and validation of a keyword-based schema definition. This method must be implemented by the specific keyword to handle invalid subnodes according to the behaviour it offers. .. seealso:: - :meth:`_deserialize_subnode` .. py:method:: _deserialize_subnode(node, cstruct, index) Deserialization and validation of sub-nodes under a keyword-based schema definition. This method must be called by keyword deserialization implementers for deserialization of every sub-node in order to apply extended behaviour operations accordingly. The original ``deserialize`` method of :mod:`colander` schema nodes should not be called directly, otherwise extensions will not be handled. This method will call it after resolving any applicable extension. .. note:: Because sub-nodes are within a non-schema node iterable, the SchemaMeta will not have extracted the destination name for us (ie: map key to compare against). Furthermore, the destination is not directly in the KeywordMapper class, but in its parent where its instance will be dumped according to the keyword resolution. Therefore, regardless of the child, they all have the same parent destination. .. seealso:: - :meth:`_deserialize_keyword` - :class:`ExtendedSchemaNode` .. py:method:: deserialize(cstruct) Deserialize the :term:`cstruct` into an :term:`appstruct` based on the schema, run this :term:`appstruct` through the preparer, if one is present, then validate the prepared appstruct. The ``cstruct`` value is deserialized into an ``appstruct`` unconditionally. If ``appstruct`` returned by type deserialization and preparation is the value :attr:`colander.null`, do something special before attempting validation: - If the ``missing`` attribute of this node has been set explicitly, return its value. No validation of this value is performed; it is simply returned. - If the ``missing`` attribute of this node has not been set explicitly, raise a :exc:`colander.Invalid` exception error. If the appstruct is not ``colander.null`` and cannot be validated , a :exc:`colander.Invalid` exception will be raised. If a ``cstruct`` argument is not explicitly provided, it defaults to :attr:`colander.null`. .. py:class:: OneOfKeywordSchema(*args, **kwargs) Allows specifying multiple supported mapping schemas variants for an underlying schema definition. Corresponds to the ``oneOf`` specifier of `OpenAPI` specification. Example:: class Variant1(MappingSchema): [...fields of Variant1...] class Variant2(MappingSchema): [...fields of Variant2...] class RequiredByBoth(MappingSchema): [...fields required by both Variant1 and Variant2...] class OneOfWithRequiredFields(OneOfKeywordSchema, RequiredByBoth): _one_of = (Variant1, Variant2) [...alternatively, field required by all variants here...] In the above example, the validation (ie: ``deserialize``) process will succeed if only one of the ``_one_of`` variants' validator completely succeed, and will fail if every variant fails validation execution. The operation will also fail if more than one validation succeeds. .. note:: Class ``OneOfWithRequiredFields`` in the example is a shortcut variant to generate a specification that represents the pseudo-code ``oneOf([])``. The real :term:`OpenAPI` method to implement the above very commonly occurring situation is as presented by the following pseudo-code:: oneOf[allOf[RequiredByBoth, Variant1], allOf[RequiredByBoth, Variant2]] This is both painful to read and is a lot of extra code to write when you actually expand it all into classes (each ``oneOf/allOf`` is another class). Class :class:`OneOfKeywordSchema` will actually simplify this by automatically making the ``allOf`` definitions for you if it detects other schema nodes than ``oneOf`` specified in the class bases. You can still do the full ``oneOf/allOf`` classes expansion manually though, it will result into the same specification. .. warning:: When ``oneOf/allOf`` automatic expansion occurs during schema generation .. warning:: When calling :meth:`deserialize`, because the validation process requires **exactly one** of the variants to succeed to consider the whole object to evaluate as valid, it is important to insert *more permissive* validators later in the ``_one_of`` iterator (or ``validator`` keyword). For example, having a variant with all fields defined as optional (ie: with ``missing=drop``) inserted as first item in ``_one_of`` will make it always succeed regardless of following variants (since an empty schema with everything dropped is valid for optional-only elements). This would have as side effect of potentially failing the validation if other object are also valid depending on the received schema because the schema cannot be discriminated between many. If this occurs, it means the your schemas are too permissive. In the event that you have very similar schemas that can sometime match except one identifier (e.g.: field ``type`` defining the type of object), consider adding a ``validator`` to each sub-node with explicit values to solve the discrimination problem. As a shortcut, the :term:`OpenAPI` keyword ``discriminator`` can be provided to try matching as a last resort. For example: .. code-block:: python class Animal(ExtendedMappingSchema): name = ExtendedSchemaNode(String()) type = ExtendedSchemaNode(String()) # with explicit definition, this shouldn't be here ## With explicit definitions, each below 'Animal' class should be defined as follows ## type = ExtendedSchemaNode(String(), validator=colander.OneOf([''])) class Cat(Animal): [...] # many **OPTIONAL** fields class Dog(Animal): [...] # many **OPTIONAL** fields # With the discriminator keyword, following is possible # (each schema must provide the same property name) class SomeAnimal(OneOfMappingSchema): discriminator = "type" _one_of = [ Cat(), Dog(), ] # If more specific mapping resolutions than 1-to-1 by name are needed, # an explicit dictionary can be specified instead. class SomeAnimal(OneOfMappingSchema): discriminator = { "propertyName": "type", # correspond to 'type' of 'Animal' "mapping": { "cat": Cat, "dog": Dog # map expected values to target schemas } } _one_of = [ Cat(), Dog(), ] .. note:: Keyword ``discriminator`` supports a map of key-string to schemas-type as presented in the example, and the key must be located at the top level of the mapping. If only ``discriminator = ""`` is provided, the definition will be created automatically using the ``example`` (which should be only the matching value) of the corresponding field of each node within the ``_one_of`` mapping. When multiple valid schemas are matched against the input data, the error will be raised and returned with corresponding erroneous elements for each sub-schema (fully listed). .. seealso:: - :class:`AllOfKeywordSchema` - :class:`AnyOfKeywordSchema` - :class:`NotKeywordSchema` .. py:attribute:: _keyword_schemas_only_object :value: False .. py:attribute:: _keyword :value: '_one_of' .. py:attribute:: _discriminator :value: 'discriminator' .. py:attribute:: discriminator :value: None .. py:method:: _one_of() -> Iterable[Union[colander.SchemaNode, Type[colander.SchemaNode]]] :classmethod: :abstractmethod: Sequence of applicable schema nested under the ``oneOf`` keyword. Must be overridden in the schema definition using it. .. py:property:: discriminator_spec .. py:method:: _deserialize_keyword(cstruct) Test each possible case, return all corresponding errors if not exactly one of the possibilities is valid. .. py:class:: AllOfKeywordSchema(*args, **kwargs) Allows specifying all the required partial mapping schemas for an underlying complete schema definition. Corresponds to the ``allOf`` specifier of `OpenAPI` specification. Example:: class RequiredItem(ExtendedMappingSchema): item = ExtendedSchemaNode(String()) class RequiredType(ExtendedMappingSchema): type = ExtendedSchemaNode(String()) class AllRequired(AnyKeywordSchema): _all_of = [RequiredItem(), RequiredType()] Value parsed with schema this definition will be valid only when every since one of the sub-schemas is valid. Any sub-schema raising an invalid error for any reason with make the whole schema validation fail. .. seealso:: - :class:`OneOfKeywordSchema` - :class:`AnyOfKeywordSchema` - :class:`NotKeywordSchema` .. py:attribute:: _keyword_schemas_only_object :value: True .. py:attribute:: _keyword_schemas_same_struct :value: True .. py:attribute:: _keyword :value: '_all_of' .. py:method:: _all_of() -> Iterable[Union[colander.SchemaNode, Type[colander.SchemaNode]]] :classmethod: :abstractmethod: Sequence of applicable schema nested under the ``allOf`` keyword. Must be overridden in the schema definition using it. .. py:method:: _deserialize_keyword(cstruct) Test each possible case, return all corresponding errors if any of the possibilities is invalid. .. py:class:: AnyOfKeywordSchema(*args, **kwargs) Allows specifying all mapping schemas that can be matched for an underlying schema definition. Corresponds to the ``anyOf`` specifier of `OpenAPI` specification. Contrary to :class:`OneOfKeywordSchema` that MUST be validated with exactly one schema, this definition will continue parsing all possibilities and apply validated sub-schemas on top of each other. Not all schemas have to be valid like in the case of :class:`AllOfKeywordSchema` to succeed, as long as at least one of them is valid. Example:: class RequiredItem(ExtendedMappingSchema): item = ExtendedSchemaNode(String()) class RequiredType(ExtendedMappingSchema): type = ExtendedSchemaNode(String()) class RequiredFields(ExtendedMappingSchema): field_str = ExtendedSchemaNode(String()) field_int = ExtendedSchemaNode(Integer()) class AnyRequired(AnyKeywordSchema): _any_of = [RequiredItem(), RequiredType(), RequiredFields()] # following is valid because their individual parts have all required sub-fields, result is their composition AnyRequired().deserialize({"type": "test", "item": "valid"}) # result: {"type": "test", "item": "valid"} # following is also valid because even though 'item' is missing, the 'type' is present AnyRequired().deserialize({"type": "test"}) # result: {"type": "test"} # following is invalid because every one of the sub-field of individual parts are missing AnyRequired().deserialize({"type": "test"}) # following is invalid because fields of 'RequiredFields' are only partially fulfilled AnyRequired().deserialize({"field_str": "str"}) # following is valid because although fields of 'RequiredFields' are not all fulfilled, 'RequiredType' is valid AnyRequired().deserialize({"field_str": "str", "type": "str"}) # result: {"type": "test"} # following is invalid because 'RequiredFields' field 'field_int' is incorrect schema type AnyRequired().deserialize({"field_str": "str", "field_int": "str"}) # following is valid, but result omits 'type' because its schema-type is incorrect, while others are valid AnyRequired().deserialize({"field_str": "str", "field_int": 1, "items": "fields", "type": 1}) # result: {"field_str": "str", "field_int": 1, "items": "fields"} .. warning:: Because valid items are applied on top of each other by merging fields during combinations, conflicting field names of any valid schema will contain only the final valid parsing during deserialization. .. seealso:: - :class:`OneOfKeywordSchema` - :class:`AllOfKeywordSchema` - :class:`NotKeywordSchema` .. py:attribute:: _keyword_schemas_only_object :value: False .. py:attribute:: _keyword_schemas_same_struct :value: False .. py:attribute:: _keyword :value: '_any_of' .. py:method:: _any_of() -> Iterable[Union[colander.SchemaNode, Type[colander.SchemaNode]]] :classmethod: :abstractmethod: Sequence of applicable schema nested under the ``anyOf`` keyword. Must be overridden in the schema definition using it. .. py:method:: _deserialize_keyword(cstruct) Test each possible case, return if no corresponding schema was found. .. py:class:: NotKeywordSchema(*args, **kwargs) Allows specifying specific schema conditions that fails underlying schema definition validation if present. Corresponds to the ``not`` specifier of `OpenAPI` specification. Example:: class RequiredItem(ExtendedMappingSchema): item = ExtendedSchemaNode(String()) class MappingWithType(ExtendedMappingSchema): type = ExtendedSchemaNode(String()) class MappingWithoutType(NotKeywordSchema, RequiredItem): _not = [MappingWithType()] class MappingOnlyNotType(NotKeywordSchema): _not = [MappingWithType()] # following will raise invalid error even if 'item' is valid because 'type' is also present MappingWithoutType().deserialize({"type": "invalid", "item": "valid"}) # following will return successfully with only 'item' because 'type' was not present MappingWithoutType().deserialize({"item": "valid", "value": "ignore"}) # result: {"item": "valid"} # following will return an empty mapping dropping 'item' since it only needs to ensure 'type' was not present, # but did not provide any additional fields requirement from other class inheritances MappingOnlyNotType().deserialize({"item": "valid"}) # result: {} .. seealso:: - :class:`OneOfKeywordSchema` - :class:`AllOfKeywordSchema` - :class:`AnyOfKeywordSchema` .. py:attribute:: _keyword_schemas_only_object :value: True .. py:attribute:: _keyword_schemas_same_struct :value: True .. py:attribute:: _keyword :value: '_not' .. py:method:: _not() -> Iterable[Union[colander.SchemaNode, Type[colander.SchemaNode]]] :classmethod: :abstractmethod: Sequence of applicable schema nested under the ``not`` keyword. Must be overridden in the schema definition using it. .. py:method:: _deserialize_keyword(cstruct) Raise if any sub-node schema that should NOT be present was successfully validated. .. py:class:: SchemaRefConverter(dispatcher) Converter that will add :term:`OpenAPI` ``$schema`` and ``$id`` references if they are provided in the schema node. .. py:method:: convert_type(schema_node: colander.SchemaNode) -> weaver.typedefs.OpenAPISchema .. py:class:: ExtendedTypeConverter(dispatcher) Base converter with support of `Extended` schema type definitions. .. py:method:: convert_type(schema_node: colander.SchemaNode) -> weaver.typedefs.OpenAPISchema .. py:class:: KeywordTypeConverter(dispatcher) Generic keyword converter that builds schema with a list of sub-schemas under the keyword. .. py:method:: convert_type(schema_node) .. py:class:: OneOfKeywordTypeConverter(dispatcher) Object converter that generates the ``oneOf`` keyword definition. This object does a bit more work than other :class:`KeywordTypeConverter` as it handles the shorthand definition as described in :class:`OneOfKeywordSchema` .. seealso:: - :class:`OneOfKeywordSchema` .. py:method:: convert_type(schema_node: OneOfKeywordSchema) -> weaver.typedefs.OpenAPISchemaOneOf .. py:class:: AllOfKeywordTypeConverter(dispatcher) Object converter that generates the ``allOf`` keyword definition. .. py:method:: convert_type(schema_node: colander.SchemaNode) -> weaver.typedefs.OpenAPISchemaAllOf .. py:class:: AnyOfKeywordTypeConverter(dispatcher) Object converter that generates the ``anyOf`` keyword definition. .. py:method:: convert_type(schema_node: colander.SchemaNode) -> weaver.typedefs.OpenAPISchemaAnyOf .. py:class:: NotKeywordTypeConverter(dispatcher) Object converter that generates the ``not`` keyword definition. .. py:method:: convert_type(schema_node: colander.SchemaNode) -> weaver.typedefs.OpenAPISchemaNot .. py:class:: ExtendedObjectTypeConverter(dispatcher) Object convert for mapping type with extended capabilities. .. py:class:: VariableObjectTypeConverter(dispatcher) Object convertor with ``additionalProperties`` for each ``properties`` marked as :class:`VariableSchemaNode`. .. py:method:: convert_type(schema_node: colander.SchemaNode) -> weaver.typedefs.OpenAPISchema .. py:class:: DecimalTypeConverter(dispatcher) Converter that applies :term:`OpenAPI` schema metadata properties defined in the schema node. .. py:attribute:: format :value: 'decimal' .. py:method:: convert_type(schema_node) .. py:class:: MoneyTypeConverter(dispatcher) Converter that applies :term:`OpenAPI` schema metadata properties defined in the schema node. .. py:attribute:: convert_validator .. py:class:: NoneTypeConverter(dispatcher) Base converter with support of `Extended` schema type definitions. .. py:attribute:: type :value: 'null' .. py:class:: AnyTypeConverter(dispatcher) Base converter with support of `Extended` schema type definitions. .. py:method:: convert_type(schema_node) .. py:class:: OAS3TypeConversionDispatcher(custom_converters: Optional[Dict[colander.SchemaType, cornice_swagger.converters.schema.TypeConverter]] = None, default_converter: Optional[cornice_swagger.converters.schema.TypeConverter] = None) .. py:attribute:: openapi_spec :value: 3 .. py:attribute:: keyword_converters .. py:attribute:: keyword_validators .. py:method:: extend_converters() -> None Extend base :class:`TypeConverter` derived classes to provide additional capabilities seamlessly. .. py:class:: OAS3ParameterConverter Converts a :class:`colander.SchemaNode` describing an :term:`OpenAPI` parameter into its appropriate definition. If extended by :class:`OASParameter`, the converted node can also include additional :term:`OAS` parameter fields. .. py:attribute:: reserved_params :value: ['name', 'in', 'required', 'schema', 'content'] .. py:method:: convert(schema_node: Union[colander.SchemaNode, OAS3Parameter], definition_handler: cornice_swagger.swagger.DefinitionHandler) -> weaver.typedefs.OpenAPISpecParameter Convert node schema into a parameter object. .. py:class:: OAS3BodyParameterConverter Converts a :class:`colander.SchemaNode` describing an :term:`OpenAPI` parameter into its appropriate definition. If extended by :class:`OASParameter`, the converted node can also include additional :term:`OAS` parameter fields. .. py:class:: OAS3PathParameterConverter Converts a :class:`colander.SchemaNode` describing an :term:`OpenAPI` parameter into its appropriate definition. If extended by :class:`OASParameter`, the converted node can also include additional :term:`OAS` parameter fields. .. py:class:: OAS3QueryParameterConverter Converts a :class:`colander.SchemaNode` describing an :term:`OpenAPI` parameter into its appropriate definition. If extended by :class:`OASParameter`, the converted node can also include additional :term:`OAS` parameter fields. .. py:class:: OAS3HeaderParameterConverter Converts a :class:`colander.SchemaNode` describing an :term:`OpenAPI` parameter into its appropriate definition. If extended by :class:`OASParameter`, the converted node can also include additional :term:`OAS` parameter fields. .. py:class:: OAS3CookieParameterConverter Converts a :class:`colander.SchemaNode` describing an :term:`OpenAPI` parameter into its appropriate definition. If extended by :class:`OASParameter`, the converted node can also include additional :term:`OAS` parameter fields. .. py:attribute:: _in :value: 'cookie' .. py:class:: OAS3ParameterConversionDispatcher(definition_handler) .. py:attribute:: converters .. py:class:: OAS3DefinitionHandler(ref=0, type_converter=TypeConverter()) Handles Swagger object definitions provided by cornice as colander schemas. :param ref: The depth that should be used by self.ref when calling self.from_schema. .. py:attribute:: json_pointer :value: '#/components/schemas/' .. py:method:: from_schema(schema_node: colander.SchemaNode, base_name: Optional[str] = None) -> weaver.typedefs.OpenAPISchema Convert the schema node to an :term:`OAS` schema. If the schema node provided ``schema_ref`` URL and that the object is not defined, use it instead as an external reference. .. py:method:: _ref_recursive(schema, depth, base_name=None) Dismantle nested swagger schemas into several definitions using JSON pointers. Note: This can be dangerous since definition titles must be unique. :param schema: Base swagger schema. :param depth: How many levels of the swagger object schemas should be split into swagger definitions with JSON pointers. Default (0) is no split. You may use negative values to split everything. :param base_name: If schema doesn't have a name, the caller may provide it to be used as reference. :rtype: dict :returns: JSON pointer to the root definition schema, or the original definition if depth is zero. .. py:method:: _process_items(schema: Dict[str, Any], list_type: Literal['oneOf', 'allOf', 'anyOf', 'not'], item_list: List[Dict[str, Any]], depth: int, base_name: str) -> Dict[str, Any] Generates recursive schema definitions with JSON ref pointers for nested keyword objects. Contrary to the original implementation, preserves additional metadata like the object title, description, etc. .. py:class:: OAS3ParameterHandler(definition_handler=DefinitionHandler(), ref=False, type_converter=TypeConverter(), parameter_converter=ParameterConverter(TypeConverter())) Handles swagger parameter definitions. :param definition_handler: Callable that handles swagger definition schemas. :param ref: Specifies the ref value when calling from_xxx methods. .. py:attribute:: json_pointer :value: '#/components/parameters/' .. py:class:: OAS3ResponseHandler(definition_handler=DefinitionHandler(), type_converter=TypeConverter(), ref=False) Handles swagger response definitions. :param definition_handler: Callable that handles swagger definition schemas. :param ref: Specifies the ref value when calling from_xxx methods. .. py:attribute:: json_pointer :value: '#/components/responses/' .. py:class:: CorniceOpenAPI(services: Optional[Sequence[cornice.Service]] = None, def_ref_depth: int = 0, param_ref: bool = False, resp_ref: bool = False, pyramid_registry: Optional[pyramid.registry.Registry] = None) Handles the creation of a swagger document from a cornice application. :param services: List of cornice services to document. You may use cornice.service.get_services() to get it. :param def_ref_depth: How depth swagger object schemas should be split into swaggger definitions with JSON pointers. Default (0) is no split. You may use negative values to split everything. :param param_ref: Defines if swagger parameters should be put inline on the operation or on the parameters section and referenced by JSON pointers. Default is inline. :param resp_ref: Defines if swagger responses should be put inline on the operation or on the responses section and referenced by JSON pointers. Default is inline. :param pyramid_registry: Pyramid registry, should be passed if you use pyramid routes instead of service level paths. .. py:attribute:: openapi_spec :value: 3 OpenAPI specification version that should be used for generation. OpenAPI 3 is required to support 'oneOf', 'allOf', 'anyOf' and 'not' keywords as well as other multiple views of same method for different content-type. .. py:method:: generate(title: Optional[str] = None, version: Optional[str] = None, base_path: Optional[str] = None, info: Optional[weaver.typedefs.OpenAPISpecInfo] = None, swagger: Optional[weaver.typedefs.JSON] = None, openapi_spec: Literal[2, 3] = 2, **kwargs) -> weaver.typedefs.OpenAPISpecification Generate an OpenAPI documentation. Keyword arguments may be used to provide additional information to build methods as such ignores. :param title: The name presented on the swagger document. :param version: The version of the API presented on the swagger document. :param base_path: The path that all requests to the API must refer to. :param info: Swagger info field. :param swagger: Extra fields that should be provided on the swagger documentation. :param openapi_spec: The OpenAPI specification version to use for swagger documentation format. :rtype: dict :returns: Full OpenAPI/Swagger compliant specification for the application.