8000 Schemas by samuelcolvin · Pull Request #190 · pydantic/pydantic · GitHub
[go: up one dir, main page]

Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
adding schema
  • Loading branch information
samuelcolvin committed Jun 28, 2018
commit af3bada0174f7ca729f0fff3ad0ce2fff85ec11d
1 change: 1 addition & 0 deletions HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ v0.11.0 (2018-XX-XX)
* make ``list``, ``tuple`` and ``set`` types stricter #86
* **breaking change**: remove msgpack parsing #201
* add ``FilePath`` and ``DirectoryPath`` types #10
* model schema generation #190

v0.10.0 (2018-06-11)
....................
Expand Down
42 changes: 42 additions & 0 deletions docs/examples/schema1.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
{
"type": "object",
"title": "Main",
"properties": {
"foo_bar": {
"type": "object",
"title": "FooBar",
"properties": {
"count": {
"type": "int",
"title": "Count",
"required": true
},
"size": {
"type": "float",
"title": "Size",
"required": false
}
},
"required": true
},
"Gender": {
"type": "int",
"title": "Gender",
"required": false,
"choices": [
[1, "Male"],
[2, "Female"],
[3, "Other"],
[4, "I'd rather not say"]
]
},
"snap": {
"type": "int",
"title": "The Snap",
"required": false,
"default": 42,
"description": "this is the value of snap"
}
},
"description": "This is the description of the main model"
}
39 changes: 39 additions & 0 deletions docs/examples/schema1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import json
from enum import IntEnum
from pydantic import BaseModel, Schema

class FooBar(BaseModel):
count: int
size: float = None

class Gender(IntEnum):
male = 1
female = 2
other = 3
not_given = 4

class MainModel(BaseModel):
"""
This is the description of the main model
"""
foo_bar: FooBar = Schema(...)
gender: Gender = Schema(
None,
alias='Gender',
choice_names={3: 'Other Gender', 4: "I'd rather not say"}
)
snap: int = Schema(
42,
title='The Snap',
description='this is the value of snap'
)

class Config:
title = 'Main'

print(json.dumps(MainModel.schema(), indent=2))

[1, "Male"],
[2, "Female"],
[3, "Other"],
[4, "I'd rather not say"]
43 changes: 42 additions & 1 deletion docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,44 @@ The ellipsis ``...`` just means "Required" same as annotation only declarations

(This script is complete, it should run "as is")

.. _schema:

Model Schema
............

*Pydantic* allows auto creation of schemas from models:

.. literalinclude:: examples/schema1.py

Outputs:

.. literalinclude:: examples/schema1.json

(This script is complete, it should run "as is")

"submodels" are recursively included in the schema.

The ``description`` for models is taken from the docstring of the class.

Enums are shown in the schema as choices, optionally the ``choice_names`` argument can be used
to provide human friendly descriptions for the choices. If ``choice_names`` is omitted or misses values,
descriptions will be generated by calling ``.title()`` on the name of the member.

Optionally the ``Schema`` class can be used to provide extra information about the field, arguments:

* ``default`` (positional argument), since the ``Schema`` is replacing the field's default, its first
argument is used to set the default, use ellipsis (``...``) to indicate the field is required
* ``title`` if omitted ``field_name.title()`` is used
* ``choice_names`` as described above
* ``alias`` - the public name of the field.
* ``**`` any other keyword arguments eg. ``description`` will be added verbatim to the field's schema

Instead of using ``Schema``, the ``fields`` property of :ref:`the Config class <config>` can be used
to set all the arguments above except ``default``.

The schema is generated by default using aliases as keys, it can also be generated using model
property names not aliases with ``MainModel.Schema(by_alias=False)``.

Error Handling
..............

Expand Down Expand Up @@ -279,6 +317,8 @@ Helper Functions
Since ``pickle`` allows complex objects to be encoded, to use it you need to explicitly pass ``allow_pickle`` to
the parsing function.

.. _config:

Model Config
............

Expand All @@ -295,7 +335,8 @@ Options:
:allow_mutation: whether or not models are faux-immutable, e.g. __setattr__ fails (default: ``True``)
:use_enum_values: whether to populate models with the ``value`` property of enums,
rather than the raw enum - useful if you want to serialise ``model.dict()`` later (default: ``False``)
:fields: extra information on each field, currently just "alias" is allowed (default: ``None``)
:fields: schema information on each field, this is equivilant to
using :ref:`the schema <schema>` class (default: ``None``)
:validate_assignment: whether to perform validation on assignment to attributes or not (default: ``False``)
:allow_population_by_alias: whether or not an aliased field may be populated by its name as given by the model
attribute, rather than strictly the alias; please be sure to read the warning below before enabling this (default:
Expand Down
9 changes: 5 additions & 4 deletions pydantic/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,10 +144,11 @@ def schema(self, by_alias=True):
if not self.required and self.default is not None:
s['default'] = self.default
if issubclass(self.type_, Enum):
if self._schema.choice_names:
s['choices'] = [(v.value, self._schema.choice_names[v.value]) for v in self.type_.__members__.values()]
else:
s['choices'] = [(v.value, k.title()) for k, v in self.type_.__members__.items()]
choice_names = self._schema.choice_names or {}
s['choices'] = [
(v.value, choice_names.get(v.value) or k.title())
for k, v in self.type_.__members__.items()
]
s.update(self._schema.extra)
return s

Expand Down
4 changes: 2 additions & 2 deletions tests/test_schema.py
5576
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ class SpamEnum(str, Enum):
class Model(BaseModel):
1E02 foo: FooEnum
bar: BarEnum
spam: SpamEnum = Schema(None, choice_names={'f': 'Sausage', 'b': 'Bacon'})
spam: SpamEnum = Schema(None, choice_names={'f': 'Sausage'})

assert Model.schema() == {
'type': 'object',
Expand Down Expand Up @@ -186,7 +186,7 @@ class Model(BaseModel):
'required': False,
'choices': [
('f', 'Sausage'),
('b', 'Bacon'),
('b', 'Bar'),
],
},
},
Expand Down
0