schema.py 47 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163
  1. # -*- coding: utf-8 -*-
  2. """The :class:`Schema` class, including its metaclass and options (class Meta)."""
  3. from __future__ import absolute_import, unicode_literals
  4. from collections import defaultdict, OrderedDict
  5. import datetime as dt
  6. import uuid
  7. import decimal
  8. import functools
  9. import copy
  10. import inspect
  11. import json
  12. import warnings
  13. from marshmallow import base, fields as ma_fields, class_registry
  14. from marshmallow.error_store import ErrorStore
  15. from marshmallow.fields import Nested
  16. from marshmallow.compat import iteritems, iterkeys, with_metaclass, text_type, binary_type, Mapping
  17. from marshmallow.exceptions import ValidationError, StringNotCollectionError
  18. from marshmallow.orderedset import OrderedSet
  19. from marshmallow.decorators import (
  20. POST_DUMP,
  21. POST_LOAD,
  22. PRE_DUMP,
  23. PRE_LOAD,
  24. VALIDATES,
  25. VALIDATES_SCHEMA,
  26. )
  27. from marshmallow.utils import (
  28. RAISE, EXCLUDE, INCLUDE, missing, set_value, get_value,
  29. is_collection, is_instance_or_subclass, is_iterable_but_not_string,
  30. )
  31. def _get_fields(attrs, field_class, pop=False, ordered=False):
  32. """Get fields from a class. If ordered=True, fields will sorted by creation index.
  33. :param attrs: Mapping of class attributes
  34. :param type field_class: Base field class
  35. :param bool pop: Remove matching fields
  36. """
  37. fields = [
  38. (field_name, field_value)
  39. for field_name, field_value in iteritems(attrs)
  40. if is_instance_or_subclass(field_value, field_class)
  41. ]
  42. if pop:
  43. for field_name, _ in fields:
  44. del attrs[field_name]
  45. if ordered:
  46. fields.sort(key=lambda pair: pair[1]._creation_index)
  47. return fields
  48. # This function allows Schemas to inherit from non-Schema classes and ensures
  49. # inheritance according to the MRO
  50. def _get_fields_by_mro(klass, field_class, ordered=False):
  51. """Collect fields from a class, following its method resolution order. The
  52. class itself is excluded from the search; only its parents are checked. Get
  53. fields from ``_declared_fields`` if available, else use ``__dict__``.
  54. :param type klass: Class whose fields to retrieve
  55. :param type field_class: Base field class
  56. """
  57. mro = inspect.getmro(klass)
  58. # Loop over mro in reverse to maintain correct order of fields
  59. return sum(
  60. (
  61. _get_fields(
  62. getattr(base, '_declared_fields', base.__dict__),
  63. field_class,
  64. ordered=ordered,
  65. )
  66. for base in mro[:0:-1]
  67. ),
  68. [],
  69. )
  70. class SchemaMeta(type):
  71. """Metaclass for the Schema class. Binds the declared fields to
  72. a ``_declared_fields`` attribute, which is a dictionary mapping attribute
  73. names to field objects. Also sets the ``opts`` class attribute, which is
  74. the Schema class's ``class Meta`` options.
  75. """
  76. def __new__(mcs, name, bases, attrs):
  77. meta = attrs.get('Meta')
  78. ordered = getattr(meta, 'ordered', False)
  79. if not ordered:
  80. # Inherit 'ordered' option
  81. # Warning: We loop through bases instead of MRO because we don't
  82. # yet have access to the class object
  83. # (i.e. can't call super before we have fields)
  84. for base_ in bases:
  85. if hasattr(base_, 'Meta') and hasattr(base_.Meta, 'ordered'):
  86. ordered = base_.Meta.ordered
  87. break
  88. else:
  89. ordered = False
  90. cls_fields = _get_fields(attrs, base.FieldABC, pop=True, ordered=ordered)
  91. klass = super(SchemaMeta, mcs).__new__(mcs, name, bases, attrs)
  92. inherited_fields = _get_fields_by_mro(klass, base.FieldABC, ordered=ordered)
  93. # Use getattr rather than attrs['Meta'] so that we get inheritance for free
  94. meta = getattr(klass, 'Meta')
  95. # Set klass.opts in __new__ rather than __init__ so that it is accessible in
  96. # get_declared_fields
  97. klass.opts = klass.OPTIONS_CLASS(meta, ordered=ordered)
  98. # Add fields specifid in the `include` class Meta option
  99. cls_fields += list(klass.opts.include.items())
  100. dict_cls = OrderedDict if ordered else dict
  101. # Assign _declared_fields on class
  102. klass._declared_fields = mcs.get_declared_fields(
  103. klass=klass,
  104. cls_fields=cls_fields,
  105. inherited_fields=inherited_fields,
  106. dict_cls=dict_cls,
  107. )
  108. return klass
  109. @classmethod
  110. def get_declared_fields(mcs, klass, cls_fields, inherited_fields, dict_cls):
  111. """Returns a dictionary of field_name => `Field` pairs declard on the class.
  112. This is exposed mainly so that plugins can add additional fields, e.g. fields
  113. computed from class Meta options.
  114. :param type klass: The class object.
  115. :param dict cls_fields: The fields declared on the class, including those added
  116. by the ``include`` class Meta option.
  117. :param dict inherited_fileds: Inherited fields.
  118. :param type dict_class: Either `dict` or `OrderedDict`, depending on the whether
  119. the user specified `ordered=True`.
  120. """
  121. return dict_cls(inherited_fields + cls_fields)
  122. # NOTE: self is the class object
  123. def __init__(self, name, bases, attrs):
  124. super(SchemaMeta, self).__init__(name, bases, attrs)
  125. if name and self.opts.register:
  126. class_registry.register(name, self)
  127. self._hooks = self.resolve_hooks()
  128. def resolve_hooks(self):
  129. """Add in the decorated processors
  130. By doing this after constructing the class, we let standard inheritance
  131. do all the hard work.
  132. """
  133. mro = inspect.getmro(self)
  134. hooks = defaultdict(list)
  135. for attr_name in dir(self):
  136. # Need to look up the actual descriptor, not whatever might be
  137. # bound to the class. This needs to come from the __dict__ of the
  138. # declaring class.
  139. for parent in mro:
  140. try:
  141. attr = parent.__dict__[attr_name]
  142. except KeyError:
  143. continue
  144. else:
  145. break
  146. else:
  147. # In case we didn't find the attribute and didn't break above.
  148. # We should never hit this - it's just here for completeness
  149. # to exclude the possibility of attr being undefined.
  150. continue
  151. try:
  152. hook_config = attr.__marshmallow_hook__
  153. except AttributeError:
  154. pass
  155. else:
  156. for key in iterkeys(hook_config):
  157. # Use name here so we can get the bound method later, in
  158. # case the processor was a descriptor or something.
  159. hooks[key].append(attr_name)
  160. return hooks
  161. class SchemaOpts(object):
  162. """class Meta options for the :class:`Schema`. Defines defaults."""
  163. def __init__(self, meta, ordered=False):
  164. self.fields = getattr(meta, 'fields', ())
  165. if not isinstance(self.fields, (list, tuple)):
  166. raise ValueError('`fields` option must be a list or tuple.')
  167. self.additional = getattr(meta, 'additional', ())
  168. if not isinstance(self.additional, (list, tuple)):
  169. raise ValueError('`additional` option must be a list or tuple.')
  170. if self.fields and self.additional:
  171. raise ValueError(
  172. 'Cannot set both `fields` and `additional` options'
  173. ' for the same Schema.',
  174. )
  175. self.exclude = getattr(meta, 'exclude', ())
  176. if not isinstance(self.exclude, (list, tuple)):
  177. raise ValueError('`exclude` must be a list or tuple.')
  178. self.dateformat = getattr(meta, 'dateformat', None)
  179. self.datetimeformat = getattr(meta, 'datetimeformat', None)
  180. if hasattr(meta, 'json_module'):
  181. warnings.warn(
  182. 'The json_module class Meta option is deprecated. Use render_module instead.',
  183. DeprecationWarning,
  184. )
  185. render_module = getattr(meta, 'json_module', json)
  186. else:
  187. render_module = json
  188. self.render_module = getattr(meta, 'render_module', render_module)
  189. self.ordered = getattr(meta, 'ordered', ordered)
  190. self.index_errors = getattr(meta, 'index_errors', True)
  191. self.include = getattr(meta, 'include', {})
  192. self.load_only = getattr(meta, 'load_only', ())
  193. self.dump_only = getattr(meta, 'dump_only', ())
  194. self.unknown = getattr(meta, 'unknown', RAISE)
  195. self.register = getattr(meta, 'register', True)
  196. class BaseSchema(base.SchemaABC):
  197. """Base schema class with which to define custom schemas.
  198. Example usage:
  199. .. code-block:: python
  200. import datetime as dt
  201. from marshmallow import Schema, fields
  202. class Album(object):
  203. def __init__(self, title, release_date):
  204. self.title = title
  205. self.release_date = release_date
  206. class AlbumSchema(Schema):
  207. title = fields.Str()
  208. release_date = fields.Date()
  209. # Or, equivalently
  210. class AlbumSchema2(Schema):
  211. class Meta:
  212. fields = ("title", "release_date")
  213. album = Album("Beggars Banquet", dt.date(1968, 12, 6))
  214. schema = AlbumSchema()
  215. data = schema.dump(album)
  216. data # {'release_date': '1968-12-06', 'title': 'Beggars Banquet'}
  217. :param tuple|list only: Whitelist of the declared fields to select when
  218. instantiating the Schema. If None, all fields are used. Nested fields
  219. can be represented with dot delimiters.
  220. :param tuple|list exclude: Blacklist of the declared fields to exclude
  221. when instantiating the Schema. If a field appears in both `only` and
  222. `exclude`, it is not used. Nested fields can be represented with dot
  223. delimiters.
  224. :param bool many: Should be set to `True` if ``obj`` is a collection
  225. so that the object will be serialized to a list.
  226. :param dict context: Optional context passed to :class:`fields.Method` and
  227. :class:`fields.Function` fields.
  228. :param tuple|list load_only: Fields to skip during serialization (write-only fields)
  229. :param tuple|list dump_only: Fields to skip during deserialization (read-only fields)
  230. :param bool|tuple partial: Whether to ignore missing fields and not require
  231. any fields declared. Propagates down to ``Nested`` fields as well. If
  232. its value is an iterable, only missing fields listed in that iterable
  233. will be ignored. Use dot delimiters to specify nested fields.
  234. :param unknown: Whether to exclude, include, or raise an error for unknown
  235. fields in the data. Use `EXCLUDE`, `INCLUDE` or `RAISE`.
  236. .. versionchanged:: 3.0.0
  237. `prefix` parameter removed.
  238. .. versionchanged:: 2.0.0
  239. `__validators__`, `__preprocessors__`, and `__data_handlers__` are removed in favor of
  240. `marshmallow.decorators.validates_schema`,
  241. `marshmallow.decorators.pre_load` and `marshmallow.decorators.post_dump`.
  242. `__accessor__` and `__error_handler__` are deprecated. Implement the
  243. `handle_error` and `get_attribute` methods instead.
  244. """
  245. TYPE_MAPPING = {
  246. text_type: ma_fields.String,
  247. binary_type: ma_fields.String,
  248. dt.datetime: ma_fields.DateTime,
  249. float: ma_fields.Float,
  250. bool: ma_fields.Boolean,
  251. tuple: ma_fields.Raw,
  252. list: ma_fields.Raw,
  253. set: ma_fields.Raw,
  254. int: ma_fields.Integer,
  255. uuid.UUID: ma_fields.UUID,
  256. dt.time: ma_fields.Time,
  257. dt.date: ma_fields.Date,
  258. dt.timedelta: ma_fields.TimeDelta,
  259. decimal.Decimal: ma_fields.Decimal,
  260. }
  261. #: Overrides for default schema-level error messages
  262. error_messages = {}
  263. _default_error_messages = {
  264. 'type': 'Invalid input type.',
  265. 'unknown': 'Unknown field.',
  266. }
  267. OPTIONS_CLASS = SchemaOpts
  268. class Meta(object):
  269. """Options object for a Schema.
  270. Example usage: ::
  271. class Meta:
  272. fields = ("id", "email", "date_created")
  273. exclude = ("password", "secret_attribute")
  274. Available options:
  275. - ``fields``: Tuple or list of fields to include in the serialized result.
  276. - ``additional``: Tuple or list of fields to include *in addition* to the
  277. explicitly declared fields. ``additional`` and ``fields`` are
  278. mutually-exclusive options.
  279. - ``include``: Dictionary of additional fields to include in the schema. It is
  280. usually better to define fields as class variables, but you may need to
  281. use this option, e.g., if your fields are Python keywords. May be an
  282. `OrderedDict`.
  283. - ``exclude``: Tuple or list of fields to exclude in the serialized result.
  284. Nested fields can be represented with dot delimiters.
  285. - ``dateformat``: Date format for all DateTime fields that do not have their
  286. date format explicitly specified.
  287. - ``render_module``: Module to use for `loads` and `dumps`. Defaults to
  288. `json` from the standard library.
  289. - ``ordered``: If `True`, order serialization output according to the
  290. order in which fields were declared. Output of `Schema.dump` will be a
  291. `collections.OrderedDict`.
  292. - ``index_errors``: If `True`, errors dictionaries will include the index
  293. of invalid items in a collection.
  294. - ``load_only``: Tuple or list of fields to exclude from serialized results.
  295. - ``dump_only``: Tuple or list of fields to exclude from deserialization
  296. - ``unknown``: Whether to exclude, include, or raise an error for unknown
  297. fields in the data. Use `EXCLUDE`, `INCLUDE` or `RAISE`.
  298. - ``register``: Whether to register the `Schema` with marshmallow's internal
  299. class registry. Must be `True` if you intend to refer to this `Schema`
  300. by class name in `Nested` fields. Only set this to `False` when memory
  301. usage is critical. Defaults to `True`.
  302. """
  303. pass
  304. def __init__(
  305. self, only=None, exclude=(), many=False, context=None,
  306. load_only=(), dump_only=(), partial=False, unknown=None,
  307. ):
  308. # Raise error if only or exclude is passed as string, not list of strings
  309. if only is not None and not is_collection(only):
  310. raise StringNotCollectionError('"only" should be a list of strings')
  311. if exclude is not None and not is_collection(exclude):
  312. raise StringNotCollectionError('"exclude" should be a list of strings')
  313. # copy declared fields from metaclass
  314. self.declared_fields = copy.deepcopy(self._declared_fields)
  315. self.many = many
  316. self.only = only
  317. self.exclude = exclude
  318. self.ordered = self.opts.ordered
  319. self.load_only = set(load_only) or set(self.opts.load_only)
  320. self.dump_only = set(dump_only) or set(self.opts.dump_only)
  321. self.partial = partial
  322. self.unknown = unknown or self.opts.unknown
  323. self.context = context or {}
  324. self._normalize_nested_options()
  325. #: Dictionary mapping field_names -> :class:`Field` objects
  326. self.fields = self._init_fields()
  327. messages = {}
  328. messages.update(self._default_error_messages)
  329. for cls in reversed(self.__class__.__mro__):
  330. messages.update(getattr(cls, 'error_messages', {}))
  331. messages.update(self.error_messages or {})
  332. self.error_messages = messages
  333. def __repr__(self):
  334. return '<{ClassName}(many={self.many})>'.format(
  335. ClassName=self.__class__.__name__, self=self,
  336. )
  337. @property
  338. def dict_class(self):
  339. return OrderedDict if self.ordered else dict
  340. @property
  341. def set_class(self):
  342. return OrderedSet if self.ordered else set
  343. ##### Override-able methods #####
  344. def handle_error(self, error, data):
  345. """Custom error handler function for the schema.
  346. :param ValidationError error: The `ValidationError` raised during (de)serialization.
  347. :param data: The original input data.
  348. .. versionadded:: 2.0.0
  349. """
  350. pass
  351. def get_attribute(self, obj, attr, default):
  352. """Defines how to pull values from an object to serialize.
  353. .. versionadded:: 2.0.0
  354. .. versionchanged:: 3.0.0a1
  355. Changed position of ``obj`` and ``attr``.
  356. """
  357. return get_value(obj, attr, default)
  358. ##### Serialization/Deserialization API #####
  359. @staticmethod
  360. def _call_and_store(getter_func, data, field_name, error_store, index=None):
  361. """Call ``getter_func`` with ``data`` as its argument, and store any `ValidationErrors`.
  362. :param callable getter_func: Function for getting the serialized/deserialized
  363. value from ``data``.
  364. :param data: The data passed to ``getter_func``.
  365. :param str field_name: Field name.
  366. :param int index: Index of the item being validated, if validating a collection,
  367. otherwise `None`.
  368. """
  369. try:
  370. value = getter_func(data)
  371. except ValidationError as err:
  372. error_store.store_error(err.messages, field_name, index=index)
  373. # When a Nested field fails validation, the marshalled data is stored
  374. # on the ValidationError's valid_data attribute
  375. return err.valid_data or missing
  376. return value
  377. def _serialize(
  378. self, obj, fields_dict, error_store, many=False,
  379. accessor=None, dict_class=dict, index_errors=True,
  380. index=None,
  381. ):
  382. """Takes raw data (a dict, list, or other object) and a dict of
  383. fields to output and serializes the data based on those fields.
  384. :param obj: The actual object(s) from which the fields are taken from
  385. :param dict fields_dict: Mapping of field names to :class:`Field` objects.
  386. :param ErrorStore error_store: Structure to store errors.
  387. :param bool many: Set to `True` if ``data`` should be serialized as
  388. a collection.
  389. :param callable accessor: Function to use for getting values from ``obj``.
  390. :param type dict_class: Dictionary class used to construct the output.
  391. :param bool index_errors: Whether to store the index of invalid items in
  392. ``self.errors`` when ``many=True``.
  393. :param int index: Index of the item being serialized (for storing errors) if
  394. serializing a collection, otherwise `None`.
  395. :return: A dictionary of the marshalled data
  396. .. versionchanged:: 1.0.0
  397. Renamed from ``marshal``.
  398. """
  399. index = index if index_errors else None
  400. if many and obj is not None:
  401. self._pending = True
  402. ret = [
  403. self._serialize(
  404. d, fields_dict, error_store, many=False,
  405. dict_class=dict_class, accessor=accessor,
  406. index=idx, index_errors=index_errors,
  407. )
  408. for idx, d in enumerate(obj)
  409. ]
  410. self._pending = False
  411. return ret
  412. items = []
  413. for attr_name, field_obj in iteritems(fields_dict):
  414. if getattr(field_obj, 'load_only', False):
  415. continue
  416. key = field_obj.data_key or attr_name
  417. getter = lambda d: field_obj.serialize(attr_name, d, accessor=accessor)
  418. value = self._call_and_store(
  419. getter_func=getter,
  420. data=obj,
  421. field_name=key,
  422. error_store=error_store,
  423. index=index,
  424. )
  425. if value is missing:
  426. continue
  427. items.append((key, value))
  428. ret = dict_class(items)
  429. return ret
  430. def dump(self, obj, many=None):
  431. """Serialize an object to native Python data types according to this
  432. Schema's fields.
  433. :param obj: The object to serialize.
  434. :param bool many: Whether to serialize `obj` as a collection. If `None`, the value
  435. for `self.many` is used.
  436. :return: A dict of serialized data
  437. :rtype: dict
  438. .. versionadded:: 1.0.0
  439. .. versionchanged:: 3.0.0b7
  440. This method returns the serialized data rather than a ``(data, errors)`` duple.
  441. A :exc:`ValidationError <marshmallow.exceptions.ValidationError>` is raised
  442. if ``obj`` is invalid.
  443. """
  444. error_store = ErrorStore()
  445. errors = {}
  446. many = self.many if many is None else bool(many)
  447. if many and is_iterable_but_not_string(obj):
  448. obj = list(obj)
  449. if self._has_processors(PRE_DUMP):
  450. try:
  451. processed_obj = self._invoke_dump_processors(
  452. PRE_DUMP,
  453. obj,
  454. many,
  455. original_data=obj,
  456. )
  457. except ValidationError as error:
  458. errors = error.normalized_messages()
  459. result = None
  460. else:
  461. processed_obj = obj
  462. if not errors:
  463. result = self._serialize(
  464. processed_obj,
  465. self.fields,
  466. error_store,
  467. many=many,
  468. accessor=self.get_attribute,
  469. dict_class=self.dict_class,
  470. index_errors=self.opts.index_errors,
  471. )
  472. errors = error_store.errors
  473. if not errors and self._has_processors(POST_DUMP):
  474. try:
  475. result = self._invoke_dump_processors(
  476. POST_DUMP,
  477. result,
  478. many,
  479. original_data=obj,
  480. )
  481. except ValidationError as error:
  482. errors = error.normalized_messages()
  483. if errors:
  484. exc = ValidationError(
  485. errors,
  486. data=obj,
  487. valid_data=result,
  488. )
  489. # User-defined error handler
  490. self.handle_error(exc, obj)
  491. raise exc
  492. return result
  493. def dumps(self, obj, many=None, *args, **kwargs):
  494. """Same as :meth:`dump`, except return a JSON-encoded string.
  495. :param obj: The object to serialize.
  496. :param bool many: Whether to serialize `obj` as a collection. If `None`, the value
  497. for `self.many` is used.
  498. :return: A ``json`` string
  499. :rtype: str
  500. .. versionadded:: 1.0.0
  501. .. versionchanged:: 3.0.0b7
  502. This method returns the serialized data rather than a ``(data, errors)`` duple.
  503. A :exc:`ValidationError <marshmallow.exceptions.ValidationError>` is raised
  504. if ``obj`` is invalid.
  505. """
  506. serialized = self.dump(obj, many=many)
  507. return self.opts.render_module.dumps(serialized, *args, **kwargs)
  508. def _deserialize(
  509. self, data, fields_dict, error_store, many=False, partial=False,
  510. unknown=RAISE, dict_class=dict, index_errors=True, index=None,
  511. ):
  512. """Deserialize ``data`` based on the schema defined by ``fields_dict``.
  513. :param dict data: The data to deserialize.
  514. :param dict fields_dict: Mapping of field names to :class:`Field` objects.
  515. :param ErrorStore error_store: Structure to store errors.
  516. :param bool many: Set to `True` if ``data`` should be deserialized as
  517. a collection.
  518. :param bool|tuple partial: Whether to ignore missing fields and not require
  519. any fields declared. Propagates down to ``Nested`` fields as well. If
  520. its value is an iterable, only missing fields listed in that iterable
  521. will be ignored. Use dot delimiters to specify nested fields.
  522. :param unknown: Whether to exclude, include, or raise an error for unknown
  523. fields in the data. Use `EXCLUDE`, `INCLUDE` or `RAISE`.
  524. :param type dict_class: Dictionary class used to construct the output.
  525. :param bool index_errors: Whether to store the index of invalid items in
  526. ``self.errors`` when ``many=True``.
  527. :param int index: Index of the item being serialized (for storing errors) if
  528. serializing a collection, otherwise `None`.
  529. :return: A dictionary of the deserialized data.
  530. """
  531. index = index if index_errors else None
  532. if many:
  533. if not is_collection(data):
  534. error_store.store_error([self.error_messages['type']], index=index)
  535. ret = []
  536. else:
  537. self._pending = True
  538. ret = [
  539. self._deserialize(
  540. d, fields_dict, error_store, many=False,
  541. partial=partial, unknown=unknown,
  542. dict_class=dict_class, index=idx,
  543. index_errors=index_errors,
  544. )
  545. for idx, d in enumerate(data)
  546. ]
  547. self._pending = False
  548. return ret
  549. ret = dict_class()
  550. # Check data is a dict
  551. if not isinstance(data, Mapping):
  552. error_store.store_error([self.error_messages['type']], index=index)
  553. else:
  554. partial_is_collection = is_collection(partial)
  555. for attr_name, field_obj in iteritems(fields_dict):
  556. if field_obj.dump_only:
  557. continue
  558. field_name = attr_name
  559. if field_obj.data_key:
  560. field_name = field_obj.data_key
  561. raw_value = data.get(field_name, missing)
  562. if raw_value is missing:
  563. # Ignore missing field if we're allowed to.
  564. if (
  565. partial is True or
  566. (partial_is_collection and attr_name in partial)
  567. ):
  568. continue
  569. d_kwargs = {}
  570. if isinstance(field_obj, Nested):
  571. # Allow partial loading of nested schemas.
  572. if partial_is_collection:
  573. prefix = field_name + '.'
  574. len_prefix = len(prefix)
  575. sub_partial = [f[len_prefix:]
  576. for f in partial if f.startswith(prefix)]
  577. else:
  578. sub_partial = partial
  579. d_kwargs['partial'] = sub_partial
  580. getter = lambda val: field_obj.deserialize(
  581. val, field_name,
  582. data, **d_kwargs
  583. )
  584. value = self._call_and_store(
  585. getter_func=getter,
  586. data=raw_value,
  587. field_name=field_name,
  588. error_store=error_store,
  589. index=index,
  590. )
  591. if value is not missing:
  592. key = fields_dict[attr_name].attribute or attr_name
  593. set_value(ret, key, value)
  594. if unknown != EXCLUDE:
  595. fields = {
  596. field_obj.data_key or field_name
  597. for field_name, field_obj in fields_dict.items()
  598. if not field_obj.dump_only
  599. }
  600. for key in set(data) - fields:
  601. value = data[key]
  602. if unknown == INCLUDE:
  603. set_value(ret, key, value)
  604. elif unknown == RAISE:
  605. error_store.store_error(
  606. [self.error_messages['unknown']],
  607. key,
  608. (index if index_errors else None),
  609. )
  610. return ret
  611. def load(self, data, many=None, partial=None, unknown=None):
  612. """Deserialize a data structure to an object defined by this Schema's fields.
  613. :param dict data: The data to deserialize.
  614. :param bool many: Whether to deserialize `data` as a collection. If `None`, the
  615. value for `self.many` is used.
  616. :param bool|tuple partial: Whether to ignore missing fields and not require
  617. any fields declared. Propagates down to ``Nested`` fields as well. If
  618. its value is an iterable, only missing fields listed in that iterable
  619. will be ignored. Use dot delimiters to specify nested fields.
  620. :param unknown: Whether to exclude, include, or raise an error for unknown
  621. fields in the data. Use `EXCLUDE`, `INCLUDE` or `RAISE`.
  622. If `None`, the value for `self.unknown` is used.
  623. :return: A dict of deserialized data
  624. :rtype: dict
  625. .. versionadded:: 1.0.0
  626. .. versionchanged:: 3.0.0b7
  627. This method returns the deserialized data rather than a ``(data, errors)`` duple.
  628. A :exc:`ValidationError <marshmallow.exceptions.ValidationError>` is raised
  629. if invalid data are passed.
  630. """
  631. return self._do_load(
  632. data, many, partial=partial, unknown=unknown,
  633. postprocess=True,
  634. )
  635. def loads(
  636. self, json_data, many=None, partial=None, unknown=None,
  637. **kwargs
  638. ):
  639. """Same as :meth:`load`, except it takes a JSON string as input.
  640. :param str json_data: A JSON string of the data to deserialize.
  641. :param bool many: Whether to deserialize `obj` as a collection. If `None`, the
  642. value for `self.many` is used.
  643. :param bool|tuple partial: Whether to ignore missing fields and not require
  644. any fields declared. Propagates down to ``Nested`` fields as well. If
  645. its value is an iterable, only missing fields listed in that iterable
  646. will be ignored. Use dot delimiters to specify nested fields.
  647. :param unknown: Whether to exclude, include, or raise an error for unknown
  648. fields in the data. Use `EXCLUDE`, `INCLUDE` or `RAISE`.
  649. If `None`, the value for `self.unknown` is used.
  650. :return: A dict of deserialized data
  651. :rtype: dict
  652. .. versionadded:: 1.0.0
  653. .. versionchanged:: 3.0.0b7
  654. This method returns the deserialized data rather than a ``(data, errors)`` duple.
  655. A :exc:`ValidationError <marshmallow.exceptions.ValidationError>` is raised
  656. if invalid data are passed.
  657. """
  658. data = self.opts.render_module.loads(json_data, **kwargs)
  659. return self.load(data, many=many, partial=partial, unknown=unknown)
  660. def _run_validator(
  661. self, validator_func, output,
  662. original_data, fields_dict, error_store, index=None,
  663. many=False, pass_original=False,
  664. ):
  665. try:
  666. if pass_original: # Pass original, raw data (before unmarshalling)
  667. validator_func(output, original_data)
  668. else:
  669. validator_func(output)
  670. except ValidationError as err:
  671. error_store.store_error(err.messages, err.field_name, index=index)
  672. def validate(self, data, many=None, partial=None):
  673. """Validate `data` against the schema, returning a dictionary of
  674. validation errors.
  675. :param dict data: The data to validate.
  676. :param bool many: Whether to validate `data` as a collection. If `None`, the
  677. value for `self.many` is used.
  678. :param bool|tuple partial: Whether to ignore missing fields and not require
  679. any fields declared. Propagates down to ``Nested`` fields as well. If
  680. its value is an iterable, only missing fields listed in that iterable
  681. will be ignored. Use dot delimiters to specify nested fields.
  682. :return: A dictionary of validation errors.
  683. :rtype: dict
  684. .. versionadded:: 1.1.0
  685. """
  686. try:
  687. self._do_load(data, many, partial=partial, postprocess=False)
  688. except ValidationError as exc:
  689. return exc.messages
  690. return {}
  691. ##### Private Helpers #####
  692. def _do_load(
  693. self, data, many=None, partial=None, unknown=None,
  694. postprocess=True,
  695. ):
  696. """Deserialize `data`, returning the deserialized result.
  697. :param data: The data to deserialize.
  698. :param bool many: Whether to deserialize `data` as a collection. If `None`, the
  699. value for `self.many` is used.
  700. :param bool|tuple partial: Whether to validate required fields. If its value is an iterable,
  701. only fields listed in that iterable will be ignored will be allowed missing.
  702. If `True`, all fields will be allowed missing.
  703. If `None`, the value for `self.partial` is used.
  704. :param unknown: Whether to exclude, include, or raise an error for unknown
  705. fields in the data. Use `EXCLUDE`, `INCLUDE` or `RAISE`.
  706. If `None`, the value for `self.unknown` is used.
  707. :param bool postprocess: Whether to run post_load methods..
  708. :return: A dict of deserialized data
  709. :rtype: dict
  710. """
  711. error_store = ErrorStore()
  712. errors = {}
  713. many = self.many if many is None else bool(many)
  714. unknown = unknown or self.unknown
  715. if partial is None:
  716. partial = self.partial
  717. # Run preprocessors
  718. if self._has_processors(PRE_LOAD):
  719. try:
  720. processed_data = self._invoke_load_processors(
  721. PRE_LOAD,
  722. data,
  723. many,
  724. original_data=data,
  725. )
  726. except ValidationError as err:
  727. errors = err.normalized_messages()
  728. result = None
  729. else:
  730. processed_data = data
  731. if not errors:
  732. # Deserialize data
  733. result = self._deserialize(
  734. processed_data,
  735. self.fields,
  736. error_store,
  737. many=many,
  738. partial=partial,
  739. unknown=unknown,
  740. dict_class=self.dict_class,
  741. index_errors=self.opts.index_errors,
  742. )
  743. # Run field-level validation
  744. self._invoke_field_validators(error_store, data=result, many=many)
  745. # Run schema-level validation
  746. if self._has_processors(VALIDATES_SCHEMA):
  747. field_errors = bool(error_store.errors)
  748. self._invoke_schema_validators(
  749. error_store,
  750. pass_many=True,
  751. data=result,
  752. original_data=data,
  753. many=many,
  754. field_errors=field_errors,
  755. )
  756. self._invoke_schema_validators(
  757. error_store,
  758. pass_many=False,
  759. data=result,
  760. original_data=data,
  761. many=many,
  762. field_errors=field_errors,
  763. )
  764. errors = error_store.errors
  765. # Run post processors
  766. if not errors and postprocess and self._has_processors(POST_LOAD):
  767. try:
  768. result = self._invoke_load_processors(
  769. POST_LOAD,
  770. result,
  771. many,
  772. original_data=data,
  773. )
  774. except ValidationError as err:
  775. errors = err.normalized_messages()
  776. if errors:
  777. exc = ValidationError(
  778. errors,
  779. data=data,
  780. valid_data=result,
  781. )
  782. self.handle_error(exc, data)
  783. raise exc
  784. return result
  785. def _normalize_nested_options(self):
  786. """Apply then flatten nested schema options"""
  787. if self.only is not None:
  788. # Apply the only option to nested fields.
  789. self.__apply_nested_option('only', self.only, 'intersection')
  790. # Remove the child field names from the only option.
  791. self.only = self.set_class(
  792. [field.split('.', 1)[0] for field in self.only],
  793. )
  794. excludes = set(self.opts.exclude) | set(self.exclude)
  795. if excludes:
  796. # Apply the exclude option to nested fields.
  797. self.__apply_nested_option('exclude', excludes, 'union')
  798. if self.exclude:
  799. # Remove the parent field names from the exclude option.
  800. self.exclude = self.set_class(
  801. [field for field in self.exclude if '.' not in field],
  802. )
  803. if self.opts.exclude:
  804. # Remove the parent field names from the meta exclude option.
  805. self.opts.exclude = self.set_class(
  806. [field for field in self.opts.exclude if '.' not in field],
  807. )
  808. def __apply_nested_option(self, option_name, field_names, set_operation):
  809. """Apply nested options to nested fields"""
  810. # Split nested field names on the first dot.
  811. nested_fields = [name.split('.', 1) for name in field_names if '.' in name]
  812. # Partition the nested field names by parent field.
  813. nested_options = defaultdict(list)
  814. for parent, nested_names in nested_fields:
  815. nested_options[parent].append(nested_names)
  816. # Apply the nested field options.
  817. for key, options in iter(nested_options.items()):
  818. new_options = self.set_class(options)
  819. original_options = getattr(self.declared_fields[key], option_name, ())
  820. if original_options:
  821. if set_operation == 'union':
  822. new_options |= self.set_class(original_options)
  823. if set_operation == 'intersection':
  824. new_options &= self.set_class(original_options)
  825. setattr(self.declared_fields[key], option_name, new_options)
  826. def _init_fields(self):
  827. """Update fields based on schema options."""
  828. if self.opts.fields:
  829. available_field_names = self.set_class(self.opts.fields)
  830. else:
  831. available_field_names = self.set_class(self.declared_fields.keys())
  832. if self.opts.additional:
  833. available_field_names |= self.set_class(self.opts.additional)
  834. invalid_fields = self.set_class()
  835. if self.only is not None:
  836. # Return only fields specified in only option
  837. field_names = self.set_class(self.only)
  838. invalid_fields |= field_names - available_field_names
  839. else:
  840. field_names = available_field_names
  841. # If "exclude" option or param is specified, remove those fields.
  842. exclude_field_names = set(self.opts.exclude) | set(self.exclude)
  843. if exclude_field_names:
  844. # Note that this isn't available_field_names, since we want to
  845. # apply "only" for the actual calculation.
  846. field_names = field_names - exclude_field_names
  847. invalid_fields |= exclude_field_names - available_field_names
  848. if invalid_fields:
  849. message = 'Invalid fields for {0}: {1}.'.format(self, invalid_fields)
  850. raise ValueError(message)
  851. fields_dict = self.dict_class()
  852. for field_name in field_names:
  853. field_obj = self.declared_fields.get(field_name, ma_fields.Inferred())
  854. self._bind_field(field_name, field_obj)
  855. fields_dict[field_name] = field_obj
  856. dump_data_keys = [
  857. obj.data_key or name for name, obj in iteritems(fields_dict) if not obj.load_only
  858. ]
  859. if len(dump_data_keys) != len(set(dump_data_keys)):
  860. data_keys_duplicates = {x for x in dump_data_keys if dump_data_keys.count(x) > 1}
  861. raise ValueError(
  862. 'The data_key argument for one or more fields collides '
  863. "with another field's name or data_key argument. "
  864. 'Check the following field names and '
  865. 'data_key arguments: {}'.format(list(data_keys_duplicates)),
  866. )
  867. load_attributes = [
  868. obj.attribute or name for name, obj in iteritems(fields_dict) if not obj.dump_only
  869. ]
  870. if len(load_attributes) != len(set(load_attributes)):
  871. attributes_duplicates = {x for x in load_attributes if load_attributes.count(x) > 1}
  872. raise ValueError(
  873. 'The attribute argument for one or more fields collides '
  874. "with another field's name or attribute argument. "
  875. 'Check the following field names and '
  876. 'attribute arguments: {}'.format(list(attributes_duplicates)),
  877. )
  878. return fields_dict
  879. def on_bind_field(self, field_name, field_obj):
  880. """Hook to modify a field when it is bound to the `Schema`.
  881. No-op by default.
  882. """
  883. return None
  884. def _bind_field(self, field_name, field_obj):
  885. """Bind field to the schema, setting any necessary attributes on the
  886. field (e.g. parent and name).
  887. Also set field load_only and dump_only values if field_name was
  888. specified in ``class Meta``.
  889. """
  890. try:
  891. if field_name in self.load_only:
  892. field_obj.load_only = True
  893. if field_name in self.dump_only:
  894. field_obj.dump_only = True
  895. field_obj._bind_to_schema(field_name, self)
  896. self.on_bind_field(field_name, field_obj)
  897. except TypeError:
  898. # field declared as a class, not an instance
  899. if (isinstance(field_obj, type) and
  900. issubclass(field_obj, base.FieldABC)):
  901. msg = ('Field for "{0}" must be declared as a '
  902. 'Field instance, not a class. '
  903. 'Did you mean "fields.{1}()"?'
  904. .format(field_name, field_obj.__name__))
  905. raise TypeError(msg)
  906. def _has_processors(self, tag):
  907. return self._hooks[(tag, True)] or self._hooks[(tag, False)]
  908. def _invoke_dump_processors(self, tag, data, many, original_data=None):
  909. # The pass_many post-dump processors may do things like add an envelope, so
  910. # invoke those after invoking the non-pass_many processors which will expect
  911. # to get a list of items.
  912. data = self._invoke_processors(
  913. tag, pass_many=False,
  914. data=data, many=many, original_data=original_data,
  915. )
  916. data = self._invoke_processors(
  917. tag, pass_many=True,
  918. data=data, many=many, original_data=original_data,
  919. )
  920. return data
  921. def _invoke_load_processors(self, tag, data, many, original_data=None):
  922. # This has to invert the order of the dump processors, so run the pass_many
  923. # processors first.
  924. data = self._invoke_processors(
  925. tag, pass_many=True,
  926. data=data, many=many, original_data=original_data,
  927. )
  928. data = self._invoke_processors(
  929. tag, pass_many=False,
  930. data=data, many=many, original_data=original_data,
  931. )
  932. return data
  933. def _invoke_field_validators(self, error_store, data, many):
  934. for attr_name in self._hooks[VALIDATES]:
  935. validator = getattr(self, attr_name)
  936. validator_kwargs = validator.__marshmallow_hook__[VALIDATES]
  937. field_name = validator_kwargs['field_name']
  938. try:
  939. field_obj = self.fields[field_name]
  940. except KeyError:
  941. if field_name in self.declared_fields:
  942. continue
  943. raise ValueError('"{0}" field does not exist.'.format(field_name))
  944. if many:
  945. for idx, item in enumerate(data):
  946. try:
  947. value = item[field_obj.attribute or field_name]
  948. except KeyError:
  949. pass
  950. else:
  951. validated_value = self._call_and_store(
  952. getter_func=validator,
  953. data=value,
  954. field_name=field_obj.data_key or field_name,
  955. error_store=error_store,
  956. index=(idx if self.opts.index_errors else None),
  957. )
  958. if validated_value is missing:
  959. data[idx].pop(field_name, None)
  960. else:
  961. try:
  962. value = data[field_obj.attribute or field_name]
  963. except KeyError:
  964. pass
  965. else:
  966. validated_value = self._call_and_store(
  967. getter_func=validator,
  968. data=value,
  969. field_name=field_obj.data_key or field_name,
  970. error_store=error_store,
  971. )
  972. if validated_value is missing:
  973. data.pop(field_name, None)
  974. def _invoke_schema_validators(
  975. self,
  976. error_store,
  977. pass_many,
  978. data,
  979. original_data,
  980. many,
  981. field_errors=False,
  982. ):
  983. for attr_name in self._hooks[(VALIDATES_SCHEMA, pass_many)]:
  984. validator = getattr(self, attr_name)
  985. validator_kwargs = validator.__marshmallow_hook__[(VALIDATES_SCHEMA, pass_many)]
  986. if field_errors and validator_kwargs['skip_on_field_errors']:
  987. continue
  988. pass_original = validator_kwargs.get('pass_original', False)
  989. if pass_many:
  990. validator = functools.partial(validator, many=many)
  991. if many and not pass_many:
  992. for idx, (item, orig) in enumerate(zip(data, original_data)):
  993. self._run_validator(
  994. validator,
  995. item,
  996. orig,
  997. self.fields,
  998. error_store,
  999. many=many,
  1000. index=idx,
  1001. pass_original=pass_original,
  1002. )
  1003. else:
  1004. self._run_validator(
  1005. validator,
  1006. data,
  1007. original_data,
  1008. self.fields,
  1009. error_store,
  1010. many=many,
  1011. pass_original=pass_original,
  1012. )
  1013. def _invoke_processors(
  1014. self,
  1015. tag,
  1016. pass_many,
  1017. data,
  1018. many,
  1019. original_data=None,
  1020. ):
  1021. key = (tag, pass_many)
  1022. for attr_name in self._hooks[key]:
  1023. # This will be a bound method.
  1024. processor = getattr(self, attr_name)
  1025. processor_kwargs = processor.__marshmallow_hook__[key]
  1026. pass_original = processor_kwargs.get('pass_original', False)
  1027. if pass_many:
  1028. if pass_original:
  1029. data = processor(data, many, original_data)
  1030. else:
  1031. data = processor(data, many)
  1032. elif many:
  1033. if pass_original:
  1034. data = [
  1035. processor(item, original)
  1036. for item, original in zip(data, original_data)
  1037. ]
  1038. else:
  1039. data = [processor(item) for item in data]
  1040. else:
  1041. if pass_original:
  1042. data = processor(data, original_data)
  1043. else:
  1044. data = processor(data)
  1045. return data
  1046. class Schema(with_metaclass(SchemaMeta, BaseSchema)):
  1047. __doc__ = BaseSchema.__doc__