Skip to content

Instantly share code, notes, and snippets.

@sloria
Last active November 28, 2019 09:19
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save sloria/2fac357710f13e855a5b9cf8f05a4da0 to your computer and use it in GitHub Desktop.
Save sloria/2fac357710f13e855a5b9cf8f05a4da0 to your computer and use it in GitHub Desktop.
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Unknown field handling"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## DRF\n",
"\n",
"Default: ignore\n",
"\n",
"Not configurable"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [],
"source": [
"from django.conf import settings\n",
"\n",
"import django\n",
"try:\n",
" settings.configure(\n",
" INSTALLED_APPS=['rest_framework'],\n",
" USE_I18N=True,\n",
" USE_L10N=True,\n",
" )\n",
" django.setup()\n",
"except:\n",
" pass\n",
"\n",
"from rest_framework import serializers as drfs\n",
"\n",
"\n",
"class AlbumSerializer(drfs.Serializer):\n",
" title = drfs.CharField()"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [],
"source": [
"result = AlbumSerializer(data={'title': 'valid', 'unknown': 1})"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"True"
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"result.is_valid()"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"ReturnDict([('title', 'valid')])"
]
},
"execution_count": 9,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"result.data"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Colander\n",
"\n",
"Default: ignore\n",
"\n",
"Configured by `unknown` param, which may be: `raise`, `ignore`, or `preserve`.\n",
"\n",
"When using `raise`, reports all unknown keys."
]
},
{
"cell_type": "code",
"execution_count": 19,
"metadata": {},
"outputs": [
{
"ename": "UnsupportedFields",
"evalue": "{'': 'Unrecognized keys in mapping: \"{\\'unknown\\': 1, \\'unknown2\\': 2}\"'}",
"output_type": "error",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[0;31mUnsupportedFields\u001b[0m Traceback (most recent call last)",
"\u001b[0;32m<ipython-input-19-8d1993fb8078>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[1;32m 9\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 10\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 11\u001b[0;31m \u001b[0mAlbum\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdeserialize\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m{\u001b[0m\u001b[0;34m'title'\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;34m'valid'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'unknown'\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'unknown2'\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;36m2\u001b[0m\u001b[0;34m}\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
"\u001b[0;32m~/.local/share/virtualenvs/marshmallow/lib/python3.6/site-packages/colander/__init__.py\u001b[0m in \u001b[0;36mdeserialize\u001b[0;34m(self, cstruct)\u001b[0m\n\u001b[1;32m 2071\u001b[0m \u001b[0mdefaults\u001b[0m \u001b[0mto\u001b[0m \u001b[0;34m:\u001b[0m\u001b[0mattr\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;31m`\u001b[0m\u001b[0mcolander\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mnull\u001b[0m\u001b[0;31m`\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2072\u001b[0m \"\"\"\n\u001b[0;32m-> 2073\u001b[0;31m \u001b[0mappstruct\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtyp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdeserialize\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcstruct\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 2074\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2075\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpreparer\u001b[0m \u001b[0;32mis\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;32m~/.local/share/virtualenvs/marshmallow/lib/python3.6/site-packages/colander/__init__.py\u001b[0m in \u001b[0;36mdeserialize\u001b[0;34m(self, node, cstruct)\u001b[0m\n\u001b[1;32m 722\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0msubnode\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdeserialize\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0msubcstruct\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 723\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 724\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_impl\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mnode\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcstruct\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcallback\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 725\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 726\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mflatten\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mnode\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mappstruct\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mprefix\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m''\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mlistitem\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mFalse\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;32m~/.local/share/virtualenvs/marshmallow/lib/python3.6/site-packages/colander/__init__.py\u001b[0m in \u001b[0;36m_impl\u001b[0;34m(self, node, value, callback)\u001b[0m\n\u001b[1;32m 696\u001b[0m \u001b[0mnode\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mvalue\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 697\u001b[0m msg=_('Unrecognized keys in mapping: \"${val}\"',\n\u001b[0;32m--> 698\u001b[0;31m mapping={'val': value}))\n\u001b[0m\u001b[1;32m 699\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 700\u001b[0m \u001b[0;32melif\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0munknown\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;34m'preserve'\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;31mUnsupportedFields\u001b[0m: {'': 'Unrecognized keys in mapping: \"{\\'unknown\\': 1, \\'unknown2\\': 2}\"'}"
]
}
],
"source": [
"import colander as col\n",
"\n",
"class Album(col.MappingSchema):\n",
" title = col.SchemaNode(col.String())\n",
" \n",
" # https://github.com/Pylons/colander/issues/116\n",
" def schema_type(self, **kw):\n",
" return col.Mapping(unknown='raise')\n",
" \n",
" \n",
"Album().deserialize({'title': 'valid', 'unknown': 1, 'unknown2': 2})"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Voluptuous\n",
"\n",
"Default: raise (reports first unknown key)\n",
"\n",
"Configurable with `extra` parameter, which may be: `ALLOW_EXTRA` and `REMOVE_EXTRA`\n",
"\n",
"https://github.com/alecthomas/voluptuous#extra-dictionary-keys"
]
},
{
"cell_type": "code",
"execution_count": 20,
"metadata": {},
"outputs": [],
"source": [
"import voluptuous as vol\n",
"\n",
"schema = vol.Schema({'title': str})"
]
},
{
"cell_type": "code",
"execution_count": 21,
"metadata": {},
"outputs": [
{
"ename": "MultipleInvalid",
"evalue": "extra keys not allowed @ data['unknown']",
"output_type": "error",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[0;31mMultipleInvalid\u001b[0m Traceback (most recent call last)",
"\u001b[0;32m<ipython-input-21-4e5142820c14>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mschema\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m{\u001b[0m\u001b[0;34m'title'\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;34m'valid'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'unknown'\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m}\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
"\u001b[0;32m~/.local/share/virtualenvs/marshmallow/lib/python3.6/site-packages/voluptuous/schema_builder.py\u001b[0m in \u001b[0;36m__call__\u001b[0;34m(self, data)\u001b[0m\n\u001b[1;32m 265\u001b[0m \u001b[0;34m\"\"\"Validate data against this schema.\"\"\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 266\u001b[0m \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 267\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_compiled\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mdata\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 268\u001b[0m \u001b[0;32mexcept\u001b[0m \u001b[0mer\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mMultipleInvalid\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 269\u001b[0m \u001b[0;32mraise\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;32m~/.local/share/virtualenvs/marshmallow/lib/python3.6/site-packages/voluptuous/schema_builder.py\u001b[0m in \u001b[0;36mvalidate_dict\u001b[0;34m(path, data)\u001b[0m\n\u001b[1;32m 585\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 586\u001b[0m \u001b[0mout\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mdata\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__class__\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 587\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mbase_validate\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0miteritems\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdata\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mout\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 588\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 589\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mvalidate_dict\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;32m~/.local/share/virtualenvs/marshmallow/lib/python3.6/site-packages/voluptuous/schema_builder.py\u001b[0m in \u001b[0;36mvalidate_mapping\u001b[0;34m(path, iterable, out)\u001b[0m\n\u001b[1;32m 423\u001b[0m \u001b[0merrors\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mappend\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mer\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mRequiredFieldInvalid\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mmsg\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mpath\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0mkey\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 424\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0merrors\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 425\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mer\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mMultipleInvalid\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0merrors\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 426\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 427\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mout\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;31mMultipleInvalid\u001b[0m: extra keys not allowed @ data['unknown']"
]
}
],
"source": [
"schema({'title': 'valid', 'unknown': 1})"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"It only seems to report on the first unknown field."
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"ename": "MultipleInvalid",
"evalue": "extra keys not allowed @ data['unknown']",
"output_type": "error",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[0;31mMultipleInvalid\u001b[0m Traceback (most recent call last)",
"\u001b[0;32m<ipython-input-10-64f87578de51>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mschema\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m{\u001b[0m\u001b[0;34m'title'\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;34m'valid'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'unknown'\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'unknown2'\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;36m2\u001b[0m\u001b[0;34m}\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;31m# unknown2 is not in error message\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
"\u001b[0;32m~/.local/share/virtualenvs/marshmallow/lib/python3.6/site-packages/voluptuous/schema_builder.py\u001b[0m in \u001b[0;36m__call__\u001b[0;34m(self, data)\u001b[0m\n\u001b[1;32m 265\u001b[0m \u001b[0;34m\"\"\"Validate data against this schema.\"\"\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 266\u001b[0m \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 267\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_compiled\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mdata\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 268\u001b[0m \u001b[0;32mexcept\u001b[0m \u001b[0mer\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mMultipleInvalid\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 269\u001b[0m \u001b[0;32mraise\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;32m~/.local/share/virtualenvs/marshmallow/lib/python3.6/site-packages/voluptuous/schema_builder.py\u001b[0m in \u001b[0;36mvalidate_dict\u001b[0;34m(path, data)\u001b[0m\n\u001b[1;32m 585\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 586\u001b[0m \u001b[0mout\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mdata\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__class__\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 587\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mbase_validate\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0miteritems\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdata\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mout\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 588\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 589\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mvalidate_dict\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;32m~/.local/share/virtualenvs/marshmallow/lib/python3.6/site-packages/voluptuous/schema_builder.py\u001b[0m in \u001b[0;36mvalidate_mapping\u001b[0;34m(path, iterable, out)\u001b[0m\n\u001b[1;32m 423\u001b[0m \u001b[0merrors\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mappend\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mer\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mRequiredFieldInvalid\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mmsg\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mpath\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0mkey\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 424\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0merrors\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 425\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mer\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mMultipleInvalid\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0merrors\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 426\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 427\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mout\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;31mMultipleInvalid\u001b[0m: extra keys not allowed @ data['unknown']"
]
}
],
"source": [
"schema({'title': 'valid', 'unknown': 1, 'unknown2': 2}) # unknown2 is not in error message"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"{'title': 'valid', 'unknown': 1}"
]
},
"execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"allow_schema = vol.Schema({'title': str}, extra=vol.ALLOW_EXTRA)\n",
"\n",
"allow_schema({'title': 'valid', 'unknown': 1})"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## schema\n",
"\n",
"Default: raise (reports all unknown keys)\n",
"\n",
"Configured by a `ignore_extra_keys` (boolean). Possible to preserve extra keys by using `object: object` as one of the items."
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [
{
"ename": "SchemaWrongKeyError",
"evalue": "Wrong keys 'unknown', 'unknown2' in {'title': 'valid', 'unknown': 1, 'unknown2': 2}",
"output_type": "error",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[0;31mSchemaWrongKeyError\u001b[0m Traceback (most recent call last)",
"\u001b[0;32m<ipython-input-12-81b4bd225264>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0malbum\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mschema\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mSchema\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m{\u001b[0m\u001b[0;34m'title'\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0mstr\u001b[0m\u001b[0;34m}\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 4\u001b[0;31m \u001b[0malbum\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mvalidate\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m{\u001b[0m\u001b[0;34m'title'\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;34m'valid'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'unknown'\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'unknown2'\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;36m2\u001b[0m\u001b[0;34m}\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
"\u001b[0;32m~/.local/share/virtualenvs/marshmallow/lib/python3.6/site-packages/schema.py\u001b[0m in \u001b[0;36mvalidate\u001b[0;34m(self, data)\u001b[0m\n\u001b[1;32m 296\u001b[0m SchemaWrongKeyError(\n\u001b[1;32m 297\u001b[0m \u001b[0;34m'Wrong keys %s in %r'\u001b[0m \u001b[0;34m%\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0ms_wrong_keys\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mdata\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 298\u001b[0;31m e.format(data) if e else None)\n\u001b[0m\u001b[1;32m 299\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 300\u001b[0m \u001b[0;31m# Apply default-having optionals that haven't been used:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;31mSchemaWrongKeyError\u001b[0m: Wrong keys 'unknown', 'unknown2' in {'title': 'valid', 'unknown': 1, 'unknown2': 2}"
]
}
],
"source": [
"import schema\n",
"\n",
"album = schema.Schema({'title': str})\n",
"album.validate({'title': 'valid', 'unknown': 1, 'unknown2': 2})"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"{'title': 'valid'}"
]
},
"execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"ignore_schema = schema.Schema({'title': str}, ignore_extra_keys=True)\n",
"ignore_schema.validate({'title': 'valid', 'unknown': 1})"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"{'title': 'valid', 'unknown': 1}"
]
},
"execution_count": 14,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"allow_schema = schema.Schema({'title': str, object: object})\n",
"allow_schema.validate({'title': 'valid', 'unknown': 1})"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Cerberus\n",
"\n",
"Default: raise (reports all unknown keys)\n",
"\n",
"Configurable with a `allow_unknown` parameter.\n",
"\n",
"http://docs.python-cerberus.org/en/stable/usage.html#allowing-the-unknown"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"False"
]
},
"execution_count": 15,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"import cerberus as cer\n",
"\n",
"v = cer.Validator()\n",
"schema = {\n",
" 'title': {'type': 'string'},\n",
"}\n",
"v.validate({'title': 'valid', 'unknown': 1, 'unknown2': 2}, schema)"
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"{'unknown': ['unknown field'], 'unknown2': ['unknown field']}"
]
},
"execution_count": 16,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"v.errors"
]
},
{
"cell_type": "code",
"execution_count": 19,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"True"
]
},
"execution_count": 19,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"allow_validator = cer.Validator(allow_unknown=True)\n",
"allow_validator.validate({'title': 'valid', 'unknown': 1}, schema)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Schematics\n",
"\n",
"default: raise (reports all unknown fields)\n",
"\n",
"Not configurable"
]
},
{
"cell_type": "code",
"execution_count": 22,
"metadata": {},
"outputs": [],
"source": [
"import schematics as sch\n",
"\n",
"class Album(sch.Model):\n",
" title = sch.types.StringType()"
]
},
{
"cell_type": "code",
"execution_count": 23,
"metadata": {},
"outputs": [
{
"ename": "DataError",
"evalue": "{\"unknown2\": \"Rogue field\", \"unknown\": \"Rogue field\"}",
"output_type": "error",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[0;31mDataError\u001b[0m Traceback (most recent call last)",
"\u001b[0;32m<ipython-input-23-2e6b79c8315c>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mAlbum\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m{\u001b[0m\u001b[0;34m'title'\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;34m'valid'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'unknown'\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'unknown2'\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;36m2\u001b[0m\u001b[0;34m}\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mvalidate\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
"\u001b[0;32m~/.local/share/virtualenvs/marshmallow/lib/python3.6/site-packages/schematics/models.py\u001b[0m in \u001b[0;36m__init__\u001b[0;34m(self, raw_data, trusted_data, deserialize_mapping, init, partial, strict, validate, app_data, lazy, **kwargs)\u001b[0m\n\u001b[1;32m 229\u001b[0m \u001b[0mtrusted_data\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mtrusted_data\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmapping\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mdeserialize_mapping\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 230\u001b[0m \u001b[0mpartial\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mpartial\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mstrict\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mstrict\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mvalidate\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mvalidate\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mnew\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mTrue\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 231\u001b[0;31m app_data=app_data, **kwargs)\n\u001b[0m\u001b[1;32m 232\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_data\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mconverted\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mdata\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 233\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mvalidate\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;32m~/.local/share/virtualenvs/marshmallow/lib/python3.6/site-packages/schematics/models.py\u001b[0m in \u001b[0;36m_convert\u001b[0;34m(self, raw_data, context, **kwargs)\u001b[0m\n\u001b[1;32m 293\u001b[0m \u001b[0mshould_validate\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mgetattr\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mcontext\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'validate'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mkwargs\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'validate'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;32mFalse\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 294\u001b[0m \u001b[0mfunc\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mvalidate\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mshould_validate\u001b[0m \u001b[0;32melse\u001b[0m \u001b[0mconvert\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 295\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mfunc\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_schema\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mraw_data\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mraw_data\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0moo\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mTrue\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcontext\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mcontext\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 296\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 297\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mexport\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mfield_converter\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mNone\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mrole\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mNone\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mapp_data\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mNone\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;32m~/.local/share/virtualenvs/marshmallow/lib/python3.6/site-packages/schematics/transforms.py\u001b[0m in \u001b[0;36mconvert\u001b[0;34m(cls, mutable, raw_data, **kwargs)\u001b[0m\n\u001b[1;32m 427\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 428\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mconvert\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mcls\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmutable\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mraw_data\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mNone\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 429\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mimport_loop\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mcls\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmutable\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mraw_data\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mimport_converter\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 430\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 431\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;32m~/.local/share/virtualenvs/marshmallow/lib/python3.6/site-packages/schematics/transforms.py\u001b[0m in \u001b[0;36mimport_loop\u001b[0;34m(schema, mutable, raw_data, field_converter, trusted_data, mapping, partial, strict, init_values, apply_defaults, convert, validate, new, oo, recursive, app_data, context)\u001b[0m\n\u001b[1;32m 174\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 175\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0merrors\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 176\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mDataError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0merrors\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mdata\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 177\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 178\u001b[0m \u001b[0mdata\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcontext\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mfield_converter\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpost\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mschema\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mdata\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcontext\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;31mDataError\u001b[0m: {\"unknown2\": \"Rogue field\", \"unknown\": \"Rogue field\"}"
]
}
],
"source": [
"Album({'title': 'valid', 'unknown': 1, 'unknown2': 2}).validate()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.6.4"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment