Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/flask_restx/fields.py: 27%
448 statements
« prev ^ index » next coverage.py v7.2.2, created at 2023-03-26 06:03 +0000
« prev ^ index » next coverage.py v7.2.2, created at 2023-03-26 06:03 +0000
1import re
2import fnmatch
3import inspect
5from calendar import timegm
6from datetime import date, datetime
7from decimal import Decimal, ROUND_HALF_EVEN
8from email.utils import formatdate
10from urllib.parse import urlparse, urlunparse
12from flask import url_for, request
13from werkzeug.utils import cached_property
15from .inputs import (
16 date_from_iso8601,
17 datetime_from_iso8601,
18 datetime_from_rfc822,
19 boolean,
20)
21from .errors import RestError
22from .marshalling import marshal
23from .utils import camel_to_dash, not_none
26__all__ = (
27 "Raw",
28 "String",
29 "FormattedString",
30 "Url",
31 "DateTime",
32 "Date",
33 "Boolean",
34 "Integer",
35 "Float",
36 "Arbitrary",
37 "Fixed",
38 "Nested",
39 "List",
40 "ClassName",
41 "Polymorph",
42 "Wildcard",
43 "StringMixin",
44 "MinMaxMixin",
45 "NumberMixin",
46 "MarshallingError",
47)
50class MarshallingError(RestError):
51 """
52 This is an encapsulating Exception in case of marshalling error.
53 """
55 def __init__(self, underlying_exception):
56 # just put the contextual representation of the error to hint on what
57 # went wrong without exposing internals
58 super(MarshallingError, self).__init__(str(underlying_exception))
61def is_indexable_but_not_string(obj):
62 return not hasattr(obj, "strip") and hasattr(obj, "__iter__")
65def is_integer_indexable(obj):
66 return isinstance(obj, list) or isinstance(obj, tuple)
69def get_value(key, obj, default=None):
70 """Helper for pulling a keyed value off various types of objects"""
71 if isinstance(key, int):
72 return _get_value_for_key(key, obj, default)
73 elif callable(key):
74 return key(obj)
75 else:
76 return _get_value_for_keys(key.split("."), obj, default)
79def _get_value_for_keys(keys, obj, default):
80 if len(keys) == 1:
81 return _get_value_for_key(keys[0], obj, default)
82 else:
83 return _get_value_for_keys(
84 keys[1:], _get_value_for_key(keys[0], obj, default), default
85 )
88def _get_value_for_key(key, obj, default):
89 if is_indexable_but_not_string(obj):
90 try:
91 return obj[key]
92 except (IndexError, TypeError, KeyError):
93 pass
94 if is_integer_indexable(obj):
95 try:
96 return obj[int(key)]
97 except (IndexError, TypeError, ValueError):
98 pass
99 return getattr(obj, key, default)
102def to_marshallable_type(obj):
103 """
104 Helper for converting an object to a dictionary only if it is not
105 dictionary already or an indexable object nor a simple type
106 """
107 if obj is None:
108 return None # make it idempotent for None
110 if hasattr(obj, "__marshallable__"):
111 return obj.__marshallable__()
113 if hasattr(obj, "__getitem__"):
114 return obj # it is indexable it is ok
116 return dict(obj.__dict__)
119class Raw(object):
120 """
121 Raw provides a base field class from which others should extend. It
122 applies no formatting by default, and should only be used in cases where
123 data does not need to be formatted before being serialized. Fields should
124 throw a :class:`MarshallingError` in case of parsing problem.
126 :param default: The default value for the field, if no value is
127 specified.
128 :param attribute: If the public facing value differs from the internal
129 value, use this to retrieve a different attribute from the response
130 than the publicly named value.
131 :param str title: The field title (for documentation purpose)
132 :param str description: The field description (for documentation purpose)
133 :param bool required: Is the field required ?
134 :param bool readonly: Is the field read only ? (for documentation purpose)
135 :param example: An optional data example (for documentation purpose)
136 :param callable mask: An optional mask function to be applied to output
137 """
139 #: The JSON/Swagger schema type
140 __schema_type__ = "object"
141 #: The JSON/Swagger schema format
142 __schema_format__ = None
143 #: An optional JSON/Swagger schema example
144 __schema_example__ = None
146 def __init__(
147 self,
148 default=None,
149 attribute=None,
150 title=None,
151 description=None,
152 required=None,
153 readonly=None,
154 example=None,
155 mask=None,
156 **kwargs
157 ):
158 self.attribute = attribute
159 self.default = default
160 self.title = title
161 self.description = description
162 self.required = required
163 self.readonly = readonly
164 self.example = example if example is not None else self.__schema_example__
165 self.mask = mask
167 def format(self, value):
168 """
169 Formats a field's value. No-op by default - field classes that
170 modify how the value of existing object keys should be presented should
171 override this and apply the appropriate formatting.
173 :param value: The value to format
174 :raises MarshallingError: In case of formatting problem
176 Ex::
178 class TitleCase(Raw):
179 def format(self, value):
180 return unicode(value).title()
181 """
182 return value
184 def output(self, key, obj, **kwargs):
185 """
186 Pulls the value for the given key from the object, applies the
187 field's formatting and returns the result. If the key is not found
188 in the object, returns the default value. Field classes that create
189 values which do not require the existence of the key in the object
190 should override this and return the desired value.
192 :raises MarshallingError: In case of formatting problem
193 """
195 value = get_value(key if self.attribute is None else self.attribute, obj)
197 if value is None:
198 default = self._v("default")
199 return self.format(default) if default else default
201 try:
202 data = self.format(value)
203 except MarshallingError as e:
204 msg = 'Unable to marshal field "{0}" value "{1}": {2}'.format(
205 key, value, str(e)
206 )
207 raise MarshallingError(msg)
208 return self.mask.apply(data) if self.mask else data
210 def _v(self, key):
211 """Helper for getting a value from attribute allowing callable"""
212 value = getattr(self, key)
213 return value() if callable(value) else value
215 @cached_property
216 def __schema__(self):
217 return not_none(self.schema())
219 def schema(self):
220 return {
221 "type": self.__schema_type__,
222 "format": self.__schema_format__,
223 "title": self.title,
224 "description": self.description,
225 "readOnly": self.readonly,
226 "default": self._v("default"),
227 "example": self.example,
228 }
231class Nested(Raw):
232 """
233 Allows you to nest one set of fields inside another.
234 See :ref:`nested-field` for more information
236 :param dict model: The model dictionary to nest
237 :param bool allow_null: Whether to return None instead of a dictionary
238 with null keys, if a nested dictionary has all-null keys
239 :param bool skip_none: Optional key will be used to eliminate inner fields
240 which value is None or the inner field's key not
241 exist in data
242 :param kwargs: If ``default`` keyword argument is present, a nested
243 dictionary will be marshaled as its value if nested dictionary is
244 all-null keys (e.g. lets you return an empty JSON object instead of
245 null)
246 """
248 __schema_type__ = None
250 def __init__(
251 self, model, allow_null=False, skip_none=False, as_list=False, **kwargs
252 ):
253 self.model = model
254 self.as_list = as_list
255 self.allow_null = allow_null
256 self.skip_none = skip_none
257 super(Nested, self).__init__(**kwargs)
259 @property
260 def nested(self):
261 return getattr(self.model, "resolved", self.model)
263 def output(self, key, obj, ordered=False, **kwargs):
264 value = get_value(key if self.attribute is None else self.attribute, obj)
265 if value is None:
266 if self.allow_null:
267 return None
268 elif self.default is not None:
269 return self.default
271 return marshal(value, self.nested, skip_none=self.skip_none, ordered=ordered)
273 def schema(self):
274 schema = super(Nested, self).schema()
275 ref = "#/definitions/{0}".format(self.nested.name)
277 if self.as_list:
278 schema["type"] = "array"
279 schema["items"] = {"$ref": ref}
280 elif any(schema.values()):
281 # There is already some properties in the schema
282 allOf = schema.get("allOf", [])
283 allOf.append({"$ref": ref})
284 schema["allOf"] = allOf
285 else:
286 schema["$ref"] = ref
287 return schema
289 def clone(self, mask=None):
290 kwargs = self.__dict__.copy()
291 model = kwargs.pop("model")
292 if mask:
293 model = mask.apply(model.resolved if hasattr(model, "resolved") else model)
294 return self.__class__(model, **kwargs)
297class List(Raw):
298 """
299 Field for marshalling lists of other fields.
301 See :ref:`list-field` for more information.
303 :param cls_or_instance: The field type the list will contain.
304 """
306 def __init__(self, cls_or_instance, **kwargs):
307 self.min_items = kwargs.pop("min_items", None)
308 self.max_items = kwargs.pop("max_items", None)
309 self.unique = kwargs.pop("unique", None)
310 super(List, self).__init__(**kwargs)
311 error_msg = "The type of the list elements must be a subclass of fields.Raw"
312 if isinstance(cls_or_instance, type):
313 if not issubclass(cls_or_instance, Raw):
314 raise MarshallingError(error_msg)
315 self.container = cls_or_instance()
316 else:
317 if not isinstance(cls_or_instance, Raw):
318 raise MarshallingError(error_msg)
319 self.container = cls_or_instance
321 def format(self, value):
322 # Convert all instances in typed list to container type
323 if isinstance(value, set):
324 value = list(value)
326 is_nested = isinstance(self.container, Nested) or type(self.container) is Raw
328 def is_attr(val):
329 return self.container.attribute and hasattr(val, self.container.attribute)
331 if value is None:
332 return []
333 return [
334 self.container.output(
335 idx,
336 val
337 if (isinstance(val, dict) or is_attr(val)) and not is_nested
338 else value,
339 )
340 for idx, val in enumerate(value)
341 ]
343 def output(self, key, data, ordered=False, **kwargs):
344 value = get_value(key if self.attribute is None else self.attribute, data)
345 # we cannot really test for external dict behavior
346 if is_indexable_but_not_string(value) and not isinstance(value, dict):
347 return self.format(value)
349 if value is None:
350 return self._v("default")
352 return [marshal(value, self.container.nested)]
354 def schema(self):
355 schema = super(List, self).schema()
356 schema.update(
357 minItems=self._v("min_items"),
358 maxItems=self._v("max_items"),
359 uniqueItems=self._v("unique"),
360 )
361 schema["type"] = "array"
362 schema["items"] = self.container.__schema__
363 return schema
365 def clone(self, mask=None):
366 kwargs = self.__dict__.copy()
367 model = kwargs.pop("container")
368 if mask:
369 model = mask.apply(model)
370 return self.__class__(model, **kwargs)
373class StringMixin(object):
374 __schema_type__ = "string"
376 def __init__(self, *args, **kwargs):
377 self.min_length = kwargs.pop("min_length", None)
378 self.max_length = kwargs.pop("max_length", None)
379 self.pattern = kwargs.pop("pattern", None)
380 super(StringMixin, self).__init__(*args, **kwargs)
382 def schema(self):
383 schema = super(StringMixin, self).schema()
384 schema.update(
385 minLength=self._v("min_length"),
386 maxLength=self._v("max_length"),
387 pattern=self._v("pattern"),
388 )
389 return schema
392class MinMaxMixin(object):
393 def __init__(self, *args, **kwargs):
394 self.minimum = kwargs.pop("min", None)
395 self.exclusiveMinimum = kwargs.pop("exclusiveMin", None)
396 self.maximum = kwargs.pop("max", None)
397 self.exclusiveMaximum = kwargs.pop("exclusiveMax", None)
398 super(MinMaxMixin, self).__init__(*args, **kwargs)
400 def schema(self):
401 schema = super(MinMaxMixin, self).schema()
402 schema.update(
403 minimum=self._v("minimum"),
404 exclusiveMinimum=self._v("exclusiveMinimum"),
405 maximum=self._v("maximum"),
406 exclusiveMaximum=self._v("exclusiveMaximum"),
407 )
408 return schema
411class NumberMixin(MinMaxMixin):
412 __schema_type__ = "number"
414 def __init__(self, *args, **kwargs):
415 self.multiple = kwargs.pop("multiple", None)
416 super(NumberMixin, self).__init__(*args, **kwargs)
418 def schema(self):
419 schema = super(NumberMixin, self).schema()
420 schema.update(multipleOf=self._v("multiple"))
421 return schema
424class String(StringMixin, Raw):
425 """
426 Marshal a value as a string.
427 """
429 def __init__(self, *args, **kwargs):
430 self.enum = kwargs.pop("enum", None)
431 self.discriminator = kwargs.pop("discriminator", None)
432 super(String, self).__init__(*args, **kwargs)
433 self.required = self.discriminator or self.required
435 def format(self, value):
436 try:
437 return str(value)
438 except ValueError as ve:
439 raise MarshallingError(ve)
441 def schema(self):
442 enum = self._v("enum")
443 schema = super(String, self).schema()
444 if enum:
445 schema.update(enum=enum)
446 if enum and schema["example"] is None:
447 schema["example"] = enum[0]
448 return schema
451class Integer(NumberMixin, Raw):
452 """
453 Field for outputting an integer value.
455 :param int default: The default value for the field, if no value is specified.
456 """
458 __schema_type__ = "integer"
460 def format(self, value):
461 try:
462 if value is None:
463 return self.default
464 return int(value)
465 except (ValueError, TypeError) as ve:
466 raise MarshallingError(ve)
469class Float(NumberMixin, Raw):
470 """
471 A double as IEEE-754 double precision.
473 ex : 3.141592653589793 3.1415926535897933e-06 3.141592653589793e+24 nan inf -inf
474 """
476 def format(self, value):
477 try:
478 if value is None:
479 return self.default
480 return float(value)
481 except (ValueError, TypeError) as ve:
482 raise MarshallingError(ve)
485class Arbitrary(NumberMixin, Raw):
486 """
487 A floating point number with an arbitrary precision.
489 ex: 634271127864378216478362784632784678324.23432
490 """
492 def format(self, value):
493 return str(Decimal(value))
496ZERO = Decimal()
499class Fixed(NumberMixin, Raw):
500 """
501 A decimal number with a fixed precision.
502 """
504 def __init__(self, decimals=5, **kwargs):
505 super(Fixed, self).__init__(**kwargs)
506 self.precision = Decimal("0." + "0" * (decimals - 1) + "1")
508 def format(self, value):
509 dvalue = Decimal(value)
510 if not dvalue.is_normal() and dvalue != ZERO:
511 raise MarshallingError("Invalid Fixed precision number.")
512 return str(dvalue.quantize(self.precision, rounding=ROUND_HALF_EVEN))
515class Boolean(Raw):
516 """
517 Field for outputting a boolean value.
519 Empty collections such as ``""``, ``{}``, ``[]``, etc. will be converted to ``False``.
520 """
522 __schema_type__ = "boolean"
524 def format(self, value):
525 return boolean(value)
528class DateTime(MinMaxMixin, Raw):
529 """
530 Return a formatted datetime string in UTC. Supported formats are RFC 822 and ISO 8601.
532 See :func:`email.utils.formatdate` for more info on the RFC 822 format.
534 See :meth:`datetime.datetime.isoformat` for more info on the ISO 8601 format.
536 :param str dt_format: ``rfc822`` or ``iso8601``
537 """
539 __schema_type__ = "string"
540 __schema_format__ = "date-time"
542 def __init__(self, dt_format="iso8601", **kwargs):
543 super(DateTime, self).__init__(**kwargs)
544 self.dt_format = dt_format
546 def parse(self, value):
547 if value is None:
548 return None
549 elif isinstance(value, str):
550 parser = (
551 datetime_from_iso8601
552 if self.dt_format == "iso8601"
553 else datetime_from_rfc822
554 )
555 return parser(value)
556 elif isinstance(value, datetime):
557 return value
558 elif isinstance(value, date):
559 return datetime(value.year, value.month, value.day)
560 else:
561 raise ValueError("Unsupported DateTime format")
563 def format(self, value):
564 try:
565 value = self.parse(value)
566 if self.dt_format == "iso8601":
567 return self.format_iso8601(value)
568 elif self.dt_format == "rfc822":
569 return self.format_rfc822(value)
570 else:
571 raise MarshallingError("Unsupported date format %s" % self.dt_format)
572 except (AttributeError, ValueError) as e:
573 raise MarshallingError(e)
575 def format_rfc822(self, dt):
576 """
577 Turn a datetime object into a formatted date.
579 :param datetime dt: The datetime to transform
580 :return: A RFC 822 formatted date string
581 """
582 return formatdate(timegm(dt.utctimetuple()))
584 def format_iso8601(self, dt):
585 """
586 Turn a datetime object into an ISO8601 formatted date.
588 :param datetime dt: The datetime to transform
589 :return: A ISO 8601 formatted date string
590 """
591 return dt.isoformat()
593 def _for_schema(self, name):
594 value = self.parse(self._v(name))
595 return self.format(value) if value else None
597 def schema(self):
598 schema = super(DateTime, self).schema()
599 schema["default"] = self._for_schema("default")
600 schema["minimum"] = self._for_schema("minimum")
601 schema["maximum"] = self._for_schema("maximum")
602 return schema
605class Date(DateTime):
606 """
607 Return a formatted date string in UTC in ISO 8601.
609 See :meth:`datetime.date.isoformat` for more info on the ISO 8601 format.
610 """
612 __schema_format__ = "date"
614 def __init__(self, **kwargs):
615 kwargs.pop("dt_format", None)
616 super(Date, self).__init__(dt_format="iso8601", **kwargs)
618 def parse(self, value):
619 if value is None:
620 return None
621 elif isinstance(value, str):
622 return date_from_iso8601(value)
623 elif isinstance(value, datetime):
624 return value.date()
625 elif isinstance(value, date):
626 return value
627 else:
628 raise ValueError("Unsupported Date format")
631class Url(StringMixin, Raw):
632 """
633 A string representation of a Url
635 :param str endpoint: Endpoint name. If endpoint is ``None``, ``request.endpoint`` is used instead
636 :param bool absolute: If ``True``, ensures that the generated urls will have the hostname included
637 :param str scheme: URL scheme specifier (e.g. ``http``, ``https``)
638 """
640 def __init__(self, endpoint=None, absolute=False, scheme=None, **kwargs):
641 super(Url, self).__init__(**kwargs)
642 self.endpoint = endpoint
643 self.absolute = absolute
644 self.scheme = scheme
646 def output(self, key, obj, **kwargs):
647 try:
648 data = to_marshallable_type(obj)
649 endpoint = self.endpoint if self.endpoint is not None else request.endpoint
650 o = urlparse(url_for(endpoint, _external=self.absolute, **data))
651 if self.absolute:
652 scheme = self.scheme if self.scheme is not None else o.scheme
653 return urlunparse((scheme, o.netloc, o.path, "", "", ""))
654 return urlunparse(("", "", o.path, "", "", ""))
655 except TypeError as te:
656 raise MarshallingError(te)
659class FormattedString(StringMixin, Raw):
660 """
661 FormattedString is used to interpolate other values from
662 the response into this field. The syntax for the source string is
663 the same as the string :meth:`~str.format` method from the python
664 stdlib.
666 Ex::
668 fields = {
669 'name': fields.String,
670 'greeting': fields.FormattedString("Hello {name}")
671 }
672 data = {
673 'name': 'Doug',
674 }
675 marshal(data, fields)
677 :param str src_str: the string to format with the other values from the response.
678 """
680 def __init__(self, src_str, **kwargs):
681 super(FormattedString, self).__init__(**kwargs)
682 self.src_str = str(src_str)
684 def output(self, key, obj, **kwargs):
685 try:
686 data = to_marshallable_type(obj)
687 return self.src_str.format(**data)
688 except (TypeError, IndexError) as error:
689 raise MarshallingError(error)
692class ClassName(String):
693 """
694 Return the serialized object class name as string.
696 :param bool dash: If `True`, transform CamelCase to kebab_case.
697 """
699 def __init__(self, dash=False, **kwargs):
700 super(ClassName, self).__init__(**kwargs)
701 self.dash = dash
703 def output(self, key, obj, **kwargs):
704 classname = obj.__class__.__name__
705 if classname == "dict":
706 return "object"
707 return camel_to_dash(classname) if self.dash else classname
710class Polymorph(Nested):
711 """
712 A Nested field handling inheritance.
714 Allows you to specify a mapping between Python classes and fields specifications.
716 .. code-block:: python
718 mapping = {
719 Child1: child1_fields,
720 Child2: child2_fields,
721 }
723 fields = api.model('Thing', {
724 owner: fields.Polymorph(mapping)
725 })
727 :param dict mapping: Maps classes to their model/fields representation
728 """
730 def __init__(self, mapping, required=False, **kwargs):
731 self.mapping = mapping
732 parent = self.resolve_ancestor(list(mapping.values()))
733 super(Polymorph, self).__init__(parent, allow_null=not required, **kwargs)
735 def output(self, key, obj, ordered=False, **kwargs):
736 # Copied from upstream NestedField
737 value = get_value(key if self.attribute is None else self.attribute, obj)
738 if value is None:
739 if self.allow_null:
740 return None
741 elif self.default is not None:
742 return self.default
744 # Handle mappings
745 if not hasattr(value, "__class__"):
746 raise ValueError("Polymorph field only accept class instances")
748 candidates = [
749 fields for cls, fields in self.mapping.items() if type(value) == cls
750 ]
752 if len(candidates) <= 0:
753 raise ValueError("Unknown class: " + value.__class__.__name__)
754 elif len(candidates) > 1:
755 raise ValueError(
756 "Unable to determine a candidate for: " + value.__class__.__name__
757 )
758 else:
759 return marshal(
760 value, candidates[0].resolved, mask=self.mask, ordered=ordered
761 )
763 def resolve_ancestor(self, models):
764 """
765 Resolve the common ancestor for all models.
767 Assume there is only one common ancestor.
768 """
769 ancestors = [m.ancestors for m in models]
770 candidates = set.intersection(*ancestors)
771 if len(candidates) != 1:
772 field_names = [f.name for f in models]
773 raise ValueError(
774 "Unable to determine the common ancestor for: " + ", ".join(field_names)
775 )
777 parent_name = candidates.pop()
778 return models[0].get_parent(parent_name)
780 def clone(self, mask=None):
781 data = self.__dict__.copy()
782 mapping = data.pop("mapping")
783 for field in ("allow_null", "model"):
784 data.pop(field, None)
786 data["mask"] = mask
787 return Polymorph(mapping, **data)
790class Wildcard(Raw):
791 """
792 Field for marshalling list of "unkown" fields.
794 :param cls_or_instance: The field type the list will contain.
795 """
797 exclude = set()
798 # cache the flat object
799 _flat = None
800 _obj = None
801 _cache = set()
802 _last = None
804 def __init__(self, cls_or_instance, **kwargs):
805 super(Wildcard, self).__init__(**kwargs)
806 error_msg = "The type of the wildcard elements must be a subclass of fields.Raw"
807 if isinstance(cls_or_instance, type):
808 if not issubclass(cls_or_instance, Raw):
809 raise MarshallingError(error_msg)
810 self.container = cls_or_instance()
811 else:
812 if not isinstance(cls_or_instance, Raw):
813 raise MarshallingError(error_msg)
814 self.container = cls_or_instance
816 def _flatten(self, obj):
817 if obj is None:
818 return None
819 if obj == self._obj and self._flat is not None:
820 return self._flat
821 if isinstance(obj, dict):
822 self._flat = [x for x in obj.items()]
823 else:
825 def __match_attributes(attribute):
826 attr_name, attr_obj = attribute
827 if inspect.isroutine(attr_obj) or (
828 attr_name.startswith("__") and attr_name.endswith("__")
829 ):
830 return False
831 return True
833 attributes = inspect.getmembers(obj)
834 self._flat = [x for x in attributes if __match_attributes(x)]
836 self._cache = set()
837 self._obj = obj
838 return self._flat
840 @property
841 def key(self):
842 return self._last
844 def reset(self):
845 self.exclude = set()
846 self._flat = None
847 self._obj = None
848 self._cache = set()
849 self._last = None
851 def output(self, key, obj, ordered=False):
852 value = None
853 reg = fnmatch.translate(key)
855 if self._flatten(obj):
856 while True:
857 try:
858 # we are using pop() so that we don't
859 # loop over the whole object every time dropping the
860 # complexity to O(n)
861 if ordered:
862 # Get first element if respecting order
863 (objkey, val) = self._flat.pop(0)
864 else:
865 # Previous default retained
866 (objkey, val) = self._flat.pop()
867 if (
868 objkey not in self._cache
869 and objkey not in self.exclude
870 and re.match(reg, objkey, re.IGNORECASE)
871 ):
872 value = val
873 self._cache.add(objkey)
874 self._last = objkey
875 break
876 except IndexError:
877 break
879 if value is None:
880 if self.default is not None:
881 return self.container.format(self.default)
882 return None
884 if isinstance(self.container, Nested):
885 return marshal(
886 value,
887 self.container.nested,
888 skip_none=self.container.skip_none,
889 ordered=ordered,
890 )
891 return self.container.format(value)
893 def schema(self):
894 schema = super(Wildcard, self).schema()
895 schema["type"] = "object"
896 schema["additionalProperties"] = self.container.__schema__
897 return schema
899 def clone(self):
900 kwargs = self.__dict__.copy()
901 model = kwargs.pop("container")
902 return self.__class__(model, **kwargs)