weaver.wps_restapi.colander_extras

This module offers multiple utility schema definitions to be employed with colander and cornice_swagger.

The colander.SchemaNode provided here can be used in-place of 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.

# 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 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 colander.SchemaNode have some additional patches needed to handle JSON-native type conversion that are not directly offered by colander

The main classes extensions are:

Multiple <ExtensionType>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 <ExtensionType>. 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 OpenAPI model definitions. If not explicitly provided, the value of title WILL default to the name of the schema node class.

Module Contents

weaver.wps_restapi.colander_extras.LITERAL_SCHEMA_TYPES[source]
exception weaver.wps_restapi.colander_extras.SchemaNodeTypeError[source]

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.

exception weaver.wps_restapi.colander_extras.ConversionTypeError[source]

Conversion error due to invalid type.

Initialize self. See help(type(self)) for accurate signature.

exception weaver.wps_restapi.colander_extras.ConversionValueError[source]

Conversion error due to invalid value.

Initialize self. See help(type(self)) for accurate signature.

class weaver.wps_restapi.colander_extras.OneOfCaseInsensitive(choices, msg_err=_MSG_ERR)[source]

Validator that ensures the given value matches one of the available choices, but allowing case insensitive values.

class weaver.wps_restapi.colander_extras.StringRange(min=None, max=None, **kwargs)[source]

Validator that provides the same functionalities as colander.Range for a numerical string value.

class weaver.wps_restapi.colander_extras.SchemeURL(schemes=None, msg=None, flags=re.IGNORECASE)[source]

String representation of an URL with extended set of allowed URI schemes.

See also

colander.url [remote http(s)/ftp(s)] colander.file_uri [local file://]

class weaver.wps_restapi.colander_extras.SemanticVersion(*args, v_prefix=False, rc_suffix=True, **kwargs)[source]

String representation that is valid against Semantic Versioning specification.

class weaver.wps_restapi.colander_extras.ExtendedBoolean(*args, true_choices=None, false_choices=None, **kwargs)[source]

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 false_choices, will be considered False.

The behaviour for values not contained in false_choices depends on true_choices: if it’s empty, any value is considered True; otherwise, only values contained in true_choices are considered True, and an Invalid exception would be raised for values outside of both false_choices and true_choices.

Serialization will produce true_val or false_val based on the value.

If the colander.null value is passed to the serialize method of this class, the colander.null value will be returned.

The subnodes of the colander.SchemaNode that wraps this type are ignored.

Initializes the extended boolean schema node.

When arguments true_choices or false_choices are provided, the corresponding string values are respectively considered as valid truthy/falsy values. Otherwise (default), strict values only of explicit type bool will be considered valid.

When values are specified 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 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.

deserialize(self, node, cstruct)[source]
class weaver.wps_restapi.colander_extras.ExtendedNumber(*_, allow_string=False, strict=True, **__)[source]

Definition of a numeric value, either explicitly or implicit with permissive 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 float, int or str are disallowed.

  • strict=True and allow_string=True: Value can be the explicit numeric type (int or float) or a numeric str value representing the corresponding base numeric type. Implicit conversion between float and 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 (int or 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 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.

abstract static number(num)[source]
abstract static strict(num)[source]
class weaver.wps_restapi.colander_extras.ExtendedFloat(*_, allow_string=False, strict=True, **__)[source]

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.

static number(num)[source]
static strict(num)[source]
serialize(self, node, cstruct)[source]
class weaver.wps_restapi.colander_extras.ExtendedInteger(*_, allow_string=False, strict=True, **__)[source]

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.

static number(num)[source]
static strict(num)[source]
serialize(self, node, cstruct)[source]
class weaver.wps_restapi.colander_extras.ExtendedString(encoding=None, allow_empty=False)[source]

A type representing a Unicode string.

This type constructor accepts two arguments:

encoding

Represents the encoding which should be applied to value serialization and deserialization, for example utf-8. If encoding is passed as None, the serialize method of this type will not do any special encoding of the appstruct it is provided, nor will the deserialize method of this type do any special decoding of the cstruct it is provided; inputs and outputs will be assumed to be Unicode. encoding defaults to None.

If encoding is None:

  • A Unicode input value to serialize is returned untouched.

  • A non-Unicode input value to serialize is run through the unicode() function without an encoding parameter (unicode(value)) and the result is returned.

  • A Unicode input value to deserialize is returned untouched.

  • A non-Unicode input value to deserialize is run through the unicode() function without an encoding parameter (unicode(value)) and the result is returned.

If encoding is not None:

  • A Unicode input value to serialize is run through the unicode function with the encoding parameter (unicode(value, encoding)) and the result (a str object) is returned.

  • A non-Unicode input value to serialize is converted to a Unicode using the encoding (unicode(value, encoding)); subsequently the Unicode object is re-encoded to a str object using the encoding and returned.

  • A Unicode input value to deserialize is returned untouched.

  • A non-Unicode input value to deserialize is converted to a str object using str(value). The resulting str value is converted to Unicode using the encoding (unicode(value, encoding)) and the result is returned.

A corollary: If a string (as opposed to a unicode object) is provided as a value to either the serialize or deserialize method of this type, and the type also has an non-None encoding, the string must be encoded with the type’s encoding. If this is not true, an colander.Invalid error will result.

allow_empty

Boolean, if True allows deserialization of an empty string. If False (default), empty strings will deserialize to colander.null

The subnodes of the colander.SchemaNode that wraps this type are ignored.

class weaver.wps_restapi.colander_extras.XMLObject[source]

Object that provides mapping to known XML extensions for OpenAPI schema definition.

Name of the schema definition in the OpenAPI will use prefix and the schema class name. Prefix can be omitted from the schema definition name by setting it to colander.drop. The value of title provided as option or

attribute[source]
name[source]
namespace[source]
prefix[source]
wrapped[source]
property xml(self)[source]
class weaver.wps_restapi.colander_extras.ExtendedNodeInterface[source]
_extension :str[source]
abstract _deserialize_impl(self, cstruct)[source]
class weaver.wps_restapi.colander_extras.ExtendedSchemaMeta(cls, name, bases, clsattrs)[source]
class weaver.wps_restapi.colander_extras.ExtendedSchemaBase(*args, **kwargs)[source]

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 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 colander.String without explicit validator, but that one can be inferred from either pattern or format OpenAPI definition, the corresponding validator gets automatically generated.

abstract static schema_type()[source]
static _validate(node)[source]
class weaver.wps_restapi.colander_extras.DropableSchemaNode(*args, **kwargs)[source]

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 colander.MappingSchema and colander.SequenceSchema are to drop the sub-node only if its value is resolved as colander.null or colander.drop. This results in optional field definitions replaced by None in many implementations to raise colander.Invalid during deserialization. Inheriting this class in a schema definition will handle this situation automatically.

Required schemas (without missing=drop, defaulting to colander.required) will still raise for undefined nodes.

The following snippet shows the result that can be achieved using this schema class:

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'}}
_extension = _ext_dropable[source]
abstract static schema_type()[source]
deserialize(self, cstruct)[source]

Deserialize the cstruct into an appstruct based on the schema, run this 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 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 colander.Invalid exception error.

If the appstruct is not colander.null and cannot be validated , a colander.Invalid exception will be raised.

If a cstruct argument is not explicitly provided, it defaults to colander.null.

_deserialize_impl(self, cstruct)[source]
class weaver.wps_restapi.colander_extras.DefaultSchemaNode(*args, **kwargs)[source]

Schema that will return the provided default value when the corresponding value is missing or invalid.

If default keyword is provided during colander.SchemaNode creation, overrides the returned value by this default if missing from the structure during deserialize() call.

Original behaviour was to drop the missing value instead of replacing by default. Executes all other colander.SchemaNode operations normally.

_extension = _ext_default[source]
abstract static schema_type()[source]
deserialize(self, cstruct)[source]

Deserialize the cstruct into an appstruct based on the schema, run this 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 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 colander.Invalid exception error.

If the appstruct is not colander.null and cannot be validated , a colander.Invalid exception will be raised.

If a cstruct argument is not explicitly provided, it defaults to colander.null.

_deserialize_impl(self, cstruct)[source]
class weaver.wps_restapi.colander_extras.VariableSchemaNode(*args, **kwargs)[source]

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.

{
    "<any-key-id>": {
        "name": "required",
        "value": "something"
    },
    "<another-key-id>": {
        "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 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 <var>.

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 giving an indication that any key is accepted.

_extension = _ext_variable[source]
_variable = variable[source]
_variable_map = variable_map[source]
classmethod is_variable(cls, node)[source]

If current node is the variable field definition.

has_variables(self)[source]

If the current container schema node has sub-node variables.

abstract static schema_type()[source]
_mark_variable_children(self)[source]

Ensures that any immediate children schema with variable key are detected.

Verifies if a colander.MappingSchema (or any of its extensions) contains children VariableSchemaNode schema nodes for adequate 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 colander.Invalid because they are supposed to be 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 VariableSchemaNode to ensure they pre-process potential variable candidates.

_get_sub_variable(self, subnodes)[source]
deserialize(self, cstruct)[source]

Deserialize the cstruct into an appstruct based on the schema, run this 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 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 colander.Invalid exception error.

If the appstruct is not colander.null and cannot be validated , a colander.Invalid exception will be raised.

If a cstruct argument is not explicitly provided, it defaults to colander.null.

static _check_deserialize(node, cstruct)[source]
static _deserialize_remap(node, cstruct, var_map, var_name, has_const_child)[source]
_deserialize_impl(self, cstruct)[source]
class weaver.wps_restapi.colander_extras.SortableMappingSchema(*args, **kwargs)[source]

Adds sorting capabilities to mapping schema.

Extended schema nodes that inherit from colander.Mapping schema-type such that they can request ordering of resulting fields by overriding properties _sort_first and _sort_after within the schema definition with lists of fields names to sort.

_extension = _ext_sortable[source]
_sort_first :Sequence[str] = [][source]
_sort_after :Sequence[str] = [][source]
deserialize(self, cstruct)[source]

Deserialize the cstruct into an appstruct based on the schema, run this 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 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 colander.Invalid exception error.

If the appstruct is not colander.null and cannot be validated , a colander.Invalid exception will be raised.

If a cstruct argument is not explicitly provided, it defaults to colander.null.

abstract static schema_type()[source]
_deserialize_impl(self, cstruct)[source]
static _order_deserialize(cstruct: Dict[str, Any], sort_first: Optional[Sequence[str]] = None, sort_after: Optional[Sequence[str]] = None)Dict[str, Any][source]

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 colander (and extended 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.

Parameters
  • cstruct – JSON structure to be sorted that has already been processed by a schema’s deserialize call.

  • sort_first – ordered list of fields to place first in the result.

  • sort_after – ordered list of fields to place last in the result.

Returns

results formed from cstruct following order: (<fields_firsts> + <other_fields> + <fields_after>)

class weaver.wps_restapi.colander_extras.ExtendedSchemaNode(*args, **kwargs)[source]

Base schema node with support of extended functionalities.

Combines all colander.SchemaNode extensions so that default keyword is used first to resolve a missing field value during deserialize() call, and then removes the node completely if no default was provided, and evaluate variables as needed.

_extension = _ext_combined[source]
abstract static schema_type()[source]
_deserialize_extensions(self, cstruct)[source]
deserialize(self, cstruct)[source]

Deserialize the cstruct into an appstruct based on the schema, run this 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 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 colander.Invalid exception error.

If the appstruct is not colander.null and cannot be validated , a colander.Invalid exception will be raised.

If a cstruct argument is not explicitly provided, it defaults to colander.null.

class weaver.wps_restapi.colander_extras.DropableSequenceSchema(*args, **kwargs)[source]

Sequence schema that supports the dropable functionality.

Extends colander.SequenceSchema to auto-handle dropping missing entry definitions when its value is either None, colander.null or colander.drop.

schema_type[source]
class weaver.wps_restapi.colander_extras.DefaultSequenceSchema(*args, **kwargs)[source]

Sequence schema that supports the default value functionality.

Extends 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.

schema_type[source]
class weaver.wps_restapi.colander_extras.ExtendedSequenceSchema(*args, **kwargs)[source]

Sequence schema that supports all applicable extended schema node functionalities.

Combines DefaultSequenceSchema and DefaultSequenceSchema extensions so that default keyword is used first to resolve a missing sequence during deserialize() call, and then removes the node completely if no default was provided.

schema_type[source]
_validate(self)[source]
class weaver.wps_restapi.colander_extras.DropableMappingSchema(*args, **kwargs)[source]

Mapping schema that supports the dropable functionality.

Override the default colander.MappingSchema to auto-handle dropping missing field definitions when the corresponding value is either None, colander.null or colander.drop.

schema_type[source]
class weaver.wps_restapi.colander_extras.DefaultMappingSchema(*args, **kwargs)[source]

Mapping schema that supports the default value functionality.

Override the default colander.MappingSchema to auto-handle replacing missing entries by their specified default during deserialization.

schema_type[source]
class weaver.wps_restapi.colander_extras.VariableMappingSchema(*args, **kwargs)[source]

Mapping schema that supports the variable functionality.

Override the default colander.MappingSchema to auto-handle replacing missing entries by their specified variable during deserialization.

schema_type[source]
class weaver.wps_restapi.colander_extras.ExtendedMappingSchema(*args, **kwargs)[source]

Combines multiple extensions of colander.MappingSchema handle their corresponding keywords.

Resolution is done so that default keyword is used first to resolve a missing object during deserialize() call, and then removes the node completely if no default was provided.

schema_type[source]
_validate_nodes(self)[source]
class weaver.wps_restapi.colander_extras.PermissiveMappingSchema(*args, **kwargs)[source]

Object schema that will allow 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.

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 preserved as it was received without any validation. Other fields that are explicitly specified with sub-schema nodes will still be validated as per usual behaviour.

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 colander.MappingSchema support this natively.

class weaver.wps_restapi.colander_extras.KeywordMapper(*args, **kwargs)[source]

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.

schema_type[source]
_keyword_schemas_only_object = False[source]
_keyword_schemas_same_struct = False[source]
_keywords[source]
_keyword_map[source]
_keyword_inv[source]
_keyword :str[source]
classmethod get_keyword_name(cls)[source]
get_keyword_items(self)[source]
_validate_keyword_unique(self)[source]
_validate_keyword_schemas(self)[source]

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 Mapping).

Validation of keyword sub-nodes to all have matching structure of container if _keyword_schemas_same_struct = True (i.e.: all colander.Mapping, all literal schema-types, etc.).

abstract _deserialize_keyword(self, cstruct)[source]

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.

_deserialize_subnode(self, node, cstruct, index)[source]

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 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.

deserialize(self, cstruct)[source]

Deserialize the cstruct into an appstruct based on the schema, run this 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 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 colander.Invalid exception error.

If the appstruct is not colander.null and cannot be validated , a colander.Invalid exception will be raised.

If a cstruct argument is not explicitly provided, it defaults to colander.null.

class weaver.wps_restapi.colander_extras.OneOfKeywordSchema(*args, **kwargs)[source]

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([<list-of-objects-with-same-base>]).

The real 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 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 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 OpenAPI keyword discriminator can be provided to try matching as a last resort.

For example:

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(['<animal>']))

class Cat(Animal):
    [...]   # many **OPTIONAL** fields

class Dog(Animal):
    [...]   # many **OPTIONAL** fields

# With the discriminator keyword, following is possible
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 = "<field>" 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).

_keyword_schemas_only_object = False[source]
_keyword = _one_of[source]
_discriminator = discriminator[source]
abstract classmethod _one_of(cls)Iterable[Union[colander.SchemaNode, Type[colander.SchemaNode]]][source]

Sequence of applicable schema nested under the oneOf keyword.

Must be overridden in the schema definition using it.

property discriminator_spec(self)[source]
_deserialize_keyword(self, cstruct)[source]

Test each possible case, return all corresponding errors if not exactly one of the possibilities is valid.

class weaver.wps_restapi.colander_extras.AllOfKeywordSchema(*args, **kwargs)[source]

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.

_keyword_schemas_only_object = True[source]
_keyword_schemas_same_struct = True[source]
_keyword = _all_of[source]
abstract classmethod _all_of(cls)Iterable[Union[colander.SchemaNode, Type[colander.SchemaNode]]][source]

Sequence of applicable schema nested under the allOf keyword.

Must be overridden in the schema definition using it.

_deserialize_keyword(self, cstruct)[source]

Test each possible case, return all corresponding errors if any of the possibilities is invalid.

class weaver.wps_restapi.colander_extras.AnyOfKeywordSchema(*args, **kwargs)[source]

Allows specifying all mapping schemas that can be matched for an underlying schema definition.

Corresponds to the anyOf specifier of OpenAPI specification.

Contrary to 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 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.

_keyword_schemas_only_object = False[source]
_keyword_schemas_same_struct = True[source]
_keyword = _any_of[source]
abstract classmethod _any_of(cls)Iterable[Union[colander.SchemaNode, Type[colander.SchemaNode]]][source]

Sequence of applicable schema nested under the anyOf keyword.

Must be overridden in the schema definition using it.

_deserialize_keyword(self, cstruct)[source]

Test each possible case, return if no corresponding schema was found.

class weaver.wps_restapi.colander_extras.NotKeywordSchema(*args, **kwargs)[source]

Allows specifying specific schema conditions that fails underlying schema definition validation if present.

Corresponds to the not specifier of OpenAPI specification.

This is equivalent to OpenAPI object mapping with additionalProperties: false, but is more explicit in the definition of invalid or conflicting field names with explicit definitions during deserialization.

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: {}
_keyword_schemas_only_object = True[source]
_keyword_schemas_same_struct = True[source]
_keyword = _not[source]
abstract classmethod _not(cls)Iterable[Union[colander.SchemaNode, Type[colander.SchemaNode]]][source]

Sequence of applicable schema nested under the not keyword.

Must be overridden in the schema definition using it.

_deserialize_keyword(self, cstruct)[source]

Raise if any sub-node schema that should NOT be present was successfully validated.

class weaver.wps_restapi.colander_extras.KeywordTypeConverter(dispatcher)[source]

Generic keyword converter that builds schema with a list of sub-schemas under the keyword.

convert_type(self, schema_node)[source]
class weaver.wps_restapi.colander_extras.OneOfKeywordTypeConverter(dispatcher)[source]

Object converter that generates the oneOf keyword definition.

This object does a bit more work than other KeywordTypeConverter as it handles the shorthand definition as described in OneOfKeywordSchema

convert_type(self: OneOfKeywordSchema, schema_node)Dict[source]
class weaver.wps_restapi.colander_extras.AllOfKeywordTypeConverter(dispatcher)[source]

Object converter that generates the allOf keyword definition.

class weaver.wps_restapi.colander_extras.AnyOfKeywordTypeConverter(dispatcher)[source]

Object converter that generates the anyOf keyword definition.

class weaver.wps_restapi.colander_extras.NotKeywordTypeConverter(dispatcher)[source]

Object converter that generates the not keyword definition.

convert_type(self, schema_node)[source]
class weaver.wps_restapi.colander_extras.VariableObjectTypeConverter(dispatcher)[source]

Object convertor with additionalProperties for each properties marked as VariableSchemaNode.

convert_type(self, schema_node)[source]
class weaver.wps_restapi.colander_extras.OAS3TypeConversionDispatcher(custom_converters=None, default_converter=None)[source]
openapi_spec = 3[source]
weaver.wps_restapi.colander_extras._make_node_instance(schema_node_or_class: Union[colander.SchemaNode, Type[colander.SchemaNode]])colander.SchemaNode[source]

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:

class Map(OneOfMappingSchema):
    # uses types instead of instances like 'SubMap1([...])' and 'SubMap2([...])'
    _one_of = (SubMap1, SubMap2)
weaver.wps_restapi.colander_extras._get_schema_type(schema_node: Union[colander.SchemaNode, Type[colander.SchemaNode]], check: bool = False)Optional[colander.SchemaType][source]

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

Parameters
  • schema_node – item to analyse

  • 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)

weaver.wps_restapi.colander_extras._get_node_name(schema_node: colander.SchemaNode, schema_name: bool = False)str[source]

Obtains the name of the node with best available value.

Parameters
  • schema_node – node for which to retrieve the name.

  • 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