Compare commits

...

18 Commits

Author SHA1 Message Date
Sebastián Ramírez
26e3dffb37 🚀 Deploy when tagged using Python 3.6 2019-04-20 22:16:07 +04:00
Sebastián Ramírez
aa7b4bd101 🔖 0.17.0 2019-04-20 22:12:55 +04:00
Sebastián Ramírez
ffc4c716c0 🚀 Make Flit publish from CI (#170) 2019-04-20 22:09:35 +04:00
Sebastián Ramírez
ef7b6e8eaf 📝 Update Release Notes 2019-04-20 21:15:03 +04:00
Sebastián Ramírez
596243f4a5 Add docs about CORS (#169) 2019-04-20 21:13:01 +04:00
Sebastián Ramírez
766bf1c5aa 📝 Update release notes 2019-04-20 20:31:44 +04:00
Sebastián Ramírez
9e748dbca4 By default, encode by alias (#168) 2019-04-20 20:29:54 +04:00
Sebastián Ramírez
cefe6cf92c 🔖 Release version 0.16.0 2019-04-16 23:28:13 +04:00
Sebastián Ramírez
be3953499f 📝 Update release notes 2019-04-16 23:27:25 +04:00
Sebastián Ramírez
546d233dec ♻️ Update Pydantic usage, types, values, minor structure changes (#164) 2019-04-16 23:26:09 +04:00
Sebastián Ramírez
61dd36a945 Upgrade docstring Markdown parsing (#163)
*  Upgrade docstring Markdown parsing

* 📝 Update release notes
2019-04-16 22:49:18 +04:00
Sebastián Ramírez
27f9d55c3e 📝 Update release notes 2019-04-16 22:43:59 +04:00
euri10
906cc60f65 ⬆️ Upgrade Pydantic to 0.23 (#160)
* Add websocket to APIRouter

* Upgrade pydantic to v0.23.0

* Forgot pyproject.toml

* ⬆️ Upgrade some Pipfile.lock dependencies
2019-04-16 22:42:00 +04:00
Sebastián Ramírez
69afaf256f 📝 Update release notes 2019-04-16 22:21:32 +04:00
Daniel Michaels
4ab349a2a8 ✏️ fixed small typo /tutorial/extra-models.md (#159) 2019-04-16 22:20:03 +04:00
Sebastián Ramírez
9c258107b4 📝 Update release notes 2019-04-16 22:18:42 +04:00
hayata-yamamoto
29a4f90bcd 📝 fix URL examples in Tutorial: Query Parameters (#157)
* modify tutorial

* modify item_id
2019-04-16 22:16:16 +04:00
Sebastián Ramírez
361fd00777 📝 Add note about Swagger UI and multi-part uploads 2019-04-14 22:24:31 +04:00
24 changed files with 209 additions and 73 deletions

View File

@@ -20,6 +20,7 @@ after_script:
deploy:
provider: script
script: bash scripts/trigger-docker.sh
script: bash scripts/deploy.sh
on:
branch: master
tags: true
python: "3.6"

View File

@@ -26,7 +26,7 @@ uvicorn = "*"
[packages]
starlette = "==0.11.1"
pydantic = "==0.21.0"
pydantic = "==0.23.0"
databases = {extras = ["sqlite"],version = "*"}
[requires]

54
Pipfile.lock generated
View File

@@ -1,7 +1,7 @@
{
"_meta": {
"hash": {
"sha256": "24b3b7b88d3cbe671ddbe296e64c15f8558f0e5d5df977200119872a363aac13"
"sha256": "02367d250c6327eac80dfcd8e5ccfa49bcdca0332bc757d527c3db27643baa0d"
},
"pipfile-spec": 6,
"requires": {
@@ -56,23 +56,38 @@
},
"immutables": {
"hashes": [
"sha256:f958ba15745e30d3a38e3c9fcead8496037135bb21c78c0f925c104abba3a6fa"
"sha256:10861f2a2b86139f0c91d5073392d76117f37e84f912dc47c943c23a64008cc7",
"sha256:3e23eeb4bc55d57b2a97bef4c1a2891bbb731050b4167c855545797d45e84e45",
"sha256:4373876879f147986808f71e6ca02380192a279e8b8d45832f6fed4e7f717562",
"sha256:46f9122da033fecf84d7f4c6257aec780f370b20f3ce6bc521702b63ee3d99f7",
"sha256:5104db6102e53702af45c6b0af36e45a80970123b11a80c14e0fce48444cdbe3",
"sha256:59274bcb631f4fdc9731e9a4a96d16d96b3a17e29fd5e46516518f38406f678f",
"sha256:65a9c624e50ca5c50464dbf432996b5c4f056a411bcff5690ef4cab59f913f99",
"sha256:b64e0672497b884d21170ca61c693da8488d77f043650efa7911378cbbad0f2c",
"sha256:b70655dba00742b033310933066a2202e1cfbbb0f63841b4597cd8787974b242",
"sha256:c3d8c238a6f9b60355578579563773348674b6da63c1a0d7394384ed341f3d41",
"sha256:cd66bcd11b6a1c1a80fb8d90e25870ff2d5c705ab5eb9666355a33d3fef6ac70",
"sha256:d59310fc4f97c1ff8c3660cb98032db266ac0c285a86ca7a512e8e84a95f44c9",
"sha256:d71d1c822498646143270580dd6f743bb31ab89ae0ded8b2307c356d3a00f1c0",
"sha256:f53da698b42db83cfb1f5073560838051430798c8d8e34a57a27031edbc3041d",
"sha256:f958ba15745e30d3a38e3c9fcead8496037135bb21c78c0f925c104abba3a6fa",
"sha256:ff95e2aa618eed1a0ef4479938f18f3522c89562b9bbb59d677597c0337569dd"
],
"version": "==0.9"
},
"pydantic": {
"hashes": [
"sha256:93fa585402e7c8c01623ea8af6ca23363e8b4c6a020b7a2de9e99fa29d642d50",
"sha256:eb441dd50779347a450494c437db3ecbb13c1f3854497df879662782af516c5c"
"sha256:1205cd1213e8acee40a9ad7160b24de74484fd79ec3f09150b255896a3f506ab",
"sha256:58b71804e9a6b4e1ccf8b3dbbca8c0f9cf4b494e5bea219a96e2e2ecb5af688e"
],
"index": "pypi",
"version": "==0.21.0"
"version": "==0.23.0"
},
"sqlalchemy": {
"hashes": [
"sha256:d5432832f91d200c3d8b473a266d59442d825f9ea744c467e68c5d9a9479fbce"
"sha256:91c54ca8345008fceaec987e10924bf07dcab36c442925357e5a467b36a38319"
],
"version": "==1.3.2"
"version": "==1.3.3"
},
"starlette": {
"hashes": [
@@ -205,10 +220,10 @@
},
"defusedxml": {
"hashes": [
"sha256:24d7f2f94f7f3cb6061acb215685e5125fbcdc40a857eff9de22518820b0a4f4",
"sha256:702a91ade2968a82beb0db1e0766a6a273f33d4616a6ce8cde475d8e09853b20"
"sha256:06d4515a8f8965624d6db922093eb11e77fb8f9a9ebedd1c5d6df5a0fcd0a12c",
"sha256:6c0b1461695877ececd6921a6a330e4392790275c5d6e88fc8ea8261445468b1"
],
"version": "==0.5.0"
"version": "==0.6.0rc1"
},
"dnspython": {
"hashes": [
@@ -441,11 +456,11 @@
},
"mkdocs-material": {
"hashes": [
"sha256:8f0a5217c24bd8635c0bda2a0ee4f91766448e9e3dd6429f1111dd992327345e",
"sha256:c2c6ef6b3e3ab4744a45d03a276e1eb106c91abf610d180d148613fd1a525c7c"
"sha256:8a572f4b3358b9c0e11af8ae319ba4f3747ebb61e2393734d875133b0d2f7891",
"sha256:91210776db541283dd4b7beb5339c190aa69de78ad661aa116a8aa97dd73c803"
],
"index": "pypi",
"version": "==4.1.1"
"version": "==4.1.2"
},
"more-itertools": {
"hashes": [
@@ -508,7 +523,8 @@
},
"parso": {
"hashes": [
"sha256:17cc2d7a945eb42c3569d4564cdf49bde221bc2b552af3eca9c1aad517dcdd33"
"sha256:17cc2d7a945eb42c3569d4564cdf49bde221bc2b552af3eca9c1aad517dcdd33",
"sha256:2e9574cb12e7112a87253e14e2c380ce312060269d04bd018478a3c92ea9a376"
],
"version": "==0.4.0"
},
@@ -599,11 +615,11 @@
},
"pytest": {
"hashes": [
"sha256:13c5e9fb5ec5179995e9357111ab089af350d788cbc944c628f3cde72285809b",
"sha256:f21d2f1fb8200830dcbb5d8ec466a9c9120e20d8b53c7585d180125cce1d297a"
"sha256:3773f4c235918987d51daf1db66d51c99fac654c81d6f2f709a046ab446d5e5d",
"sha256:b7802283b70ca24d7119b32915efa7c409982f59913c1a6c0640aacf118b95f5"
],
"index": "pypi",
"version": "==4.4.0"
"version": "==4.4.1"
},
"pytest-cov": {
"hashes": [
@@ -710,9 +726,9 @@
},
"sqlalchemy": {
"hashes": [
"sha256:d5432832f91d200c3d8b473a266d59442d825f9ea744c467e68c5d9a9479fbce"
"sha256:91c54ca8345008fceaec987e10924bf07dcab36c442925357e5a467b36a38319"
],
"version": "==1.3.2"
"version": "==1.3.3"
},
"terminado": {
"hashes": [

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 87 KiB

After

Width:  |  Height:  |  Size: 85 KiB

View File

@@ -1,5 +1,25 @@
## Next release
## 0.17.0
* Make Flit publish from CI. PR <a href="https://github.com/tiangolo/fastapi/pull/170" target="_blank">#170</a>.
* Add documentation about handling <a href="https://fastapi.tiangolo.com/tutorial/cors/" target="_blank">CORS (Cross-Origin Resource Sharing)</a>. PR <a href="https://github.com/tiangolo/fastapi/pull/169" target="_blank">#169</a>.
* By default, encode by alias. This allows using Pydantic `alias` parameters working by default. PR <a href="https://github.com/tiangolo/fastapi/pull/168" target="_blank">#168</a>.
## 0.16.0
* Upgrade *path operation* `doctsring` parsing to support proper Markdown descriptions. New documentation at <a href="https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#description-from-docstring" target="_blank">Path Operation Configuration</a>. PR <a href="https://github.com/tiangolo/fastapi/pull/163" target="_blank">#163</a>.
* Refactor internal usage of Pydantic to use correct data types. PR <a href="https://github.com/tiangolo/fastapi/pull/164" target="_blank">#164</a>.
* Upgrade Pydantic to version `0.23`. PR <a href="https://github.com/tiangolo/fastapi/pull/160" target="_blank">#160</a> by <a href="https://github.com/euri10" target="_blank">@euri10</a>.
* Fix typo in Tutorial about Extra Models. PR <a href="https://github.com/tiangolo/fastapi/pull/159" target="_blank">#159</a> by <a href="https://github.com/danielmichaels" target="_blank">@danielmichaels</a>.
* Fix <a href="https://fastapi.tiangolo.com/tutorial/query-params/" target="_blank">Query Parameters</a> URL examples in docs. PR <a href="https://github.com/tiangolo/fastapi/pull/157" target="_blank">#157</a> by <a href="https://github.com/hayata-yamamoto" target="_blank">@hayata-yamamoto</a>.
## 0.15.0
* Add support for multiple file uploads (as a single form field). New docs at: <a href="https://fastapi.tiangolo.com/tutorial/request-files/#multiple-file-uploads" target="_blank">Multiple file uploads</a>. PR <a href="https://github.com/tiangolo/fastapi/pull/158" target="_blank">#158</a>.

View File

@@ -0,0 +1,19 @@
from fastapi import FastAPI
from starlette.middleware.cors import CORSMiddleware
app = FastAPI()
origins = [
"http://localhost.tiangolo.com",
"https://localhost.tiangolo.com",
"http:localhost",
"http:localhost:8080",
]
app.add_middleware(
CORSMiddleware,
allow_origins=origins,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)

View File

@@ -18,11 +18,11 @@ class Item(BaseModel):
async def create_item(*, item: Item):
"""
Create an item with all the information:
* name: each item must have a name
* description: a long description
* price: required
* tax: if the item doesn't have tax, you can omit this
* tags: a set of unique tag strings for this item
- **name**: each item must have a name
- **description**: a long description
- **price**: required
- **tax**: if the item doesn't have tax, you can omit this
- **tags**: a set of unique tag strings for this item
"""
return item

View File

@@ -23,11 +23,11 @@ class Item(BaseModel):
async def create_item(*, item: Item):
"""
Create an item with all the information:
* name: each item must have a name
* description: a long description
* price: required
* tax: if the item doesn't have tax, you can omit this
* tags: a set of unique tag strings for this item
- **name**: each item must have a name
- **description**: a long description
- **price**: required
- **tax**: if the item doesn't have tax, you can omit this
- **tags**: a set of unique tag strings for this item
"""
return item

55
docs/tutorial/cors.md Normal file
View File

@@ -0,0 +1,55 @@
<a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS" target="_blank">CORS or "Cross-Origin Resource Sharing"</a> refers to the situations when a frontend running in a browser has JavaScript code that communicates with a backend, and the backend is in a different "origin" than the frontend.
## Origin
An origin is the combination of protocol (`http`, `https`), domain (`myapp.com`, `localhost`, `localhost.tiangolo.com`), and port (`80`, `443`, `8080`).
So, all these are different origins:
* `http://localhost`
* `https://localhost`
* `http://localhost:8080`
Even if they are all in `localhost`, they use different protocols or ports, so, they are different "origins".
## Steps
So, let's say you have a frontend running in your browser at `http://localhost:8080`, and its JavaScript is trying to communicate with a backend running at `http://localhost` (because we don't specify a port, the browser will assume the default port `80`).
Then, the browser will send an HTTP `OPTIONS` request to the backend, and if the backend sends the appropriate headers authorizing the communication from this different origin (`http://localhost:8080`) then the browser will let the JavaScript in the frontend send its request to the backend.
To achieve this, the backend must have a list of "allowed origins".
In this case, it would have to include `http://localhost:8080` for the frontend to work correctly.
## Wildcards
It's also possible to declare the list as `"*"` (a "wildcard") to say that all are allowed.
But that will only allow certain types of communication, excluding everything that involves credentials: Cookies, Authorization headers like those used with Bearer Tokens, etc.
So, for everything to work correctly, it's better to specify explicitly the allowed origins.
## Use `CORSMiddleware`
You can configure it in your **FastAPI** application using Starlette's <a href="https://www.starlette.io/middleware/#corsmiddleware" target="_blank">`CORSMiddleware`</a>.
* Import it form Starlette.
* Create a list of allowed origins (as strings).
* Add it as a "middleware" to your **FastAPI** application.
You can also specify if your backend allows:
* Credentials (Authorization headers, Cookies, etc).
* Specific HTTP methods (`POST`, `PUT`) or all of them with the wildcard `"*"`.
* Specific HTTP headers or all of them with the wildcard `"*"`.
```Python hl_lines="2 6 7 8 9 10 11 13 14 15 16 17 18 19"
{!./src/cors/tutorial001.py!}
```
## More info
For more details of what you can specify in `CORSMiddleware`, check <a href="https://www.starlette.io/middleware/#corsmiddleware" target="_blank">Starlette's `CORSMiddleware` docs</a>.
For more info about <abbr title="Cross-Origin Resource Sharing">CORS</abbr>, check the <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS" target="_blank">Mozilla CORS documentation</a>.

View File

@@ -3,7 +3,7 @@ Continuing with the previous example, it will be common to have more than one re
This is especially the case for user models, because:
* The **input model** needs to be able to have a password.
* The **output model** should do not have a password.
* The **output model** should not have a password.
* The **database model** would probably need to have a hashed password.
!!! danger

View File

@@ -42,6 +42,8 @@ You can add a `summary` and `description`:
As descriptions tend to be long and cover multiple lines, you can declare the path operation description in the function <abbr title="a multi-line string as the first expression inside a function (not assigned to any variable) used for documentation">docstring</abbr> and **FastAPI** will read it from there.
You can write <a href="https://en.wikipedia.org/wiki/Markdown" target="_blank">Markdown</a> in the docstring, it will be interpreted and displayed correctly (taking into account docstring indentation).
```Python hl_lines="19 20 21 22 23 24 25 26 27"
{!./src/path_operation_configuration/tutorial004.py!}
```
@@ -50,9 +52,6 @@ It will be used in the interactive docs:
<img src="/img/tutorial/path-operation-configuration/image02.png">
!!! info
OpenAPI specifies that descriptions can be written in Markdown syntax, but the interactive documentation systems included still don't support it at the time of writing this, although they have it in their plans.
## Response description
You can specify the response description with the parameter `response_description`:

View File

@@ -81,31 +81,31 @@ You can also declare `bool` types, and they will be converted:
In this case, if you go to:
```
http://127.0.0.1:8000/items/?short=1
http://127.0.0.1:8000/items/foo?short=1
```
or
```
http://127.0.0.1:8000/items/?short=True
http://127.0.0.1:8000/items/foo?short=True
```
or
```
http://127.0.0.1:8000/items/?short=true
http://127.0.0.1:8000/items/foo?short=true
```
or
```
http://127.0.0.1:8000/items/?short=on
http://127.0.0.1:8000/items/foo?short=on
```
or
```
http://127.0.0.1:8000/items/?short=yes
http://127.0.0.1:8000/items/foo?short=yes
```
or any other case variation (uppercase, first letter in uppercase, etc), your function will see the parameter `short` with a `bool` value of `True`. Otherwise as `False`.

View File

@@ -121,6 +121,13 @@ To use that, declare a `List` of `bytes` or `UploadFile`:
You will receive, as declared, a `list` of `bytes` or `UploadFile`s.
!!! note
Notice that, as of 2019-04-14, Swagger UI doesn't support multiple file uploads in the same form field. For more information, check <a href="https://github.com/swagger-api/swagger-ui/issues/4276" target="_blank">#4276</a> and <a href="https://github.com/swagger-api/swagger-ui/issues/3641" target="_blank">#3641</a>.
Nevertheless, **FastAPI** is already compatible with it, using the standard OpenAPI.
So, whenever Swagger UI supports multi-file uploads, or any other tools that supports OpenAPI, they will be compatible with **FastAPI**.
## Recap
Use `File` to declare files to be uploaded as input parameters (as form data).

View File

@@ -1,6 +1,6 @@
"""FastAPI framework, high performance, easy to learn, fast to code, ready for production"""
__version__ = "0.15.0"
__version__ = "0.17.0"
from starlette.background import BackgroundTasks

View File

@@ -22,8 +22,8 @@ from fastapi.dependencies.models import Dependant, SecurityRequirement
from fastapi.security.base import SecurityBase
from fastapi.security.oauth2 import OAuth2, SecurityScopes
from fastapi.security.open_id_connect_url import OpenIdConnect
from fastapi.utils import UnconstrainedConfig, get_path_param_names
from pydantic import Schema, create_model
from fastapi.utils import get_path_param_names
from pydantic import BaseConfig, Schema, create_model
from pydantic.error_wrappers import ErrorWrapper
from pydantic.errors import MissingError
from pydantic.fields import Field, Required, Shape
@@ -203,8 +203,8 @@ def add_param_to_fields(
default=None if required else default_value,
alias=alias,
required=required,
model_config=UnconstrainedConfig,
class_validators=[],
model_config=BaseConfig,
class_validators={},
schema=schema,
)
if schema.in_ == params.ParamTypes.path:
@@ -237,8 +237,8 @@ def add_param_to_body_fields(*, param: inspect.Parameter, dependant: Dependant)
default=None if required else default_value,
alias=schema.alias or param.name,
required=required,
model_config=UnconstrainedConfig,
class_validators=[],
model_config=BaseConfig,
class_validators={},
schema=schema,
)
dependant.body_params.append(field)
@@ -336,7 +336,7 @@ def request_params_to_args(
ErrorWrapper(
MissingError(),
loc=(schema.in_.value, field.alias),
config=UnconstrainedConfig,
config=BaseConfig,
)
)
else:
@@ -379,9 +379,7 @@ async def request_body_to_args(
if field.required:
errors.append(
ErrorWrapper(
MissingError(),
loc=("body", field.alias),
config=UnconstrainedConfig,
MissingError(), loc=("body", field.alias), config=BaseConfig
)
)
else:
@@ -456,8 +454,8 @@ def get_body_field(*, dependant: Dependant, name: str) -> Optional[Field]:
type_=BodyModel,
default=None,
required=required,
model_config=UnconstrainedConfig,
class_validators=[],
model_config=BaseConfig,
class_validators={},
alias="body",
schema=BodySchema(None),
)

View File

@@ -10,7 +10,7 @@ def jsonable_encoder(
obj: Any,
include: Set[str] = None,
exclude: Set[str] = set(),
by_alias: bool = False,
by_alias: bool = True,
include_none: bool = True,
custom_encoder: dict = {},
sqlalchemy_safe: bool = True,

View File

@@ -7,8 +7,7 @@ from fastapi import params
from fastapi.dependencies.models import Dependant
from fastapi.dependencies.utils import get_body_field, get_dependant, solve_dependencies
from fastapi.encoders import jsonable_encoder
from fastapi.utils import UnconstrainedConfig
from pydantic import BaseModel, Schema
from pydantic import BaseConfig, BaseModel, Schema
from pydantic.error_wrappers import ErrorWrapper, ValidationError
from pydantic.fields import Field
from pydantic.utils import lenient_issubclass
@@ -59,7 +58,7 @@ def get_app(
if body_bytes:
body = await request.json()
except Exception as e:
logging.error("Error getting request body", e)
logging.error(f"Error getting request body: {e}")
raise HTTPException(
status_code=400, detail="There was an error parsing the body"
)
@@ -126,10 +125,10 @@ class APIRoute(routing.Route):
self.response_field: Optional[Field] = Field(
name=response_name,
type_=self.response_model,
class_validators=[],
class_validators={},
default=None,
required=False,
model_config=UnconstrainedConfig,
model_config=BaseConfig,
schema=Schema(None),
)
else:
@@ -137,7 +136,7 @@ class APIRoute(routing.Route):
self.status_code = status_code
self.tags = tags or []
self.summary = summary
self.description = description or self.endpoint.__doc__
self.description = description or inspect.cleandoc(self.endpoint.__doc__ or "")
self.response_description = response_description
self.responses = responses or {}
response_fields = {}
@@ -155,7 +154,7 @@ class APIRoute(routing.Route):
class_validators=None,
default=None,
required=False,
model_config=UnconstrainedConfig,
model_config=BaseConfig,
schema=Schema(None),
)
response_fields[additional_status_code] = response_field

View File

@@ -3,17 +3,12 @@ from typing import Any, Dict, List, Sequence, Set, Type
from fastapi import routing
from fastapi.openapi.constants import REF_PREFIX
from pydantic import BaseConfig, BaseModel
from pydantic import BaseModel
from pydantic.fields import Field
from pydantic.schema import get_flat_models_from_fields, model_process_schema
from starlette.routing import BaseRoute
class UnconstrainedConfig(BaseConfig):
min_anystr_length = None
max_anystr_length = None
def get_flat_models_from_routes(
routes: Sequence[Type[BaseRoute]]
) -> Set[Type[BaseModel]]:

View File

@@ -58,6 +58,7 @@ nav:
- Simple OAuth2 with Password and Bearer: 'tutorial/security/simple-oauth2.md'
- OAuth2 with Password (and hashing), Bearer with JWT tokens: 'tutorial/security/oauth2-jwt.md'
- OAuth2 scopes: 'tutorial/security/oauth2-scopes.md'
- CORS (Cross-Origin Resource Sharing): 'tutorial/cors.md'
- Using the Request Directly: 'tutorial/using-request-directly.md'
- SQL (Relational) Databases: 'tutorial/sql-databases.md'
- Async SQL (Relational) Databases: 'tutorial/async-sql-databases.md'

View File

@@ -20,7 +20,7 @@ classifiers = [
]
requires = [
"starlette ==0.11.1",
"pydantic >=0.17,<=0.21.0"
"pydantic >=0.17,<=0.23.0"
]
description-file = "README.md"
requires-python = ">=3.6"

7
scripts/deploy.sh Executable file
View File

@@ -0,0 +1,7 @@
#!/usr/bin/env bash
set -e
bash scripts/publish.sh
bash scripts/trigger-docker.sh

5
scripts/publish.sh Executable file
View File

@@ -0,0 +1,5 @@
#!/usr/bin/env bash
set -e
flit publish

View File

@@ -3,7 +3,7 @@ from enum import Enum
import pytest
from fastapi.encoders import jsonable_encoder
from pydantic import BaseModel
from pydantic import BaseModel, Schema, ValidationError
class Person:
@@ -59,6 +59,10 @@ class ModelWithConfig(BaseModel):
use_enum_values = True
class ModelWithAlias(BaseModel):
foo: str = Schema(..., alias="Foo")
def test_encode_class():
person = Person(name="Foo")
pet = Pet(owner=person, name="Firulais")
@@ -85,3 +89,13 @@ def test_encode_custom_json_encoders_model():
def test_encode_model_with_config():
model = ModelWithConfig(role=RoleEnum.admin)
assert jsonable_encoder(model) == {"role": "admin"}
def test_encode_model_with_alias_raises():
with pytest.raises(ValidationError):
model = ModelWithAlias(foo="Bar")
def test_encode_model_with_alias():
model = ModelWithAlias(Foo="Bar")
assert jsonable_encoder(model) == {"Foo": "Bar"}

View File

@@ -31,7 +31,7 @@ openapi_schema = {
},
},
"summary": "Create an item",
"description": "\n Create an item with all the information:\n \n * name: each item must have a name\n * description: a long description\n * price: required\n * tax: if the item doesn't have tax, you can omit this\n * tags: a set of unique tag strings for this item\n ",
"description": "Create an item with all the information:\n\n- **name**: each item must have a name\n- **description**: a long description\n- **price**: required\n- **tax**: if the item doesn't have tax, you can omit this\n- **tags**: a set of unique tag strings for this item",
"operationId": "create_item_items__post",
"requestBody": {
"content": {