Add files using upload-large-folder tool
Browse filesThis view is limited to 50 files because it contains too many changes. See raw diff
- lib/python3.12/site-packages/cloudpickle-3.1.2.dist-info/INSTALLER +1 -0
- lib/python3.12/site-packages/cloudpickle-3.1.2.dist-info/METADATA +187 -0
- lib/python3.12/site-packages/cloudpickle-3.1.2.dist-info/RECORD +11 -0
- lib/python3.12/site-packages/cloudpickle-3.1.2.dist-info/WHEEL +4 -0
- lib/python3.12/site-packages/cloudpickle-3.1.2.dist-info/licenses/LICENSE +32 -0
- lib/python3.12/site-packages/compressed_tensors-0.9.3.dist-info/INSTALLER +1 -0
- lib/python3.12/site-packages/compressed_tensors-0.9.3.dist-info/METADATA +169 -0
- lib/python3.12/site-packages/compressed_tensors-0.9.3.dist-info/RECORD +101 -0
- lib/python3.12/site-packages/compressed_tensors-0.9.3.dist-info/REQUESTED +0 -0
- lib/python3.12/site-packages/compressed_tensors-0.9.3.dist-info/WHEEL +5 -0
- lib/python3.12/site-packages/compressed_tensors-0.9.3.dist-info/licenses/LICENSE +201 -0
- lib/python3.12/site-packages/compressed_tensors-0.9.3.dist-info/top_level.txt +1 -0
- lib/python3.12/site-packages/fastapi/__init__.py +25 -0
- lib/python3.12/site-packages/fastapi/__main__.py +3 -0
- lib/python3.12/site-packages/fastapi/__pycache__/param_functions.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/fastapi/_compat.py +659 -0
- lib/python3.12/site-packages/fastapi/applications.py +0 -0
- lib/python3.12/site-packages/fastapi/background.py +59 -0
- lib/python3.12/site-packages/fastapi/cli.py +13 -0
- lib/python3.12/site-packages/fastapi/concurrency.py +39 -0
- lib/python3.12/site-packages/fastapi/datastructures.py +204 -0
- lib/python3.12/site-packages/fastapi/encoders.py +343 -0
- lib/python3.12/site-packages/fastapi/exception_handlers.py +34 -0
- lib/python3.12/site-packages/fastapi/exceptions.py +176 -0
- lib/python3.12/site-packages/fastapi/logger.py +3 -0
- lib/python3.12/site-packages/fastapi/openapi/__init__.py +0 -0
- lib/python3.12/site-packages/fastapi/openapi/__pycache__/__init__.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/fastapi/openapi/__pycache__/constants.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/fastapi/openapi/__pycache__/docs.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/fastapi/openapi/__pycache__/models.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/fastapi/openapi/__pycache__/utils.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/fastapi/openapi/constants.py +3 -0
- lib/python3.12/site-packages/fastapi/openapi/docs.py +344 -0
- lib/python3.12/site-packages/fastapi/openapi/models.py +445 -0
- lib/python3.12/site-packages/fastapi/openapi/utils.py +569 -0
- lib/python3.12/site-packages/fastapi/param_functions.py +2360 -0
- lib/python3.12/site-packages/fastapi/params.py +786 -0
- lib/python3.12/site-packages/fastapi/py.typed +0 -0
- lib/python3.12/site-packages/fastapi/requests.py +2 -0
- lib/python3.12/site-packages/fastapi/responses.py +48 -0
- lib/python3.12/site-packages/fastapi/routing.py +0 -0
- lib/python3.12/site-packages/fastapi/security/__init__.py +15 -0
- lib/python3.12/site-packages/fastapi/security/__pycache__/__init__.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/fastapi/security/__pycache__/api_key.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/fastapi/security/__pycache__/base.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/fastapi/security/__pycache__/http.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/fastapi/security/__pycache__/oauth2.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/fastapi/security/__pycache__/open_id_connect_url.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/fastapi/security/__pycache__/utils.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/fastapi/security/api_key.py +288 -0
lib/python3.12/site-packages/cloudpickle-3.1.2.dist-info/INSTALLER
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
pip
|
lib/python3.12/site-packages/cloudpickle-3.1.2.dist-info/METADATA
ADDED
|
@@ -0,0 +1,187 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Metadata-Version: 2.4
|
| 2 |
+
Name: cloudpickle
|
| 3 |
+
Version: 3.1.2
|
| 4 |
+
Summary: Pickler class to extend the standard pickle.Pickler functionality
|
| 5 |
+
Home-page: https://github.com/cloudpipe/cloudpickle
|
| 6 |
+
Author: The cloudpickle developer team
|
| 7 |
+
Author-email: cloudpipe@googlegroups.com
|
| 8 |
+
Requires-Python: >=3.8
|
| 9 |
+
Description-Content-Type: text/markdown
|
| 10 |
+
License: BSD-3-Clause
|
| 11 |
+
Classifier: Development Status :: 5 - Production/Stable
|
| 12 |
+
Classifier: Intended Audience :: Developers
|
| 13 |
+
Classifier: License :: OSI Approved :: BSD License
|
| 14 |
+
Classifier: Operating System :: POSIX
|
| 15 |
+
Classifier: Operating System :: Microsoft :: Windows
|
| 16 |
+
Classifier: Operating System :: MacOS :: MacOS X
|
| 17 |
+
Classifier: Programming Language :: Python :: 3.8
|
| 18 |
+
Classifier: Programming Language :: Python :: 3.9
|
| 19 |
+
Classifier: Programming Language :: Python :: 3.10
|
| 20 |
+
Classifier: Programming Language :: Python :: 3.11
|
| 21 |
+
Classifier: Programming Language :: Python :: 3.12
|
| 22 |
+
Classifier: Programming Language :: Python :: 3.13
|
| 23 |
+
Classifier: Programming Language :: Python :: 3.14
|
| 24 |
+
Classifier: Programming Language :: Python :: Implementation :: CPython
|
| 25 |
+
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
| 26 |
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
| 27 |
+
Classifier: Topic :: Scientific/Engineering
|
| 28 |
+
Classifier: Topic :: System :: Distributed Computing
|
| 29 |
+
License-File: LICENSE
|
| 30 |
+
|
| 31 |
+
# cloudpickle
|
| 32 |
+
|
| 33 |
+
[](https://github.com/cloudpipe/cloudpickle/actions)
|
| 34 |
+
[](https://codecov.io/github/cloudpipe/cloudpickle?branch=master)
|
| 35 |
+
|
| 36 |
+
`cloudpickle` makes it possible to serialize Python constructs not supported
|
| 37 |
+
by the default `pickle` module from the Python standard library.
|
| 38 |
+
|
| 39 |
+
`cloudpickle` is especially useful for **cluster computing** where Python
|
| 40 |
+
code is shipped over the network to execute on remote hosts, possibly close
|
| 41 |
+
to the data.
|
| 42 |
+
|
| 43 |
+
Among other things, `cloudpickle` supports pickling for **lambda functions**
|
| 44 |
+
along with **functions and classes defined interactively** in the
|
| 45 |
+
`__main__` module (for instance in a script, a shell or a Jupyter notebook).
|
| 46 |
+
|
| 47 |
+
Cloudpickle can only be used to send objects between the **exact same version
|
| 48 |
+
of Python**.
|
| 49 |
+
|
| 50 |
+
Using `cloudpickle` for **long-term object storage is not supported and
|
| 51 |
+
strongly discouraged.**
|
| 52 |
+
|
| 53 |
+
**Security notice**: one should **only load pickle data from trusted sources** as
|
| 54 |
+
otherwise `pickle.load` can lead to arbitrary code execution resulting in a critical
|
| 55 |
+
security vulnerability.
|
| 56 |
+
|
| 57 |
+
|
| 58 |
+
Installation
|
| 59 |
+
------------
|
| 60 |
+
|
| 61 |
+
The latest release of `cloudpickle` is available from
|
| 62 |
+
[pypi](https://pypi.python.org/pypi/cloudpickle):
|
| 63 |
+
|
| 64 |
+
pip install cloudpickle
|
| 65 |
+
|
| 66 |
+
|
| 67 |
+
Examples
|
| 68 |
+
--------
|
| 69 |
+
|
| 70 |
+
Pickling a lambda expression:
|
| 71 |
+
|
| 72 |
+
```python
|
| 73 |
+
>>> import cloudpickle
|
| 74 |
+
>>> squared = lambda x: x ** 2
|
| 75 |
+
>>> pickled_lambda = cloudpickle.dumps(squared)
|
| 76 |
+
|
| 77 |
+
>>> import pickle
|
| 78 |
+
>>> new_squared = pickle.loads(pickled_lambda)
|
| 79 |
+
>>> new_squared(2)
|
| 80 |
+
4
|
| 81 |
+
```
|
| 82 |
+
|
| 83 |
+
Pickling a function interactively defined in a Python shell session
|
| 84 |
+
(in the `__main__` module):
|
| 85 |
+
|
| 86 |
+
```python
|
| 87 |
+
>>> CONSTANT = 42
|
| 88 |
+
>>> def my_function(data: int) -> int:
|
| 89 |
+
... return data + CONSTANT
|
| 90 |
+
...
|
| 91 |
+
>>> pickled_function = cloudpickle.dumps(my_function)
|
| 92 |
+
>>> depickled_function = pickle.loads(pickled_function)
|
| 93 |
+
>>> depickled_function
|
| 94 |
+
<function __main__.my_function(data:int) -> int>
|
| 95 |
+
>>> depickled_function(43)
|
| 96 |
+
85
|
| 97 |
+
```
|
| 98 |
+
|
| 99 |
+
|
| 100 |
+
Overriding pickle's serialization mechanism for importable constructs:
|
| 101 |
+
----------------------------------------------------------------------
|
| 102 |
+
|
| 103 |
+
An important difference between `cloudpickle` and `pickle` is that
|
| 104 |
+
`cloudpickle` can serialize a function or class **by value**, whereas `pickle`
|
| 105 |
+
can only serialize it **by reference**. Serialization by reference treats
|
| 106 |
+
functions and classes as attributes of modules, and pickles them through
|
| 107 |
+
instructions that trigger the import of their module at load time.
|
| 108 |
+
Serialization by reference is thus limited in that it assumes that the module
|
| 109 |
+
containing the function or class is available/importable in the unpickling
|
| 110 |
+
environment. This assumption breaks when pickling constructs defined in an
|
| 111 |
+
interactive session, a case that is automatically detected by `cloudpickle`,
|
| 112 |
+
that pickles such constructs **by value**.
|
| 113 |
+
|
| 114 |
+
Another case where the importability assumption is expected to break is when
|
| 115 |
+
developing a module in a distributed execution environment: the worker
|
| 116 |
+
processes may not have access to the said module, for example if they live on a
|
| 117 |
+
different machine than the process in which the module is being developed. By
|
| 118 |
+
itself, `cloudpickle` cannot detect such "locally importable" modules and
|
| 119 |
+
switch to serialization by value; instead, it relies on its default mode, which
|
| 120 |
+
is serialization by reference. However, since `cloudpickle 2.0.0`, one can
|
| 121 |
+
explicitly specify modules for which serialization by value should be used,
|
| 122 |
+
using the
|
| 123 |
+
`register_pickle_by_value(module)`/`/unregister_pickle_by_value(module)` API:
|
| 124 |
+
|
| 125 |
+
```python
|
| 126 |
+
>>> import cloudpickle
|
| 127 |
+
>>> import my_module
|
| 128 |
+
>>> cloudpickle.register_pickle_by_value(my_module)
|
| 129 |
+
>>> cloudpickle.dumps(my_module.my_function) # my_function is pickled by value
|
| 130 |
+
>>> cloudpickle.unregister_pickle_by_value(my_module)
|
| 131 |
+
>>> cloudpickle.dumps(my_module.my_function) # my_function is pickled by reference
|
| 132 |
+
```
|
| 133 |
+
|
| 134 |
+
Using this API, there is no need to re-install the new version of the module on
|
| 135 |
+
all the worker nodes nor to restart the workers: restarting the client Python
|
| 136 |
+
process with the new source code is enough.
|
| 137 |
+
|
| 138 |
+
Note that this feature is still **experimental**, and may fail in the following
|
| 139 |
+
situations:
|
| 140 |
+
|
| 141 |
+
- If the body of a function/class pickled by value contains an `import` statement:
|
| 142 |
+
```python
|
| 143 |
+
>>> def f():
|
| 144 |
+
>>> ... from another_module import g
|
| 145 |
+
>>> ... # calling f in the unpickling environment may fail if another_module
|
| 146 |
+
>>> ... # is unavailable
|
| 147 |
+
>>> ... return g() + 1
|
| 148 |
+
```
|
| 149 |
+
|
| 150 |
+
- If a function pickled by reference uses a function pickled by value during its execution.
|
| 151 |
+
|
| 152 |
+
|
| 153 |
+
Running the tests
|
| 154 |
+
-----------------
|
| 155 |
+
|
| 156 |
+
- With `tox`, to test run the tests for all the supported versions of
|
| 157 |
+
Python and PyPy:
|
| 158 |
+
|
| 159 |
+
pip install tox
|
| 160 |
+
tox
|
| 161 |
+
|
| 162 |
+
or alternatively for a specific environment:
|
| 163 |
+
|
| 164 |
+
tox -e py312
|
| 165 |
+
|
| 166 |
+
|
| 167 |
+
- With `pytest` to only run the tests for your current version of
|
| 168 |
+
Python:
|
| 169 |
+
|
| 170 |
+
pip install -r dev-requirements.txt
|
| 171 |
+
PYTHONPATH='.:tests' pytest
|
| 172 |
+
|
| 173 |
+
History
|
| 174 |
+
-------
|
| 175 |
+
|
| 176 |
+
`cloudpickle` was initially developed by [picloud.com](http://web.archive.org/web/20140721022102/http://blog.picloud.com/2013/11/17/picloud-has-joined-dropbox/) and shipped as part of
|
| 177 |
+
the client SDK.
|
| 178 |
+
|
| 179 |
+
A copy of `cloudpickle.py` was included as part of PySpark, the Python
|
| 180 |
+
interface to [Apache Spark](https://spark.apache.org/). Davies Liu, Josh
|
| 181 |
+
Rosen, Thom Neale and other Apache Spark developers improved it significantly,
|
| 182 |
+
most notably to add support for PyPy and Python 3.
|
| 183 |
+
|
| 184 |
+
The aim of the `cloudpickle` project is to make that work available to a wider
|
| 185 |
+
audience outside of the Spark ecosystem and to make it easier to improve it
|
| 186 |
+
further notably with the help of a dedicated non-regression test suite.
|
| 187 |
+
|
lib/python3.12/site-packages/cloudpickle-3.1.2.dist-info/RECORD
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
cloudpickle-3.1.2.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
|
| 2 |
+
cloudpickle-3.1.2.dist-info/METADATA,sha256=PQJjv-nuTyOyRL3K_3OsvnoZV-v4J0O2rkJpOtxI1yE,7079
|
| 3 |
+
cloudpickle-3.1.2.dist-info/RECORD,,
|
| 4 |
+
cloudpickle-3.1.2.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82
|
| 5 |
+
cloudpickle-3.1.2.dist-info/licenses/LICENSE,sha256=MCnqNBc-n9wjOtMV3GsQC9HqcfUpscGvl2ZKJy_cVfU,1754
|
| 6 |
+
cloudpickle/__init__.py,sha256=ErKyvqqAErOkbCowrizhGpN9DN-TaD22QtqI9CQ9sDw,308
|
| 7 |
+
cloudpickle/__pycache__/__init__.cpython-312.pyc,,
|
| 8 |
+
cloudpickle/__pycache__/cloudpickle.cpython-312.pyc,,
|
| 9 |
+
cloudpickle/__pycache__/cloudpickle_fast.cpython-312.pyc,,
|
| 10 |
+
cloudpickle/cloudpickle.py,sha256=KcLA_uAxp2KuMJb9vaTVve7FLFUQu7mYkD3dCscxeRc,58874
|
| 11 |
+
cloudpickle/cloudpickle_fast.py,sha256=AI5ZKf2AbLNxD8lXyLDpKZyzeZ2ofFtdK1ZWFq_ec1c,323
|
lib/python3.12/site-packages/cloudpickle-3.1.2.dist-info/WHEEL
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Wheel-Version: 1.0
|
| 2 |
+
Generator: flit 3.12.0
|
| 3 |
+
Root-Is-Purelib: true
|
| 4 |
+
Tag: py3-none-any
|
lib/python3.12/site-packages/cloudpickle-3.1.2.dist-info/licenses/LICENSE
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
This module was extracted from the `cloud` package, developed by
|
| 2 |
+
PiCloud, Inc.
|
| 3 |
+
|
| 4 |
+
Copyright (c) 2015, Cloudpickle contributors.
|
| 5 |
+
Copyright (c) 2012, Regents of the University of California.
|
| 6 |
+
Copyright (c) 2009 PiCloud, Inc. http://www.picloud.com.
|
| 7 |
+
All rights reserved.
|
| 8 |
+
|
| 9 |
+
Redistribution and use in source and binary forms, with or without
|
| 10 |
+
modification, are permitted provided that the following conditions
|
| 11 |
+
are met:
|
| 12 |
+
* Redistributions of source code must retain the above copyright
|
| 13 |
+
notice, this list of conditions and the following disclaimer.
|
| 14 |
+
* Redistributions in binary form must reproduce the above copyright
|
| 15 |
+
notice, this list of conditions and the following disclaimer in the
|
| 16 |
+
documentation and/or other materials provided with the distribution.
|
| 17 |
+
* Neither the name of the University of California, Berkeley nor the
|
| 18 |
+
names of its contributors may be used to endorse or promote
|
| 19 |
+
products derived from this software without specific prior written
|
| 20 |
+
permission.
|
| 21 |
+
|
| 22 |
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
| 23 |
+
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
| 24 |
+
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
| 25 |
+
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
| 26 |
+
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
| 27 |
+
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
| 28 |
+
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
| 29 |
+
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
| 30 |
+
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
| 31 |
+
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
| 32 |
+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
lib/python3.12/site-packages/compressed_tensors-0.9.3.dist-info/INSTALLER
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
pip
|
lib/python3.12/site-packages/compressed_tensors-0.9.3.dist-info/METADATA
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Metadata-Version: 2.4
|
| 2 |
+
Name: compressed-tensors
|
| 3 |
+
Version: 0.9.3
|
| 4 |
+
Summary: Library for utilization of compressed safetensors of neural network models
|
| 5 |
+
Home-page: https://github.com/neuralmagic/compressed-tensors
|
| 6 |
+
Author: Neuralmagic, Inc.
|
| 7 |
+
Author-email: support@neuralmagic.com
|
| 8 |
+
License: Apache 2.0
|
| 9 |
+
Description-Content-Type: text/markdown
|
| 10 |
+
License-File: LICENSE
|
| 11 |
+
Requires-Dist: torch>=1.7.0
|
| 12 |
+
Requires-Dist: transformers
|
| 13 |
+
Requires-Dist: pydantic>=2.0
|
| 14 |
+
Provides-Extra: dev
|
| 15 |
+
Requires-Dist: black==22.12.0; extra == "dev"
|
| 16 |
+
Requires-Dist: isort==5.8.0; extra == "dev"
|
| 17 |
+
Requires-Dist: wheel>=0.36.2; extra == "dev"
|
| 18 |
+
Requires-Dist: flake8>=3.8.3; extra == "dev"
|
| 19 |
+
Requires-Dist: pytest>=6.0.0; extra == "dev"
|
| 20 |
+
Requires-Dist: nbconvert>=7.16.3; extra == "dev"
|
| 21 |
+
Provides-Extra: accelerate
|
| 22 |
+
Requires-Dist: accelerate; extra == "accelerate"
|
| 23 |
+
Dynamic: author
|
| 24 |
+
Dynamic: author-email
|
| 25 |
+
Dynamic: description
|
| 26 |
+
Dynamic: description-content-type
|
| 27 |
+
Dynamic: home-page
|
| 28 |
+
Dynamic: license
|
| 29 |
+
Dynamic: license-file
|
| 30 |
+
Dynamic: provides-extra
|
| 31 |
+
Dynamic: requires-dist
|
| 32 |
+
Dynamic: summary
|
| 33 |
+
|
| 34 |
+
# compressed-tensors
|
| 35 |
+
|
| 36 |
+
The `compressed-tensors` library extends the [safetensors](https://github.com/huggingface/safetensors) format, providing a versatile and efficient way to store and manage compressed tensor data. This library supports various quantization and sparsity schemes, making it a unified format for handling different model optimizations like GPTQ, AWQ, SmoothQuant, INT8, FP8, SparseGPT, and more.
|
| 37 |
+
|
| 38 |
+
## Why `compressed-tensors`?
|
| 39 |
+
|
| 40 |
+
As model compression becomes increasingly important for efficient deployment of LLMs, the landscape of quantization and compression techniques has become increasingly fragmented.
|
| 41 |
+
Each method often comes with its own storage format and loading procedures, making it challenging to work with multiple techniques or switch between them.
|
| 42 |
+
`compressed-tensors` addresses this by providing a single, extensible format that can represent a wide variety of compression schemes.
|
| 43 |
+
|
| 44 |
+
* **Unified Checkpoint Format**: Supports various compression schemes in a single, consistent format.
|
| 45 |
+
* **Wide Compatibility**: Works with popular quantization methods like GPTQ, SmoothQuant, and FP8. See [llm-compressor](https://github.com/vllm-project/llm-compressor)
|
| 46 |
+
* **Flexible Quantization Support**:
|
| 47 |
+
* Weight-only quantization (e.g., W4A16, W8A16, WnA16)
|
| 48 |
+
* Activation quantization (e.g., W8A8)
|
| 49 |
+
* KV cache quantization
|
| 50 |
+
* Non-uniform schemes (different layers can be quantized in different ways!)
|
| 51 |
+
* **Sparsity Support**: Handles both unstructured and semi-structured (e.g., 2:4) sparsity patterns.
|
| 52 |
+
* **Open-Source Integration**: Designed to work seamlessly with Hugging Face models and PyTorch.
|
| 53 |
+
|
| 54 |
+
This allows developers and researchers to easily experiment with composing different quantization methods, simplify model deployment pipelines, and reduce the overhead of supporting multiple compression formats in inference engines.
|
| 55 |
+
|
| 56 |
+
## Installation
|
| 57 |
+
|
| 58 |
+
### From [PyPI](https://pypi.org/project/compressed-tensors)
|
| 59 |
+
|
| 60 |
+
Stable release:
|
| 61 |
+
```bash
|
| 62 |
+
pip install compressed-tensors
|
| 63 |
+
```
|
| 64 |
+
|
| 65 |
+
Nightly release:
|
| 66 |
+
```bash
|
| 67 |
+
pip install compressed-tensors-nightly
|
| 68 |
+
```
|
| 69 |
+
|
| 70 |
+
### From Source
|
| 71 |
+
|
| 72 |
+
```bash
|
| 73 |
+
git clone https://github.com/neuralmagic/compressed-tensors
|
| 74 |
+
cd compressed-tensors
|
| 75 |
+
pip install -e .
|
| 76 |
+
```
|
| 77 |
+
|
| 78 |
+
## Getting started
|
| 79 |
+
|
| 80 |
+
### Saving/Loading Compressed Tensors (Bitmask Compression)
|
| 81 |
+
|
| 82 |
+
The function `save_compressed` uses the `compression_format` argument to apply compression to tensors.
|
| 83 |
+
The function `load_compressed` reverses the process: converts the compressed weights on disk to decompressed weights in device memory.
|
| 84 |
+
|
| 85 |
+
```python
|
| 86 |
+
from compressed_tensors import save_compressed, load_compressed, BitmaskConfig
|
| 87 |
+
from torch import Tensor
|
| 88 |
+
from typing import Dict
|
| 89 |
+
|
| 90 |
+
# the example BitmaskConfig method efficiently compresses
|
| 91 |
+
# tensors with large number of zero entries
|
| 92 |
+
compression_config = BitmaskConfig()
|
| 93 |
+
|
| 94 |
+
tensors: Dict[str, Tensor] = {"tensor_1": Tensor(
|
| 95 |
+
[[0.0, 0.0, 0.0],
|
| 96 |
+
[1.0, 1.0, 1.0]]
|
| 97 |
+
)}
|
| 98 |
+
# compress tensors using BitmaskConfig compression format (save them efficiently on disk)
|
| 99 |
+
save_compressed(tensors, "model.safetensors", compression_format=compression_config.format)
|
| 100 |
+
|
| 101 |
+
# decompress tensors (load_compressed returns a generator for memory efficiency)
|
| 102 |
+
decompressed_tensors = {}
|
| 103 |
+
for tensor_name, tensor in load_compressed("model.safetensors", compression_config = compression_config):
|
| 104 |
+
decompressed_tensors[tensor_name] = tensor
|
| 105 |
+
```
|
| 106 |
+
|
| 107 |
+
## Saving/Loading Compressed Models (Bitmask Compression)
|
| 108 |
+
|
| 109 |
+
We can apply bitmask compression to a whole model. For more detailed example see `example` directory.
|
| 110 |
+
```python
|
| 111 |
+
from compressed_tensors import save_compressed_model, load_compressed, BitmaskConfig
|
| 112 |
+
from transformers import AutoModelForCausalLM
|
| 113 |
+
|
| 114 |
+
model_name = "neuralmagic/llama2.c-stories110M-pruned50"
|
| 115 |
+
model = AutoModelForCausalLM.from_pretrained(model_name, torch_dtype="auto")
|
| 116 |
+
|
| 117 |
+
original_state_dict = model.state_dict()
|
| 118 |
+
|
| 119 |
+
compression_config = BitmaskConfig()
|
| 120 |
+
|
| 121 |
+
# save compressed model weights
|
| 122 |
+
save_compressed_model(model, "compressed_model.safetensors", compression_format=compression_config.format)
|
| 123 |
+
|
| 124 |
+
# load compressed model weights (`dict` turns generator into a dictionary)
|
| 125 |
+
state_dict = dict(load_compressed("compressed_model.safetensors", compression_config))
|
| 126 |
+
```
|
| 127 |
+
|
| 128 |
+
For more in-depth tutorial on bitmask compression, refer to the [notebook](https://github.com/neuralmagic/compressed-tensors/blob/d707c5b84bc3fef164aebdcd97cb6eaa571982f8/examples/bitmask_compression.ipynb).
|
| 129 |
+
|
| 130 |
+
|
| 131 |
+
## Saving a Compressed Model with PTQ
|
| 132 |
+
|
| 133 |
+
We can use compressed-tensors to run basic post training quantization (PTQ) and save the quantized model compressed on disk
|
| 134 |
+
|
| 135 |
+
```python
|
| 136 |
+
model_name = "TinyLlama/TinyLlama-1.1B-intermediate-step-1431k-3T"
|
| 137 |
+
model = AutoModelForCausalLM.from_pretrained(model_name, device_map="cuda:0", torch_dtype="auto")
|
| 138 |
+
|
| 139 |
+
config = QuantizationConfig.parse_file("./examples/bit_packing/int4_config.json")
|
| 140 |
+
config.quantization_status = QuantizationStatus.CALIBRATION
|
| 141 |
+
apply_quantization_config(model, config)
|
| 142 |
+
|
| 143 |
+
dataset = load_dataset("ptb_text_only")["train"]
|
| 144 |
+
tokenizer = AutoTokenizer.from_pretrained(model_name)
|
| 145 |
+
|
| 146 |
+
def tokenize_function(examples):
|
| 147 |
+
return tokenizer(examples["sentence"], padding=False, truncation=True, max_length=1024)
|
| 148 |
+
|
| 149 |
+
tokenized_dataset = dataset.map(tokenize_function, batched=True)
|
| 150 |
+
data_loader = DataLoader(tokenized_dataset, batch_size=1, collate_fn=DefaultDataCollator())
|
| 151 |
+
|
| 152 |
+
with torch.no_grad():
|
| 153 |
+
for idx, sample in tqdm(enumerate(data_loader), desc="Running calibration"):
|
| 154 |
+
sample = {key: value.to(device) for key,value in sample.items()}
|
| 155 |
+
_ = model(**sample)
|
| 156 |
+
|
| 157 |
+
if idx >= 512:
|
| 158 |
+
break
|
| 159 |
+
|
| 160 |
+
model.apply(freeze_module_quantization)
|
| 161 |
+
model.apply(compress_quantized_weights)
|
| 162 |
+
|
| 163 |
+
output_dir = "./ex_llama1.1b_w4a16_packed_quantize"
|
| 164 |
+
compressor = ModelCompressor(quantization_config=config)
|
| 165 |
+
compressed_state_dict = compressor.compress(model)
|
| 166 |
+
model.save_pretrained(output_dir, state_dict=compressed_state_dict)
|
| 167 |
+
```
|
| 168 |
+
|
| 169 |
+
For more in-depth tutorial on quantization compression, refer to the [notebook](./examples/quantize_and_pack_int4.ipynb).
|
lib/python3.12/site-packages/compressed_tensors-0.9.3.dist-info/RECORD
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
compressed_tensors-0.9.3.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
|
| 2 |
+
compressed_tensors-0.9.3.dist-info/METADATA,sha256=zs3aFaG-BGV9hqJbW9Zwzex0TVcM5sPZhiaeVx2qjR0,6997
|
| 3 |
+
compressed_tensors-0.9.3.dist-info/RECORD,,
|
| 4 |
+
compressed_tensors-0.9.3.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
| 5 |
+
compressed_tensors-0.9.3.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
|
| 6 |
+
compressed_tensors-0.9.3.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
| 7 |
+
compressed_tensors-0.9.3.dist-info/top_level.txt,sha256=w2i-GyPs2s1UwVxvutSvN_lM22SXC2hQFBmoMcPnV7Y,19
|
| 8 |
+
compressed_tensors/__init__.py,sha256=UtKmifNeBCSE2TZSAfduVNNzHY-3V7bLjZ7n7RuXLOE,812
|
| 9 |
+
compressed_tensors/__pycache__/__init__.cpython-312.pyc,,
|
| 10 |
+
compressed_tensors/__pycache__/base.cpython-312.pyc,,
|
| 11 |
+
compressed_tensors/__pycache__/version.cpython-312.pyc,,
|
| 12 |
+
compressed_tensors/base.py,sha256=73HYH7HY7O2roC89yG_piPFnZwrBfn_i7HmKl90SKc0,875
|
| 13 |
+
compressed_tensors/compressors/__init__.py,sha256=smSygTSfcfuujRrAXDc6uZm4L_ccV1tWZewqVnOb4lM,825
|
| 14 |
+
compressed_tensors/compressors/__pycache__/__init__.cpython-312.pyc,,
|
| 15 |
+
compressed_tensors/compressors/__pycache__/base.cpython-312.pyc,,
|
| 16 |
+
compressed_tensors/compressors/__pycache__/helpers.cpython-312.pyc,,
|
| 17 |
+
compressed_tensors/compressors/base.py,sha256=x8dQrWVEurynXw03yHJZTaAmrRTOsdZJoHjmvs0IKwk,7002
|
| 18 |
+
compressed_tensors/compressors/helpers.py,sha256=OK6qxX9j3bHwF9JfIYSGMgBJe2PWjlTA3byXKCJaTIQ,5431
|
| 19 |
+
compressed_tensors/compressors/model_compressors/__init__.py,sha256=5RGGPFu4YqEt_aOdFSQYFYFDjcZFJN0CsMqRtDZz3Js,666
|
| 20 |
+
compressed_tensors/compressors/model_compressors/__pycache__/__init__.cpython-312.pyc,,
|
| 21 |
+
compressed_tensors/compressors/model_compressors/__pycache__/model_compressor.cpython-312.pyc,,
|
| 22 |
+
compressed_tensors/compressors/model_compressors/model_compressor.py,sha256=n0gcrKwefJuO6b4LNjCynJQf7NNqNHDcoLlzZgTCPGc,23080
|
| 23 |
+
compressed_tensors/compressors/quantized_compressors/__init__.py,sha256=09UJq68Pht6Bf-4iP9xYl3tetKsncNPHD8IAGbePsr4,714
|
| 24 |
+
compressed_tensors/compressors/quantized_compressors/__pycache__/__init__.cpython-312.pyc,,
|
| 25 |
+
compressed_tensors/compressors/quantized_compressors/__pycache__/base.cpython-312.pyc,,
|
| 26 |
+
compressed_tensors/compressors/quantized_compressors/__pycache__/naive_quantized.cpython-312.pyc,,
|
| 27 |
+
compressed_tensors/compressors/quantized_compressors/__pycache__/pack_quantized.cpython-312.pyc,,
|
| 28 |
+
compressed_tensors/compressors/quantized_compressors/base.py,sha256=GXTSWgFAhksbno94Ulpth9-YM4a7NsDlx4oQGGB0swQ,8567
|
| 29 |
+
compressed_tensors/compressors/quantized_compressors/naive_quantized.py,sha256=fd0KlkSx6bvZ3xwIkK3jEUdPSUPs56Eua4dEDOtzKW0,5150
|
| 30 |
+
compressed_tensors/compressors/quantized_compressors/pack_quantized.py,sha256=zH2PocRe_T5yt1-3kLdZH9AUQWQyaVOi4U9nEJiYaWA,8509
|
| 31 |
+
compressed_tensors/compressors/sparse_compressors/__init__.py,sha256=Atuz-OdEgn8OCUhx7Ovd6gXdyImAI186uCR-uR0t_Nk,737
|
| 32 |
+
compressed_tensors/compressors/sparse_compressors/__pycache__/__init__.cpython-312.pyc,,
|
| 33 |
+
compressed_tensors/compressors/sparse_compressors/__pycache__/base.cpython-312.pyc,,
|
| 34 |
+
compressed_tensors/compressors/sparse_compressors/__pycache__/dense.cpython-312.pyc,,
|
| 35 |
+
compressed_tensors/compressors/sparse_compressors/__pycache__/sparse_24_bitmask.cpython-312.pyc,,
|
| 36 |
+
compressed_tensors/compressors/sparse_compressors/__pycache__/sparse_bitmask.cpython-312.pyc,,
|
| 37 |
+
compressed_tensors/compressors/sparse_compressors/base.py,sha256=CVWbs3sd7GKJEoWOIKImABQ01VOTX8dlF2AQaEVPotw,5883
|
| 38 |
+
compressed_tensors/compressors/sparse_compressors/dense.py,sha256=_uW_HISeDNz4yboSZWoh6GwrkUE6HFibzPQSKrHOCkg,1505
|
| 39 |
+
compressed_tensors/compressors/sparse_compressors/sparse_24_bitmask.py,sha256=mEKSSgpXookqYSJw3mlyP6cYYKD-eaIvpQMvi4JO6TY,8807
|
| 40 |
+
compressed_tensors/compressors/sparse_compressors/sparse_bitmask.py,sha256=S8vW0FI9ep_XtUQOxj0P5utJt3vKEYOHjWEPp-Xd9aY,5820
|
| 41 |
+
compressed_tensors/compressors/sparse_quantized_compressors/__init__.py,sha256=4f_cwcKXB1nVVMoiKgTFAc8jAPjPLElo-Df_EDm1_xw,675
|
| 42 |
+
compressed_tensors/compressors/sparse_quantized_compressors/__pycache__/__init__.cpython-312.pyc,,
|
| 43 |
+
compressed_tensors/compressors/sparse_quantized_compressors/__pycache__/marlin_24.cpython-312.pyc,,
|
| 44 |
+
compressed_tensors/compressors/sparse_quantized_compressors/marlin_24.py,sha256=xY0CdHXAzVHeDeSCD_I-5UZKcntKzd3FiKSP-ZqcSBs,9614
|
| 45 |
+
compressed_tensors/config/__init__.py,sha256=8sOoZ6xvYSC79mBvEtO8l6xk4PC80d29AnnJiGMrY2M,737
|
| 46 |
+
compressed_tensors/config/__pycache__/__init__.cpython-312.pyc,,
|
| 47 |
+
compressed_tensors/config/__pycache__/base.cpython-312.pyc,,
|
| 48 |
+
compressed_tensors/config/__pycache__/dense.cpython-312.pyc,,
|
| 49 |
+
compressed_tensors/config/__pycache__/sparse_24_bitmask.cpython-312.pyc,,
|
| 50 |
+
compressed_tensors/config/__pycache__/sparse_bitmask.cpython-312.pyc,,
|
| 51 |
+
compressed_tensors/config/base.py,sha256=R3iUmFf1MslEjin5LgwQbmfJHIsS7Uw0UIxfn780uqY,3479
|
| 52 |
+
compressed_tensors/config/dense.py,sha256=NgSxnFCnckU9-iunxEaqiFwqgdO7YYxlWKR74jNbjks,1317
|
| 53 |
+
compressed_tensors/config/sparse_24_bitmask.py,sha256=Lhj39zT2V1hxftprvxvneyhv45ShlXOKd75DBbDTyTE,1401
|
| 54 |
+
compressed_tensors/config/sparse_bitmask.py,sha256=pZUboRNZTu6NajGOQEFExoPknak5ynVAUeiiYpS1Gt8,1308
|
| 55 |
+
compressed_tensors/linear/__init__.py,sha256=fH6rjBYAxuwrTzBTlTjTgCYNyh6TCvCqajCz4Im4YrA,617
|
| 56 |
+
compressed_tensors/linear/__pycache__/__init__.cpython-312.pyc,,
|
| 57 |
+
compressed_tensors/linear/__pycache__/compressed_linear.cpython-312.pyc,,
|
| 58 |
+
compressed_tensors/linear/compressed_linear.py,sha256=_m6XpNcI53eeSHO8VdiuAM6UBTdpDhn5Ivd8iRMwEKc,3980
|
| 59 |
+
compressed_tensors/quantization/__init__.py,sha256=83J5bPB7PavN2TfCoW7_vEDhfYpm4TDrqYO9vdSQ5bk,760
|
| 60 |
+
compressed_tensors/quantization/__pycache__/__init__.cpython-312.pyc,,
|
| 61 |
+
compressed_tensors/quantization/__pycache__/quant_args.cpython-312.pyc,,
|
| 62 |
+
compressed_tensors/quantization/__pycache__/quant_config.cpython-312.pyc,,
|
| 63 |
+
compressed_tensors/quantization/__pycache__/quant_scheme.cpython-312.pyc,,
|
| 64 |
+
compressed_tensors/quantization/lifecycle/__init__.py,sha256=_uItzFWusyV74Zco_pHLOTdE9a83cL-R-ZdyQrBkIyw,772
|
| 65 |
+
compressed_tensors/quantization/lifecycle/__pycache__/__init__.cpython-312.pyc,,
|
| 66 |
+
compressed_tensors/quantization/lifecycle/__pycache__/apply.cpython-312.pyc,,
|
| 67 |
+
compressed_tensors/quantization/lifecycle/__pycache__/compressed.cpython-312.pyc,,
|
| 68 |
+
compressed_tensors/quantization/lifecycle/__pycache__/forward.cpython-312.pyc,,
|
| 69 |
+
compressed_tensors/quantization/lifecycle/__pycache__/helpers.cpython-312.pyc,,
|
| 70 |
+
compressed_tensors/quantization/lifecycle/__pycache__/initialize.cpython-312.pyc,,
|
| 71 |
+
compressed_tensors/quantization/lifecycle/apply.py,sha256=lZmCCSm1_o79iUAy460w6Bv9FaOvntVisMdS-dN9fnk,16594
|
| 72 |
+
compressed_tensors/quantization/lifecycle/compressed.py,sha256=Fj9n66IN0EWsOAkBHg3O0GlOQpxstqjCcs0ttzMXrJ0,2296
|
| 73 |
+
compressed_tensors/quantization/lifecycle/forward.py,sha256=DOWouUqfaLA4Qhg-ojVVBdhhSAlgZqFC26vZARxE0ko,12961
|
| 74 |
+
compressed_tensors/quantization/lifecycle/helpers.py,sha256=C0mhy2vJ0fCjVeN4kFNhw8Eq1wkteBGHiZ36RVLThRY,944
|
| 75 |
+
compressed_tensors/quantization/lifecycle/initialize.py,sha256=sK3PLm69N91QepBuq-83Qd2Br6XcOmRDpD5qo_WWNJo,7469
|
| 76 |
+
compressed_tensors/quantization/quant_args.py,sha256=sKpb8DcNObidjXjNol1Tn_Iih3ZXBycSp-fyz68TGhY,9117
|
| 77 |
+
compressed_tensors/quantization/quant_config.py,sha256=vx06wBo91p4LCb3Vzd-2eCTUeIf_Sz2ZXRP263eQyjQ,10385
|
| 78 |
+
compressed_tensors/quantization/quant_scheme.py,sha256=eQ0JrRZ80GX69fpwW87VzPzzhajhk4mUaJScjk82OY4,6010
|
| 79 |
+
compressed_tensors/quantization/utils/__init__.py,sha256=VdtEmP0bvuND_IGQnyqUPc5lnFp-1_yD7StKSX4x80w,656
|
| 80 |
+
compressed_tensors/quantization/utils/__pycache__/__init__.cpython-312.pyc,,
|
| 81 |
+
compressed_tensors/quantization/utils/__pycache__/helpers.cpython-312.pyc,,
|
| 82 |
+
compressed_tensors/quantization/utils/helpers.py,sha256=DBP-sGRpGAY01K0LFE7qqonNj4hkTYL_mXrMs2LtAD8,14100
|
| 83 |
+
compressed_tensors/registry/__init__.py,sha256=FwLSNYqfIrb5JD_6OK_MT4_svvKTN_nEhpgQlQvGbjI,658
|
| 84 |
+
compressed_tensors/registry/__pycache__/__init__.cpython-312.pyc,,
|
| 85 |
+
compressed_tensors/registry/__pycache__/registry.cpython-312.pyc,,
|
| 86 |
+
compressed_tensors/registry/registry.py,sha256=vRcjVB1ITfSbfYUaGndBBmqhip_5vsS62weorVg0iXo,11896
|
| 87 |
+
compressed_tensors/utils/__init__.py,sha256=gS4gSU2pwcAbsKj-6YMaqhm25udFy6ISYaWBf-myRSM,808
|
| 88 |
+
compressed_tensors/utils/__pycache__/__init__.cpython-312.pyc,,
|
| 89 |
+
compressed_tensors/utils/__pycache__/helpers.cpython-312.pyc,,
|
| 90 |
+
compressed_tensors/utils/__pycache__/offload.cpython-312.pyc,,
|
| 91 |
+
compressed_tensors/utils/__pycache__/permutations_24.cpython-312.pyc,,
|
| 92 |
+
compressed_tensors/utils/__pycache__/permute.cpython-312.pyc,,
|
| 93 |
+
compressed_tensors/utils/__pycache__/safetensors_load.cpython-312.pyc,,
|
| 94 |
+
compressed_tensors/utils/__pycache__/semi_structured_conversions.cpython-312.pyc,,
|
| 95 |
+
compressed_tensors/utils/helpers.py,sha256=RrNvzD08naEjEiXdU-FdZjQVda1nQywu1hA_GCDj0vg,10415
|
| 96 |
+
compressed_tensors/utils/offload.py,sha256=H4aAg21zUvJM2uwE6QCNYazX_p_o41yQUAgLLWBqR0w,14079
|
| 97 |
+
compressed_tensors/utils/permutations_24.py,sha256=kx6fsfDHebx94zsSzhXGyCyuC9sVyah6BUUir_StT28,2530
|
| 98 |
+
compressed_tensors/utils/permute.py,sha256=V6tJLKo3Syccj-viv4F7ZKZgJeCB-hl-dK8RKI_kBwI,2355
|
| 99 |
+
compressed_tensors/utils/safetensors_load.py,sha256=5SeM2hzLh77Ne8Vk7qR6-km7cf8bhov41ExpWITqX3A,11470
|
| 100 |
+
compressed_tensors/utils/semi_structured_conversions.py,sha256=XKNffPum54kPASgqKzgKvyeqWPAkair2XEQXjkp7ho8,13489
|
| 101 |
+
compressed_tensors/version.py,sha256=X4y5lqlF1QFUgl25iumzagpg3dzyVoLP6i82HZEhCJA,1585
|
lib/python3.12/site-packages/compressed_tensors-0.9.3.dist-info/REQUESTED
ADDED
|
File without changes
|
lib/python3.12/site-packages/compressed_tensors-0.9.3.dist-info/WHEEL
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Wheel-Version: 1.0
|
| 2 |
+
Generator: setuptools (78.1.0)
|
| 3 |
+
Root-Is-Purelib: true
|
| 4 |
+
Tag: py3-none-any
|
| 5 |
+
|
lib/python3.12/site-packages/compressed_tensors-0.9.3.dist-info/licenses/LICENSE
ADDED
|
@@ -0,0 +1,201 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Apache License
|
| 2 |
+
Version 2.0, January 2004
|
| 3 |
+
http://www.apache.org/licenses/
|
| 4 |
+
|
| 5 |
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
| 6 |
+
|
| 7 |
+
1. Definitions.
|
| 8 |
+
|
| 9 |
+
"License" shall mean the terms and conditions for use, reproduction,
|
| 10 |
+
and distribution as defined by Sections 1 through 9 of this document.
|
| 11 |
+
|
| 12 |
+
"Licensor" shall mean the copyright owner or entity authorized by
|
| 13 |
+
the copyright owner that is granting the License.
|
| 14 |
+
|
| 15 |
+
"Legal Entity" shall mean the union of the acting entity and all
|
| 16 |
+
other entities that control, are controlled by, or are under common
|
| 17 |
+
control with that entity. For the purposes of this definition,
|
| 18 |
+
"control" means (i) the power, direct or indirect, to cause the
|
| 19 |
+
direction or management of such entity, whether by contract or
|
| 20 |
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
| 21 |
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
| 22 |
+
|
| 23 |
+
"You" (or "Your") shall mean an individual or Legal Entity
|
| 24 |
+
exercising permissions granted by this License.
|
| 25 |
+
|
| 26 |
+
"Source" form shall mean the preferred form for making modifications,
|
| 27 |
+
including but not limited to software source code, documentation
|
| 28 |
+
source, and configuration files.
|
| 29 |
+
|
| 30 |
+
"Object" form shall mean any form resulting from mechanical
|
| 31 |
+
transformation or translation of a Source form, including but
|
| 32 |
+
not limited to compiled object code, generated documentation,
|
| 33 |
+
and conversions to other media types.
|
| 34 |
+
|
| 35 |
+
"Work" shall mean the work of authorship, whether in Source or
|
| 36 |
+
Object form, made available under the License, as indicated by a
|
| 37 |
+
copyright notice that is included in or attached to the work
|
| 38 |
+
(an example is provided in the Appendix below).
|
| 39 |
+
|
| 40 |
+
"Derivative Works" shall mean any work, whether in Source or Object
|
| 41 |
+
form, that is based on (or derived from) the Work and for which the
|
| 42 |
+
editorial revisions, annotations, elaborations, or other modifications
|
| 43 |
+
represent, as a whole, an original work of authorship. For the purposes
|
| 44 |
+
of this License, Derivative Works shall not include works that remain
|
| 45 |
+
separable from, or merely link (or bind by name) to the interfaces of,
|
| 46 |
+
the Work and Derivative Works thereof.
|
| 47 |
+
|
| 48 |
+
"Contribution" shall mean any work of authorship, including
|
| 49 |
+
the original version of the Work and any modifications or additions
|
| 50 |
+
to that Work or Derivative Works thereof, that is intentionally
|
| 51 |
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
| 52 |
+
or by an individual or Legal Entity authorized to submit on behalf of
|
| 53 |
+
the copyright owner. For the purposes of this definition, "submitted"
|
| 54 |
+
means any form of electronic, verbal, or written communication sent
|
| 55 |
+
to the Licensor or its representatives, including but not limited to
|
| 56 |
+
communication on electronic mailing lists, source code control systems,
|
| 57 |
+
and issue tracking systems that are managed by, or on behalf of, the
|
| 58 |
+
Licensor for the purpose of discussing and improving the Work, but
|
| 59 |
+
excluding communication that is conspicuously marked or otherwise
|
| 60 |
+
designated in writing by the copyright owner as "Not a Contribution."
|
| 61 |
+
|
| 62 |
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
| 63 |
+
on behalf of whom a Contribution has been received by Licensor and
|
| 64 |
+
subsequently incorporated within the Work.
|
| 65 |
+
|
| 66 |
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
| 67 |
+
this License, each Contributor hereby grants to You a perpetual,
|
| 68 |
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
| 69 |
+
copyright license to reproduce, prepare Derivative Works of,
|
| 70 |
+
publicly display, publicly perform, sublicense, and distribute the
|
| 71 |
+
Work and such Derivative Works in Source or Object form.
|
| 72 |
+
|
| 73 |
+
3. Grant of Patent License. Subject to the terms and conditions of
|
| 74 |
+
this License, each Contributor hereby grants to You a perpetual,
|
| 75 |
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
| 76 |
+
(except as stated in this section) patent license to make, have made,
|
| 77 |
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
| 78 |
+
where such license applies only to those patent claims licensable
|
| 79 |
+
by such Contributor that are necessarily infringed by their
|
| 80 |
+
Contribution(s) alone or by combination of their Contribution(s)
|
| 81 |
+
with the Work to which such Contribution(s) was submitted. If You
|
| 82 |
+
institute patent litigation against any entity (including a
|
| 83 |
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
| 84 |
+
or a Contribution incorporated within the Work constitutes direct
|
| 85 |
+
or contributory patent infringement, then any patent licenses
|
| 86 |
+
granted to You under this License for that Work shall terminate
|
| 87 |
+
as of the date such litigation is filed.
|
| 88 |
+
|
| 89 |
+
4. Redistribution. You may reproduce and distribute copies of the
|
| 90 |
+
Work or Derivative Works thereof in any medium, with or without
|
| 91 |
+
modifications, and in Source or Object form, provided that You
|
| 92 |
+
meet the following conditions:
|
| 93 |
+
|
| 94 |
+
(a) You must give any other recipients of the Work or
|
| 95 |
+
Derivative Works a copy of this License; and
|
| 96 |
+
|
| 97 |
+
(b) You must cause any modified files to carry prominent notices
|
| 98 |
+
stating that You changed the files; and
|
| 99 |
+
|
| 100 |
+
(c) You must retain, in the Source form of any Derivative Works
|
| 101 |
+
that You distribute, all copyright, patent, trademark, and
|
| 102 |
+
attribution notices from the Source form of the Work,
|
| 103 |
+
excluding those notices that do not pertain to any part of
|
| 104 |
+
the Derivative Works; and
|
| 105 |
+
|
| 106 |
+
(d) If the Work includes a "NOTICE" text file as part of its
|
| 107 |
+
distribution, then any Derivative Works that You distribute must
|
| 108 |
+
include a readable copy of the attribution notices contained
|
| 109 |
+
within such NOTICE file, excluding those notices that do not
|
| 110 |
+
pertain to any part of the Derivative Works, in at least one
|
| 111 |
+
of the following places: within a NOTICE text file distributed
|
| 112 |
+
as part of the Derivative Works; within the Source form or
|
| 113 |
+
documentation, if provided along with the Derivative Works; or,
|
| 114 |
+
within a display generated by the Derivative Works, if and
|
| 115 |
+
wherever such third-party notices normally appear. The contents
|
| 116 |
+
of the NOTICE file are for informational purposes only and
|
| 117 |
+
do not modify the License. You may add Your own attribution
|
| 118 |
+
notices within Derivative Works that You distribute, alongside
|
| 119 |
+
or as an addendum to the NOTICE text from the Work, provided
|
| 120 |
+
that such additional attribution notices cannot be construed
|
| 121 |
+
as modifying the License.
|
| 122 |
+
|
| 123 |
+
You may add Your own copyright statement to Your modifications and
|
| 124 |
+
may provide additional or different license terms and conditions
|
| 125 |
+
for use, reproduction, or distribution of Your modifications, or
|
| 126 |
+
for any such Derivative Works as a whole, provided Your use,
|
| 127 |
+
reproduction, and distribution of the Work otherwise complies with
|
| 128 |
+
the conditions stated in this License.
|
| 129 |
+
|
| 130 |
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
| 131 |
+
any Contribution intentionally submitted for inclusion in the Work
|
| 132 |
+
by You to the Licensor shall be under the terms and conditions of
|
| 133 |
+
this License, without any additional terms or conditions.
|
| 134 |
+
Notwithstanding the above, nothing herein shall supersede or modify
|
| 135 |
+
the terms of any separate license agreement you may have executed
|
| 136 |
+
with Licensor regarding such Contributions.
|
| 137 |
+
|
| 138 |
+
6. Trademarks. This License does not grant permission to use the trade
|
| 139 |
+
names, trademarks, service marks, or product names of the Licensor,
|
| 140 |
+
except as required for reasonable and customary use in describing the
|
| 141 |
+
origin of the Work and reproducing the content of the NOTICE file.
|
| 142 |
+
|
| 143 |
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
| 144 |
+
agreed to in writing, Licensor provides the Work (and each
|
| 145 |
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
| 146 |
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
| 147 |
+
implied, including, without limitation, any warranties or conditions
|
| 148 |
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
| 149 |
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
| 150 |
+
appropriateness of using or redistributing the Work and assume any
|
| 151 |
+
risks associated with Your exercise of permissions under this License.
|
| 152 |
+
|
| 153 |
+
8. Limitation of Liability. In no event and under no legal theory,
|
| 154 |
+
whether in tort (including negligence), contract, or otherwise,
|
| 155 |
+
unless required by applicable law (such as deliberate and grossly
|
| 156 |
+
negligent acts) or agreed to in writing, shall any Contributor be
|
| 157 |
+
liable to You for damages, including any direct, indirect, special,
|
| 158 |
+
incidental, or consequential damages of any character arising as a
|
| 159 |
+
result of this License or out of the use or inability to use the
|
| 160 |
+
Work (including but not limited to damages for loss of goodwill,
|
| 161 |
+
work stoppage, computer failure or malfunction, or any and all
|
| 162 |
+
other commercial damages or losses), even if such Contributor
|
| 163 |
+
has been advised of the possibility of such damages.
|
| 164 |
+
|
| 165 |
+
9. Accepting Warranty or Additional Liability. While redistributing
|
| 166 |
+
the Work or Derivative Works thereof, You may choose to offer,
|
| 167 |
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
| 168 |
+
or other liability obligations and/or rights consistent with this
|
| 169 |
+
License. However, in accepting such obligations, You may act only
|
| 170 |
+
on Your own behalf and on Your sole responsibility, not on behalf
|
| 171 |
+
of any other Contributor, and only if You agree to indemnify,
|
| 172 |
+
defend, and hold each Contributor harmless for any liability
|
| 173 |
+
incurred by, or claims asserted against, such Contributor by reason
|
| 174 |
+
of your accepting any such warranty or additional liability.
|
| 175 |
+
|
| 176 |
+
END OF TERMS AND CONDITIONS
|
| 177 |
+
|
| 178 |
+
APPENDIX: How to apply the Apache License to your work.
|
| 179 |
+
|
| 180 |
+
To apply the Apache License to your work, attach the following
|
| 181 |
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
| 182 |
+
replaced with your own identifying information. (Don't include
|
| 183 |
+
the brackets!) The text should be enclosed in the appropriate
|
| 184 |
+
comment syntax for the file format. We also recommend that a
|
| 185 |
+
file or class name and description of purpose be included on the
|
| 186 |
+
same "printed page" as the copyright notice for easier
|
| 187 |
+
identification within third-party archives.
|
| 188 |
+
|
| 189 |
+
Copyright [yyyy] [name of copyright owner]
|
| 190 |
+
|
| 191 |
+
Licensed under the Apache License, Version 2.0 (the "License");
|
| 192 |
+
you may not use this file except in compliance with the License.
|
| 193 |
+
You may obtain a copy of the License at
|
| 194 |
+
|
| 195 |
+
http://www.apache.org/licenses/LICENSE-2.0
|
| 196 |
+
|
| 197 |
+
Unless required by applicable law or agreed to in writing, software
|
| 198 |
+
distributed under the License is distributed on an "AS IS" BASIS,
|
| 199 |
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 200 |
+
See the License for the specific language governing permissions and
|
| 201 |
+
limitations under the License.
|
lib/python3.12/site-packages/compressed_tensors-0.9.3.dist-info/top_level.txt
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
compressed_tensors
|
lib/python3.12/site-packages/fastapi/__init__.py
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""FastAPI framework, high performance, easy to learn, fast to code, ready for production"""
|
| 2 |
+
|
| 3 |
+
__version__ = "0.115.12"
|
| 4 |
+
|
| 5 |
+
from starlette import status as status
|
| 6 |
+
|
| 7 |
+
from .applications import FastAPI as FastAPI
|
| 8 |
+
from .background import BackgroundTasks as BackgroundTasks
|
| 9 |
+
from .datastructures import UploadFile as UploadFile
|
| 10 |
+
from .exceptions import HTTPException as HTTPException
|
| 11 |
+
from .exceptions import WebSocketException as WebSocketException
|
| 12 |
+
from .param_functions import Body as Body
|
| 13 |
+
from .param_functions import Cookie as Cookie
|
| 14 |
+
from .param_functions import Depends as Depends
|
| 15 |
+
from .param_functions import File as File
|
| 16 |
+
from .param_functions import Form as Form
|
| 17 |
+
from .param_functions import Header as Header
|
| 18 |
+
from .param_functions import Path as Path
|
| 19 |
+
from .param_functions import Query as Query
|
| 20 |
+
from .param_functions import Security as Security
|
| 21 |
+
from .requests import Request as Request
|
| 22 |
+
from .responses import Response as Response
|
| 23 |
+
from .routing import APIRouter as APIRouter
|
| 24 |
+
from .websockets import WebSocket as WebSocket
|
| 25 |
+
from .websockets import WebSocketDisconnect as WebSocketDisconnect
|
lib/python3.12/site-packages/fastapi/__main__.py
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from fastapi.cli import main
|
| 2 |
+
|
| 3 |
+
main()
|
lib/python3.12/site-packages/fastapi/__pycache__/param_functions.cpython-312.pyc
ADDED
|
Binary file (35.1 kB). View file
|
|
|
lib/python3.12/site-packages/fastapi/_compat.py
ADDED
|
@@ -0,0 +1,659 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from collections import deque
|
| 2 |
+
from copy import copy
|
| 3 |
+
from dataclasses import dataclass, is_dataclass
|
| 4 |
+
from enum import Enum
|
| 5 |
+
from functools import lru_cache
|
| 6 |
+
from typing import (
|
| 7 |
+
Any,
|
| 8 |
+
Callable,
|
| 9 |
+
Deque,
|
| 10 |
+
Dict,
|
| 11 |
+
FrozenSet,
|
| 12 |
+
List,
|
| 13 |
+
Mapping,
|
| 14 |
+
Sequence,
|
| 15 |
+
Set,
|
| 16 |
+
Tuple,
|
| 17 |
+
Type,
|
| 18 |
+
Union,
|
| 19 |
+
)
|
| 20 |
+
|
| 21 |
+
from fastapi.exceptions import RequestErrorModel
|
| 22 |
+
from fastapi.types import IncEx, ModelNameMap, UnionType
|
| 23 |
+
from pydantic import BaseModel, create_model
|
| 24 |
+
from pydantic.version import VERSION as PYDANTIC_VERSION
|
| 25 |
+
from starlette.datastructures import UploadFile
|
| 26 |
+
from typing_extensions import Annotated, Literal, get_args, get_origin
|
| 27 |
+
|
| 28 |
+
PYDANTIC_VERSION_MINOR_TUPLE = tuple(int(x) for x in PYDANTIC_VERSION.split(".")[:2])
|
| 29 |
+
PYDANTIC_V2 = PYDANTIC_VERSION_MINOR_TUPLE[0] == 2
|
| 30 |
+
|
| 31 |
+
|
| 32 |
+
sequence_annotation_to_type = {
|
| 33 |
+
Sequence: list,
|
| 34 |
+
List: list,
|
| 35 |
+
list: list,
|
| 36 |
+
Tuple: tuple,
|
| 37 |
+
tuple: tuple,
|
| 38 |
+
Set: set,
|
| 39 |
+
set: set,
|
| 40 |
+
FrozenSet: frozenset,
|
| 41 |
+
frozenset: frozenset,
|
| 42 |
+
Deque: deque,
|
| 43 |
+
deque: deque,
|
| 44 |
+
}
|
| 45 |
+
|
| 46 |
+
sequence_types = tuple(sequence_annotation_to_type.keys())
|
| 47 |
+
|
| 48 |
+
Url: Type[Any]
|
| 49 |
+
|
| 50 |
+
if PYDANTIC_V2:
|
| 51 |
+
from pydantic import PydanticSchemaGenerationError as PydanticSchemaGenerationError
|
| 52 |
+
from pydantic import TypeAdapter
|
| 53 |
+
from pydantic import ValidationError as ValidationError
|
| 54 |
+
from pydantic._internal._schema_generation_shared import ( # type: ignore[attr-defined]
|
| 55 |
+
GetJsonSchemaHandler as GetJsonSchemaHandler,
|
| 56 |
+
)
|
| 57 |
+
from pydantic._internal._typing_extra import eval_type_lenient
|
| 58 |
+
from pydantic._internal._utils import lenient_issubclass as lenient_issubclass
|
| 59 |
+
from pydantic.fields import FieldInfo
|
| 60 |
+
from pydantic.json_schema import GenerateJsonSchema as GenerateJsonSchema
|
| 61 |
+
from pydantic.json_schema import JsonSchemaValue as JsonSchemaValue
|
| 62 |
+
from pydantic_core import CoreSchema as CoreSchema
|
| 63 |
+
from pydantic_core import PydanticUndefined, PydanticUndefinedType
|
| 64 |
+
from pydantic_core import Url as Url
|
| 65 |
+
|
| 66 |
+
try:
|
| 67 |
+
from pydantic_core.core_schema import (
|
| 68 |
+
with_info_plain_validator_function as with_info_plain_validator_function,
|
| 69 |
+
)
|
| 70 |
+
except ImportError: # pragma: no cover
|
| 71 |
+
from pydantic_core.core_schema import (
|
| 72 |
+
general_plain_validator_function as with_info_plain_validator_function, # noqa: F401
|
| 73 |
+
)
|
| 74 |
+
|
| 75 |
+
RequiredParam = PydanticUndefined
|
| 76 |
+
Undefined = PydanticUndefined
|
| 77 |
+
UndefinedType = PydanticUndefinedType
|
| 78 |
+
evaluate_forwardref = eval_type_lenient
|
| 79 |
+
Validator = Any
|
| 80 |
+
|
| 81 |
+
class BaseConfig:
|
| 82 |
+
pass
|
| 83 |
+
|
| 84 |
+
class ErrorWrapper(Exception):
|
| 85 |
+
pass
|
| 86 |
+
|
| 87 |
+
@dataclass
|
| 88 |
+
class ModelField:
|
| 89 |
+
field_info: FieldInfo
|
| 90 |
+
name: str
|
| 91 |
+
mode: Literal["validation", "serialization"] = "validation"
|
| 92 |
+
|
| 93 |
+
@property
|
| 94 |
+
def alias(self) -> str:
|
| 95 |
+
a = self.field_info.alias
|
| 96 |
+
return a if a is not None else self.name
|
| 97 |
+
|
| 98 |
+
@property
|
| 99 |
+
def required(self) -> bool:
|
| 100 |
+
return self.field_info.is_required()
|
| 101 |
+
|
| 102 |
+
@property
|
| 103 |
+
def default(self) -> Any:
|
| 104 |
+
return self.get_default()
|
| 105 |
+
|
| 106 |
+
@property
|
| 107 |
+
def type_(self) -> Any:
|
| 108 |
+
return self.field_info.annotation
|
| 109 |
+
|
| 110 |
+
def __post_init__(self) -> None:
|
| 111 |
+
self._type_adapter: TypeAdapter[Any] = TypeAdapter(
|
| 112 |
+
Annotated[self.field_info.annotation, self.field_info]
|
| 113 |
+
)
|
| 114 |
+
|
| 115 |
+
def get_default(self) -> Any:
|
| 116 |
+
if self.field_info.is_required():
|
| 117 |
+
return Undefined
|
| 118 |
+
return self.field_info.get_default(call_default_factory=True)
|
| 119 |
+
|
| 120 |
+
def validate(
|
| 121 |
+
self,
|
| 122 |
+
value: Any,
|
| 123 |
+
values: Dict[str, Any] = {}, # noqa: B006
|
| 124 |
+
*,
|
| 125 |
+
loc: Tuple[Union[int, str], ...] = (),
|
| 126 |
+
) -> Tuple[Any, Union[List[Dict[str, Any]], None]]:
|
| 127 |
+
try:
|
| 128 |
+
return (
|
| 129 |
+
self._type_adapter.validate_python(value, from_attributes=True),
|
| 130 |
+
None,
|
| 131 |
+
)
|
| 132 |
+
except ValidationError as exc:
|
| 133 |
+
return None, _regenerate_error_with_loc(
|
| 134 |
+
errors=exc.errors(include_url=False), loc_prefix=loc
|
| 135 |
+
)
|
| 136 |
+
|
| 137 |
+
def serialize(
|
| 138 |
+
self,
|
| 139 |
+
value: Any,
|
| 140 |
+
*,
|
| 141 |
+
mode: Literal["json", "python"] = "json",
|
| 142 |
+
include: Union[IncEx, None] = None,
|
| 143 |
+
exclude: Union[IncEx, None] = None,
|
| 144 |
+
by_alias: bool = True,
|
| 145 |
+
exclude_unset: bool = False,
|
| 146 |
+
exclude_defaults: bool = False,
|
| 147 |
+
exclude_none: bool = False,
|
| 148 |
+
) -> Any:
|
| 149 |
+
# What calls this code passes a value that already called
|
| 150 |
+
# self._type_adapter.validate_python(value)
|
| 151 |
+
return self._type_adapter.dump_python(
|
| 152 |
+
value,
|
| 153 |
+
mode=mode,
|
| 154 |
+
include=include,
|
| 155 |
+
exclude=exclude,
|
| 156 |
+
by_alias=by_alias,
|
| 157 |
+
exclude_unset=exclude_unset,
|
| 158 |
+
exclude_defaults=exclude_defaults,
|
| 159 |
+
exclude_none=exclude_none,
|
| 160 |
+
)
|
| 161 |
+
|
| 162 |
+
def __hash__(self) -> int:
|
| 163 |
+
# Each ModelField is unique for our purposes, to allow making a dict from
|
| 164 |
+
# ModelField to its JSON Schema.
|
| 165 |
+
return id(self)
|
| 166 |
+
|
| 167 |
+
def get_annotation_from_field_info(
|
| 168 |
+
annotation: Any, field_info: FieldInfo, field_name: str
|
| 169 |
+
) -> Any:
|
| 170 |
+
return annotation
|
| 171 |
+
|
| 172 |
+
def _normalize_errors(errors: Sequence[Any]) -> List[Dict[str, Any]]:
|
| 173 |
+
return errors # type: ignore[return-value]
|
| 174 |
+
|
| 175 |
+
def _model_rebuild(model: Type[BaseModel]) -> None:
|
| 176 |
+
model.model_rebuild()
|
| 177 |
+
|
| 178 |
+
def _model_dump(
|
| 179 |
+
model: BaseModel, mode: Literal["json", "python"] = "json", **kwargs: Any
|
| 180 |
+
) -> Any:
|
| 181 |
+
return model.model_dump(mode=mode, **kwargs)
|
| 182 |
+
|
| 183 |
+
def _get_model_config(model: BaseModel) -> Any:
|
| 184 |
+
return model.model_config
|
| 185 |
+
|
| 186 |
+
def get_schema_from_model_field(
|
| 187 |
+
*,
|
| 188 |
+
field: ModelField,
|
| 189 |
+
schema_generator: GenerateJsonSchema,
|
| 190 |
+
model_name_map: ModelNameMap,
|
| 191 |
+
field_mapping: Dict[
|
| 192 |
+
Tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue
|
| 193 |
+
],
|
| 194 |
+
separate_input_output_schemas: bool = True,
|
| 195 |
+
) -> Dict[str, Any]:
|
| 196 |
+
override_mode: Union[Literal["validation"], None] = (
|
| 197 |
+
None if separate_input_output_schemas else "validation"
|
| 198 |
+
)
|
| 199 |
+
# This expects that GenerateJsonSchema was already used to generate the definitions
|
| 200 |
+
json_schema = field_mapping[(field, override_mode or field.mode)]
|
| 201 |
+
if "$ref" not in json_schema:
|
| 202 |
+
# TODO remove when deprecating Pydantic v1
|
| 203 |
+
# Ref: https://github.com/pydantic/pydantic/blob/d61792cc42c80b13b23e3ffa74bc37ec7c77f7d1/pydantic/schema.py#L207
|
| 204 |
+
json_schema["title"] = (
|
| 205 |
+
field.field_info.title or field.alias.title().replace("_", " ")
|
| 206 |
+
)
|
| 207 |
+
return json_schema
|
| 208 |
+
|
| 209 |
+
def get_compat_model_name_map(fields: List[ModelField]) -> ModelNameMap:
|
| 210 |
+
return {}
|
| 211 |
+
|
| 212 |
+
def get_definitions(
|
| 213 |
+
*,
|
| 214 |
+
fields: List[ModelField],
|
| 215 |
+
schema_generator: GenerateJsonSchema,
|
| 216 |
+
model_name_map: ModelNameMap,
|
| 217 |
+
separate_input_output_schemas: bool = True,
|
| 218 |
+
) -> Tuple[
|
| 219 |
+
Dict[
|
| 220 |
+
Tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue
|
| 221 |
+
],
|
| 222 |
+
Dict[str, Dict[str, Any]],
|
| 223 |
+
]:
|
| 224 |
+
override_mode: Union[Literal["validation"], None] = (
|
| 225 |
+
None if separate_input_output_schemas else "validation"
|
| 226 |
+
)
|
| 227 |
+
inputs = [
|
| 228 |
+
(field, override_mode or field.mode, field._type_adapter.core_schema)
|
| 229 |
+
for field in fields
|
| 230 |
+
]
|
| 231 |
+
field_mapping, definitions = schema_generator.generate_definitions(
|
| 232 |
+
inputs=inputs
|
| 233 |
+
)
|
| 234 |
+
return field_mapping, definitions # type: ignore[return-value]
|
| 235 |
+
|
| 236 |
+
def is_scalar_field(field: ModelField) -> bool:
|
| 237 |
+
from fastapi import params
|
| 238 |
+
|
| 239 |
+
return field_annotation_is_scalar(
|
| 240 |
+
field.field_info.annotation
|
| 241 |
+
) and not isinstance(field.field_info, params.Body)
|
| 242 |
+
|
| 243 |
+
def is_sequence_field(field: ModelField) -> bool:
|
| 244 |
+
return field_annotation_is_sequence(field.field_info.annotation)
|
| 245 |
+
|
| 246 |
+
def is_scalar_sequence_field(field: ModelField) -> bool:
|
| 247 |
+
return field_annotation_is_scalar_sequence(field.field_info.annotation)
|
| 248 |
+
|
| 249 |
+
def is_bytes_field(field: ModelField) -> bool:
|
| 250 |
+
return is_bytes_or_nonable_bytes_annotation(field.type_)
|
| 251 |
+
|
| 252 |
+
def is_bytes_sequence_field(field: ModelField) -> bool:
|
| 253 |
+
return is_bytes_sequence_annotation(field.type_)
|
| 254 |
+
|
| 255 |
+
def copy_field_info(*, field_info: FieldInfo, annotation: Any) -> FieldInfo:
|
| 256 |
+
cls = type(field_info)
|
| 257 |
+
merged_field_info = cls.from_annotation(annotation)
|
| 258 |
+
new_field_info = copy(field_info)
|
| 259 |
+
new_field_info.metadata = merged_field_info.metadata
|
| 260 |
+
new_field_info.annotation = merged_field_info.annotation
|
| 261 |
+
return new_field_info
|
| 262 |
+
|
| 263 |
+
def serialize_sequence_value(*, field: ModelField, value: Any) -> Sequence[Any]:
|
| 264 |
+
origin_type = (
|
| 265 |
+
get_origin(field.field_info.annotation) or field.field_info.annotation
|
| 266 |
+
)
|
| 267 |
+
assert issubclass(origin_type, sequence_types) # type: ignore[arg-type]
|
| 268 |
+
return sequence_annotation_to_type[origin_type](value) # type: ignore[no-any-return]
|
| 269 |
+
|
| 270 |
+
def get_missing_field_error(loc: Tuple[str, ...]) -> Dict[str, Any]:
|
| 271 |
+
error = ValidationError.from_exception_data(
|
| 272 |
+
"Field required", [{"type": "missing", "loc": loc, "input": {}}]
|
| 273 |
+
).errors(include_url=False)[0]
|
| 274 |
+
error["input"] = None
|
| 275 |
+
return error # type: ignore[return-value]
|
| 276 |
+
|
| 277 |
+
def create_body_model(
|
| 278 |
+
*, fields: Sequence[ModelField], model_name: str
|
| 279 |
+
) -> Type[BaseModel]:
|
| 280 |
+
field_params = {f.name: (f.field_info.annotation, f.field_info) for f in fields}
|
| 281 |
+
BodyModel: Type[BaseModel] = create_model(model_name, **field_params) # type: ignore[call-overload]
|
| 282 |
+
return BodyModel
|
| 283 |
+
|
| 284 |
+
def get_model_fields(model: Type[BaseModel]) -> List[ModelField]:
|
| 285 |
+
return [
|
| 286 |
+
ModelField(field_info=field_info, name=name)
|
| 287 |
+
for name, field_info in model.model_fields.items()
|
| 288 |
+
]
|
| 289 |
+
|
| 290 |
+
else:
|
| 291 |
+
from fastapi.openapi.constants import REF_PREFIX as REF_PREFIX
|
| 292 |
+
from pydantic import AnyUrl as Url # noqa: F401
|
| 293 |
+
from pydantic import ( # type: ignore[assignment]
|
| 294 |
+
BaseConfig as BaseConfig, # noqa: F401
|
| 295 |
+
)
|
| 296 |
+
from pydantic import ValidationError as ValidationError # noqa: F401
|
| 297 |
+
from pydantic.class_validators import ( # type: ignore[no-redef]
|
| 298 |
+
Validator as Validator, # noqa: F401
|
| 299 |
+
)
|
| 300 |
+
from pydantic.error_wrappers import ( # type: ignore[no-redef]
|
| 301 |
+
ErrorWrapper as ErrorWrapper, # noqa: F401
|
| 302 |
+
)
|
| 303 |
+
from pydantic.errors import MissingError
|
| 304 |
+
from pydantic.fields import ( # type: ignore[attr-defined]
|
| 305 |
+
SHAPE_FROZENSET,
|
| 306 |
+
SHAPE_LIST,
|
| 307 |
+
SHAPE_SEQUENCE,
|
| 308 |
+
SHAPE_SET,
|
| 309 |
+
SHAPE_SINGLETON,
|
| 310 |
+
SHAPE_TUPLE,
|
| 311 |
+
SHAPE_TUPLE_ELLIPSIS,
|
| 312 |
+
)
|
| 313 |
+
from pydantic.fields import FieldInfo as FieldInfo
|
| 314 |
+
from pydantic.fields import ( # type: ignore[no-redef,attr-defined]
|
| 315 |
+
ModelField as ModelField, # noqa: F401
|
| 316 |
+
)
|
| 317 |
+
|
| 318 |
+
# Keeping old "Required" functionality from Pydantic V1, without
|
| 319 |
+
# shadowing typing.Required.
|
| 320 |
+
RequiredParam: Any = Ellipsis # type: ignore[no-redef]
|
| 321 |
+
from pydantic.fields import ( # type: ignore[no-redef,attr-defined]
|
| 322 |
+
Undefined as Undefined,
|
| 323 |
+
)
|
| 324 |
+
from pydantic.fields import ( # type: ignore[no-redef, attr-defined]
|
| 325 |
+
UndefinedType as UndefinedType, # noqa: F401
|
| 326 |
+
)
|
| 327 |
+
from pydantic.schema import (
|
| 328 |
+
field_schema,
|
| 329 |
+
get_flat_models_from_fields,
|
| 330 |
+
get_model_name_map,
|
| 331 |
+
model_process_schema,
|
| 332 |
+
)
|
| 333 |
+
from pydantic.schema import ( # type: ignore[no-redef] # noqa: F401
|
| 334 |
+
get_annotation_from_field_info as get_annotation_from_field_info,
|
| 335 |
+
)
|
| 336 |
+
from pydantic.typing import ( # type: ignore[no-redef]
|
| 337 |
+
evaluate_forwardref as evaluate_forwardref, # noqa: F401
|
| 338 |
+
)
|
| 339 |
+
from pydantic.utils import ( # type: ignore[no-redef]
|
| 340 |
+
lenient_issubclass as lenient_issubclass, # noqa: F401
|
| 341 |
+
)
|
| 342 |
+
|
| 343 |
+
GetJsonSchemaHandler = Any # type: ignore[assignment,misc]
|
| 344 |
+
JsonSchemaValue = Dict[str, Any] # type: ignore[misc]
|
| 345 |
+
CoreSchema = Any # type: ignore[assignment,misc]
|
| 346 |
+
|
| 347 |
+
sequence_shapes = {
|
| 348 |
+
SHAPE_LIST,
|
| 349 |
+
SHAPE_SET,
|
| 350 |
+
SHAPE_FROZENSET,
|
| 351 |
+
SHAPE_TUPLE,
|
| 352 |
+
SHAPE_SEQUENCE,
|
| 353 |
+
SHAPE_TUPLE_ELLIPSIS,
|
| 354 |
+
}
|
| 355 |
+
sequence_shape_to_type = {
|
| 356 |
+
SHAPE_LIST: list,
|
| 357 |
+
SHAPE_SET: set,
|
| 358 |
+
SHAPE_TUPLE: tuple,
|
| 359 |
+
SHAPE_SEQUENCE: list,
|
| 360 |
+
SHAPE_TUPLE_ELLIPSIS: list,
|
| 361 |
+
}
|
| 362 |
+
|
| 363 |
+
@dataclass
|
| 364 |
+
class GenerateJsonSchema: # type: ignore[no-redef]
|
| 365 |
+
ref_template: str
|
| 366 |
+
|
| 367 |
+
class PydanticSchemaGenerationError(Exception): # type: ignore[no-redef]
|
| 368 |
+
pass
|
| 369 |
+
|
| 370 |
+
def with_info_plain_validator_function( # type: ignore[misc]
|
| 371 |
+
function: Callable[..., Any],
|
| 372 |
+
*,
|
| 373 |
+
ref: Union[str, None] = None,
|
| 374 |
+
metadata: Any = None,
|
| 375 |
+
serialization: Any = None,
|
| 376 |
+
) -> Any:
|
| 377 |
+
return {}
|
| 378 |
+
|
| 379 |
+
def get_model_definitions(
|
| 380 |
+
*,
|
| 381 |
+
flat_models: Set[Union[Type[BaseModel], Type[Enum]]],
|
| 382 |
+
model_name_map: Dict[Union[Type[BaseModel], Type[Enum]], str],
|
| 383 |
+
) -> Dict[str, Any]:
|
| 384 |
+
definitions: Dict[str, Dict[str, Any]] = {}
|
| 385 |
+
for model in flat_models:
|
| 386 |
+
m_schema, m_definitions, m_nested_models = model_process_schema(
|
| 387 |
+
model, model_name_map=model_name_map, ref_prefix=REF_PREFIX
|
| 388 |
+
)
|
| 389 |
+
definitions.update(m_definitions)
|
| 390 |
+
model_name = model_name_map[model]
|
| 391 |
+
if "description" in m_schema:
|
| 392 |
+
m_schema["description"] = m_schema["description"].split("\f")[0]
|
| 393 |
+
definitions[model_name] = m_schema
|
| 394 |
+
return definitions
|
| 395 |
+
|
| 396 |
+
def is_pv1_scalar_field(field: ModelField) -> bool:
|
| 397 |
+
from fastapi import params
|
| 398 |
+
|
| 399 |
+
field_info = field.field_info
|
| 400 |
+
if not (
|
| 401 |
+
field.shape == SHAPE_SINGLETON # type: ignore[attr-defined]
|
| 402 |
+
and not lenient_issubclass(field.type_, BaseModel)
|
| 403 |
+
and not lenient_issubclass(field.type_, dict)
|
| 404 |
+
and not field_annotation_is_sequence(field.type_)
|
| 405 |
+
and not is_dataclass(field.type_)
|
| 406 |
+
and not isinstance(field_info, params.Body)
|
| 407 |
+
):
|
| 408 |
+
return False
|
| 409 |
+
if field.sub_fields: # type: ignore[attr-defined]
|
| 410 |
+
if not all(
|
| 411 |
+
is_pv1_scalar_field(f)
|
| 412 |
+
for f in field.sub_fields # type: ignore[attr-defined]
|
| 413 |
+
):
|
| 414 |
+
return False
|
| 415 |
+
return True
|
| 416 |
+
|
| 417 |
+
def is_pv1_scalar_sequence_field(field: ModelField) -> bool:
|
| 418 |
+
if (field.shape in sequence_shapes) and not lenient_issubclass( # type: ignore[attr-defined]
|
| 419 |
+
field.type_, BaseModel
|
| 420 |
+
):
|
| 421 |
+
if field.sub_fields is not None: # type: ignore[attr-defined]
|
| 422 |
+
for sub_field in field.sub_fields: # type: ignore[attr-defined]
|
| 423 |
+
if not is_pv1_scalar_field(sub_field):
|
| 424 |
+
return False
|
| 425 |
+
return True
|
| 426 |
+
if _annotation_is_sequence(field.type_):
|
| 427 |
+
return True
|
| 428 |
+
return False
|
| 429 |
+
|
| 430 |
+
def _normalize_errors(errors: Sequence[Any]) -> List[Dict[str, Any]]:
|
| 431 |
+
use_errors: List[Any] = []
|
| 432 |
+
for error in errors:
|
| 433 |
+
if isinstance(error, ErrorWrapper):
|
| 434 |
+
new_errors = ValidationError( # type: ignore[call-arg]
|
| 435 |
+
errors=[error], model=RequestErrorModel
|
| 436 |
+
).errors()
|
| 437 |
+
use_errors.extend(new_errors)
|
| 438 |
+
elif isinstance(error, list):
|
| 439 |
+
use_errors.extend(_normalize_errors(error))
|
| 440 |
+
else:
|
| 441 |
+
use_errors.append(error)
|
| 442 |
+
return use_errors
|
| 443 |
+
|
| 444 |
+
def _model_rebuild(model: Type[BaseModel]) -> None:
|
| 445 |
+
model.update_forward_refs()
|
| 446 |
+
|
| 447 |
+
def _model_dump(
|
| 448 |
+
model: BaseModel, mode: Literal["json", "python"] = "json", **kwargs: Any
|
| 449 |
+
) -> Any:
|
| 450 |
+
return model.dict(**kwargs)
|
| 451 |
+
|
| 452 |
+
def _get_model_config(model: BaseModel) -> Any:
|
| 453 |
+
return model.__config__ # type: ignore[attr-defined]
|
| 454 |
+
|
| 455 |
+
def get_schema_from_model_field(
|
| 456 |
+
*,
|
| 457 |
+
field: ModelField,
|
| 458 |
+
schema_generator: GenerateJsonSchema,
|
| 459 |
+
model_name_map: ModelNameMap,
|
| 460 |
+
field_mapping: Dict[
|
| 461 |
+
Tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue
|
| 462 |
+
],
|
| 463 |
+
separate_input_output_schemas: bool = True,
|
| 464 |
+
) -> Dict[str, Any]:
|
| 465 |
+
# This expects that GenerateJsonSchema was already used to generate the definitions
|
| 466 |
+
return field_schema( # type: ignore[no-any-return]
|
| 467 |
+
field, model_name_map=model_name_map, ref_prefix=REF_PREFIX
|
| 468 |
+
)[0]
|
| 469 |
+
|
| 470 |
+
def get_compat_model_name_map(fields: List[ModelField]) -> ModelNameMap:
|
| 471 |
+
models = get_flat_models_from_fields(fields, known_models=set())
|
| 472 |
+
return get_model_name_map(models) # type: ignore[no-any-return]
|
| 473 |
+
|
| 474 |
+
def get_definitions(
|
| 475 |
+
*,
|
| 476 |
+
fields: List[ModelField],
|
| 477 |
+
schema_generator: GenerateJsonSchema,
|
| 478 |
+
model_name_map: ModelNameMap,
|
| 479 |
+
separate_input_output_schemas: bool = True,
|
| 480 |
+
) -> Tuple[
|
| 481 |
+
Dict[
|
| 482 |
+
Tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue
|
| 483 |
+
],
|
| 484 |
+
Dict[str, Dict[str, Any]],
|
| 485 |
+
]:
|
| 486 |
+
models = get_flat_models_from_fields(fields, known_models=set())
|
| 487 |
+
return {}, get_model_definitions(
|
| 488 |
+
flat_models=models, model_name_map=model_name_map
|
| 489 |
+
)
|
| 490 |
+
|
| 491 |
+
def is_scalar_field(field: ModelField) -> bool:
|
| 492 |
+
return is_pv1_scalar_field(field)
|
| 493 |
+
|
| 494 |
+
def is_sequence_field(field: ModelField) -> bool:
|
| 495 |
+
return field.shape in sequence_shapes or _annotation_is_sequence(field.type_) # type: ignore[attr-defined]
|
| 496 |
+
|
| 497 |
+
def is_scalar_sequence_field(field: ModelField) -> bool:
|
| 498 |
+
return is_pv1_scalar_sequence_field(field)
|
| 499 |
+
|
| 500 |
+
def is_bytes_field(field: ModelField) -> bool:
|
| 501 |
+
return lenient_issubclass(field.type_, bytes)
|
| 502 |
+
|
| 503 |
+
def is_bytes_sequence_field(field: ModelField) -> bool:
|
| 504 |
+
return field.shape in sequence_shapes and lenient_issubclass(field.type_, bytes) # type: ignore[attr-defined]
|
| 505 |
+
|
| 506 |
+
def copy_field_info(*, field_info: FieldInfo, annotation: Any) -> FieldInfo:
|
| 507 |
+
return copy(field_info)
|
| 508 |
+
|
| 509 |
+
def serialize_sequence_value(*, field: ModelField, value: Any) -> Sequence[Any]:
|
| 510 |
+
return sequence_shape_to_type[field.shape](value) # type: ignore[no-any-return,attr-defined]
|
| 511 |
+
|
| 512 |
+
def get_missing_field_error(loc: Tuple[str, ...]) -> Dict[str, Any]:
|
| 513 |
+
missing_field_error = ErrorWrapper(MissingError(), loc=loc) # type: ignore[call-arg]
|
| 514 |
+
new_error = ValidationError([missing_field_error], RequestErrorModel)
|
| 515 |
+
return new_error.errors()[0] # type: ignore[return-value]
|
| 516 |
+
|
| 517 |
+
def create_body_model(
|
| 518 |
+
*, fields: Sequence[ModelField], model_name: str
|
| 519 |
+
) -> Type[BaseModel]:
|
| 520 |
+
BodyModel = create_model(model_name)
|
| 521 |
+
for f in fields:
|
| 522 |
+
BodyModel.__fields__[f.name] = f # type: ignore[index]
|
| 523 |
+
return BodyModel
|
| 524 |
+
|
| 525 |
+
def get_model_fields(model: Type[BaseModel]) -> List[ModelField]:
|
| 526 |
+
return list(model.__fields__.values()) # type: ignore[attr-defined]
|
| 527 |
+
|
| 528 |
+
|
| 529 |
+
def _regenerate_error_with_loc(
|
| 530 |
+
*, errors: Sequence[Any], loc_prefix: Tuple[Union[str, int], ...]
|
| 531 |
+
) -> List[Dict[str, Any]]:
|
| 532 |
+
updated_loc_errors: List[Any] = [
|
| 533 |
+
{**err, "loc": loc_prefix + err.get("loc", ())}
|
| 534 |
+
for err in _normalize_errors(errors)
|
| 535 |
+
]
|
| 536 |
+
|
| 537 |
+
return updated_loc_errors
|
| 538 |
+
|
| 539 |
+
|
| 540 |
+
def _annotation_is_sequence(annotation: Union[Type[Any], None]) -> bool:
|
| 541 |
+
if lenient_issubclass(annotation, (str, bytes)):
|
| 542 |
+
return False
|
| 543 |
+
return lenient_issubclass(annotation, sequence_types)
|
| 544 |
+
|
| 545 |
+
|
| 546 |
+
def field_annotation_is_sequence(annotation: Union[Type[Any], None]) -> bool:
|
| 547 |
+
origin = get_origin(annotation)
|
| 548 |
+
if origin is Union or origin is UnionType:
|
| 549 |
+
for arg in get_args(annotation):
|
| 550 |
+
if field_annotation_is_sequence(arg):
|
| 551 |
+
return True
|
| 552 |
+
return False
|
| 553 |
+
return _annotation_is_sequence(annotation) or _annotation_is_sequence(
|
| 554 |
+
get_origin(annotation)
|
| 555 |
+
)
|
| 556 |
+
|
| 557 |
+
|
| 558 |
+
def value_is_sequence(value: Any) -> bool:
|
| 559 |
+
return isinstance(value, sequence_types) and not isinstance(value, (str, bytes)) # type: ignore[arg-type]
|
| 560 |
+
|
| 561 |
+
|
| 562 |
+
def _annotation_is_complex(annotation: Union[Type[Any], None]) -> bool:
|
| 563 |
+
return (
|
| 564 |
+
lenient_issubclass(annotation, (BaseModel, Mapping, UploadFile))
|
| 565 |
+
or _annotation_is_sequence(annotation)
|
| 566 |
+
or is_dataclass(annotation)
|
| 567 |
+
)
|
| 568 |
+
|
| 569 |
+
|
| 570 |
+
def field_annotation_is_complex(annotation: Union[Type[Any], None]) -> bool:
|
| 571 |
+
origin = get_origin(annotation)
|
| 572 |
+
if origin is Union or origin is UnionType:
|
| 573 |
+
return any(field_annotation_is_complex(arg) for arg in get_args(annotation))
|
| 574 |
+
|
| 575 |
+
return (
|
| 576 |
+
_annotation_is_complex(annotation)
|
| 577 |
+
or _annotation_is_complex(origin)
|
| 578 |
+
or hasattr(origin, "__pydantic_core_schema__")
|
| 579 |
+
or hasattr(origin, "__get_pydantic_core_schema__")
|
| 580 |
+
)
|
| 581 |
+
|
| 582 |
+
|
| 583 |
+
def field_annotation_is_scalar(annotation: Any) -> bool:
|
| 584 |
+
# handle Ellipsis here to make tuple[int, ...] work nicely
|
| 585 |
+
return annotation is Ellipsis or not field_annotation_is_complex(annotation)
|
| 586 |
+
|
| 587 |
+
|
| 588 |
+
def field_annotation_is_scalar_sequence(annotation: Union[Type[Any], None]) -> bool:
|
| 589 |
+
origin = get_origin(annotation)
|
| 590 |
+
if origin is Union or origin is UnionType:
|
| 591 |
+
at_least_one_scalar_sequence = False
|
| 592 |
+
for arg in get_args(annotation):
|
| 593 |
+
if field_annotation_is_scalar_sequence(arg):
|
| 594 |
+
at_least_one_scalar_sequence = True
|
| 595 |
+
continue
|
| 596 |
+
elif not field_annotation_is_scalar(arg):
|
| 597 |
+
return False
|
| 598 |
+
return at_least_one_scalar_sequence
|
| 599 |
+
return field_annotation_is_sequence(annotation) and all(
|
| 600 |
+
field_annotation_is_scalar(sub_annotation)
|
| 601 |
+
for sub_annotation in get_args(annotation)
|
| 602 |
+
)
|
| 603 |
+
|
| 604 |
+
|
| 605 |
+
def is_bytes_or_nonable_bytes_annotation(annotation: Any) -> bool:
|
| 606 |
+
if lenient_issubclass(annotation, bytes):
|
| 607 |
+
return True
|
| 608 |
+
origin = get_origin(annotation)
|
| 609 |
+
if origin is Union or origin is UnionType:
|
| 610 |
+
for arg in get_args(annotation):
|
| 611 |
+
if lenient_issubclass(arg, bytes):
|
| 612 |
+
return True
|
| 613 |
+
return False
|
| 614 |
+
|
| 615 |
+
|
| 616 |
+
def is_uploadfile_or_nonable_uploadfile_annotation(annotation: Any) -> bool:
|
| 617 |
+
if lenient_issubclass(annotation, UploadFile):
|
| 618 |
+
return True
|
| 619 |
+
origin = get_origin(annotation)
|
| 620 |
+
if origin is Union or origin is UnionType:
|
| 621 |
+
for arg in get_args(annotation):
|
| 622 |
+
if lenient_issubclass(arg, UploadFile):
|
| 623 |
+
return True
|
| 624 |
+
return False
|
| 625 |
+
|
| 626 |
+
|
| 627 |
+
def is_bytes_sequence_annotation(annotation: Any) -> bool:
|
| 628 |
+
origin = get_origin(annotation)
|
| 629 |
+
if origin is Union or origin is UnionType:
|
| 630 |
+
at_least_one = False
|
| 631 |
+
for arg in get_args(annotation):
|
| 632 |
+
if is_bytes_sequence_annotation(arg):
|
| 633 |
+
at_least_one = True
|
| 634 |
+
continue
|
| 635 |
+
return at_least_one
|
| 636 |
+
return field_annotation_is_sequence(annotation) and all(
|
| 637 |
+
is_bytes_or_nonable_bytes_annotation(sub_annotation)
|
| 638 |
+
for sub_annotation in get_args(annotation)
|
| 639 |
+
)
|
| 640 |
+
|
| 641 |
+
|
| 642 |
+
def is_uploadfile_sequence_annotation(annotation: Any) -> bool:
|
| 643 |
+
origin = get_origin(annotation)
|
| 644 |
+
if origin is Union or origin is UnionType:
|
| 645 |
+
at_least_one = False
|
| 646 |
+
for arg in get_args(annotation):
|
| 647 |
+
if is_uploadfile_sequence_annotation(arg):
|
| 648 |
+
at_least_one = True
|
| 649 |
+
continue
|
| 650 |
+
return at_least_one
|
| 651 |
+
return field_annotation_is_sequence(annotation) and all(
|
| 652 |
+
is_uploadfile_or_nonable_uploadfile_annotation(sub_annotation)
|
| 653 |
+
for sub_annotation in get_args(annotation)
|
| 654 |
+
)
|
| 655 |
+
|
| 656 |
+
|
| 657 |
+
@lru_cache
|
| 658 |
+
def get_cached_model_fields(model: Type[BaseModel]) -> List[ModelField]:
|
| 659 |
+
return get_model_fields(model)
|
lib/python3.12/site-packages/fastapi/applications.py
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
lib/python3.12/site-packages/fastapi/background.py
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from typing import Any, Callable
|
| 2 |
+
|
| 3 |
+
from starlette.background import BackgroundTasks as StarletteBackgroundTasks
|
| 4 |
+
from typing_extensions import Annotated, Doc, ParamSpec
|
| 5 |
+
|
| 6 |
+
P = ParamSpec("P")
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
class BackgroundTasks(StarletteBackgroundTasks):
|
| 10 |
+
"""
|
| 11 |
+
A collection of background tasks that will be called after a response has been
|
| 12 |
+
sent to the client.
|
| 13 |
+
|
| 14 |
+
Read more about it in the
|
| 15 |
+
[FastAPI docs for Background Tasks](https://fastapi.tiangolo.com/tutorial/background-tasks/).
|
| 16 |
+
|
| 17 |
+
## Example
|
| 18 |
+
|
| 19 |
+
```python
|
| 20 |
+
from fastapi import BackgroundTasks, FastAPI
|
| 21 |
+
|
| 22 |
+
app = FastAPI()
|
| 23 |
+
|
| 24 |
+
|
| 25 |
+
def write_notification(email: str, message=""):
|
| 26 |
+
with open("log.txt", mode="w") as email_file:
|
| 27 |
+
content = f"notification for {email}: {message}"
|
| 28 |
+
email_file.write(content)
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
@app.post("/send-notification/{email}")
|
| 32 |
+
async def send_notification(email: str, background_tasks: BackgroundTasks):
|
| 33 |
+
background_tasks.add_task(write_notification, email, message="some notification")
|
| 34 |
+
return {"message": "Notification sent in the background"}
|
| 35 |
+
```
|
| 36 |
+
"""
|
| 37 |
+
|
| 38 |
+
def add_task(
|
| 39 |
+
self,
|
| 40 |
+
func: Annotated[
|
| 41 |
+
Callable[P, Any],
|
| 42 |
+
Doc(
|
| 43 |
+
"""
|
| 44 |
+
The function to call after the response is sent.
|
| 45 |
+
|
| 46 |
+
It can be a regular `def` function or an `async def` function.
|
| 47 |
+
"""
|
| 48 |
+
),
|
| 49 |
+
],
|
| 50 |
+
*args: P.args,
|
| 51 |
+
**kwargs: P.kwargs,
|
| 52 |
+
) -> None:
|
| 53 |
+
"""
|
| 54 |
+
Add a function to be called in the background after the response is sent.
|
| 55 |
+
|
| 56 |
+
Read more about it in the
|
| 57 |
+
[FastAPI docs for Background Tasks](https://fastapi.tiangolo.com/tutorial/background-tasks/).
|
| 58 |
+
"""
|
| 59 |
+
return super().add_task(func, *args, **kwargs)
|
lib/python3.12/site-packages/fastapi/cli.py
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
try:
|
| 2 |
+
from fastapi_cli.cli import main as cli_main
|
| 3 |
+
|
| 4 |
+
except ImportError: # pragma: no cover
|
| 5 |
+
cli_main = None # type: ignore
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
def main() -> None:
|
| 9 |
+
if not cli_main: # type: ignore[truthy-function]
|
| 10 |
+
message = 'To use the fastapi command, please install "fastapi[standard]":\n\n\tpip install "fastapi[standard]"\n'
|
| 11 |
+
print(message)
|
| 12 |
+
raise RuntimeError(message) # noqa: B904
|
| 13 |
+
cli_main()
|
lib/python3.12/site-packages/fastapi/concurrency.py
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from contextlib import asynccontextmanager as asynccontextmanager
|
| 2 |
+
from typing import AsyncGenerator, ContextManager, TypeVar
|
| 3 |
+
|
| 4 |
+
import anyio.to_thread
|
| 5 |
+
from anyio import CapacityLimiter
|
| 6 |
+
from starlette.concurrency import iterate_in_threadpool as iterate_in_threadpool # noqa
|
| 7 |
+
from starlette.concurrency import run_in_threadpool as run_in_threadpool # noqa
|
| 8 |
+
from starlette.concurrency import ( # noqa
|
| 9 |
+
run_until_first_complete as run_until_first_complete,
|
| 10 |
+
)
|
| 11 |
+
|
| 12 |
+
_T = TypeVar("_T")
|
| 13 |
+
|
| 14 |
+
|
| 15 |
+
@asynccontextmanager
|
| 16 |
+
async def contextmanager_in_threadpool(
|
| 17 |
+
cm: ContextManager[_T],
|
| 18 |
+
) -> AsyncGenerator[_T, None]:
|
| 19 |
+
# blocking __exit__ from running waiting on a free thread
|
| 20 |
+
# can create race conditions/deadlocks if the context manager itself
|
| 21 |
+
# has its own internal pool (e.g. a database connection pool)
|
| 22 |
+
# to avoid this we let __exit__ run without a capacity limit
|
| 23 |
+
# since we're creating a new limiter for each call, any non-zero limit
|
| 24 |
+
# works (1 is arbitrary)
|
| 25 |
+
exit_limiter = CapacityLimiter(1)
|
| 26 |
+
try:
|
| 27 |
+
yield await run_in_threadpool(cm.__enter__)
|
| 28 |
+
except Exception as e:
|
| 29 |
+
ok = bool(
|
| 30 |
+
await anyio.to_thread.run_sync(
|
| 31 |
+
cm.__exit__, type(e), e, e.__traceback__, limiter=exit_limiter
|
| 32 |
+
)
|
| 33 |
+
)
|
| 34 |
+
if not ok:
|
| 35 |
+
raise e
|
| 36 |
+
else:
|
| 37 |
+
await anyio.to_thread.run_sync(
|
| 38 |
+
cm.__exit__, None, None, None, limiter=exit_limiter
|
| 39 |
+
)
|
lib/python3.12/site-packages/fastapi/datastructures.py
ADDED
|
@@ -0,0 +1,204 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from typing import (
|
| 2 |
+
Any,
|
| 3 |
+
BinaryIO,
|
| 4 |
+
Callable,
|
| 5 |
+
Dict,
|
| 6 |
+
Iterable,
|
| 7 |
+
Optional,
|
| 8 |
+
Type,
|
| 9 |
+
TypeVar,
|
| 10 |
+
cast,
|
| 11 |
+
)
|
| 12 |
+
|
| 13 |
+
from fastapi._compat import (
|
| 14 |
+
PYDANTIC_V2,
|
| 15 |
+
CoreSchema,
|
| 16 |
+
GetJsonSchemaHandler,
|
| 17 |
+
JsonSchemaValue,
|
| 18 |
+
with_info_plain_validator_function,
|
| 19 |
+
)
|
| 20 |
+
from starlette.datastructures import URL as URL # noqa: F401
|
| 21 |
+
from starlette.datastructures import Address as Address # noqa: F401
|
| 22 |
+
from starlette.datastructures import FormData as FormData # noqa: F401
|
| 23 |
+
from starlette.datastructures import Headers as Headers # noqa: F401
|
| 24 |
+
from starlette.datastructures import QueryParams as QueryParams # noqa: F401
|
| 25 |
+
from starlette.datastructures import State as State # noqa: F401
|
| 26 |
+
from starlette.datastructures import UploadFile as StarletteUploadFile
|
| 27 |
+
from typing_extensions import Annotated, Doc
|
| 28 |
+
|
| 29 |
+
|
| 30 |
+
class UploadFile(StarletteUploadFile):
|
| 31 |
+
"""
|
| 32 |
+
A file uploaded in a request.
|
| 33 |
+
|
| 34 |
+
Define it as a *path operation function* (or dependency) parameter.
|
| 35 |
+
|
| 36 |
+
If you are using a regular `def` function, you can use the `upload_file.file`
|
| 37 |
+
attribute to access the raw standard Python file (blocking, not async), useful and
|
| 38 |
+
needed for non-async code.
|
| 39 |
+
|
| 40 |
+
Read more about it in the
|
| 41 |
+
[FastAPI docs for Request Files](https://fastapi.tiangolo.com/tutorial/request-files/).
|
| 42 |
+
|
| 43 |
+
## Example
|
| 44 |
+
|
| 45 |
+
```python
|
| 46 |
+
from typing import Annotated
|
| 47 |
+
|
| 48 |
+
from fastapi import FastAPI, File, UploadFile
|
| 49 |
+
|
| 50 |
+
app = FastAPI()
|
| 51 |
+
|
| 52 |
+
|
| 53 |
+
@app.post("/files/")
|
| 54 |
+
async def create_file(file: Annotated[bytes, File()]):
|
| 55 |
+
return {"file_size": len(file)}
|
| 56 |
+
|
| 57 |
+
|
| 58 |
+
@app.post("/uploadfile/")
|
| 59 |
+
async def create_upload_file(file: UploadFile):
|
| 60 |
+
return {"filename": file.filename}
|
| 61 |
+
```
|
| 62 |
+
"""
|
| 63 |
+
|
| 64 |
+
file: Annotated[
|
| 65 |
+
BinaryIO,
|
| 66 |
+
Doc("The standard Python file object (non-async)."),
|
| 67 |
+
]
|
| 68 |
+
filename: Annotated[Optional[str], Doc("The original file name.")]
|
| 69 |
+
size: Annotated[Optional[int], Doc("The size of the file in bytes.")]
|
| 70 |
+
headers: Annotated[Headers, Doc("The headers of the request.")]
|
| 71 |
+
content_type: Annotated[
|
| 72 |
+
Optional[str], Doc("The content type of the request, from the headers.")
|
| 73 |
+
]
|
| 74 |
+
|
| 75 |
+
async def write(
|
| 76 |
+
self,
|
| 77 |
+
data: Annotated[
|
| 78 |
+
bytes,
|
| 79 |
+
Doc(
|
| 80 |
+
"""
|
| 81 |
+
The bytes to write to the file.
|
| 82 |
+
"""
|
| 83 |
+
),
|
| 84 |
+
],
|
| 85 |
+
) -> None:
|
| 86 |
+
"""
|
| 87 |
+
Write some bytes to the file.
|
| 88 |
+
|
| 89 |
+
You normally wouldn't use this from a file you read in a request.
|
| 90 |
+
|
| 91 |
+
To be awaitable, compatible with async, this is run in threadpool.
|
| 92 |
+
"""
|
| 93 |
+
return await super().write(data)
|
| 94 |
+
|
| 95 |
+
async def read(
|
| 96 |
+
self,
|
| 97 |
+
size: Annotated[
|
| 98 |
+
int,
|
| 99 |
+
Doc(
|
| 100 |
+
"""
|
| 101 |
+
The number of bytes to read from the file.
|
| 102 |
+
"""
|
| 103 |
+
),
|
| 104 |
+
] = -1,
|
| 105 |
+
) -> bytes:
|
| 106 |
+
"""
|
| 107 |
+
Read some bytes from the file.
|
| 108 |
+
|
| 109 |
+
To be awaitable, compatible with async, this is run in threadpool.
|
| 110 |
+
"""
|
| 111 |
+
return await super().read(size)
|
| 112 |
+
|
| 113 |
+
async def seek(
|
| 114 |
+
self,
|
| 115 |
+
offset: Annotated[
|
| 116 |
+
int,
|
| 117 |
+
Doc(
|
| 118 |
+
"""
|
| 119 |
+
The position in bytes to seek to in the file.
|
| 120 |
+
"""
|
| 121 |
+
),
|
| 122 |
+
],
|
| 123 |
+
) -> None:
|
| 124 |
+
"""
|
| 125 |
+
Move to a position in the file.
|
| 126 |
+
|
| 127 |
+
Any next read or write will be done from that position.
|
| 128 |
+
|
| 129 |
+
To be awaitable, compatible with async, this is run in threadpool.
|
| 130 |
+
"""
|
| 131 |
+
return await super().seek(offset)
|
| 132 |
+
|
| 133 |
+
async def close(self) -> None:
|
| 134 |
+
"""
|
| 135 |
+
Close the file.
|
| 136 |
+
|
| 137 |
+
To be awaitable, compatible with async, this is run in threadpool.
|
| 138 |
+
"""
|
| 139 |
+
return await super().close()
|
| 140 |
+
|
| 141 |
+
@classmethod
|
| 142 |
+
def __get_validators__(cls: Type["UploadFile"]) -> Iterable[Callable[..., Any]]:
|
| 143 |
+
yield cls.validate
|
| 144 |
+
|
| 145 |
+
@classmethod
|
| 146 |
+
def validate(cls: Type["UploadFile"], v: Any) -> Any:
|
| 147 |
+
if not isinstance(v, StarletteUploadFile):
|
| 148 |
+
raise ValueError(f"Expected UploadFile, received: {type(v)}")
|
| 149 |
+
return v
|
| 150 |
+
|
| 151 |
+
@classmethod
|
| 152 |
+
def _validate(cls, __input_value: Any, _: Any) -> "UploadFile":
|
| 153 |
+
if not isinstance(__input_value, StarletteUploadFile):
|
| 154 |
+
raise ValueError(f"Expected UploadFile, received: {type(__input_value)}")
|
| 155 |
+
return cast(UploadFile, __input_value)
|
| 156 |
+
|
| 157 |
+
if not PYDANTIC_V2:
|
| 158 |
+
|
| 159 |
+
@classmethod
|
| 160 |
+
def __modify_schema__(cls, field_schema: Dict[str, Any]) -> None:
|
| 161 |
+
field_schema.update({"type": "string", "format": "binary"})
|
| 162 |
+
|
| 163 |
+
@classmethod
|
| 164 |
+
def __get_pydantic_json_schema__(
|
| 165 |
+
cls, core_schema: CoreSchema, handler: GetJsonSchemaHandler
|
| 166 |
+
) -> JsonSchemaValue:
|
| 167 |
+
return {"type": "string", "format": "binary"}
|
| 168 |
+
|
| 169 |
+
@classmethod
|
| 170 |
+
def __get_pydantic_core_schema__(
|
| 171 |
+
cls, source: Type[Any], handler: Callable[[Any], CoreSchema]
|
| 172 |
+
) -> CoreSchema:
|
| 173 |
+
return with_info_plain_validator_function(cls._validate)
|
| 174 |
+
|
| 175 |
+
|
| 176 |
+
class DefaultPlaceholder:
|
| 177 |
+
"""
|
| 178 |
+
You shouldn't use this class directly.
|
| 179 |
+
|
| 180 |
+
It's used internally to recognize when a default value has been overwritten, even
|
| 181 |
+
if the overridden default value was truthy.
|
| 182 |
+
"""
|
| 183 |
+
|
| 184 |
+
def __init__(self, value: Any):
|
| 185 |
+
self.value = value
|
| 186 |
+
|
| 187 |
+
def __bool__(self) -> bool:
|
| 188 |
+
return bool(self.value)
|
| 189 |
+
|
| 190 |
+
def __eq__(self, o: object) -> bool:
|
| 191 |
+
return isinstance(o, DefaultPlaceholder) and o.value == self.value
|
| 192 |
+
|
| 193 |
+
|
| 194 |
+
DefaultType = TypeVar("DefaultType")
|
| 195 |
+
|
| 196 |
+
|
| 197 |
+
def Default(value: DefaultType) -> DefaultType:
|
| 198 |
+
"""
|
| 199 |
+
You shouldn't use this function directly.
|
| 200 |
+
|
| 201 |
+
It's used internally to recognize when a default value has been overwritten, even
|
| 202 |
+
if the overridden default value was truthy.
|
| 203 |
+
"""
|
| 204 |
+
return DefaultPlaceholder(value) # type: ignore
|
lib/python3.12/site-packages/fastapi/encoders.py
ADDED
|
@@ -0,0 +1,343 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import dataclasses
|
| 2 |
+
import datetime
|
| 3 |
+
from collections import defaultdict, deque
|
| 4 |
+
from decimal import Decimal
|
| 5 |
+
from enum import Enum
|
| 6 |
+
from ipaddress import (
|
| 7 |
+
IPv4Address,
|
| 8 |
+
IPv4Interface,
|
| 9 |
+
IPv4Network,
|
| 10 |
+
IPv6Address,
|
| 11 |
+
IPv6Interface,
|
| 12 |
+
IPv6Network,
|
| 13 |
+
)
|
| 14 |
+
from pathlib import Path, PurePath
|
| 15 |
+
from re import Pattern
|
| 16 |
+
from types import GeneratorType
|
| 17 |
+
from typing import Any, Callable, Dict, List, Optional, Tuple, Type, Union
|
| 18 |
+
from uuid import UUID
|
| 19 |
+
|
| 20 |
+
from fastapi.types import IncEx
|
| 21 |
+
from pydantic import BaseModel
|
| 22 |
+
from pydantic.color import Color
|
| 23 |
+
from pydantic.networks import AnyUrl, NameEmail
|
| 24 |
+
from pydantic.types import SecretBytes, SecretStr
|
| 25 |
+
from typing_extensions import Annotated, Doc
|
| 26 |
+
|
| 27 |
+
from ._compat import PYDANTIC_V2, UndefinedType, Url, _model_dump
|
| 28 |
+
|
| 29 |
+
|
| 30 |
+
# Taken from Pydantic v1 as is
|
| 31 |
+
def isoformat(o: Union[datetime.date, datetime.time]) -> str:
|
| 32 |
+
return o.isoformat()
|
| 33 |
+
|
| 34 |
+
|
| 35 |
+
# Taken from Pydantic v1 as is
|
| 36 |
+
# TODO: pv2 should this return strings instead?
|
| 37 |
+
def decimal_encoder(dec_value: Decimal) -> Union[int, float]:
|
| 38 |
+
"""
|
| 39 |
+
Encodes a Decimal as int of there's no exponent, otherwise float
|
| 40 |
+
|
| 41 |
+
This is useful when we use ConstrainedDecimal to represent Numeric(x,0)
|
| 42 |
+
where a integer (but not int typed) is used. Encoding this as a float
|
| 43 |
+
results in failed round-tripping between encode and parse.
|
| 44 |
+
Our Id type is a prime example of this.
|
| 45 |
+
|
| 46 |
+
>>> decimal_encoder(Decimal("1.0"))
|
| 47 |
+
1.0
|
| 48 |
+
|
| 49 |
+
>>> decimal_encoder(Decimal("1"))
|
| 50 |
+
1
|
| 51 |
+
"""
|
| 52 |
+
if dec_value.as_tuple().exponent >= 0: # type: ignore[operator]
|
| 53 |
+
return int(dec_value)
|
| 54 |
+
else:
|
| 55 |
+
return float(dec_value)
|
| 56 |
+
|
| 57 |
+
|
| 58 |
+
ENCODERS_BY_TYPE: Dict[Type[Any], Callable[[Any], Any]] = {
|
| 59 |
+
bytes: lambda o: o.decode(),
|
| 60 |
+
Color: str,
|
| 61 |
+
datetime.date: isoformat,
|
| 62 |
+
datetime.datetime: isoformat,
|
| 63 |
+
datetime.time: isoformat,
|
| 64 |
+
datetime.timedelta: lambda td: td.total_seconds(),
|
| 65 |
+
Decimal: decimal_encoder,
|
| 66 |
+
Enum: lambda o: o.value,
|
| 67 |
+
frozenset: list,
|
| 68 |
+
deque: list,
|
| 69 |
+
GeneratorType: list,
|
| 70 |
+
IPv4Address: str,
|
| 71 |
+
IPv4Interface: str,
|
| 72 |
+
IPv4Network: str,
|
| 73 |
+
IPv6Address: str,
|
| 74 |
+
IPv6Interface: str,
|
| 75 |
+
IPv6Network: str,
|
| 76 |
+
NameEmail: str,
|
| 77 |
+
Path: str,
|
| 78 |
+
Pattern: lambda o: o.pattern,
|
| 79 |
+
SecretBytes: str,
|
| 80 |
+
SecretStr: str,
|
| 81 |
+
set: list,
|
| 82 |
+
UUID: str,
|
| 83 |
+
Url: str,
|
| 84 |
+
AnyUrl: str,
|
| 85 |
+
}
|
| 86 |
+
|
| 87 |
+
|
| 88 |
+
def generate_encoders_by_class_tuples(
|
| 89 |
+
type_encoder_map: Dict[Any, Callable[[Any], Any]],
|
| 90 |
+
) -> Dict[Callable[[Any], Any], Tuple[Any, ...]]:
|
| 91 |
+
encoders_by_class_tuples: Dict[Callable[[Any], Any], Tuple[Any, ...]] = defaultdict(
|
| 92 |
+
tuple
|
| 93 |
+
)
|
| 94 |
+
for type_, encoder in type_encoder_map.items():
|
| 95 |
+
encoders_by_class_tuples[encoder] += (type_,)
|
| 96 |
+
return encoders_by_class_tuples
|
| 97 |
+
|
| 98 |
+
|
| 99 |
+
encoders_by_class_tuples = generate_encoders_by_class_tuples(ENCODERS_BY_TYPE)
|
| 100 |
+
|
| 101 |
+
|
| 102 |
+
def jsonable_encoder(
|
| 103 |
+
obj: Annotated[
|
| 104 |
+
Any,
|
| 105 |
+
Doc(
|
| 106 |
+
"""
|
| 107 |
+
The input object to convert to JSON.
|
| 108 |
+
"""
|
| 109 |
+
),
|
| 110 |
+
],
|
| 111 |
+
include: Annotated[
|
| 112 |
+
Optional[IncEx],
|
| 113 |
+
Doc(
|
| 114 |
+
"""
|
| 115 |
+
Pydantic's `include` parameter, passed to Pydantic models to set the
|
| 116 |
+
fields to include.
|
| 117 |
+
"""
|
| 118 |
+
),
|
| 119 |
+
] = None,
|
| 120 |
+
exclude: Annotated[
|
| 121 |
+
Optional[IncEx],
|
| 122 |
+
Doc(
|
| 123 |
+
"""
|
| 124 |
+
Pydantic's `exclude` parameter, passed to Pydantic models to set the
|
| 125 |
+
fields to exclude.
|
| 126 |
+
"""
|
| 127 |
+
),
|
| 128 |
+
] = None,
|
| 129 |
+
by_alias: Annotated[
|
| 130 |
+
bool,
|
| 131 |
+
Doc(
|
| 132 |
+
"""
|
| 133 |
+
Pydantic's `by_alias` parameter, passed to Pydantic models to define if
|
| 134 |
+
the output should use the alias names (when provided) or the Python
|
| 135 |
+
attribute names. In an API, if you set an alias, it's probably because you
|
| 136 |
+
want to use it in the result, so you probably want to leave this set to
|
| 137 |
+
`True`.
|
| 138 |
+
"""
|
| 139 |
+
),
|
| 140 |
+
] = True,
|
| 141 |
+
exclude_unset: Annotated[
|
| 142 |
+
bool,
|
| 143 |
+
Doc(
|
| 144 |
+
"""
|
| 145 |
+
Pydantic's `exclude_unset` parameter, passed to Pydantic models to define
|
| 146 |
+
if it should exclude from the output the fields that were not explicitly
|
| 147 |
+
set (and that only had their default values).
|
| 148 |
+
"""
|
| 149 |
+
),
|
| 150 |
+
] = False,
|
| 151 |
+
exclude_defaults: Annotated[
|
| 152 |
+
bool,
|
| 153 |
+
Doc(
|
| 154 |
+
"""
|
| 155 |
+
Pydantic's `exclude_defaults` parameter, passed to Pydantic models to define
|
| 156 |
+
if it should exclude from the output the fields that had the same default
|
| 157 |
+
value, even when they were explicitly set.
|
| 158 |
+
"""
|
| 159 |
+
),
|
| 160 |
+
] = False,
|
| 161 |
+
exclude_none: Annotated[
|
| 162 |
+
bool,
|
| 163 |
+
Doc(
|
| 164 |
+
"""
|
| 165 |
+
Pydantic's `exclude_none` parameter, passed to Pydantic models to define
|
| 166 |
+
if it should exclude from the output any fields that have a `None` value.
|
| 167 |
+
"""
|
| 168 |
+
),
|
| 169 |
+
] = False,
|
| 170 |
+
custom_encoder: Annotated[
|
| 171 |
+
Optional[Dict[Any, Callable[[Any], Any]]],
|
| 172 |
+
Doc(
|
| 173 |
+
"""
|
| 174 |
+
Pydantic's `custom_encoder` parameter, passed to Pydantic models to define
|
| 175 |
+
a custom encoder.
|
| 176 |
+
"""
|
| 177 |
+
),
|
| 178 |
+
] = None,
|
| 179 |
+
sqlalchemy_safe: Annotated[
|
| 180 |
+
bool,
|
| 181 |
+
Doc(
|
| 182 |
+
"""
|
| 183 |
+
Exclude from the output any fields that start with the name `_sa`.
|
| 184 |
+
|
| 185 |
+
This is mainly a hack for compatibility with SQLAlchemy objects, they
|
| 186 |
+
store internal SQLAlchemy-specific state in attributes named with `_sa`,
|
| 187 |
+
and those objects can't (and shouldn't be) serialized to JSON.
|
| 188 |
+
"""
|
| 189 |
+
),
|
| 190 |
+
] = True,
|
| 191 |
+
) -> Any:
|
| 192 |
+
"""
|
| 193 |
+
Convert any object to something that can be encoded in JSON.
|
| 194 |
+
|
| 195 |
+
This is used internally by FastAPI to make sure anything you return can be
|
| 196 |
+
encoded as JSON before it is sent to the client.
|
| 197 |
+
|
| 198 |
+
You can also use it yourself, for example to convert objects before saving them
|
| 199 |
+
in a database that supports only JSON.
|
| 200 |
+
|
| 201 |
+
Read more about it in the
|
| 202 |
+
[FastAPI docs for JSON Compatible Encoder](https://fastapi.tiangolo.com/tutorial/encoder/).
|
| 203 |
+
"""
|
| 204 |
+
custom_encoder = custom_encoder or {}
|
| 205 |
+
if custom_encoder:
|
| 206 |
+
if type(obj) in custom_encoder:
|
| 207 |
+
return custom_encoder[type(obj)](obj)
|
| 208 |
+
else:
|
| 209 |
+
for encoder_type, encoder_instance in custom_encoder.items():
|
| 210 |
+
if isinstance(obj, encoder_type):
|
| 211 |
+
return encoder_instance(obj)
|
| 212 |
+
if include is not None and not isinstance(include, (set, dict)):
|
| 213 |
+
include = set(include)
|
| 214 |
+
if exclude is not None and not isinstance(exclude, (set, dict)):
|
| 215 |
+
exclude = set(exclude)
|
| 216 |
+
if isinstance(obj, BaseModel):
|
| 217 |
+
# TODO: remove when deprecating Pydantic v1
|
| 218 |
+
encoders: Dict[Any, Any] = {}
|
| 219 |
+
if not PYDANTIC_V2:
|
| 220 |
+
encoders = getattr(obj.__config__, "json_encoders", {}) # type: ignore[attr-defined]
|
| 221 |
+
if custom_encoder:
|
| 222 |
+
encoders.update(custom_encoder)
|
| 223 |
+
obj_dict = _model_dump(
|
| 224 |
+
obj,
|
| 225 |
+
mode="json",
|
| 226 |
+
include=include,
|
| 227 |
+
exclude=exclude,
|
| 228 |
+
by_alias=by_alias,
|
| 229 |
+
exclude_unset=exclude_unset,
|
| 230 |
+
exclude_none=exclude_none,
|
| 231 |
+
exclude_defaults=exclude_defaults,
|
| 232 |
+
)
|
| 233 |
+
if "__root__" in obj_dict:
|
| 234 |
+
obj_dict = obj_dict["__root__"]
|
| 235 |
+
return jsonable_encoder(
|
| 236 |
+
obj_dict,
|
| 237 |
+
exclude_none=exclude_none,
|
| 238 |
+
exclude_defaults=exclude_defaults,
|
| 239 |
+
# TODO: remove when deprecating Pydantic v1
|
| 240 |
+
custom_encoder=encoders,
|
| 241 |
+
sqlalchemy_safe=sqlalchemy_safe,
|
| 242 |
+
)
|
| 243 |
+
if dataclasses.is_dataclass(obj):
|
| 244 |
+
obj_dict = dataclasses.asdict(obj)
|
| 245 |
+
return jsonable_encoder(
|
| 246 |
+
obj_dict,
|
| 247 |
+
include=include,
|
| 248 |
+
exclude=exclude,
|
| 249 |
+
by_alias=by_alias,
|
| 250 |
+
exclude_unset=exclude_unset,
|
| 251 |
+
exclude_defaults=exclude_defaults,
|
| 252 |
+
exclude_none=exclude_none,
|
| 253 |
+
custom_encoder=custom_encoder,
|
| 254 |
+
sqlalchemy_safe=sqlalchemy_safe,
|
| 255 |
+
)
|
| 256 |
+
if isinstance(obj, Enum):
|
| 257 |
+
return obj.value
|
| 258 |
+
if isinstance(obj, PurePath):
|
| 259 |
+
return str(obj)
|
| 260 |
+
if isinstance(obj, (str, int, float, type(None))):
|
| 261 |
+
return obj
|
| 262 |
+
if isinstance(obj, UndefinedType):
|
| 263 |
+
return None
|
| 264 |
+
if isinstance(obj, dict):
|
| 265 |
+
encoded_dict = {}
|
| 266 |
+
allowed_keys = set(obj.keys())
|
| 267 |
+
if include is not None:
|
| 268 |
+
allowed_keys &= set(include)
|
| 269 |
+
if exclude is not None:
|
| 270 |
+
allowed_keys -= set(exclude)
|
| 271 |
+
for key, value in obj.items():
|
| 272 |
+
if (
|
| 273 |
+
(
|
| 274 |
+
not sqlalchemy_safe
|
| 275 |
+
or (not isinstance(key, str))
|
| 276 |
+
or (not key.startswith("_sa"))
|
| 277 |
+
)
|
| 278 |
+
and (value is not None or not exclude_none)
|
| 279 |
+
and key in allowed_keys
|
| 280 |
+
):
|
| 281 |
+
encoded_key = jsonable_encoder(
|
| 282 |
+
key,
|
| 283 |
+
by_alias=by_alias,
|
| 284 |
+
exclude_unset=exclude_unset,
|
| 285 |
+
exclude_none=exclude_none,
|
| 286 |
+
custom_encoder=custom_encoder,
|
| 287 |
+
sqlalchemy_safe=sqlalchemy_safe,
|
| 288 |
+
)
|
| 289 |
+
encoded_value = jsonable_encoder(
|
| 290 |
+
value,
|
| 291 |
+
by_alias=by_alias,
|
| 292 |
+
exclude_unset=exclude_unset,
|
| 293 |
+
exclude_none=exclude_none,
|
| 294 |
+
custom_encoder=custom_encoder,
|
| 295 |
+
sqlalchemy_safe=sqlalchemy_safe,
|
| 296 |
+
)
|
| 297 |
+
encoded_dict[encoded_key] = encoded_value
|
| 298 |
+
return encoded_dict
|
| 299 |
+
if isinstance(obj, (list, set, frozenset, GeneratorType, tuple, deque)):
|
| 300 |
+
encoded_list = []
|
| 301 |
+
for item in obj:
|
| 302 |
+
encoded_list.append(
|
| 303 |
+
jsonable_encoder(
|
| 304 |
+
item,
|
| 305 |
+
include=include,
|
| 306 |
+
exclude=exclude,
|
| 307 |
+
by_alias=by_alias,
|
| 308 |
+
exclude_unset=exclude_unset,
|
| 309 |
+
exclude_defaults=exclude_defaults,
|
| 310 |
+
exclude_none=exclude_none,
|
| 311 |
+
custom_encoder=custom_encoder,
|
| 312 |
+
sqlalchemy_safe=sqlalchemy_safe,
|
| 313 |
+
)
|
| 314 |
+
)
|
| 315 |
+
return encoded_list
|
| 316 |
+
|
| 317 |
+
if type(obj) in ENCODERS_BY_TYPE:
|
| 318 |
+
return ENCODERS_BY_TYPE[type(obj)](obj)
|
| 319 |
+
for encoder, classes_tuple in encoders_by_class_tuples.items():
|
| 320 |
+
if isinstance(obj, classes_tuple):
|
| 321 |
+
return encoder(obj)
|
| 322 |
+
|
| 323 |
+
try:
|
| 324 |
+
data = dict(obj)
|
| 325 |
+
except Exception as e:
|
| 326 |
+
errors: List[Exception] = []
|
| 327 |
+
errors.append(e)
|
| 328 |
+
try:
|
| 329 |
+
data = vars(obj)
|
| 330 |
+
except Exception as e:
|
| 331 |
+
errors.append(e)
|
| 332 |
+
raise ValueError(errors) from e
|
| 333 |
+
return jsonable_encoder(
|
| 334 |
+
data,
|
| 335 |
+
include=include,
|
| 336 |
+
exclude=exclude,
|
| 337 |
+
by_alias=by_alias,
|
| 338 |
+
exclude_unset=exclude_unset,
|
| 339 |
+
exclude_defaults=exclude_defaults,
|
| 340 |
+
exclude_none=exclude_none,
|
| 341 |
+
custom_encoder=custom_encoder,
|
| 342 |
+
sqlalchemy_safe=sqlalchemy_safe,
|
| 343 |
+
)
|
lib/python3.12/site-packages/fastapi/exception_handlers.py
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from fastapi.encoders import jsonable_encoder
|
| 2 |
+
from fastapi.exceptions import RequestValidationError, WebSocketRequestValidationError
|
| 3 |
+
from fastapi.utils import is_body_allowed_for_status_code
|
| 4 |
+
from fastapi.websockets import WebSocket
|
| 5 |
+
from starlette.exceptions import HTTPException
|
| 6 |
+
from starlette.requests import Request
|
| 7 |
+
from starlette.responses import JSONResponse, Response
|
| 8 |
+
from starlette.status import HTTP_422_UNPROCESSABLE_ENTITY, WS_1008_POLICY_VIOLATION
|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
async def http_exception_handler(request: Request, exc: HTTPException) -> Response:
|
| 12 |
+
headers = getattr(exc, "headers", None)
|
| 13 |
+
if not is_body_allowed_for_status_code(exc.status_code):
|
| 14 |
+
return Response(status_code=exc.status_code, headers=headers)
|
| 15 |
+
return JSONResponse(
|
| 16 |
+
{"detail": exc.detail}, status_code=exc.status_code, headers=headers
|
| 17 |
+
)
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
async def request_validation_exception_handler(
|
| 21 |
+
request: Request, exc: RequestValidationError
|
| 22 |
+
) -> JSONResponse:
|
| 23 |
+
return JSONResponse(
|
| 24 |
+
status_code=HTTP_422_UNPROCESSABLE_ENTITY,
|
| 25 |
+
content={"detail": jsonable_encoder(exc.errors())},
|
| 26 |
+
)
|
| 27 |
+
|
| 28 |
+
|
| 29 |
+
async def websocket_request_validation_exception_handler(
|
| 30 |
+
websocket: WebSocket, exc: WebSocketRequestValidationError
|
| 31 |
+
) -> None:
|
| 32 |
+
await websocket.close(
|
| 33 |
+
code=WS_1008_POLICY_VIOLATION, reason=jsonable_encoder(exc.errors())
|
| 34 |
+
)
|
lib/python3.12/site-packages/fastapi/exceptions.py
ADDED
|
@@ -0,0 +1,176 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from typing import Any, Dict, Optional, Sequence, Type, Union
|
| 2 |
+
|
| 3 |
+
from pydantic import BaseModel, create_model
|
| 4 |
+
from starlette.exceptions import HTTPException as StarletteHTTPException
|
| 5 |
+
from starlette.exceptions import WebSocketException as StarletteWebSocketException
|
| 6 |
+
from typing_extensions import Annotated, Doc
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
class HTTPException(StarletteHTTPException):
|
| 10 |
+
"""
|
| 11 |
+
An HTTP exception you can raise in your own code to show errors to the client.
|
| 12 |
+
|
| 13 |
+
This is for client errors, invalid authentication, invalid data, etc. Not for server
|
| 14 |
+
errors in your code.
|
| 15 |
+
|
| 16 |
+
Read more about it in the
|
| 17 |
+
[FastAPI docs for Handling Errors](https://fastapi.tiangolo.com/tutorial/handling-errors/).
|
| 18 |
+
|
| 19 |
+
## Example
|
| 20 |
+
|
| 21 |
+
```python
|
| 22 |
+
from fastapi import FastAPI, HTTPException
|
| 23 |
+
|
| 24 |
+
app = FastAPI()
|
| 25 |
+
|
| 26 |
+
items = {"foo": "The Foo Wrestlers"}
|
| 27 |
+
|
| 28 |
+
|
| 29 |
+
@app.get("/items/{item_id}")
|
| 30 |
+
async def read_item(item_id: str):
|
| 31 |
+
if item_id not in items:
|
| 32 |
+
raise HTTPException(status_code=404, detail="Item not found")
|
| 33 |
+
return {"item": items[item_id]}
|
| 34 |
+
```
|
| 35 |
+
"""
|
| 36 |
+
|
| 37 |
+
def __init__(
|
| 38 |
+
self,
|
| 39 |
+
status_code: Annotated[
|
| 40 |
+
int,
|
| 41 |
+
Doc(
|
| 42 |
+
"""
|
| 43 |
+
HTTP status code to send to the client.
|
| 44 |
+
"""
|
| 45 |
+
),
|
| 46 |
+
],
|
| 47 |
+
detail: Annotated[
|
| 48 |
+
Any,
|
| 49 |
+
Doc(
|
| 50 |
+
"""
|
| 51 |
+
Any data to be sent to the client in the `detail` key of the JSON
|
| 52 |
+
response.
|
| 53 |
+
"""
|
| 54 |
+
),
|
| 55 |
+
] = None,
|
| 56 |
+
headers: Annotated[
|
| 57 |
+
Optional[Dict[str, str]],
|
| 58 |
+
Doc(
|
| 59 |
+
"""
|
| 60 |
+
Any headers to send to the client in the response.
|
| 61 |
+
"""
|
| 62 |
+
),
|
| 63 |
+
] = None,
|
| 64 |
+
) -> None:
|
| 65 |
+
super().__init__(status_code=status_code, detail=detail, headers=headers)
|
| 66 |
+
|
| 67 |
+
|
| 68 |
+
class WebSocketException(StarletteWebSocketException):
|
| 69 |
+
"""
|
| 70 |
+
A WebSocket exception you can raise in your own code to show errors to the client.
|
| 71 |
+
|
| 72 |
+
This is for client errors, invalid authentication, invalid data, etc. Not for server
|
| 73 |
+
errors in your code.
|
| 74 |
+
|
| 75 |
+
Read more about it in the
|
| 76 |
+
[FastAPI docs for WebSockets](https://fastapi.tiangolo.com/advanced/websockets/).
|
| 77 |
+
|
| 78 |
+
## Example
|
| 79 |
+
|
| 80 |
+
```python
|
| 81 |
+
from typing import Annotated
|
| 82 |
+
|
| 83 |
+
from fastapi import (
|
| 84 |
+
Cookie,
|
| 85 |
+
FastAPI,
|
| 86 |
+
WebSocket,
|
| 87 |
+
WebSocketException,
|
| 88 |
+
status,
|
| 89 |
+
)
|
| 90 |
+
|
| 91 |
+
app = FastAPI()
|
| 92 |
+
|
| 93 |
+
@app.websocket("/items/{item_id}/ws")
|
| 94 |
+
async def websocket_endpoint(
|
| 95 |
+
*,
|
| 96 |
+
websocket: WebSocket,
|
| 97 |
+
session: Annotated[str | None, Cookie()] = None,
|
| 98 |
+
item_id: str,
|
| 99 |
+
):
|
| 100 |
+
if session is None:
|
| 101 |
+
raise WebSocketException(code=status.WS_1008_POLICY_VIOLATION)
|
| 102 |
+
await websocket.accept()
|
| 103 |
+
while True:
|
| 104 |
+
data = await websocket.receive_text()
|
| 105 |
+
await websocket.send_text(f"Session cookie is: {session}")
|
| 106 |
+
await websocket.send_text(f"Message text was: {data}, for item ID: {item_id}")
|
| 107 |
+
```
|
| 108 |
+
"""
|
| 109 |
+
|
| 110 |
+
def __init__(
|
| 111 |
+
self,
|
| 112 |
+
code: Annotated[
|
| 113 |
+
int,
|
| 114 |
+
Doc(
|
| 115 |
+
"""
|
| 116 |
+
A closing code from the
|
| 117 |
+
[valid codes defined in the specification](https://datatracker.ietf.org/doc/html/rfc6455#section-7.4.1).
|
| 118 |
+
"""
|
| 119 |
+
),
|
| 120 |
+
],
|
| 121 |
+
reason: Annotated[
|
| 122 |
+
Union[str, None],
|
| 123 |
+
Doc(
|
| 124 |
+
"""
|
| 125 |
+
The reason to close the WebSocket connection.
|
| 126 |
+
|
| 127 |
+
It is UTF-8-encoded data. The interpretation of the reason is up to the
|
| 128 |
+
application, it is not specified by the WebSocket specification.
|
| 129 |
+
|
| 130 |
+
It could contain text that could be human-readable or interpretable
|
| 131 |
+
by the client code, etc.
|
| 132 |
+
"""
|
| 133 |
+
),
|
| 134 |
+
] = None,
|
| 135 |
+
) -> None:
|
| 136 |
+
super().__init__(code=code, reason=reason)
|
| 137 |
+
|
| 138 |
+
|
| 139 |
+
RequestErrorModel: Type[BaseModel] = create_model("Request")
|
| 140 |
+
WebSocketErrorModel: Type[BaseModel] = create_model("WebSocket")
|
| 141 |
+
|
| 142 |
+
|
| 143 |
+
class FastAPIError(RuntimeError):
|
| 144 |
+
"""
|
| 145 |
+
A generic, FastAPI-specific error.
|
| 146 |
+
"""
|
| 147 |
+
|
| 148 |
+
|
| 149 |
+
class ValidationException(Exception):
|
| 150 |
+
def __init__(self, errors: Sequence[Any]) -> None:
|
| 151 |
+
self._errors = errors
|
| 152 |
+
|
| 153 |
+
def errors(self) -> Sequence[Any]:
|
| 154 |
+
return self._errors
|
| 155 |
+
|
| 156 |
+
|
| 157 |
+
class RequestValidationError(ValidationException):
|
| 158 |
+
def __init__(self, errors: Sequence[Any], *, body: Any = None) -> None:
|
| 159 |
+
super().__init__(errors)
|
| 160 |
+
self.body = body
|
| 161 |
+
|
| 162 |
+
|
| 163 |
+
class WebSocketRequestValidationError(ValidationException):
|
| 164 |
+
pass
|
| 165 |
+
|
| 166 |
+
|
| 167 |
+
class ResponseValidationError(ValidationException):
|
| 168 |
+
def __init__(self, errors: Sequence[Any], *, body: Any = None) -> None:
|
| 169 |
+
super().__init__(errors)
|
| 170 |
+
self.body = body
|
| 171 |
+
|
| 172 |
+
def __str__(self) -> str:
|
| 173 |
+
message = f"{len(self._errors)} validation errors:\n"
|
| 174 |
+
for err in self._errors:
|
| 175 |
+
message += f" {err}\n"
|
| 176 |
+
return message
|
lib/python3.12/site-packages/fastapi/logger.py
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import logging
|
| 2 |
+
|
| 3 |
+
logger = logging.getLogger("fastapi")
|
lib/python3.12/site-packages/fastapi/openapi/__init__.py
ADDED
|
File without changes
|
lib/python3.12/site-packages/fastapi/openapi/__pycache__/__init__.cpython-312.pyc
ADDED
|
Binary file (194 Bytes). View file
|
|
|
lib/python3.12/site-packages/fastapi/openapi/__pycache__/constants.cpython-312.pyc
ADDED
|
Binary file (364 Bytes). View file
|
|
|
lib/python3.12/site-packages/fastapi/openapi/__pycache__/docs.cpython-312.pyc
ADDED
|
Binary file (10.8 kB). View file
|
|
|
lib/python3.12/site-packages/fastapi/openapi/__pycache__/models.cpython-312.pyc
ADDED
|
Binary file (23 kB). View file
|
|
|
lib/python3.12/site-packages/fastapi/openapi/__pycache__/utils.cpython-312.pyc
ADDED
|
Binary file (21.1 kB). View file
|
|
|
lib/python3.12/site-packages/fastapi/openapi/constants.py
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
METHODS_WITH_BODY = {"GET", "HEAD", "POST", "PUT", "DELETE", "PATCH"}
|
| 2 |
+
REF_PREFIX = "#/components/schemas/"
|
| 3 |
+
REF_TEMPLATE = "#/components/schemas/{model}"
|
lib/python3.12/site-packages/fastapi/openapi/docs.py
ADDED
|
@@ -0,0 +1,344 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import json
|
| 2 |
+
from typing import Any, Dict, Optional
|
| 3 |
+
|
| 4 |
+
from fastapi.encoders import jsonable_encoder
|
| 5 |
+
from starlette.responses import HTMLResponse
|
| 6 |
+
from typing_extensions import Annotated, Doc
|
| 7 |
+
|
| 8 |
+
swagger_ui_default_parameters: Annotated[
|
| 9 |
+
Dict[str, Any],
|
| 10 |
+
Doc(
|
| 11 |
+
"""
|
| 12 |
+
Default configurations for Swagger UI.
|
| 13 |
+
|
| 14 |
+
You can use it as a template to add any other configurations needed.
|
| 15 |
+
"""
|
| 16 |
+
),
|
| 17 |
+
] = {
|
| 18 |
+
"dom_id": "#swagger-ui",
|
| 19 |
+
"layout": "BaseLayout",
|
| 20 |
+
"deepLinking": True,
|
| 21 |
+
"showExtensions": True,
|
| 22 |
+
"showCommonExtensions": True,
|
| 23 |
+
}
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
def get_swagger_ui_html(
|
| 27 |
+
*,
|
| 28 |
+
openapi_url: Annotated[
|
| 29 |
+
str,
|
| 30 |
+
Doc(
|
| 31 |
+
"""
|
| 32 |
+
The OpenAPI URL that Swagger UI should load and use.
|
| 33 |
+
|
| 34 |
+
This is normally done automatically by FastAPI using the default URL
|
| 35 |
+
`/openapi.json`.
|
| 36 |
+
"""
|
| 37 |
+
),
|
| 38 |
+
],
|
| 39 |
+
title: Annotated[
|
| 40 |
+
str,
|
| 41 |
+
Doc(
|
| 42 |
+
"""
|
| 43 |
+
The HTML `<title>` content, normally shown in the browser tab.
|
| 44 |
+
"""
|
| 45 |
+
),
|
| 46 |
+
],
|
| 47 |
+
swagger_js_url: Annotated[
|
| 48 |
+
str,
|
| 49 |
+
Doc(
|
| 50 |
+
"""
|
| 51 |
+
The URL to use to load the Swagger UI JavaScript.
|
| 52 |
+
|
| 53 |
+
It is normally set to a CDN URL.
|
| 54 |
+
"""
|
| 55 |
+
),
|
| 56 |
+
] = "https://cdn.jsdelivr.net/npm/swagger-ui-dist@5/swagger-ui-bundle.js",
|
| 57 |
+
swagger_css_url: Annotated[
|
| 58 |
+
str,
|
| 59 |
+
Doc(
|
| 60 |
+
"""
|
| 61 |
+
The URL to use to load the Swagger UI CSS.
|
| 62 |
+
|
| 63 |
+
It is normally set to a CDN URL.
|
| 64 |
+
"""
|
| 65 |
+
),
|
| 66 |
+
] = "https://cdn.jsdelivr.net/npm/swagger-ui-dist@5/swagger-ui.css",
|
| 67 |
+
swagger_favicon_url: Annotated[
|
| 68 |
+
str,
|
| 69 |
+
Doc(
|
| 70 |
+
"""
|
| 71 |
+
The URL of the favicon to use. It is normally shown in the browser tab.
|
| 72 |
+
"""
|
| 73 |
+
),
|
| 74 |
+
] = "https://fastapi.tiangolo.com/img/favicon.png",
|
| 75 |
+
oauth2_redirect_url: Annotated[
|
| 76 |
+
Optional[str],
|
| 77 |
+
Doc(
|
| 78 |
+
"""
|
| 79 |
+
The OAuth2 redirect URL, it is normally automatically handled by FastAPI.
|
| 80 |
+
"""
|
| 81 |
+
),
|
| 82 |
+
] = None,
|
| 83 |
+
init_oauth: Annotated[
|
| 84 |
+
Optional[Dict[str, Any]],
|
| 85 |
+
Doc(
|
| 86 |
+
"""
|
| 87 |
+
A dictionary with Swagger UI OAuth2 initialization configurations.
|
| 88 |
+
"""
|
| 89 |
+
),
|
| 90 |
+
] = None,
|
| 91 |
+
swagger_ui_parameters: Annotated[
|
| 92 |
+
Optional[Dict[str, Any]],
|
| 93 |
+
Doc(
|
| 94 |
+
"""
|
| 95 |
+
Configuration parameters for Swagger UI.
|
| 96 |
+
|
| 97 |
+
It defaults to [swagger_ui_default_parameters][fastapi.openapi.docs.swagger_ui_default_parameters].
|
| 98 |
+
"""
|
| 99 |
+
),
|
| 100 |
+
] = None,
|
| 101 |
+
) -> HTMLResponse:
|
| 102 |
+
"""
|
| 103 |
+
Generate and return the HTML that loads Swagger UI for the interactive
|
| 104 |
+
API docs (normally served at `/docs`).
|
| 105 |
+
|
| 106 |
+
You would only call this function yourself if you needed to override some parts,
|
| 107 |
+
for example the URLs to use to load Swagger UI's JavaScript and CSS.
|
| 108 |
+
|
| 109 |
+
Read more about it in the
|
| 110 |
+
[FastAPI docs for Configure Swagger UI](https://fastapi.tiangolo.com/how-to/configure-swagger-ui/)
|
| 111 |
+
and the [FastAPI docs for Custom Docs UI Static Assets (Self-Hosting)](https://fastapi.tiangolo.com/how-to/custom-docs-ui-assets/).
|
| 112 |
+
"""
|
| 113 |
+
current_swagger_ui_parameters = swagger_ui_default_parameters.copy()
|
| 114 |
+
if swagger_ui_parameters:
|
| 115 |
+
current_swagger_ui_parameters.update(swagger_ui_parameters)
|
| 116 |
+
|
| 117 |
+
html = f"""
|
| 118 |
+
<!DOCTYPE html>
|
| 119 |
+
<html>
|
| 120 |
+
<head>
|
| 121 |
+
<link type="text/css" rel="stylesheet" href="{swagger_css_url}">
|
| 122 |
+
<link rel="shortcut icon" href="{swagger_favicon_url}">
|
| 123 |
+
<title>{title}</title>
|
| 124 |
+
</head>
|
| 125 |
+
<body>
|
| 126 |
+
<div id="swagger-ui">
|
| 127 |
+
</div>
|
| 128 |
+
<script src="{swagger_js_url}"></script>
|
| 129 |
+
<!-- `SwaggerUIBundle` is now available on the page -->
|
| 130 |
+
<script>
|
| 131 |
+
const ui = SwaggerUIBundle({{
|
| 132 |
+
url: '{openapi_url}',
|
| 133 |
+
"""
|
| 134 |
+
|
| 135 |
+
for key, value in current_swagger_ui_parameters.items():
|
| 136 |
+
html += f"{json.dumps(key)}: {json.dumps(jsonable_encoder(value))},\n"
|
| 137 |
+
|
| 138 |
+
if oauth2_redirect_url:
|
| 139 |
+
html += f"oauth2RedirectUrl: window.location.origin + '{oauth2_redirect_url}',"
|
| 140 |
+
|
| 141 |
+
html += """
|
| 142 |
+
presets: [
|
| 143 |
+
SwaggerUIBundle.presets.apis,
|
| 144 |
+
SwaggerUIBundle.SwaggerUIStandalonePreset
|
| 145 |
+
],
|
| 146 |
+
})"""
|
| 147 |
+
|
| 148 |
+
if init_oauth:
|
| 149 |
+
html += f"""
|
| 150 |
+
ui.initOAuth({json.dumps(jsonable_encoder(init_oauth))})
|
| 151 |
+
"""
|
| 152 |
+
|
| 153 |
+
html += """
|
| 154 |
+
</script>
|
| 155 |
+
</body>
|
| 156 |
+
</html>
|
| 157 |
+
"""
|
| 158 |
+
return HTMLResponse(html)
|
| 159 |
+
|
| 160 |
+
|
| 161 |
+
def get_redoc_html(
|
| 162 |
+
*,
|
| 163 |
+
openapi_url: Annotated[
|
| 164 |
+
str,
|
| 165 |
+
Doc(
|
| 166 |
+
"""
|
| 167 |
+
The OpenAPI URL that ReDoc should load and use.
|
| 168 |
+
|
| 169 |
+
This is normally done automatically by FastAPI using the default URL
|
| 170 |
+
`/openapi.json`.
|
| 171 |
+
"""
|
| 172 |
+
),
|
| 173 |
+
],
|
| 174 |
+
title: Annotated[
|
| 175 |
+
str,
|
| 176 |
+
Doc(
|
| 177 |
+
"""
|
| 178 |
+
The HTML `<title>` content, normally shown in the browser tab.
|
| 179 |
+
"""
|
| 180 |
+
),
|
| 181 |
+
],
|
| 182 |
+
redoc_js_url: Annotated[
|
| 183 |
+
str,
|
| 184 |
+
Doc(
|
| 185 |
+
"""
|
| 186 |
+
The URL to use to load the ReDoc JavaScript.
|
| 187 |
+
|
| 188 |
+
It is normally set to a CDN URL.
|
| 189 |
+
"""
|
| 190 |
+
),
|
| 191 |
+
] = "https://cdn.jsdelivr.net/npm/redoc@next/bundles/redoc.standalone.js",
|
| 192 |
+
redoc_favicon_url: Annotated[
|
| 193 |
+
str,
|
| 194 |
+
Doc(
|
| 195 |
+
"""
|
| 196 |
+
The URL of the favicon to use. It is normally shown in the browser tab.
|
| 197 |
+
"""
|
| 198 |
+
),
|
| 199 |
+
] = "https://fastapi.tiangolo.com/img/favicon.png",
|
| 200 |
+
with_google_fonts: Annotated[
|
| 201 |
+
bool,
|
| 202 |
+
Doc(
|
| 203 |
+
"""
|
| 204 |
+
Load and use Google Fonts.
|
| 205 |
+
"""
|
| 206 |
+
),
|
| 207 |
+
] = True,
|
| 208 |
+
) -> HTMLResponse:
|
| 209 |
+
"""
|
| 210 |
+
Generate and return the HTML response that loads ReDoc for the alternative
|
| 211 |
+
API docs (normally served at `/redoc`).
|
| 212 |
+
|
| 213 |
+
You would only call this function yourself if you needed to override some parts,
|
| 214 |
+
for example the URLs to use to load ReDoc's JavaScript and CSS.
|
| 215 |
+
|
| 216 |
+
Read more about it in the
|
| 217 |
+
[FastAPI docs for Custom Docs UI Static Assets (Self-Hosting)](https://fastapi.tiangolo.com/how-to/custom-docs-ui-assets/).
|
| 218 |
+
"""
|
| 219 |
+
html = f"""
|
| 220 |
+
<!DOCTYPE html>
|
| 221 |
+
<html>
|
| 222 |
+
<head>
|
| 223 |
+
<title>{title}</title>
|
| 224 |
+
<!-- needed for adaptive design -->
|
| 225 |
+
<meta charset="utf-8"/>
|
| 226 |
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
| 227 |
+
"""
|
| 228 |
+
if with_google_fonts:
|
| 229 |
+
html += """
|
| 230 |
+
<link href="https://fonts.googleapis.com/css?family=Montserrat:300,400,700|Roboto:300,400,700" rel="stylesheet">
|
| 231 |
+
"""
|
| 232 |
+
html += f"""
|
| 233 |
+
<link rel="shortcut icon" href="{redoc_favicon_url}">
|
| 234 |
+
<!--
|
| 235 |
+
ReDoc doesn't change outer page styles
|
| 236 |
+
-->
|
| 237 |
+
<style>
|
| 238 |
+
body {{
|
| 239 |
+
margin: 0;
|
| 240 |
+
padding: 0;
|
| 241 |
+
}}
|
| 242 |
+
</style>
|
| 243 |
+
</head>
|
| 244 |
+
<body>
|
| 245 |
+
<noscript>
|
| 246 |
+
ReDoc requires Javascript to function. Please enable it to browse the documentation.
|
| 247 |
+
</noscript>
|
| 248 |
+
<redoc spec-url="{openapi_url}"></redoc>
|
| 249 |
+
<script src="{redoc_js_url}"> </script>
|
| 250 |
+
</body>
|
| 251 |
+
</html>
|
| 252 |
+
"""
|
| 253 |
+
return HTMLResponse(html)
|
| 254 |
+
|
| 255 |
+
|
| 256 |
+
def get_swagger_ui_oauth2_redirect_html() -> HTMLResponse:
|
| 257 |
+
"""
|
| 258 |
+
Generate the HTML response with the OAuth2 redirection for Swagger UI.
|
| 259 |
+
|
| 260 |
+
You normally don't need to use or change this.
|
| 261 |
+
"""
|
| 262 |
+
# copied from https://github.com/swagger-api/swagger-ui/blob/v4.14.0/dist/oauth2-redirect.html
|
| 263 |
+
html = """
|
| 264 |
+
<!doctype html>
|
| 265 |
+
<html lang="en-US">
|
| 266 |
+
<head>
|
| 267 |
+
<title>Swagger UI: OAuth2 Redirect</title>
|
| 268 |
+
</head>
|
| 269 |
+
<body>
|
| 270 |
+
<script>
|
| 271 |
+
'use strict';
|
| 272 |
+
function run () {
|
| 273 |
+
var oauth2 = window.opener.swaggerUIRedirectOauth2;
|
| 274 |
+
var sentState = oauth2.state;
|
| 275 |
+
var redirectUrl = oauth2.redirectUrl;
|
| 276 |
+
var isValid, qp, arr;
|
| 277 |
+
|
| 278 |
+
if (/code|token|error/.test(window.location.hash)) {
|
| 279 |
+
qp = window.location.hash.substring(1).replace('?', '&');
|
| 280 |
+
} else {
|
| 281 |
+
qp = location.search.substring(1);
|
| 282 |
+
}
|
| 283 |
+
|
| 284 |
+
arr = qp.split("&");
|
| 285 |
+
arr.forEach(function (v,i,_arr) { _arr[i] = '"' + v.replace('=', '":"') + '"';});
|
| 286 |
+
qp = qp ? JSON.parse('{' + arr.join() + '}',
|
| 287 |
+
function (key, value) {
|
| 288 |
+
return key === "" ? value : decodeURIComponent(value);
|
| 289 |
+
}
|
| 290 |
+
) : {};
|
| 291 |
+
|
| 292 |
+
isValid = qp.state === sentState;
|
| 293 |
+
|
| 294 |
+
if ((
|
| 295 |
+
oauth2.auth.schema.get("flow") === "accessCode" ||
|
| 296 |
+
oauth2.auth.schema.get("flow") === "authorizationCode" ||
|
| 297 |
+
oauth2.auth.schema.get("flow") === "authorization_code"
|
| 298 |
+
) && !oauth2.auth.code) {
|
| 299 |
+
if (!isValid) {
|
| 300 |
+
oauth2.errCb({
|
| 301 |
+
authId: oauth2.auth.name,
|
| 302 |
+
source: "auth",
|
| 303 |
+
level: "warning",
|
| 304 |
+
message: "Authorization may be unsafe, passed state was changed in server. The passed state wasn't returned from auth server."
|
| 305 |
+
});
|
| 306 |
+
}
|
| 307 |
+
|
| 308 |
+
if (qp.code) {
|
| 309 |
+
delete oauth2.state;
|
| 310 |
+
oauth2.auth.code = qp.code;
|
| 311 |
+
oauth2.callback({auth: oauth2.auth, redirectUrl: redirectUrl});
|
| 312 |
+
} else {
|
| 313 |
+
let oauthErrorMsg;
|
| 314 |
+
if (qp.error) {
|
| 315 |
+
oauthErrorMsg = "["+qp.error+"]: " +
|
| 316 |
+
(qp.error_description ? qp.error_description+ ". " : "no accessCode received from the server. ") +
|
| 317 |
+
(qp.error_uri ? "More info: "+qp.error_uri : "");
|
| 318 |
+
}
|
| 319 |
+
|
| 320 |
+
oauth2.errCb({
|
| 321 |
+
authId: oauth2.auth.name,
|
| 322 |
+
source: "auth",
|
| 323 |
+
level: "error",
|
| 324 |
+
message: oauthErrorMsg || "[Authorization failed]: no accessCode received from the server."
|
| 325 |
+
});
|
| 326 |
+
}
|
| 327 |
+
} else {
|
| 328 |
+
oauth2.callback({auth: oauth2.auth, token: qp, isValid: isValid, redirectUrl: redirectUrl});
|
| 329 |
+
}
|
| 330 |
+
window.close();
|
| 331 |
+
}
|
| 332 |
+
|
| 333 |
+
if (document.readyState !== 'loading') {
|
| 334 |
+
run();
|
| 335 |
+
} else {
|
| 336 |
+
document.addEventListener('DOMContentLoaded', function () {
|
| 337 |
+
run();
|
| 338 |
+
});
|
| 339 |
+
}
|
| 340 |
+
</script>
|
| 341 |
+
</body>
|
| 342 |
+
</html>
|
| 343 |
+
"""
|
| 344 |
+
return HTMLResponse(content=html)
|
lib/python3.12/site-packages/fastapi/openapi/models.py
ADDED
|
@@ -0,0 +1,445 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from enum import Enum
|
| 2 |
+
from typing import Any, Callable, Dict, Iterable, List, Optional, Set, Type, Union
|
| 3 |
+
|
| 4 |
+
from fastapi._compat import (
|
| 5 |
+
PYDANTIC_V2,
|
| 6 |
+
CoreSchema,
|
| 7 |
+
GetJsonSchemaHandler,
|
| 8 |
+
JsonSchemaValue,
|
| 9 |
+
_model_rebuild,
|
| 10 |
+
with_info_plain_validator_function,
|
| 11 |
+
)
|
| 12 |
+
from fastapi.logger import logger
|
| 13 |
+
from pydantic import AnyUrl, BaseModel, Field
|
| 14 |
+
from typing_extensions import Annotated, Literal, TypedDict
|
| 15 |
+
from typing_extensions import deprecated as typing_deprecated
|
| 16 |
+
|
| 17 |
+
try:
|
| 18 |
+
import email_validator
|
| 19 |
+
|
| 20 |
+
assert email_validator # make autoflake ignore the unused import
|
| 21 |
+
from pydantic import EmailStr
|
| 22 |
+
except ImportError: # pragma: no cover
|
| 23 |
+
|
| 24 |
+
class EmailStr(str): # type: ignore
|
| 25 |
+
@classmethod
|
| 26 |
+
def __get_validators__(cls) -> Iterable[Callable[..., Any]]:
|
| 27 |
+
yield cls.validate
|
| 28 |
+
|
| 29 |
+
@classmethod
|
| 30 |
+
def validate(cls, v: Any) -> str:
|
| 31 |
+
logger.warning(
|
| 32 |
+
"email-validator not installed, email fields will be treated as str.\n"
|
| 33 |
+
"To install, run: pip install email-validator"
|
| 34 |
+
)
|
| 35 |
+
return str(v)
|
| 36 |
+
|
| 37 |
+
@classmethod
|
| 38 |
+
def _validate(cls, __input_value: Any, _: Any) -> str:
|
| 39 |
+
logger.warning(
|
| 40 |
+
"email-validator not installed, email fields will be treated as str.\n"
|
| 41 |
+
"To install, run: pip install email-validator"
|
| 42 |
+
)
|
| 43 |
+
return str(__input_value)
|
| 44 |
+
|
| 45 |
+
@classmethod
|
| 46 |
+
def __get_pydantic_json_schema__(
|
| 47 |
+
cls, core_schema: CoreSchema, handler: GetJsonSchemaHandler
|
| 48 |
+
) -> JsonSchemaValue:
|
| 49 |
+
return {"type": "string", "format": "email"}
|
| 50 |
+
|
| 51 |
+
@classmethod
|
| 52 |
+
def __get_pydantic_core_schema__(
|
| 53 |
+
cls, source: Type[Any], handler: Callable[[Any], CoreSchema]
|
| 54 |
+
) -> CoreSchema:
|
| 55 |
+
return with_info_plain_validator_function(cls._validate)
|
| 56 |
+
|
| 57 |
+
|
| 58 |
+
class BaseModelWithConfig(BaseModel):
|
| 59 |
+
if PYDANTIC_V2:
|
| 60 |
+
model_config = {"extra": "allow"}
|
| 61 |
+
|
| 62 |
+
else:
|
| 63 |
+
|
| 64 |
+
class Config:
|
| 65 |
+
extra = "allow"
|
| 66 |
+
|
| 67 |
+
|
| 68 |
+
class Contact(BaseModelWithConfig):
|
| 69 |
+
name: Optional[str] = None
|
| 70 |
+
url: Optional[AnyUrl] = None
|
| 71 |
+
email: Optional[EmailStr] = None
|
| 72 |
+
|
| 73 |
+
|
| 74 |
+
class License(BaseModelWithConfig):
|
| 75 |
+
name: str
|
| 76 |
+
identifier: Optional[str] = None
|
| 77 |
+
url: Optional[AnyUrl] = None
|
| 78 |
+
|
| 79 |
+
|
| 80 |
+
class Info(BaseModelWithConfig):
|
| 81 |
+
title: str
|
| 82 |
+
summary: Optional[str] = None
|
| 83 |
+
description: Optional[str] = None
|
| 84 |
+
termsOfService: Optional[str] = None
|
| 85 |
+
contact: Optional[Contact] = None
|
| 86 |
+
license: Optional[License] = None
|
| 87 |
+
version: str
|
| 88 |
+
|
| 89 |
+
|
| 90 |
+
class ServerVariable(BaseModelWithConfig):
|
| 91 |
+
enum: Annotated[Optional[List[str]], Field(min_length=1)] = None
|
| 92 |
+
default: str
|
| 93 |
+
description: Optional[str] = None
|
| 94 |
+
|
| 95 |
+
|
| 96 |
+
class Server(BaseModelWithConfig):
|
| 97 |
+
url: Union[AnyUrl, str]
|
| 98 |
+
description: Optional[str] = None
|
| 99 |
+
variables: Optional[Dict[str, ServerVariable]] = None
|
| 100 |
+
|
| 101 |
+
|
| 102 |
+
class Reference(BaseModel):
|
| 103 |
+
ref: str = Field(alias="$ref")
|
| 104 |
+
|
| 105 |
+
|
| 106 |
+
class Discriminator(BaseModel):
|
| 107 |
+
propertyName: str
|
| 108 |
+
mapping: Optional[Dict[str, str]] = None
|
| 109 |
+
|
| 110 |
+
|
| 111 |
+
class XML(BaseModelWithConfig):
|
| 112 |
+
name: Optional[str] = None
|
| 113 |
+
namespace: Optional[str] = None
|
| 114 |
+
prefix: Optional[str] = None
|
| 115 |
+
attribute: Optional[bool] = None
|
| 116 |
+
wrapped: Optional[bool] = None
|
| 117 |
+
|
| 118 |
+
|
| 119 |
+
class ExternalDocumentation(BaseModelWithConfig):
|
| 120 |
+
description: Optional[str] = None
|
| 121 |
+
url: AnyUrl
|
| 122 |
+
|
| 123 |
+
|
| 124 |
+
class Schema(BaseModelWithConfig):
|
| 125 |
+
# Ref: JSON Schema 2020-12: https://json-schema.org/draft/2020-12/json-schema-core.html#name-the-json-schema-core-vocabu
|
| 126 |
+
# Core Vocabulary
|
| 127 |
+
schema_: Optional[str] = Field(default=None, alias="$schema")
|
| 128 |
+
vocabulary: Optional[str] = Field(default=None, alias="$vocabulary")
|
| 129 |
+
id: Optional[str] = Field(default=None, alias="$id")
|
| 130 |
+
anchor: Optional[str] = Field(default=None, alias="$anchor")
|
| 131 |
+
dynamicAnchor: Optional[str] = Field(default=None, alias="$dynamicAnchor")
|
| 132 |
+
ref: Optional[str] = Field(default=None, alias="$ref")
|
| 133 |
+
dynamicRef: Optional[str] = Field(default=None, alias="$dynamicRef")
|
| 134 |
+
defs: Optional[Dict[str, "SchemaOrBool"]] = Field(default=None, alias="$defs")
|
| 135 |
+
comment: Optional[str] = Field(default=None, alias="$comment")
|
| 136 |
+
# Ref: JSON Schema 2020-12: https://json-schema.org/draft/2020-12/json-schema-core.html#name-a-vocabulary-for-applying-s
|
| 137 |
+
# A Vocabulary for Applying Subschemas
|
| 138 |
+
allOf: Optional[List["SchemaOrBool"]] = None
|
| 139 |
+
anyOf: Optional[List["SchemaOrBool"]] = None
|
| 140 |
+
oneOf: Optional[List["SchemaOrBool"]] = None
|
| 141 |
+
not_: Optional["SchemaOrBool"] = Field(default=None, alias="not")
|
| 142 |
+
if_: Optional["SchemaOrBool"] = Field(default=None, alias="if")
|
| 143 |
+
then: Optional["SchemaOrBool"] = None
|
| 144 |
+
else_: Optional["SchemaOrBool"] = Field(default=None, alias="else")
|
| 145 |
+
dependentSchemas: Optional[Dict[str, "SchemaOrBool"]] = None
|
| 146 |
+
prefixItems: Optional[List["SchemaOrBool"]] = None
|
| 147 |
+
# TODO: uncomment and remove below when deprecating Pydantic v1
|
| 148 |
+
# It generales a list of schemas for tuples, before prefixItems was available
|
| 149 |
+
# items: Optional["SchemaOrBool"] = None
|
| 150 |
+
items: Optional[Union["SchemaOrBool", List["SchemaOrBool"]]] = None
|
| 151 |
+
contains: Optional["SchemaOrBool"] = None
|
| 152 |
+
properties: Optional[Dict[str, "SchemaOrBool"]] = None
|
| 153 |
+
patternProperties: Optional[Dict[str, "SchemaOrBool"]] = None
|
| 154 |
+
additionalProperties: Optional["SchemaOrBool"] = None
|
| 155 |
+
propertyNames: Optional["SchemaOrBool"] = None
|
| 156 |
+
unevaluatedItems: Optional["SchemaOrBool"] = None
|
| 157 |
+
unevaluatedProperties: Optional["SchemaOrBool"] = None
|
| 158 |
+
# Ref: JSON Schema Validation 2020-12: https://json-schema.org/draft/2020-12/json-schema-validation.html#name-a-vocabulary-for-structural
|
| 159 |
+
# A Vocabulary for Structural Validation
|
| 160 |
+
type: Optional[str] = None
|
| 161 |
+
enum: Optional[List[Any]] = None
|
| 162 |
+
const: Optional[Any] = None
|
| 163 |
+
multipleOf: Optional[float] = Field(default=None, gt=0)
|
| 164 |
+
maximum: Optional[float] = None
|
| 165 |
+
exclusiveMaximum: Optional[float] = None
|
| 166 |
+
minimum: Optional[float] = None
|
| 167 |
+
exclusiveMinimum: Optional[float] = None
|
| 168 |
+
maxLength: Optional[int] = Field(default=None, ge=0)
|
| 169 |
+
minLength: Optional[int] = Field(default=None, ge=0)
|
| 170 |
+
pattern: Optional[str] = None
|
| 171 |
+
maxItems: Optional[int] = Field(default=None, ge=0)
|
| 172 |
+
minItems: Optional[int] = Field(default=None, ge=0)
|
| 173 |
+
uniqueItems: Optional[bool] = None
|
| 174 |
+
maxContains: Optional[int] = Field(default=None, ge=0)
|
| 175 |
+
minContains: Optional[int] = Field(default=None, ge=0)
|
| 176 |
+
maxProperties: Optional[int] = Field(default=None, ge=0)
|
| 177 |
+
minProperties: Optional[int] = Field(default=None, ge=0)
|
| 178 |
+
required: Optional[List[str]] = None
|
| 179 |
+
dependentRequired: Optional[Dict[str, Set[str]]] = None
|
| 180 |
+
# Ref: JSON Schema Validation 2020-12: https://json-schema.org/draft/2020-12/json-schema-validation.html#name-vocabularies-for-semantic-c
|
| 181 |
+
# Vocabularies for Semantic Content With "format"
|
| 182 |
+
format: Optional[str] = None
|
| 183 |
+
# Ref: JSON Schema Validation 2020-12: https://json-schema.org/draft/2020-12/json-schema-validation.html#name-a-vocabulary-for-the-conten
|
| 184 |
+
# A Vocabulary for the Contents of String-Encoded Data
|
| 185 |
+
contentEncoding: Optional[str] = None
|
| 186 |
+
contentMediaType: Optional[str] = None
|
| 187 |
+
contentSchema: Optional["SchemaOrBool"] = None
|
| 188 |
+
# Ref: JSON Schema Validation 2020-12: https://json-schema.org/draft/2020-12/json-schema-validation.html#name-a-vocabulary-for-basic-meta
|
| 189 |
+
# A Vocabulary for Basic Meta-Data Annotations
|
| 190 |
+
title: Optional[str] = None
|
| 191 |
+
description: Optional[str] = None
|
| 192 |
+
default: Optional[Any] = None
|
| 193 |
+
deprecated: Optional[bool] = None
|
| 194 |
+
readOnly: Optional[bool] = None
|
| 195 |
+
writeOnly: Optional[bool] = None
|
| 196 |
+
examples: Optional[List[Any]] = None
|
| 197 |
+
# Ref: OpenAPI 3.1.0: https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#schema-object
|
| 198 |
+
# Schema Object
|
| 199 |
+
discriminator: Optional[Discriminator] = None
|
| 200 |
+
xml: Optional[XML] = None
|
| 201 |
+
externalDocs: Optional[ExternalDocumentation] = None
|
| 202 |
+
example: Annotated[
|
| 203 |
+
Optional[Any],
|
| 204 |
+
typing_deprecated(
|
| 205 |
+
"Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, "
|
| 206 |
+
"although still supported. Use examples instead."
|
| 207 |
+
),
|
| 208 |
+
] = None
|
| 209 |
+
|
| 210 |
+
|
| 211 |
+
# Ref: https://json-schema.org/draft/2020-12/json-schema-core.html#name-json-schema-documents
|
| 212 |
+
# A JSON Schema MUST be an object or a boolean.
|
| 213 |
+
SchemaOrBool = Union[Schema, bool]
|
| 214 |
+
|
| 215 |
+
|
| 216 |
+
class Example(TypedDict, total=False):
|
| 217 |
+
summary: Optional[str]
|
| 218 |
+
description: Optional[str]
|
| 219 |
+
value: Optional[Any]
|
| 220 |
+
externalValue: Optional[AnyUrl]
|
| 221 |
+
|
| 222 |
+
if PYDANTIC_V2: # type: ignore [misc]
|
| 223 |
+
__pydantic_config__ = {"extra": "allow"}
|
| 224 |
+
|
| 225 |
+
else:
|
| 226 |
+
|
| 227 |
+
class Config:
|
| 228 |
+
extra = "allow"
|
| 229 |
+
|
| 230 |
+
|
| 231 |
+
class ParameterInType(Enum):
|
| 232 |
+
query = "query"
|
| 233 |
+
header = "header"
|
| 234 |
+
path = "path"
|
| 235 |
+
cookie = "cookie"
|
| 236 |
+
|
| 237 |
+
|
| 238 |
+
class Encoding(BaseModelWithConfig):
|
| 239 |
+
contentType: Optional[str] = None
|
| 240 |
+
headers: Optional[Dict[str, Union["Header", Reference]]] = None
|
| 241 |
+
style: Optional[str] = None
|
| 242 |
+
explode: Optional[bool] = None
|
| 243 |
+
allowReserved: Optional[bool] = None
|
| 244 |
+
|
| 245 |
+
|
| 246 |
+
class MediaType(BaseModelWithConfig):
|
| 247 |
+
schema_: Optional[Union[Schema, Reference]] = Field(default=None, alias="schema")
|
| 248 |
+
example: Optional[Any] = None
|
| 249 |
+
examples: Optional[Dict[str, Union[Example, Reference]]] = None
|
| 250 |
+
encoding: Optional[Dict[str, Encoding]] = None
|
| 251 |
+
|
| 252 |
+
|
| 253 |
+
class ParameterBase(BaseModelWithConfig):
|
| 254 |
+
description: Optional[str] = None
|
| 255 |
+
required: Optional[bool] = None
|
| 256 |
+
deprecated: Optional[bool] = None
|
| 257 |
+
# Serialization rules for simple scenarios
|
| 258 |
+
style: Optional[str] = None
|
| 259 |
+
explode: Optional[bool] = None
|
| 260 |
+
allowReserved: Optional[bool] = None
|
| 261 |
+
schema_: Optional[Union[Schema, Reference]] = Field(default=None, alias="schema")
|
| 262 |
+
example: Optional[Any] = None
|
| 263 |
+
examples: Optional[Dict[str, Union[Example, Reference]]] = None
|
| 264 |
+
# Serialization rules for more complex scenarios
|
| 265 |
+
content: Optional[Dict[str, MediaType]] = None
|
| 266 |
+
|
| 267 |
+
|
| 268 |
+
class Parameter(ParameterBase):
|
| 269 |
+
name: str
|
| 270 |
+
in_: ParameterInType = Field(alias="in")
|
| 271 |
+
|
| 272 |
+
|
| 273 |
+
class Header(ParameterBase):
|
| 274 |
+
pass
|
| 275 |
+
|
| 276 |
+
|
| 277 |
+
class RequestBody(BaseModelWithConfig):
|
| 278 |
+
description: Optional[str] = None
|
| 279 |
+
content: Dict[str, MediaType]
|
| 280 |
+
required: Optional[bool] = None
|
| 281 |
+
|
| 282 |
+
|
| 283 |
+
class Link(BaseModelWithConfig):
|
| 284 |
+
operationRef: Optional[str] = None
|
| 285 |
+
operationId: Optional[str] = None
|
| 286 |
+
parameters: Optional[Dict[str, Union[Any, str]]] = None
|
| 287 |
+
requestBody: Optional[Union[Any, str]] = None
|
| 288 |
+
description: Optional[str] = None
|
| 289 |
+
server: Optional[Server] = None
|
| 290 |
+
|
| 291 |
+
|
| 292 |
+
class Response(BaseModelWithConfig):
|
| 293 |
+
description: str
|
| 294 |
+
headers: Optional[Dict[str, Union[Header, Reference]]] = None
|
| 295 |
+
content: Optional[Dict[str, MediaType]] = None
|
| 296 |
+
links: Optional[Dict[str, Union[Link, Reference]]] = None
|
| 297 |
+
|
| 298 |
+
|
| 299 |
+
class Operation(BaseModelWithConfig):
|
| 300 |
+
tags: Optional[List[str]] = None
|
| 301 |
+
summary: Optional[str] = None
|
| 302 |
+
description: Optional[str] = None
|
| 303 |
+
externalDocs: Optional[ExternalDocumentation] = None
|
| 304 |
+
operationId: Optional[str] = None
|
| 305 |
+
parameters: Optional[List[Union[Parameter, Reference]]] = None
|
| 306 |
+
requestBody: Optional[Union[RequestBody, Reference]] = None
|
| 307 |
+
# Using Any for Specification Extensions
|
| 308 |
+
responses: Optional[Dict[str, Union[Response, Any]]] = None
|
| 309 |
+
callbacks: Optional[Dict[str, Union[Dict[str, "PathItem"], Reference]]] = None
|
| 310 |
+
deprecated: Optional[bool] = None
|
| 311 |
+
security: Optional[List[Dict[str, List[str]]]] = None
|
| 312 |
+
servers: Optional[List[Server]] = None
|
| 313 |
+
|
| 314 |
+
|
| 315 |
+
class PathItem(BaseModelWithConfig):
|
| 316 |
+
ref: Optional[str] = Field(default=None, alias="$ref")
|
| 317 |
+
summary: Optional[str] = None
|
| 318 |
+
description: Optional[str] = None
|
| 319 |
+
get: Optional[Operation] = None
|
| 320 |
+
put: Optional[Operation] = None
|
| 321 |
+
post: Optional[Operation] = None
|
| 322 |
+
delete: Optional[Operation] = None
|
| 323 |
+
options: Optional[Operation] = None
|
| 324 |
+
head: Optional[Operation] = None
|
| 325 |
+
patch: Optional[Operation] = None
|
| 326 |
+
trace: Optional[Operation] = None
|
| 327 |
+
servers: Optional[List[Server]] = None
|
| 328 |
+
parameters: Optional[List[Union[Parameter, Reference]]] = None
|
| 329 |
+
|
| 330 |
+
|
| 331 |
+
class SecuritySchemeType(Enum):
|
| 332 |
+
apiKey = "apiKey"
|
| 333 |
+
http = "http"
|
| 334 |
+
oauth2 = "oauth2"
|
| 335 |
+
openIdConnect = "openIdConnect"
|
| 336 |
+
|
| 337 |
+
|
| 338 |
+
class SecurityBase(BaseModelWithConfig):
|
| 339 |
+
type_: SecuritySchemeType = Field(alias="type")
|
| 340 |
+
description: Optional[str] = None
|
| 341 |
+
|
| 342 |
+
|
| 343 |
+
class APIKeyIn(Enum):
|
| 344 |
+
query = "query"
|
| 345 |
+
header = "header"
|
| 346 |
+
cookie = "cookie"
|
| 347 |
+
|
| 348 |
+
|
| 349 |
+
class APIKey(SecurityBase):
|
| 350 |
+
type_: SecuritySchemeType = Field(default=SecuritySchemeType.apiKey, alias="type")
|
| 351 |
+
in_: APIKeyIn = Field(alias="in")
|
| 352 |
+
name: str
|
| 353 |
+
|
| 354 |
+
|
| 355 |
+
class HTTPBase(SecurityBase):
|
| 356 |
+
type_: SecuritySchemeType = Field(default=SecuritySchemeType.http, alias="type")
|
| 357 |
+
scheme: str
|
| 358 |
+
|
| 359 |
+
|
| 360 |
+
class HTTPBearer(HTTPBase):
|
| 361 |
+
scheme: Literal["bearer"] = "bearer"
|
| 362 |
+
bearerFormat: Optional[str] = None
|
| 363 |
+
|
| 364 |
+
|
| 365 |
+
class OAuthFlow(BaseModelWithConfig):
|
| 366 |
+
refreshUrl: Optional[str] = None
|
| 367 |
+
scopes: Dict[str, str] = {}
|
| 368 |
+
|
| 369 |
+
|
| 370 |
+
class OAuthFlowImplicit(OAuthFlow):
|
| 371 |
+
authorizationUrl: str
|
| 372 |
+
|
| 373 |
+
|
| 374 |
+
class OAuthFlowPassword(OAuthFlow):
|
| 375 |
+
tokenUrl: str
|
| 376 |
+
|
| 377 |
+
|
| 378 |
+
class OAuthFlowClientCredentials(OAuthFlow):
|
| 379 |
+
tokenUrl: str
|
| 380 |
+
|
| 381 |
+
|
| 382 |
+
class OAuthFlowAuthorizationCode(OAuthFlow):
|
| 383 |
+
authorizationUrl: str
|
| 384 |
+
tokenUrl: str
|
| 385 |
+
|
| 386 |
+
|
| 387 |
+
class OAuthFlows(BaseModelWithConfig):
|
| 388 |
+
implicit: Optional[OAuthFlowImplicit] = None
|
| 389 |
+
password: Optional[OAuthFlowPassword] = None
|
| 390 |
+
clientCredentials: Optional[OAuthFlowClientCredentials] = None
|
| 391 |
+
authorizationCode: Optional[OAuthFlowAuthorizationCode] = None
|
| 392 |
+
|
| 393 |
+
|
| 394 |
+
class OAuth2(SecurityBase):
|
| 395 |
+
type_: SecuritySchemeType = Field(default=SecuritySchemeType.oauth2, alias="type")
|
| 396 |
+
flows: OAuthFlows
|
| 397 |
+
|
| 398 |
+
|
| 399 |
+
class OpenIdConnect(SecurityBase):
|
| 400 |
+
type_: SecuritySchemeType = Field(
|
| 401 |
+
default=SecuritySchemeType.openIdConnect, alias="type"
|
| 402 |
+
)
|
| 403 |
+
openIdConnectUrl: str
|
| 404 |
+
|
| 405 |
+
|
| 406 |
+
SecurityScheme = Union[APIKey, HTTPBase, OAuth2, OpenIdConnect, HTTPBearer]
|
| 407 |
+
|
| 408 |
+
|
| 409 |
+
class Components(BaseModelWithConfig):
|
| 410 |
+
schemas: Optional[Dict[str, Union[Schema, Reference]]] = None
|
| 411 |
+
responses: Optional[Dict[str, Union[Response, Reference]]] = None
|
| 412 |
+
parameters: Optional[Dict[str, Union[Parameter, Reference]]] = None
|
| 413 |
+
examples: Optional[Dict[str, Union[Example, Reference]]] = None
|
| 414 |
+
requestBodies: Optional[Dict[str, Union[RequestBody, Reference]]] = None
|
| 415 |
+
headers: Optional[Dict[str, Union[Header, Reference]]] = None
|
| 416 |
+
securitySchemes: Optional[Dict[str, Union[SecurityScheme, Reference]]] = None
|
| 417 |
+
links: Optional[Dict[str, Union[Link, Reference]]] = None
|
| 418 |
+
# Using Any for Specification Extensions
|
| 419 |
+
callbacks: Optional[Dict[str, Union[Dict[str, PathItem], Reference, Any]]] = None
|
| 420 |
+
pathItems: Optional[Dict[str, Union[PathItem, Reference]]] = None
|
| 421 |
+
|
| 422 |
+
|
| 423 |
+
class Tag(BaseModelWithConfig):
|
| 424 |
+
name: str
|
| 425 |
+
description: Optional[str] = None
|
| 426 |
+
externalDocs: Optional[ExternalDocumentation] = None
|
| 427 |
+
|
| 428 |
+
|
| 429 |
+
class OpenAPI(BaseModelWithConfig):
|
| 430 |
+
openapi: str
|
| 431 |
+
info: Info
|
| 432 |
+
jsonSchemaDialect: Optional[str] = None
|
| 433 |
+
servers: Optional[List[Server]] = None
|
| 434 |
+
# Using Any for Specification Extensions
|
| 435 |
+
paths: Optional[Dict[str, Union[PathItem, Any]]] = None
|
| 436 |
+
webhooks: Optional[Dict[str, Union[PathItem, Reference]]] = None
|
| 437 |
+
components: Optional[Components] = None
|
| 438 |
+
security: Optional[List[Dict[str, List[str]]]] = None
|
| 439 |
+
tags: Optional[List[Tag]] = None
|
| 440 |
+
externalDocs: Optional[ExternalDocumentation] = None
|
| 441 |
+
|
| 442 |
+
|
| 443 |
+
_model_rebuild(Schema)
|
| 444 |
+
_model_rebuild(Operation)
|
| 445 |
+
_model_rebuild(Encoding)
|
lib/python3.12/site-packages/fastapi/openapi/utils.py
ADDED
|
@@ -0,0 +1,569 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import http.client
|
| 2 |
+
import inspect
|
| 3 |
+
import warnings
|
| 4 |
+
from typing import Any, Dict, List, Optional, Sequence, Set, Tuple, Type, Union, cast
|
| 5 |
+
|
| 6 |
+
from fastapi import routing
|
| 7 |
+
from fastapi._compat import (
|
| 8 |
+
GenerateJsonSchema,
|
| 9 |
+
JsonSchemaValue,
|
| 10 |
+
ModelField,
|
| 11 |
+
Undefined,
|
| 12 |
+
get_compat_model_name_map,
|
| 13 |
+
get_definitions,
|
| 14 |
+
get_schema_from_model_field,
|
| 15 |
+
lenient_issubclass,
|
| 16 |
+
)
|
| 17 |
+
from fastapi.datastructures import DefaultPlaceholder
|
| 18 |
+
from fastapi.dependencies.models import Dependant
|
| 19 |
+
from fastapi.dependencies.utils import (
|
| 20 |
+
_get_flat_fields_from_params,
|
| 21 |
+
get_flat_dependant,
|
| 22 |
+
get_flat_params,
|
| 23 |
+
)
|
| 24 |
+
from fastapi.encoders import jsonable_encoder
|
| 25 |
+
from fastapi.openapi.constants import METHODS_WITH_BODY, REF_PREFIX, REF_TEMPLATE
|
| 26 |
+
from fastapi.openapi.models import OpenAPI
|
| 27 |
+
from fastapi.params import Body, ParamTypes
|
| 28 |
+
from fastapi.responses import Response
|
| 29 |
+
from fastapi.types import ModelNameMap
|
| 30 |
+
from fastapi.utils import (
|
| 31 |
+
deep_dict_update,
|
| 32 |
+
generate_operation_id_for_path,
|
| 33 |
+
is_body_allowed_for_status_code,
|
| 34 |
+
)
|
| 35 |
+
from pydantic import BaseModel
|
| 36 |
+
from starlette.responses import JSONResponse
|
| 37 |
+
from starlette.routing import BaseRoute
|
| 38 |
+
from starlette.status import HTTP_422_UNPROCESSABLE_ENTITY
|
| 39 |
+
from typing_extensions import Literal
|
| 40 |
+
|
| 41 |
+
validation_error_definition = {
|
| 42 |
+
"title": "ValidationError",
|
| 43 |
+
"type": "object",
|
| 44 |
+
"properties": {
|
| 45 |
+
"loc": {
|
| 46 |
+
"title": "Location",
|
| 47 |
+
"type": "array",
|
| 48 |
+
"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
|
| 49 |
+
},
|
| 50 |
+
"msg": {"title": "Message", "type": "string"},
|
| 51 |
+
"type": {"title": "Error Type", "type": "string"},
|
| 52 |
+
},
|
| 53 |
+
"required": ["loc", "msg", "type"],
|
| 54 |
+
}
|
| 55 |
+
|
| 56 |
+
validation_error_response_definition = {
|
| 57 |
+
"title": "HTTPValidationError",
|
| 58 |
+
"type": "object",
|
| 59 |
+
"properties": {
|
| 60 |
+
"detail": {
|
| 61 |
+
"title": "Detail",
|
| 62 |
+
"type": "array",
|
| 63 |
+
"items": {"$ref": REF_PREFIX + "ValidationError"},
|
| 64 |
+
}
|
| 65 |
+
},
|
| 66 |
+
}
|
| 67 |
+
|
| 68 |
+
status_code_ranges: Dict[str, str] = {
|
| 69 |
+
"1XX": "Information",
|
| 70 |
+
"2XX": "Success",
|
| 71 |
+
"3XX": "Redirection",
|
| 72 |
+
"4XX": "Client Error",
|
| 73 |
+
"5XX": "Server Error",
|
| 74 |
+
"DEFAULT": "Default Response",
|
| 75 |
+
}
|
| 76 |
+
|
| 77 |
+
|
| 78 |
+
def get_openapi_security_definitions(
|
| 79 |
+
flat_dependant: Dependant,
|
| 80 |
+
) -> Tuple[Dict[str, Any], List[Dict[str, Any]]]:
|
| 81 |
+
security_definitions = {}
|
| 82 |
+
operation_security = []
|
| 83 |
+
for security_requirement in flat_dependant.security_requirements:
|
| 84 |
+
security_definition = jsonable_encoder(
|
| 85 |
+
security_requirement.security_scheme.model,
|
| 86 |
+
by_alias=True,
|
| 87 |
+
exclude_none=True,
|
| 88 |
+
)
|
| 89 |
+
security_name = security_requirement.security_scheme.scheme_name
|
| 90 |
+
security_definitions[security_name] = security_definition
|
| 91 |
+
operation_security.append({security_name: security_requirement.scopes})
|
| 92 |
+
return security_definitions, operation_security
|
| 93 |
+
|
| 94 |
+
|
| 95 |
+
def _get_openapi_operation_parameters(
|
| 96 |
+
*,
|
| 97 |
+
dependant: Dependant,
|
| 98 |
+
schema_generator: GenerateJsonSchema,
|
| 99 |
+
model_name_map: ModelNameMap,
|
| 100 |
+
field_mapping: Dict[
|
| 101 |
+
Tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue
|
| 102 |
+
],
|
| 103 |
+
separate_input_output_schemas: bool = True,
|
| 104 |
+
) -> List[Dict[str, Any]]:
|
| 105 |
+
parameters = []
|
| 106 |
+
flat_dependant = get_flat_dependant(dependant, skip_repeats=True)
|
| 107 |
+
path_params = _get_flat_fields_from_params(flat_dependant.path_params)
|
| 108 |
+
query_params = _get_flat_fields_from_params(flat_dependant.query_params)
|
| 109 |
+
header_params = _get_flat_fields_from_params(flat_dependant.header_params)
|
| 110 |
+
cookie_params = _get_flat_fields_from_params(flat_dependant.cookie_params)
|
| 111 |
+
parameter_groups = [
|
| 112 |
+
(ParamTypes.path, path_params),
|
| 113 |
+
(ParamTypes.query, query_params),
|
| 114 |
+
(ParamTypes.header, header_params),
|
| 115 |
+
(ParamTypes.cookie, cookie_params),
|
| 116 |
+
]
|
| 117 |
+
default_convert_underscores = True
|
| 118 |
+
if len(flat_dependant.header_params) == 1:
|
| 119 |
+
first_field = flat_dependant.header_params[0]
|
| 120 |
+
if lenient_issubclass(first_field.type_, BaseModel):
|
| 121 |
+
default_convert_underscores = getattr(
|
| 122 |
+
first_field.field_info, "convert_underscores", True
|
| 123 |
+
)
|
| 124 |
+
for param_type, param_group in parameter_groups:
|
| 125 |
+
for param in param_group:
|
| 126 |
+
field_info = param.field_info
|
| 127 |
+
# field_info = cast(Param, field_info)
|
| 128 |
+
if not getattr(field_info, "include_in_schema", True):
|
| 129 |
+
continue
|
| 130 |
+
param_schema = get_schema_from_model_field(
|
| 131 |
+
field=param,
|
| 132 |
+
schema_generator=schema_generator,
|
| 133 |
+
model_name_map=model_name_map,
|
| 134 |
+
field_mapping=field_mapping,
|
| 135 |
+
separate_input_output_schemas=separate_input_output_schemas,
|
| 136 |
+
)
|
| 137 |
+
name = param.alias
|
| 138 |
+
convert_underscores = getattr(
|
| 139 |
+
param.field_info,
|
| 140 |
+
"convert_underscores",
|
| 141 |
+
default_convert_underscores,
|
| 142 |
+
)
|
| 143 |
+
if (
|
| 144 |
+
param_type == ParamTypes.header
|
| 145 |
+
and param.alias == param.name
|
| 146 |
+
and convert_underscores
|
| 147 |
+
):
|
| 148 |
+
name = param.name.replace("_", "-")
|
| 149 |
+
|
| 150 |
+
parameter = {
|
| 151 |
+
"name": name,
|
| 152 |
+
"in": param_type.value,
|
| 153 |
+
"required": param.required,
|
| 154 |
+
"schema": param_schema,
|
| 155 |
+
}
|
| 156 |
+
if field_info.description:
|
| 157 |
+
parameter["description"] = field_info.description
|
| 158 |
+
openapi_examples = getattr(field_info, "openapi_examples", None)
|
| 159 |
+
example = getattr(field_info, "example", None)
|
| 160 |
+
if openapi_examples:
|
| 161 |
+
parameter["examples"] = jsonable_encoder(openapi_examples)
|
| 162 |
+
elif example != Undefined:
|
| 163 |
+
parameter["example"] = jsonable_encoder(example)
|
| 164 |
+
if getattr(field_info, "deprecated", None):
|
| 165 |
+
parameter["deprecated"] = True
|
| 166 |
+
parameters.append(parameter)
|
| 167 |
+
return parameters
|
| 168 |
+
|
| 169 |
+
|
| 170 |
+
def get_openapi_operation_request_body(
|
| 171 |
+
*,
|
| 172 |
+
body_field: Optional[ModelField],
|
| 173 |
+
schema_generator: GenerateJsonSchema,
|
| 174 |
+
model_name_map: ModelNameMap,
|
| 175 |
+
field_mapping: Dict[
|
| 176 |
+
Tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue
|
| 177 |
+
],
|
| 178 |
+
separate_input_output_schemas: bool = True,
|
| 179 |
+
) -> Optional[Dict[str, Any]]:
|
| 180 |
+
if not body_field:
|
| 181 |
+
return None
|
| 182 |
+
assert isinstance(body_field, ModelField)
|
| 183 |
+
body_schema = get_schema_from_model_field(
|
| 184 |
+
field=body_field,
|
| 185 |
+
schema_generator=schema_generator,
|
| 186 |
+
model_name_map=model_name_map,
|
| 187 |
+
field_mapping=field_mapping,
|
| 188 |
+
separate_input_output_schemas=separate_input_output_schemas,
|
| 189 |
+
)
|
| 190 |
+
field_info = cast(Body, body_field.field_info)
|
| 191 |
+
request_media_type = field_info.media_type
|
| 192 |
+
required = body_field.required
|
| 193 |
+
request_body_oai: Dict[str, Any] = {}
|
| 194 |
+
if required:
|
| 195 |
+
request_body_oai["required"] = required
|
| 196 |
+
request_media_content: Dict[str, Any] = {"schema": body_schema}
|
| 197 |
+
if field_info.openapi_examples:
|
| 198 |
+
request_media_content["examples"] = jsonable_encoder(
|
| 199 |
+
field_info.openapi_examples
|
| 200 |
+
)
|
| 201 |
+
elif field_info.example != Undefined:
|
| 202 |
+
request_media_content["example"] = jsonable_encoder(field_info.example)
|
| 203 |
+
request_body_oai["content"] = {request_media_type: request_media_content}
|
| 204 |
+
return request_body_oai
|
| 205 |
+
|
| 206 |
+
|
| 207 |
+
def generate_operation_id(
|
| 208 |
+
*, route: routing.APIRoute, method: str
|
| 209 |
+
) -> str: # pragma: nocover
|
| 210 |
+
warnings.warn(
|
| 211 |
+
"fastapi.openapi.utils.generate_operation_id() was deprecated, "
|
| 212 |
+
"it is not used internally, and will be removed soon",
|
| 213 |
+
DeprecationWarning,
|
| 214 |
+
stacklevel=2,
|
| 215 |
+
)
|
| 216 |
+
if route.operation_id:
|
| 217 |
+
return route.operation_id
|
| 218 |
+
path: str = route.path_format
|
| 219 |
+
return generate_operation_id_for_path(name=route.name, path=path, method=method)
|
| 220 |
+
|
| 221 |
+
|
| 222 |
+
def generate_operation_summary(*, route: routing.APIRoute, method: str) -> str:
|
| 223 |
+
if route.summary:
|
| 224 |
+
return route.summary
|
| 225 |
+
return route.name.replace("_", " ").title()
|
| 226 |
+
|
| 227 |
+
|
| 228 |
+
def get_openapi_operation_metadata(
|
| 229 |
+
*, route: routing.APIRoute, method: str, operation_ids: Set[str]
|
| 230 |
+
) -> Dict[str, Any]:
|
| 231 |
+
operation: Dict[str, Any] = {}
|
| 232 |
+
if route.tags:
|
| 233 |
+
operation["tags"] = route.tags
|
| 234 |
+
operation["summary"] = generate_operation_summary(route=route, method=method)
|
| 235 |
+
if route.description:
|
| 236 |
+
operation["description"] = route.description
|
| 237 |
+
operation_id = route.operation_id or route.unique_id
|
| 238 |
+
if operation_id in operation_ids:
|
| 239 |
+
message = (
|
| 240 |
+
f"Duplicate Operation ID {operation_id} for function "
|
| 241 |
+
+ f"{route.endpoint.__name__}"
|
| 242 |
+
)
|
| 243 |
+
file_name = getattr(route.endpoint, "__globals__", {}).get("__file__")
|
| 244 |
+
if file_name:
|
| 245 |
+
message += f" at {file_name}"
|
| 246 |
+
warnings.warn(message, stacklevel=1)
|
| 247 |
+
operation_ids.add(operation_id)
|
| 248 |
+
operation["operationId"] = operation_id
|
| 249 |
+
if route.deprecated:
|
| 250 |
+
operation["deprecated"] = route.deprecated
|
| 251 |
+
return operation
|
| 252 |
+
|
| 253 |
+
|
| 254 |
+
def get_openapi_path(
|
| 255 |
+
*,
|
| 256 |
+
route: routing.APIRoute,
|
| 257 |
+
operation_ids: Set[str],
|
| 258 |
+
schema_generator: GenerateJsonSchema,
|
| 259 |
+
model_name_map: ModelNameMap,
|
| 260 |
+
field_mapping: Dict[
|
| 261 |
+
Tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue
|
| 262 |
+
],
|
| 263 |
+
separate_input_output_schemas: bool = True,
|
| 264 |
+
) -> Tuple[Dict[str, Any], Dict[str, Any], Dict[str, Any]]:
|
| 265 |
+
path = {}
|
| 266 |
+
security_schemes: Dict[str, Any] = {}
|
| 267 |
+
definitions: Dict[str, Any] = {}
|
| 268 |
+
assert route.methods is not None, "Methods must be a list"
|
| 269 |
+
if isinstance(route.response_class, DefaultPlaceholder):
|
| 270 |
+
current_response_class: Type[Response] = route.response_class.value
|
| 271 |
+
else:
|
| 272 |
+
current_response_class = route.response_class
|
| 273 |
+
assert current_response_class, "A response class is needed to generate OpenAPI"
|
| 274 |
+
route_response_media_type: Optional[str] = current_response_class.media_type
|
| 275 |
+
if route.include_in_schema:
|
| 276 |
+
for method in route.methods:
|
| 277 |
+
operation = get_openapi_operation_metadata(
|
| 278 |
+
route=route, method=method, operation_ids=operation_ids
|
| 279 |
+
)
|
| 280 |
+
parameters: List[Dict[str, Any]] = []
|
| 281 |
+
flat_dependant = get_flat_dependant(route.dependant, skip_repeats=True)
|
| 282 |
+
security_definitions, operation_security = get_openapi_security_definitions(
|
| 283 |
+
flat_dependant=flat_dependant
|
| 284 |
+
)
|
| 285 |
+
if operation_security:
|
| 286 |
+
operation.setdefault("security", []).extend(operation_security)
|
| 287 |
+
if security_definitions:
|
| 288 |
+
security_schemes.update(security_definitions)
|
| 289 |
+
operation_parameters = _get_openapi_operation_parameters(
|
| 290 |
+
dependant=route.dependant,
|
| 291 |
+
schema_generator=schema_generator,
|
| 292 |
+
model_name_map=model_name_map,
|
| 293 |
+
field_mapping=field_mapping,
|
| 294 |
+
separate_input_output_schemas=separate_input_output_schemas,
|
| 295 |
+
)
|
| 296 |
+
parameters.extend(operation_parameters)
|
| 297 |
+
if parameters:
|
| 298 |
+
all_parameters = {
|
| 299 |
+
(param["in"], param["name"]): param for param in parameters
|
| 300 |
+
}
|
| 301 |
+
required_parameters = {
|
| 302 |
+
(param["in"], param["name"]): param
|
| 303 |
+
for param in parameters
|
| 304 |
+
if param.get("required")
|
| 305 |
+
}
|
| 306 |
+
# Make sure required definitions of the same parameter take precedence
|
| 307 |
+
# over non-required definitions
|
| 308 |
+
all_parameters.update(required_parameters)
|
| 309 |
+
operation["parameters"] = list(all_parameters.values())
|
| 310 |
+
if method in METHODS_WITH_BODY:
|
| 311 |
+
request_body_oai = get_openapi_operation_request_body(
|
| 312 |
+
body_field=route.body_field,
|
| 313 |
+
schema_generator=schema_generator,
|
| 314 |
+
model_name_map=model_name_map,
|
| 315 |
+
field_mapping=field_mapping,
|
| 316 |
+
separate_input_output_schemas=separate_input_output_schemas,
|
| 317 |
+
)
|
| 318 |
+
if request_body_oai:
|
| 319 |
+
operation["requestBody"] = request_body_oai
|
| 320 |
+
if route.callbacks:
|
| 321 |
+
callbacks = {}
|
| 322 |
+
for callback in route.callbacks:
|
| 323 |
+
if isinstance(callback, routing.APIRoute):
|
| 324 |
+
(
|
| 325 |
+
cb_path,
|
| 326 |
+
cb_security_schemes,
|
| 327 |
+
cb_definitions,
|
| 328 |
+
) = get_openapi_path(
|
| 329 |
+
route=callback,
|
| 330 |
+
operation_ids=operation_ids,
|
| 331 |
+
schema_generator=schema_generator,
|
| 332 |
+
model_name_map=model_name_map,
|
| 333 |
+
field_mapping=field_mapping,
|
| 334 |
+
separate_input_output_schemas=separate_input_output_schemas,
|
| 335 |
+
)
|
| 336 |
+
callbacks[callback.name] = {callback.path: cb_path}
|
| 337 |
+
operation["callbacks"] = callbacks
|
| 338 |
+
if route.status_code is not None:
|
| 339 |
+
status_code = str(route.status_code)
|
| 340 |
+
else:
|
| 341 |
+
# It would probably make more sense for all response classes to have an
|
| 342 |
+
# explicit default status_code, and to extract it from them, instead of
|
| 343 |
+
# doing this inspection tricks, that would probably be in the future
|
| 344 |
+
# TODO: probably make status_code a default class attribute for all
|
| 345 |
+
# responses in Starlette
|
| 346 |
+
response_signature = inspect.signature(current_response_class.__init__)
|
| 347 |
+
status_code_param = response_signature.parameters.get("status_code")
|
| 348 |
+
if status_code_param is not None:
|
| 349 |
+
if isinstance(status_code_param.default, int):
|
| 350 |
+
status_code = str(status_code_param.default)
|
| 351 |
+
operation.setdefault("responses", {}).setdefault(status_code, {})[
|
| 352 |
+
"description"
|
| 353 |
+
] = route.response_description
|
| 354 |
+
if route_response_media_type and is_body_allowed_for_status_code(
|
| 355 |
+
route.status_code
|
| 356 |
+
):
|
| 357 |
+
response_schema = {"type": "string"}
|
| 358 |
+
if lenient_issubclass(current_response_class, JSONResponse):
|
| 359 |
+
if route.response_field:
|
| 360 |
+
response_schema = get_schema_from_model_field(
|
| 361 |
+
field=route.response_field,
|
| 362 |
+
schema_generator=schema_generator,
|
| 363 |
+
model_name_map=model_name_map,
|
| 364 |
+
field_mapping=field_mapping,
|
| 365 |
+
separate_input_output_schemas=separate_input_output_schemas,
|
| 366 |
+
)
|
| 367 |
+
else:
|
| 368 |
+
response_schema = {}
|
| 369 |
+
operation.setdefault("responses", {}).setdefault(
|
| 370 |
+
status_code, {}
|
| 371 |
+
).setdefault("content", {}).setdefault(route_response_media_type, {})[
|
| 372 |
+
"schema"
|
| 373 |
+
] = response_schema
|
| 374 |
+
if route.responses:
|
| 375 |
+
operation_responses = operation.setdefault("responses", {})
|
| 376 |
+
for (
|
| 377 |
+
additional_status_code,
|
| 378 |
+
additional_response,
|
| 379 |
+
) in route.responses.items():
|
| 380 |
+
process_response = additional_response.copy()
|
| 381 |
+
process_response.pop("model", None)
|
| 382 |
+
status_code_key = str(additional_status_code).upper()
|
| 383 |
+
if status_code_key == "DEFAULT":
|
| 384 |
+
status_code_key = "default"
|
| 385 |
+
openapi_response = operation_responses.setdefault(
|
| 386 |
+
status_code_key, {}
|
| 387 |
+
)
|
| 388 |
+
assert isinstance(process_response, dict), (
|
| 389 |
+
"An additional response must be a dict"
|
| 390 |
+
)
|
| 391 |
+
field = route.response_fields.get(additional_status_code)
|
| 392 |
+
additional_field_schema: Optional[Dict[str, Any]] = None
|
| 393 |
+
if field:
|
| 394 |
+
additional_field_schema = get_schema_from_model_field(
|
| 395 |
+
field=field,
|
| 396 |
+
schema_generator=schema_generator,
|
| 397 |
+
model_name_map=model_name_map,
|
| 398 |
+
field_mapping=field_mapping,
|
| 399 |
+
separate_input_output_schemas=separate_input_output_schemas,
|
| 400 |
+
)
|
| 401 |
+
media_type = route_response_media_type or "application/json"
|
| 402 |
+
additional_schema = (
|
| 403 |
+
process_response.setdefault("content", {})
|
| 404 |
+
.setdefault(media_type, {})
|
| 405 |
+
.setdefault("schema", {})
|
| 406 |
+
)
|
| 407 |
+
deep_dict_update(additional_schema, additional_field_schema)
|
| 408 |
+
status_text: Optional[str] = status_code_ranges.get(
|
| 409 |
+
str(additional_status_code).upper()
|
| 410 |
+
) or http.client.responses.get(int(additional_status_code))
|
| 411 |
+
description = (
|
| 412 |
+
process_response.get("description")
|
| 413 |
+
or openapi_response.get("description")
|
| 414 |
+
or status_text
|
| 415 |
+
or "Additional Response"
|
| 416 |
+
)
|
| 417 |
+
deep_dict_update(openapi_response, process_response)
|
| 418 |
+
openapi_response["description"] = description
|
| 419 |
+
http422 = str(HTTP_422_UNPROCESSABLE_ENTITY)
|
| 420 |
+
all_route_params = get_flat_params(route.dependant)
|
| 421 |
+
if (all_route_params or route.body_field) and not any(
|
| 422 |
+
status in operation["responses"]
|
| 423 |
+
for status in [http422, "4XX", "default"]
|
| 424 |
+
):
|
| 425 |
+
operation["responses"][http422] = {
|
| 426 |
+
"description": "Validation Error",
|
| 427 |
+
"content": {
|
| 428 |
+
"application/json": {
|
| 429 |
+
"schema": {"$ref": REF_PREFIX + "HTTPValidationError"}
|
| 430 |
+
}
|
| 431 |
+
},
|
| 432 |
+
}
|
| 433 |
+
if "ValidationError" not in definitions:
|
| 434 |
+
definitions.update(
|
| 435 |
+
{
|
| 436 |
+
"ValidationError": validation_error_definition,
|
| 437 |
+
"HTTPValidationError": validation_error_response_definition,
|
| 438 |
+
}
|
| 439 |
+
)
|
| 440 |
+
if route.openapi_extra:
|
| 441 |
+
deep_dict_update(operation, route.openapi_extra)
|
| 442 |
+
path[method.lower()] = operation
|
| 443 |
+
return path, security_schemes, definitions
|
| 444 |
+
|
| 445 |
+
|
| 446 |
+
def get_fields_from_routes(
|
| 447 |
+
routes: Sequence[BaseRoute],
|
| 448 |
+
) -> List[ModelField]:
|
| 449 |
+
body_fields_from_routes: List[ModelField] = []
|
| 450 |
+
responses_from_routes: List[ModelField] = []
|
| 451 |
+
request_fields_from_routes: List[ModelField] = []
|
| 452 |
+
callback_flat_models: List[ModelField] = []
|
| 453 |
+
for route in routes:
|
| 454 |
+
if getattr(route, "include_in_schema", None) and isinstance(
|
| 455 |
+
route, routing.APIRoute
|
| 456 |
+
):
|
| 457 |
+
if route.body_field:
|
| 458 |
+
assert isinstance(route.body_field, ModelField), (
|
| 459 |
+
"A request body must be a Pydantic Field"
|
| 460 |
+
)
|
| 461 |
+
body_fields_from_routes.append(route.body_field)
|
| 462 |
+
if route.response_field:
|
| 463 |
+
responses_from_routes.append(route.response_field)
|
| 464 |
+
if route.response_fields:
|
| 465 |
+
responses_from_routes.extend(route.response_fields.values())
|
| 466 |
+
if route.callbacks:
|
| 467 |
+
callback_flat_models.extend(get_fields_from_routes(route.callbacks))
|
| 468 |
+
params = get_flat_params(route.dependant)
|
| 469 |
+
request_fields_from_routes.extend(params)
|
| 470 |
+
|
| 471 |
+
flat_models = callback_flat_models + list(
|
| 472 |
+
body_fields_from_routes + responses_from_routes + request_fields_from_routes
|
| 473 |
+
)
|
| 474 |
+
return flat_models
|
| 475 |
+
|
| 476 |
+
|
| 477 |
+
def get_openapi(
|
| 478 |
+
*,
|
| 479 |
+
title: str,
|
| 480 |
+
version: str,
|
| 481 |
+
openapi_version: str = "3.1.0",
|
| 482 |
+
summary: Optional[str] = None,
|
| 483 |
+
description: Optional[str] = None,
|
| 484 |
+
routes: Sequence[BaseRoute],
|
| 485 |
+
webhooks: Optional[Sequence[BaseRoute]] = None,
|
| 486 |
+
tags: Optional[List[Dict[str, Any]]] = None,
|
| 487 |
+
servers: Optional[List[Dict[str, Union[str, Any]]]] = None,
|
| 488 |
+
terms_of_service: Optional[str] = None,
|
| 489 |
+
contact: Optional[Dict[str, Union[str, Any]]] = None,
|
| 490 |
+
license_info: Optional[Dict[str, Union[str, Any]]] = None,
|
| 491 |
+
separate_input_output_schemas: bool = True,
|
| 492 |
+
) -> Dict[str, Any]:
|
| 493 |
+
info: Dict[str, Any] = {"title": title, "version": version}
|
| 494 |
+
if summary:
|
| 495 |
+
info["summary"] = summary
|
| 496 |
+
if description:
|
| 497 |
+
info["description"] = description
|
| 498 |
+
if terms_of_service:
|
| 499 |
+
info["termsOfService"] = terms_of_service
|
| 500 |
+
if contact:
|
| 501 |
+
info["contact"] = contact
|
| 502 |
+
if license_info:
|
| 503 |
+
info["license"] = license_info
|
| 504 |
+
output: Dict[str, Any] = {"openapi": openapi_version, "info": info}
|
| 505 |
+
if servers:
|
| 506 |
+
output["servers"] = servers
|
| 507 |
+
components: Dict[str, Dict[str, Any]] = {}
|
| 508 |
+
paths: Dict[str, Dict[str, Any]] = {}
|
| 509 |
+
webhook_paths: Dict[str, Dict[str, Any]] = {}
|
| 510 |
+
operation_ids: Set[str] = set()
|
| 511 |
+
all_fields = get_fields_from_routes(list(routes or []) + list(webhooks or []))
|
| 512 |
+
model_name_map = get_compat_model_name_map(all_fields)
|
| 513 |
+
schema_generator = GenerateJsonSchema(ref_template=REF_TEMPLATE)
|
| 514 |
+
field_mapping, definitions = get_definitions(
|
| 515 |
+
fields=all_fields,
|
| 516 |
+
schema_generator=schema_generator,
|
| 517 |
+
model_name_map=model_name_map,
|
| 518 |
+
separate_input_output_schemas=separate_input_output_schemas,
|
| 519 |
+
)
|
| 520 |
+
for route in routes or []:
|
| 521 |
+
if isinstance(route, routing.APIRoute):
|
| 522 |
+
result = get_openapi_path(
|
| 523 |
+
route=route,
|
| 524 |
+
operation_ids=operation_ids,
|
| 525 |
+
schema_generator=schema_generator,
|
| 526 |
+
model_name_map=model_name_map,
|
| 527 |
+
field_mapping=field_mapping,
|
| 528 |
+
separate_input_output_schemas=separate_input_output_schemas,
|
| 529 |
+
)
|
| 530 |
+
if result:
|
| 531 |
+
path, security_schemes, path_definitions = result
|
| 532 |
+
if path:
|
| 533 |
+
paths.setdefault(route.path_format, {}).update(path)
|
| 534 |
+
if security_schemes:
|
| 535 |
+
components.setdefault("securitySchemes", {}).update(
|
| 536 |
+
security_schemes
|
| 537 |
+
)
|
| 538 |
+
if path_definitions:
|
| 539 |
+
definitions.update(path_definitions)
|
| 540 |
+
for webhook in webhooks or []:
|
| 541 |
+
if isinstance(webhook, routing.APIRoute):
|
| 542 |
+
result = get_openapi_path(
|
| 543 |
+
route=webhook,
|
| 544 |
+
operation_ids=operation_ids,
|
| 545 |
+
schema_generator=schema_generator,
|
| 546 |
+
model_name_map=model_name_map,
|
| 547 |
+
field_mapping=field_mapping,
|
| 548 |
+
separate_input_output_schemas=separate_input_output_schemas,
|
| 549 |
+
)
|
| 550 |
+
if result:
|
| 551 |
+
path, security_schemes, path_definitions = result
|
| 552 |
+
if path:
|
| 553 |
+
webhook_paths.setdefault(webhook.path_format, {}).update(path)
|
| 554 |
+
if security_schemes:
|
| 555 |
+
components.setdefault("securitySchemes", {}).update(
|
| 556 |
+
security_schemes
|
| 557 |
+
)
|
| 558 |
+
if path_definitions:
|
| 559 |
+
definitions.update(path_definitions)
|
| 560 |
+
if definitions:
|
| 561 |
+
components["schemas"] = {k: definitions[k] for k in sorted(definitions)}
|
| 562 |
+
if components:
|
| 563 |
+
output["components"] = components
|
| 564 |
+
output["paths"] = paths
|
| 565 |
+
if webhook_paths:
|
| 566 |
+
output["webhooks"] = webhook_paths
|
| 567 |
+
if tags:
|
| 568 |
+
output["tags"] = tags
|
| 569 |
+
return jsonable_encoder(OpenAPI(**output), by_alias=True, exclude_none=True) # type: ignore
|
lib/python3.12/site-packages/fastapi/param_functions.py
ADDED
|
@@ -0,0 +1,2360 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from typing import Any, Callable, Dict, List, Optional, Sequence, Union
|
| 2 |
+
|
| 3 |
+
from fastapi import params
|
| 4 |
+
from fastapi._compat import Undefined
|
| 5 |
+
from fastapi.openapi.models import Example
|
| 6 |
+
from typing_extensions import Annotated, Doc, deprecated
|
| 7 |
+
|
| 8 |
+
_Unset: Any = Undefined
|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
def Path( # noqa: N802
|
| 12 |
+
default: Annotated[
|
| 13 |
+
Any,
|
| 14 |
+
Doc(
|
| 15 |
+
"""
|
| 16 |
+
Default value if the parameter field is not set.
|
| 17 |
+
|
| 18 |
+
This doesn't affect `Path` parameters as the value is always required.
|
| 19 |
+
The parameter is available only for compatibility.
|
| 20 |
+
"""
|
| 21 |
+
),
|
| 22 |
+
] = ...,
|
| 23 |
+
*,
|
| 24 |
+
default_factory: Annotated[
|
| 25 |
+
Union[Callable[[], Any], None],
|
| 26 |
+
Doc(
|
| 27 |
+
"""
|
| 28 |
+
A callable to generate the default value.
|
| 29 |
+
|
| 30 |
+
This doesn't affect `Path` parameters as the value is always required.
|
| 31 |
+
The parameter is available only for compatibility.
|
| 32 |
+
"""
|
| 33 |
+
),
|
| 34 |
+
] = _Unset,
|
| 35 |
+
alias: Annotated[
|
| 36 |
+
Optional[str],
|
| 37 |
+
Doc(
|
| 38 |
+
"""
|
| 39 |
+
An alternative name for the parameter field.
|
| 40 |
+
|
| 41 |
+
This will be used to extract the data and for the generated OpenAPI.
|
| 42 |
+
It is particularly useful when you can't use the name you want because it
|
| 43 |
+
is a Python reserved keyword or similar.
|
| 44 |
+
"""
|
| 45 |
+
),
|
| 46 |
+
] = None,
|
| 47 |
+
alias_priority: Annotated[
|
| 48 |
+
Union[int, None],
|
| 49 |
+
Doc(
|
| 50 |
+
"""
|
| 51 |
+
Priority of the alias. This affects whether an alias generator is used.
|
| 52 |
+
"""
|
| 53 |
+
),
|
| 54 |
+
] = _Unset,
|
| 55 |
+
# TODO: update when deprecating Pydantic v1, import these types
|
| 56 |
+
# validation_alias: str | AliasPath | AliasChoices | None
|
| 57 |
+
validation_alias: Annotated[
|
| 58 |
+
Union[str, None],
|
| 59 |
+
Doc(
|
| 60 |
+
"""
|
| 61 |
+
'Whitelist' validation step. The parameter field will be the single one
|
| 62 |
+
allowed by the alias or set of aliases defined.
|
| 63 |
+
"""
|
| 64 |
+
),
|
| 65 |
+
] = None,
|
| 66 |
+
serialization_alias: Annotated[
|
| 67 |
+
Union[str, None],
|
| 68 |
+
Doc(
|
| 69 |
+
"""
|
| 70 |
+
'Blacklist' validation step. The vanilla parameter field will be the
|
| 71 |
+
single one of the alias' or set of aliases' fields and all the other
|
| 72 |
+
fields will be ignored at serialization time.
|
| 73 |
+
"""
|
| 74 |
+
),
|
| 75 |
+
] = None,
|
| 76 |
+
title: Annotated[
|
| 77 |
+
Optional[str],
|
| 78 |
+
Doc(
|
| 79 |
+
"""
|
| 80 |
+
Human-readable title.
|
| 81 |
+
"""
|
| 82 |
+
),
|
| 83 |
+
] = None,
|
| 84 |
+
description: Annotated[
|
| 85 |
+
Optional[str],
|
| 86 |
+
Doc(
|
| 87 |
+
"""
|
| 88 |
+
Human-readable description.
|
| 89 |
+
"""
|
| 90 |
+
),
|
| 91 |
+
] = None,
|
| 92 |
+
gt: Annotated[
|
| 93 |
+
Optional[float],
|
| 94 |
+
Doc(
|
| 95 |
+
"""
|
| 96 |
+
Greater than. If set, value must be greater than this. Only applicable to
|
| 97 |
+
numbers.
|
| 98 |
+
"""
|
| 99 |
+
),
|
| 100 |
+
] = None,
|
| 101 |
+
ge: Annotated[
|
| 102 |
+
Optional[float],
|
| 103 |
+
Doc(
|
| 104 |
+
"""
|
| 105 |
+
Greater than or equal. If set, value must be greater than or equal to
|
| 106 |
+
this. Only applicable to numbers.
|
| 107 |
+
"""
|
| 108 |
+
),
|
| 109 |
+
] = None,
|
| 110 |
+
lt: Annotated[
|
| 111 |
+
Optional[float],
|
| 112 |
+
Doc(
|
| 113 |
+
"""
|
| 114 |
+
Less than. If set, value must be less than this. Only applicable to numbers.
|
| 115 |
+
"""
|
| 116 |
+
),
|
| 117 |
+
] = None,
|
| 118 |
+
le: Annotated[
|
| 119 |
+
Optional[float],
|
| 120 |
+
Doc(
|
| 121 |
+
"""
|
| 122 |
+
Less than or equal. If set, value must be less than or equal to this.
|
| 123 |
+
Only applicable to numbers.
|
| 124 |
+
"""
|
| 125 |
+
),
|
| 126 |
+
] = None,
|
| 127 |
+
min_length: Annotated[
|
| 128 |
+
Optional[int],
|
| 129 |
+
Doc(
|
| 130 |
+
"""
|
| 131 |
+
Minimum length for strings.
|
| 132 |
+
"""
|
| 133 |
+
),
|
| 134 |
+
] = None,
|
| 135 |
+
max_length: Annotated[
|
| 136 |
+
Optional[int],
|
| 137 |
+
Doc(
|
| 138 |
+
"""
|
| 139 |
+
Maximum length for strings.
|
| 140 |
+
"""
|
| 141 |
+
),
|
| 142 |
+
] = None,
|
| 143 |
+
pattern: Annotated[
|
| 144 |
+
Optional[str],
|
| 145 |
+
Doc(
|
| 146 |
+
"""
|
| 147 |
+
RegEx pattern for strings.
|
| 148 |
+
"""
|
| 149 |
+
),
|
| 150 |
+
] = None,
|
| 151 |
+
regex: Annotated[
|
| 152 |
+
Optional[str],
|
| 153 |
+
Doc(
|
| 154 |
+
"""
|
| 155 |
+
RegEx pattern for strings.
|
| 156 |
+
"""
|
| 157 |
+
),
|
| 158 |
+
deprecated(
|
| 159 |
+
"Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead."
|
| 160 |
+
),
|
| 161 |
+
] = None,
|
| 162 |
+
discriminator: Annotated[
|
| 163 |
+
Union[str, None],
|
| 164 |
+
Doc(
|
| 165 |
+
"""
|
| 166 |
+
Parameter field name for discriminating the type in a tagged union.
|
| 167 |
+
"""
|
| 168 |
+
),
|
| 169 |
+
] = None,
|
| 170 |
+
strict: Annotated[
|
| 171 |
+
Union[bool, None],
|
| 172 |
+
Doc(
|
| 173 |
+
"""
|
| 174 |
+
If `True`, strict validation is applied to the field.
|
| 175 |
+
"""
|
| 176 |
+
),
|
| 177 |
+
] = _Unset,
|
| 178 |
+
multiple_of: Annotated[
|
| 179 |
+
Union[float, None],
|
| 180 |
+
Doc(
|
| 181 |
+
"""
|
| 182 |
+
Value must be a multiple of this. Only applicable to numbers.
|
| 183 |
+
"""
|
| 184 |
+
),
|
| 185 |
+
] = _Unset,
|
| 186 |
+
allow_inf_nan: Annotated[
|
| 187 |
+
Union[bool, None],
|
| 188 |
+
Doc(
|
| 189 |
+
"""
|
| 190 |
+
Allow `inf`, `-inf`, `nan`. Only applicable to numbers.
|
| 191 |
+
"""
|
| 192 |
+
),
|
| 193 |
+
] = _Unset,
|
| 194 |
+
max_digits: Annotated[
|
| 195 |
+
Union[int, None],
|
| 196 |
+
Doc(
|
| 197 |
+
"""
|
| 198 |
+
Maximum number of allow digits for strings.
|
| 199 |
+
"""
|
| 200 |
+
),
|
| 201 |
+
] = _Unset,
|
| 202 |
+
decimal_places: Annotated[
|
| 203 |
+
Union[int, None],
|
| 204 |
+
Doc(
|
| 205 |
+
"""
|
| 206 |
+
Maximum number of decimal places allowed for numbers.
|
| 207 |
+
"""
|
| 208 |
+
),
|
| 209 |
+
] = _Unset,
|
| 210 |
+
examples: Annotated[
|
| 211 |
+
Optional[List[Any]],
|
| 212 |
+
Doc(
|
| 213 |
+
"""
|
| 214 |
+
Example values for this field.
|
| 215 |
+
"""
|
| 216 |
+
),
|
| 217 |
+
] = None,
|
| 218 |
+
example: Annotated[
|
| 219 |
+
Optional[Any],
|
| 220 |
+
deprecated(
|
| 221 |
+
"Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, "
|
| 222 |
+
"although still supported. Use examples instead."
|
| 223 |
+
),
|
| 224 |
+
] = _Unset,
|
| 225 |
+
openapi_examples: Annotated[
|
| 226 |
+
Optional[Dict[str, Example]],
|
| 227 |
+
Doc(
|
| 228 |
+
"""
|
| 229 |
+
OpenAPI-specific examples.
|
| 230 |
+
|
| 231 |
+
It will be added to the generated OpenAPI (e.g. visible at `/docs`).
|
| 232 |
+
|
| 233 |
+
Swagger UI (that provides the `/docs` interface) has better support for the
|
| 234 |
+
OpenAPI-specific examples than the JSON Schema `examples`, that's the main
|
| 235 |
+
use case for this.
|
| 236 |
+
|
| 237 |
+
Read more about it in the
|
| 238 |
+
[FastAPI docs for Declare Request Example Data](https://fastapi.tiangolo.com/tutorial/schema-extra-example/#using-the-openapi_examples-parameter).
|
| 239 |
+
"""
|
| 240 |
+
),
|
| 241 |
+
] = None,
|
| 242 |
+
deprecated: Annotated[
|
| 243 |
+
Union[deprecated, str, bool, None],
|
| 244 |
+
Doc(
|
| 245 |
+
"""
|
| 246 |
+
Mark this parameter field as deprecated.
|
| 247 |
+
|
| 248 |
+
It will affect the generated OpenAPI (e.g. visible at `/docs`).
|
| 249 |
+
"""
|
| 250 |
+
),
|
| 251 |
+
] = None,
|
| 252 |
+
include_in_schema: Annotated[
|
| 253 |
+
bool,
|
| 254 |
+
Doc(
|
| 255 |
+
"""
|
| 256 |
+
To include (or not) this parameter field in the generated OpenAPI.
|
| 257 |
+
You probably don't need it, but it's available.
|
| 258 |
+
|
| 259 |
+
This affects the generated OpenAPI (e.g. visible at `/docs`).
|
| 260 |
+
"""
|
| 261 |
+
),
|
| 262 |
+
] = True,
|
| 263 |
+
json_schema_extra: Annotated[
|
| 264 |
+
Union[Dict[str, Any], None],
|
| 265 |
+
Doc(
|
| 266 |
+
"""
|
| 267 |
+
Any additional JSON schema data.
|
| 268 |
+
"""
|
| 269 |
+
),
|
| 270 |
+
] = None,
|
| 271 |
+
**extra: Annotated[
|
| 272 |
+
Any,
|
| 273 |
+
Doc(
|
| 274 |
+
"""
|
| 275 |
+
Include extra fields used by the JSON Schema.
|
| 276 |
+
"""
|
| 277 |
+
),
|
| 278 |
+
deprecated(
|
| 279 |
+
"""
|
| 280 |
+
The `extra` kwargs is deprecated. Use `json_schema_extra` instead.
|
| 281 |
+
"""
|
| 282 |
+
),
|
| 283 |
+
],
|
| 284 |
+
) -> Any:
|
| 285 |
+
"""
|
| 286 |
+
Declare a path parameter for a *path operation*.
|
| 287 |
+
|
| 288 |
+
Read more about it in the
|
| 289 |
+
[FastAPI docs for Path Parameters and Numeric Validations](https://fastapi.tiangolo.com/tutorial/path-params-numeric-validations/).
|
| 290 |
+
|
| 291 |
+
```python
|
| 292 |
+
from typing import Annotated
|
| 293 |
+
|
| 294 |
+
from fastapi import FastAPI, Path
|
| 295 |
+
|
| 296 |
+
app = FastAPI()
|
| 297 |
+
|
| 298 |
+
|
| 299 |
+
@app.get("/items/{item_id}")
|
| 300 |
+
async def read_items(
|
| 301 |
+
item_id: Annotated[int, Path(title="The ID of the item to get")],
|
| 302 |
+
):
|
| 303 |
+
return {"item_id": item_id}
|
| 304 |
+
```
|
| 305 |
+
"""
|
| 306 |
+
return params.Path(
|
| 307 |
+
default=default,
|
| 308 |
+
default_factory=default_factory,
|
| 309 |
+
alias=alias,
|
| 310 |
+
alias_priority=alias_priority,
|
| 311 |
+
validation_alias=validation_alias,
|
| 312 |
+
serialization_alias=serialization_alias,
|
| 313 |
+
title=title,
|
| 314 |
+
description=description,
|
| 315 |
+
gt=gt,
|
| 316 |
+
ge=ge,
|
| 317 |
+
lt=lt,
|
| 318 |
+
le=le,
|
| 319 |
+
min_length=min_length,
|
| 320 |
+
max_length=max_length,
|
| 321 |
+
pattern=pattern,
|
| 322 |
+
regex=regex,
|
| 323 |
+
discriminator=discriminator,
|
| 324 |
+
strict=strict,
|
| 325 |
+
multiple_of=multiple_of,
|
| 326 |
+
allow_inf_nan=allow_inf_nan,
|
| 327 |
+
max_digits=max_digits,
|
| 328 |
+
decimal_places=decimal_places,
|
| 329 |
+
example=example,
|
| 330 |
+
examples=examples,
|
| 331 |
+
openapi_examples=openapi_examples,
|
| 332 |
+
deprecated=deprecated,
|
| 333 |
+
include_in_schema=include_in_schema,
|
| 334 |
+
json_schema_extra=json_schema_extra,
|
| 335 |
+
**extra,
|
| 336 |
+
)
|
| 337 |
+
|
| 338 |
+
|
| 339 |
+
def Query( # noqa: N802
|
| 340 |
+
default: Annotated[
|
| 341 |
+
Any,
|
| 342 |
+
Doc(
|
| 343 |
+
"""
|
| 344 |
+
Default value if the parameter field is not set.
|
| 345 |
+
"""
|
| 346 |
+
),
|
| 347 |
+
] = Undefined,
|
| 348 |
+
*,
|
| 349 |
+
default_factory: Annotated[
|
| 350 |
+
Union[Callable[[], Any], None],
|
| 351 |
+
Doc(
|
| 352 |
+
"""
|
| 353 |
+
A callable to generate the default value.
|
| 354 |
+
|
| 355 |
+
This doesn't affect `Path` parameters as the value is always required.
|
| 356 |
+
The parameter is available only for compatibility.
|
| 357 |
+
"""
|
| 358 |
+
),
|
| 359 |
+
] = _Unset,
|
| 360 |
+
alias: Annotated[
|
| 361 |
+
Optional[str],
|
| 362 |
+
Doc(
|
| 363 |
+
"""
|
| 364 |
+
An alternative name for the parameter field.
|
| 365 |
+
|
| 366 |
+
This will be used to extract the data and for the generated OpenAPI.
|
| 367 |
+
It is particularly useful when you can't use the name you want because it
|
| 368 |
+
is a Python reserved keyword or similar.
|
| 369 |
+
"""
|
| 370 |
+
),
|
| 371 |
+
] = None,
|
| 372 |
+
alias_priority: Annotated[
|
| 373 |
+
Union[int, None],
|
| 374 |
+
Doc(
|
| 375 |
+
"""
|
| 376 |
+
Priority of the alias. This affects whether an alias generator is used.
|
| 377 |
+
"""
|
| 378 |
+
),
|
| 379 |
+
] = _Unset,
|
| 380 |
+
# TODO: update when deprecating Pydantic v1, import these types
|
| 381 |
+
# validation_alias: str | AliasPath | AliasChoices | None
|
| 382 |
+
validation_alias: Annotated[
|
| 383 |
+
Union[str, None],
|
| 384 |
+
Doc(
|
| 385 |
+
"""
|
| 386 |
+
'Whitelist' validation step. The parameter field will be the single one
|
| 387 |
+
allowed by the alias or set of aliases defined.
|
| 388 |
+
"""
|
| 389 |
+
),
|
| 390 |
+
] = None,
|
| 391 |
+
serialization_alias: Annotated[
|
| 392 |
+
Union[str, None],
|
| 393 |
+
Doc(
|
| 394 |
+
"""
|
| 395 |
+
'Blacklist' validation step. The vanilla parameter field will be the
|
| 396 |
+
single one of the alias' or set of aliases' fields and all the other
|
| 397 |
+
fields will be ignored at serialization time.
|
| 398 |
+
"""
|
| 399 |
+
),
|
| 400 |
+
] = None,
|
| 401 |
+
title: Annotated[
|
| 402 |
+
Optional[str],
|
| 403 |
+
Doc(
|
| 404 |
+
"""
|
| 405 |
+
Human-readable title.
|
| 406 |
+
"""
|
| 407 |
+
),
|
| 408 |
+
] = None,
|
| 409 |
+
description: Annotated[
|
| 410 |
+
Optional[str],
|
| 411 |
+
Doc(
|
| 412 |
+
"""
|
| 413 |
+
Human-readable description.
|
| 414 |
+
"""
|
| 415 |
+
),
|
| 416 |
+
] = None,
|
| 417 |
+
gt: Annotated[
|
| 418 |
+
Optional[float],
|
| 419 |
+
Doc(
|
| 420 |
+
"""
|
| 421 |
+
Greater than. If set, value must be greater than this. Only applicable to
|
| 422 |
+
numbers.
|
| 423 |
+
"""
|
| 424 |
+
),
|
| 425 |
+
] = None,
|
| 426 |
+
ge: Annotated[
|
| 427 |
+
Optional[float],
|
| 428 |
+
Doc(
|
| 429 |
+
"""
|
| 430 |
+
Greater than or equal. If set, value must be greater than or equal to
|
| 431 |
+
this. Only applicable to numbers.
|
| 432 |
+
"""
|
| 433 |
+
),
|
| 434 |
+
] = None,
|
| 435 |
+
lt: Annotated[
|
| 436 |
+
Optional[float],
|
| 437 |
+
Doc(
|
| 438 |
+
"""
|
| 439 |
+
Less than. If set, value must be less than this. Only applicable to numbers.
|
| 440 |
+
"""
|
| 441 |
+
),
|
| 442 |
+
] = None,
|
| 443 |
+
le: Annotated[
|
| 444 |
+
Optional[float],
|
| 445 |
+
Doc(
|
| 446 |
+
"""
|
| 447 |
+
Less than or equal. If set, value must be less than or equal to this.
|
| 448 |
+
Only applicable to numbers.
|
| 449 |
+
"""
|
| 450 |
+
),
|
| 451 |
+
] = None,
|
| 452 |
+
min_length: Annotated[
|
| 453 |
+
Optional[int],
|
| 454 |
+
Doc(
|
| 455 |
+
"""
|
| 456 |
+
Minimum length for strings.
|
| 457 |
+
"""
|
| 458 |
+
),
|
| 459 |
+
] = None,
|
| 460 |
+
max_length: Annotated[
|
| 461 |
+
Optional[int],
|
| 462 |
+
Doc(
|
| 463 |
+
"""
|
| 464 |
+
Maximum length for strings.
|
| 465 |
+
"""
|
| 466 |
+
),
|
| 467 |
+
] = None,
|
| 468 |
+
pattern: Annotated[
|
| 469 |
+
Optional[str],
|
| 470 |
+
Doc(
|
| 471 |
+
"""
|
| 472 |
+
RegEx pattern for strings.
|
| 473 |
+
"""
|
| 474 |
+
),
|
| 475 |
+
] = None,
|
| 476 |
+
regex: Annotated[
|
| 477 |
+
Optional[str],
|
| 478 |
+
Doc(
|
| 479 |
+
"""
|
| 480 |
+
RegEx pattern for strings.
|
| 481 |
+
"""
|
| 482 |
+
),
|
| 483 |
+
deprecated(
|
| 484 |
+
"Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead."
|
| 485 |
+
),
|
| 486 |
+
] = None,
|
| 487 |
+
discriminator: Annotated[
|
| 488 |
+
Union[str, None],
|
| 489 |
+
Doc(
|
| 490 |
+
"""
|
| 491 |
+
Parameter field name for discriminating the type in a tagged union.
|
| 492 |
+
"""
|
| 493 |
+
),
|
| 494 |
+
] = None,
|
| 495 |
+
strict: Annotated[
|
| 496 |
+
Union[bool, None],
|
| 497 |
+
Doc(
|
| 498 |
+
"""
|
| 499 |
+
If `True`, strict validation is applied to the field.
|
| 500 |
+
"""
|
| 501 |
+
),
|
| 502 |
+
] = _Unset,
|
| 503 |
+
multiple_of: Annotated[
|
| 504 |
+
Union[float, None],
|
| 505 |
+
Doc(
|
| 506 |
+
"""
|
| 507 |
+
Value must be a multiple of this. Only applicable to numbers.
|
| 508 |
+
"""
|
| 509 |
+
),
|
| 510 |
+
] = _Unset,
|
| 511 |
+
allow_inf_nan: Annotated[
|
| 512 |
+
Union[bool, None],
|
| 513 |
+
Doc(
|
| 514 |
+
"""
|
| 515 |
+
Allow `inf`, `-inf`, `nan`. Only applicable to numbers.
|
| 516 |
+
"""
|
| 517 |
+
),
|
| 518 |
+
] = _Unset,
|
| 519 |
+
max_digits: Annotated[
|
| 520 |
+
Union[int, None],
|
| 521 |
+
Doc(
|
| 522 |
+
"""
|
| 523 |
+
Maximum number of allow digits for strings.
|
| 524 |
+
"""
|
| 525 |
+
),
|
| 526 |
+
] = _Unset,
|
| 527 |
+
decimal_places: Annotated[
|
| 528 |
+
Union[int, None],
|
| 529 |
+
Doc(
|
| 530 |
+
"""
|
| 531 |
+
Maximum number of decimal places allowed for numbers.
|
| 532 |
+
"""
|
| 533 |
+
),
|
| 534 |
+
] = _Unset,
|
| 535 |
+
examples: Annotated[
|
| 536 |
+
Optional[List[Any]],
|
| 537 |
+
Doc(
|
| 538 |
+
"""
|
| 539 |
+
Example values for this field.
|
| 540 |
+
"""
|
| 541 |
+
),
|
| 542 |
+
] = None,
|
| 543 |
+
example: Annotated[
|
| 544 |
+
Optional[Any],
|
| 545 |
+
deprecated(
|
| 546 |
+
"Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, "
|
| 547 |
+
"although still supported. Use examples instead."
|
| 548 |
+
),
|
| 549 |
+
] = _Unset,
|
| 550 |
+
openapi_examples: Annotated[
|
| 551 |
+
Optional[Dict[str, Example]],
|
| 552 |
+
Doc(
|
| 553 |
+
"""
|
| 554 |
+
OpenAPI-specific examples.
|
| 555 |
+
|
| 556 |
+
It will be added to the generated OpenAPI (e.g. visible at `/docs`).
|
| 557 |
+
|
| 558 |
+
Swagger UI (that provides the `/docs` interface) has better support for the
|
| 559 |
+
OpenAPI-specific examples than the JSON Schema `examples`, that's the main
|
| 560 |
+
use case for this.
|
| 561 |
+
|
| 562 |
+
Read more about it in the
|
| 563 |
+
[FastAPI docs for Declare Request Example Data](https://fastapi.tiangolo.com/tutorial/schema-extra-example/#using-the-openapi_examples-parameter).
|
| 564 |
+
"""
|
| 565 |
+
),
|
| 566 |
+
] = None,
|
| 567 |
+
deprecated: Annotated[
|
| 568 |
+
Union[deprecated, str, bool, None],
|
| 569 |
+
Doc(
|
| 570 |
+
"""
|
| 571 |
+
Mark this parameter field as deprecated.
|
| 572 |
+
|
| 573 |
+
It will affect the generated OpenAPI (e.g. visible at `/docs`).
|
| 574 |
+
"""
|
| 575 |
+
),
|
| 576 |
+
] = None,
|
| 577 |
+
include_in_schema: Annotated[
|
| 578 |
+
bool,
|
| 579 |
+
Doc(
|
| 580 |
+
"""
|
| 581 |
+
To include (or not) this parameter field in the generated OpenAPI.
|
| 582 |
+
You probably don't need it, but it's available.
|
| 583 |
+
|
| 584 |
+
This affects the generated OpenAPI (e.g. visible at `/docs`).
|
| 585 |
+
"""
|
| 586 |
+
),
|
| 587 |
+
] = True,
|
| 588 |
+
json_schema_extra: Annotated[
|
| 589 |
+
Union[Dict[str, Any], None],
|
| 590 |
+
Doc(
|
| 591 |
+
"""
|
| 592 |
+
Any additional JSON schema data.
|
| 593 |
+
"""
|
| 594 |
+
),
|
| 595 |
+
] = None,
|
| 596 |
+
**extra: Annotated[
|
| 597 |
+
Any,
|
| 598 |
+
Doc(
|
| 599 |
+
"""
|
| 600 |
+
Include extra fields used by the JSON Schema.
|
| 601 |
+
"""
|
| 602 |
+
),
|
| 603 |
+
deprecated(
|
| 604 |
+
"""
|
| 605 |
+
The `extra` kwargs is deprecated. Use `json_schema_extra` instead.
|
| 606 |
+
"""
|
| 607 |
+
),
|
| 608 |
+
],
|
| 609 |
+
) -> Any:
|
| 610 |
+
return params.Query(
|
| 611 |
+
default=default,
|
| 612 |
+
default_factory=default_factory,
|
| 613 |
+
alias=alias,
|
| 614 |
+
alias_priority=alias_priority,
|
| 615 |
+
validation_alias=validation_alias,
|
| 616 |
+
serialization_alias=serialization_alias,
|
| 617 |
+
title=title,
|
| 618 |
+
description=description,
|
| 619 |
+
gt=gt,
|
| 620 |
+
ge=ge,
|
| 621 |
+
lt=lt,
|
| 622 |
+
le=le,
|
| 623 |
+
min_length=min_length,
|
| 624 |
+
max_length=max_length,
|
| 625 |
+
pattern=pattern,
|
| 626 |
+
regex=regex,
|
| 627 |
+
discriminator=discriminator,
|
| 628 |
+
strict=strict,
|
| 629 |
+
multiple_of=multiple_of,
|
| 630 |
+
allow_inf_nan=allow_inf_nan,
|
| 631 |
+
max_digits=max_digits,
|
| 632 |
+
decimal_places=decimal_places,
|
| 633 |
+
example=example,
|
| 634 |
+
examples=examples,
|
| 635 |
+
openapi_examples=openapi_examples,
|
| 636 |
+
deprecated=deprecated,
|
| 637 |
+
include_in_schema=include_in_schema,
|
| 638 |
+
json_schema_extra=json_schema_extra,
|
| 639 |
+
**extra,
|
| 640 |
+
)
|
| 641 |
+
|
| 642 |
+
|
| 643 |
+
def Header( # noqa: N802
|
| 644 |
+
default: Annotated[
|
| 645 |
+
Any,
|
| 646 |
+
Doc(
|
| 647 |
+
"""
|
| 648 |
+
Default value if the parameter field is not set.
|
| 649 |
+
"""
|
| 650 |
+
),
|
| 651 |
+
] = Undefined,
|
| 652 |
+
*,
|
| 653 |
+
default_factory: Annotated[
|
| 654 |
+
Union[Callable[[], Any], None],
|
| 655 |
+
Doc(
|
| 656 |
+
"""
|
| 657 |
+
A callable to generate the default value.
|
| 658 |
+
|
| 659 |
+
This doesn't affect `Path` parameters as the value is always required.
|
| 660 |
+
The parameter is available only for compatibility.
|
| 661 |
+
"""
|
| 662 |
+
),
|
| 663 |
+
] = _Unset,
|
| 664 |
+
alias: Annotated[
|
| 665 |
+
Optional[str],
|
| 666 |
+
Doc(
|
| 667 |
+
"""
|
| 668 |
+
An alternative name for the parameter field.
|
| 669 |
+
|
| 670 |
+
This will be used to extract the data and for the generated OpenAPI.
|
| 671 |
+
It is particularly useful when you can't use the name you want because it
|
| 672 |
+
is a Python reserved keyword or similar.
|
| 673 |
+
"""
|
| 674 |
+
),
|
| 675 |
+
] = None,
|
| 676 |
+
alias_priority: Annotated[
|
| 677 |
+
Union[int, None],
|
| 678 |
+
Doc(
|
| 679 |
+
"""
|
| 680 |
+
Priority of the alias. This affects whether an alias generator is used.
|
| 681 |
+
"""
|
| 682 |
+
),
|
| 683 |
+
] = _Unset,
|
| 684 |
+
# TODO: update when deprecating Pydantic v1, import these types
|
| 685 |
+
# validation_alias: str | AliasPath | AliasChoices | None
|
| 686 |
+
validation_alias: Annotated[
|
| 687 |
+
Union[str, None],
|
| 688 |
+
Doc(
|
| 689 |
+
"""
|
| 690 |
+
'Whitelist' validation step. The parameter field will be the single one
|
| 691 |
+
allowed by the alias or set of aliases defined.
|
| 692 |
+
"""
|
| 693 |
+
),
|
| 694 |
+
] = None,
|
| 695 |
+
serialization_alias: Annotated[
|
| 696 |
+
Union[str, None],
|
| 697 |
+
Doc(
|
| 698 |
+
"""
|
| 699 |
+
'Blacklist' validation step. The vanilla parameter field will be the
|
| 700 |
+
single one of the alias' or set of aliases' fields and all the other
|
| 701 |
+
fields will be ignored at serialization time.
|
| 702 |
+
"""
|
| 703 |
+
),
|
| 704 |
+
] = None,
|
| 705 |
+
convert_underscores: Annotated[
|
| 706 |
+
bool,
|
| 707 |
+
Doc(
|
| 708 |
+
"""
|
| 709 |
+
Automatically convert underscores to hyphens in the parameter field name.
|
| 710 |
+
|
| 711 |
+
Read more about it in the
|
| 712 |
+
[FastAPI docs for Header Parameters](https://fastapi.tiangolo.com/tutorial/header-params/#automatic-conversion)
|
| 713 |
+
"""
|
| 714 |
+
),
|
| 715 |
+
] = True,
|
| 716 |
+
title: Annotated[
|
| 717 |
+
Optional[str],
|
| 718 |
+
Doc(
|
| 719 |
+
"""
|
| 720 |
+
Human-readable title.
|
| 721 |
+
"""
|
| 722 |
+
),
|
| 723 |
+
] = None,
|
| 724 |
+
description: Annotated[
|
| 725 |
+
Optional[str],
|
| 726 |
+
Doc(
|
| 727 |
+
"""
|
| 728 |
+
Human-readable description.
|
| 729 |
+
"""
|
| 730 |
+
),
|
| 731 |
+
] = None,
|
| 732 |
+
gt: Annotated[
|
| 733 |
+
Optional[float],
|
| 734 |
+
Doc(
|
| 735 |
+
"""
|
| 736 |
+
Greater than. If set, value must be greater than this. Only applicable to
|
| 737 |
+
numbers.
|
| 738 |
+
"""
|
| 739 |
+
),
|
| 740 |
+
] = None,
|
| 741 |
+
ge: Annotated[
|
| 742 |
+
Optional[float],
|
| 743 |
+
Doc(
|
| 744 |
+
"""
|
| 745 |
+
Greater than or equal. If set, value must be greater than or equal to
|
| 746 |
+
this. Only applicable to numbers.
|
| 747 |
+
"""
|
| 748 |
+
),
|
| 749 |
+
] = None,
|
| 750 |
+
lt: Annotated[
|
| 751 |
+
Optional[float],
|
| 752 |
+
Doc(
|
| 753 |
+
"""
|
| 754 |
+
Less than. If set, value must be less than this. Only applicable to numbers.
|
| 755 |
+
"""
|
| 756 |
+
),
|
| 757 |
+
] = None,
|
| 758 |
+
le: Annotated[
|
| 759 |
+
Optional[float],
|
| 760 |
+
Doc(
|
| 761 |
+
"""
|
| 762 |
+
Less than or equal. If set, value must be less than or equal to this.
|
| 763 |
+
Only applicable to numbers.
|
| 764 |
+
"""
|
| 765 |
+
),
|
| 766 |
+
] = None,
|
| 767 |
+
min_length: Annotated[
|
| 768 |
+
Optional[int],
|
| 769 |
+
Doc(
|
| 770 |
+
"""
|
| 771 |
+
Minimum length for strings.
|
| 772 |
+
"""
|
| 773 |
+
),
|
| 774 |
+
] = None,
|
| 775 |
+
max_length: Annotated[
|
| 776 |
+
Optional[int],
|
| 777 |
+
Doc(
|
| 778 |
+
"""
|
| 779 |
+
Maximum length for strings.
|
| 780 |
+
"""
|
| 781 |
+
),
|
| 782 |
+
] = None,
|
| 783 |
+
pattern: Annotated[
|
| 784 |
+
Optional[str],
|
| 785 |
+
Doc(
|
| 786 |
+
"""
|
| 787 |
+
RegEx pattern for strings.
|
| 788 |
+
"""
|
| 789 |
+
),
|
| 790 |
+
] = None,
|
| 791 |
+
regex: Annotated[
|
| 792 |
+
Optional[str],
|
| 793 |
+
Doc(
|
| 794 |
+
"""
|
| 795 |
+
RegEx pattern for strings.
|
| 796 |
+
"""
|
| 797 |
+
),
|
| 798 |
+
deprecated(
|
| 799 |
+
"Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead."
|
| 800 |
+
),
|
| 801 |
+
] = None,
|
| 802 |
+
discriminator: Annotated[
|
| 803 |
+
Union[str, None],
|
| 804 |
+
Doc(
|
| 805 |
+
"""
|
| 806 |
+
Parameter field name for discriminating the type in a tagged union.
|
| 807 |
+
"""
|
| 808 |
+
),
|
| 809 |
+
] = None,
|
| 810 |
+
strict: Annotated[
|
| 811 |
+
Union[bool, None],
|
| 812 |
+
Doc(
|
| 813 |
+
"""
|
| 814 |
+
If `True`, strict validation is applied to the field.
|
| 815 |
+
"""
|
| 816 |
+
),
|
| 817 |
+
] = _Unset,
|
| 818 |
+
multiple_of: Annotated[
|
| 819 |
+
Union[float, None],
|
| 820 |
+
Doc(
|
| 821 |
+
"""
|
| 822 |
+
Value must be a multiple of this. Only applicable to numbers.
|
| 823 |
+
"""
|
| 824 |
+
),
|
| 825 |
+
] = _Unset,
|
| 826 |
+
allow_inf_nan: Annotated[
|
| 827 |
+
Union[bool, None],
|
| 828 |
+
Doc(
|
| 829 |
+
"""
|
| 830 |
+
Allow `inf`, `-inf`, `nan`. Only applicable to numbers.
|
| 831 |
+
"""
|
| 832 |
+
),
|
| 833 |
+
] = _Unset,
|
| 834 |
+
max_digits: Annotated[
|
| 835 |
+
Union[int, None],
|
| 836 |
+
Doc(
|
| 837 |
+
"""
|
| 838 |
+
Maximum number of allow digits for strings.
|
| 839 |
+
"""
|
| 840 |
+
),
|
| 841 |
+
] = _Unset,
|
| 842 |
+
decimal_places: Annotated[
|
| 843 |
+
Union[int, None],
|
| 844 |
+
Doc(
|
| 845 |
+
"""
|
| 846 |
+
Maximum number of decimal places allowed for numbers.
|
| 847 |
+
"""
|
| 848 |
+
),
|
| 849 |
+
] = _Unset,
|
| 850 |
+
examples: Annotated[
|
| 851 |
+
Optional[List[Any]],
|
| 852 |
+
Doc(
|
| 853 |
+
"""
|
| 854 |
+
Example values for this field.
|
| 855 |
+
"""
|
| 856 |
+
),
|
| 857 |
+
] = None,
|
| 858 |
+
example: Annotated[
|
| 859 |
+
Optional[Any],
|
| 860 |
+
deprecated(
|
| 861 |
+
"Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, "
|
| 862 |
+
"although still supported. Use examples instead."
|
| 863 |
+
),
|
| 864 |
+
] = _Unset,
|
| 865 |
+
openapi_examples: Annotated[
|
| 866 |
+
Optional[Dict[str, Example]],
|
| 867 |
+
Doc(
|
| 868 |
+
"""
|
| 869 |
+
OpenAPI-specific examples.
|
| 870 |
+
|
| 871 |
+
It will be added to the generated OpenAPI (e.g. visible at `/docs`).
|
| 872 |
+
|
| 873 |
+
Swagger UI (that provides the `/docs` interface) has better support for the
|
| 874 |
+
OpenAPI-specific examples than the JSON Schema `examples`, that's the main
|
| 875 |
+
use case for this.
|
| 876 |
+
|
| 877 |
+
Read more about it in the
|
| 878 |
+
[FastAPI docs for Declare Request Example Data](https://fastapi.tiangolo.com/tutorial/schema-extra-example/#using-the-openapi_examples-parameter).
|
| 879 |
+
"""
|
| 880 |
+
),
|
| 881 |
+
] = None,
|
| 882 |
+
deprecated: Annotated[
|
| 883 |
+
Union[deprecated, str, bool, None],
|
| 884 |
+
Doc(
|
| 885 |
+
"""
|
| 886 |
+
Mark this parameter field as deprecated.
|
| 887 |
+
|
| 888 |
+
It will affect the generated OpenAPI (e.g. visible at `/docs`).
|
| 889 |
+
"""
|
| 890 |
+
),
|
| 891 |
+
] = None,
|
| 892 |
+
include_in_schema: Annotated[
|
| 893 |
+
bool,
|
| 894 |
+
Doc(
|
| 895 |
+
"""
|
| 896 |
+
To include (or not) this parameter field in the generated OpenAPI.
|
| 897 |
+
You probably don't need it, but it's available.
|
| 898 |
+
|
| 899 |
+
This affects the generated OpenAPI (e.g. visible at `/docs`).
|
| 900 |
+
"""
|
| 901 |
+
),
|
| 902 |
+
] = True,
|
| 903 |
+
json_schema_extra: Annotated[
|
| 904 |
+
Union[Dict[str, Any], None],
|
| 905 |
+
Doc(
|
| 906 |
+
"""
|
| 907 |
+
Any additional JSON schema data.
|
| 908 |
+
"""
|
| 909 |
+
),
|
| 910 |
+
] = None,
|
| 911 |
+
**extra: Annotated[
|
| 912 |
+
Any,
|
| 913 |
+
Doc(
|
| 914 |
+
"""
|
| 915 |
+
Include extra fields used by the JSON Schema.
|
| 916 |
+
"""
|
| 917 |
+
),
|
| 918 |
+
deprecated(
|
| 919 |
+
"""
|
| 920 |
+
The `extra` kwargs is deprecated. Use `json_schema_extra` instead.
|
| 921 |
+
"""
|
| 922 |
+
),
|
| 923 |
+
],
|
| 924 |
+
) -> Any:
|
| 925 |
+
return params.Header(
|
| 926 |
+
default=default,
|
| 927 |
+
default_factory=default_factory,
|
| 928 |
+
alias=alias,
|
| 929 |
+
alias_priority=alias_priority,
|
| 930 |
+
validation_alias=validation_alias,
|
| 931 |
+
serialization_alias=serialization_alias,
|
| 932 |
+
convert_underscores=convert_underscores,
|
| 933 |
+
title=title,
|
| 934 |
+
description=description,
|
| 935 |
+
gt=gt,
|
| 936 |
+
ge=ge,
|
| 937 |
+
lt=lt,
|
| 938 |
+
le=le,
|
| 939 |
+
min_length=min_length,
|
| 940 |
+
max_length=max_length,
|
| 941 |
+
pattern=pattern,
|
| 942 |
+
regex=regex,
|
| 943 |
+
discriminator=discriminator,
|
| 944 |
+
strict=strict,
|
| 945 |
+
multiple_of=multiple_of,
|
| 946 |
+
allow_inf_nan=allow_inf_nan,
|
| 947 |
+
max_digits=max_digits,
|
| 948 |
+
decimal_places=decimal_places,
|
| 949 |
+
example=example,
|
| 950 |
+
examples=examples,
|
| 951 |
+
openapi_examples=openapi_examples,
|
| 952 |
+
deprecated=deprecated,
|
| 953 |
+
include_in_schema=include_in_schema,
|
| 954 |
+
json_schema_extra=json_schema_extra,
|
| 955 |
+
**extra,
|
| 956 |
+
)
|
| 957 |
+
|
| 958 |
+
|
| 959 |
+
def Cookie( # noqa: N802
|
| 960 |
+
default: Annotated[
|
| 961 |
+
Any,
|
| 962 |
+
Doc(
|
| 963 |
+
"""
|
| 964 |
+
Default value if the parameter field is not set.
|
| 965 |
+
"""
|
| 966 |
+
),
|
| 967 |
+
] = Undefined,
|
| 968 |
+
*,
|
| 969 |
+
default_factory: Annotated[
|
| 970 |
+
Union[Callable[[], Any], None],
|
| 971 |
+
Doc(
|
| 972 |
+
"""
|
| 973 |
+
A callable to generate the default value.
|
| 974 |
+
|
| 975 |
+
This doesn't affect `Path` parameters as the value is always required.
|
| 976 |
+
The parameter is available only for compatibility.
|
| 977 |
+
"""
|
| 978 |
+
),
|
| 979 |
+
] = _Unset,
|
| 980 |
+
alias: Annotated[
|
| 981 |
+
Optional[str],
|
| 982 |
+
Doc(
|
| 983 |
+
"""
|
| 984 |
+
An alternative name for the parameter field.
|
| 985 |
+
|
| 986 |
+
This will be used to extract the data and for the generated OpenAPI.
|
| 987 |
+
It is particularly useful when you can't use the name you want because it
|
| 988 |
+
is a Python reserved keyword or similar.
|
| 989 |
+
"""
|
| 990 |
+
),
|
| 991 |
+
] = None,
|
| 992 |
+
alias_priority: Annotated[
|
| 993 |
+
Union[int, None],
|
| 994 |
+
Doc(
|
| 995 |
+
"""
|
| 996 |
+
Priority of the alias. This affects whether an alias generator is used.
|
| 997 |
+
"""
|
| 998 |
+
),
|
| 999 |
+
] = _Unset,
|
| 1000 |
+
# TODO: update when deprecating Pydantic v1, import these types
|
| 1001 |
+
# validation_alias: str | AliasPath | AliasChoices | None
|
| 1002 |
+
validation_alias: Annotated[
|
| 1003 |
+
Union[str, None],
|
| 1004 |
+
Doc(
|
| 1005 |
+
"""
|
| 1006 |
+
'Whitelist' validation step. The parameter field will be the single one
|
| 1007 |
+
allowed by the alias or set of aliases defined.
|
| 1008 |
+
"""
|
| 1009 |
+
),
|
| 1010 |
+
] = None,
|
| 1011 |
+
serialization_alias: Annotated[
|
| 1012 |
+
Union[str, None],
|
| 1013 |
+
Doc(
|
| 1014 |
+
"""
|
| 1015 |
+
'Blacklist' validation step. The vanilla parameter field will be the
|
| 1016 |
+
single one of the alias' or set of aliases' fields and all the other
|
| 1017 |
+
fields will be ignored at serialization time.
|
| 1018 |
+
"""
|
| 1019 |
+
),
|
| 1020 |
+
] = None,
|
| 1021 |
+
title: Annotated[
|
| 1022 |
+
Optional[str],
|
| 1023 |
+
Doc(
|
| 1024 |
+
"""
|
| 1025 |
+
Human-readable title.
|
| 1026 |
+
"""
|
| 1027 |
+
),
|
| 1028 |
+
] = None,
|
| 1029 |
+
description: Annotated[
|
| 1030 |
+
Optional[str],
|
| 1031 |
+
Doc(
|
| 1032 |
+
"""
|
| 1033 |
+
Human-readable description.
|
| 1034 |
+
"""
|
| 1035 |
+
),
|
| 1036 |
+
] = None,
|
| 1037 |
+
gt: Annotated[
|
| 1038 |
+
Optional[float],
|
| 1039 |
+
Doc(
|
| 1040 |
+
"""
|
| 1041 |
+
Greater than. If set, value must be greater than this. Only applicable to
|
| 1042 |
+
numbers.
|
| 1043 |
+
"""
|
| 1044 |
+
),
|
| 1045 |
+
] = None,
|
| 1046 |
+
ge: Annotated[
|
| 1047 |
+
Optional[float],
|
| 1048 |
+
Doc(
|
| 1049 |
+
"""
|
| 1050 |
+
Greater than or equal. If set, value must be greater than or equal to
|
| 1051 |
+
this. Only applicable to numbers.
|
| 1052 |
+
"""
|
| 1053 |
+
),
|
| 1054 |
+
] = None,
|
| 1055 |
+
lt: Annotated[
|
| 1056 |
+
Optional[float],
|
| 1057 |
+
Doc(
|
| 1058 |
+
"""
|
| 1059 |
+
Less than. If set, value must be less than this. Only applicable to numbers.
|
| 1060 |
+
"""
|
| 1061 |
+
),
|
| 1062 |
+
] = None,
|
| 1063 |
+
le: Annotated[
|
| 1064 |
+
Optional[float],
|
| 1065 |
+
Doc(
|
| 1066 |
+
"""
|
| 1067 |
+
Less than or equal. If set, value must be less than or equal to this.
|
| 1068 |
+
Only applicable to numbers.
|
| 1069 |
+
"""
|
| 1070 |
+
),
|
| 1071 |
+
] = None,
|
| 1072 |
+
min_length: Annotated[
|
| 1073 |
+
Optional[int],
|
| 1074 |
+
Doc(
|
| 1075 |
+
"""
|
| 1076 |
+
Minimum length for strings.
|
| 1077 |
+
"""
|
| 1078 |
+
),
|
| 1079 |
+
] = None,
|
| 1080 |
+
max_length: Annotated[
|
| 1081 |
+
Optional[int],
|
| 1082 |
+
Doc(
|
| 1083 |
+
"""
|
| 1084 |
+
Maximum length for strings.
|
| 1085 |
+
"""
|
| 1086 |
+
),
|
| 1087 |
+
] = None,
|
| 1088 |
+
pattern: Annotated[
|
| 1089 |
+
Optional[str],
|
| 1090 |
+
Doc(
|
| 1091 |
+
"""
|
| 1092 |
+
RegEx pattern for strings.
|
| 1093 |
+
"""
|
| 1094 |
+
),
|
| 1095 |
+
] = None,
|
| 1096 |
+
regex: Annotated[
|
| 1097 |
+
Optional[str],
|
| 1098 |
+
Doc(
|
| 1099 |
+
"""
|
| 1100 |
+
RegEx pattern for strings.
|
| 1101 |
+
"""
|
| 1102 |
+
),
|
| 1103 |
+
deprecated(
|
| 1104 |
+
"Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead."
|
| 1105 |
+
),
|
| 1106 |
+
] = None,
|
| 1107 |
+
discriminator: Annotated[
|
| 1108 |
+
Union[str, None],
|
| 1109 |
+
Doc(
|
| 1110 |
+
"""
|
| 1111 |
+
Parameter field name for discriminating the type in a tagged union.
|
| 1112 |
+
"""
|
| 1113 |
+
),
|
| 1114 |
+
] = None,
|
| 1115 |
+
strict: Annotated[
|
| 1116 |
+
Union[bool, None],
|
| 1117 |
+
Doc(
|
| 1118 |
+
"""
|
| 1119 |
+
If `True`, strict validation is applied to the field.
|
| 1120 |
+
"""
|
| 1121 |
+
),
|
| 1122 |
+
] = _Unset,
|
| 1123 |
+
multiple_of: Annotated[
|
| 1124 |
+
Union[float, None],
|
| 1125 |
+
Doc(
|
| 1126 |
+
"""
|
| 1127 |
+
Value must be a multiple of this. Only applicable to numbers.
|
| 1128 |
+
"""
|
| 1129 |
+
),
|
| 1130 |
+
] = _Unset,
|
| 1131 |
+
allow_inf_nan: Annotated[
|
| 1132 |
+
Union[bool, None],
|
| 1133 |
+
Doc(
|
| 1134 |
+
"""
|
| 1135 |
+
Allow `inf`, `-inf`, `nan`. Only applicable to numbers.
|
| 1136 |
+
"""
|
| 1137 |
+
),
|
| 1138 |
+
] = _Unset,
|
| 1139 |
+
max_digits: Annotated[
|
| 1140 |
+
Union[int, None],
|
| 1141 |
+
Doc(
|
| 1142 |
+
"""
|
| 1143 |
+
Maximum number of allow digits for strings.
|
| 1144 |
+
"""
|
| 1145 |
+
),
|
| 1146 |
+
] = _Unset,
|
| 1147 |
+
decimal_places: Annotated[
|
| 1148 |
+
Union[int, None],
|
| 1149 |
+
Doc(
|
| 1150 |
+
"""
|
| 1151 |
+
Maximum number of decimal places allowed for numbers.
|
| 1152 |
+
"""
|
| 1153 |
+
),
|
| 1154 |
+
] = _Unset,
|
| 1155 |
+
examples: Annotated[
|
| 1156 |
+
Optional[List[Any]],
|
| 1157 |
+
Doc(
|
| 1158 |
+
"""
|
| 1159 |
+
Example values for this field.
|
| 1160 |
+
"""
|
| 1161 |
+
),
|
| 1162 |
+
] = None,
|
| 1163 |
+
example: Annotated[
|
| 1164 |
+
Optional[Any],
|
| 1165 |
+
deprecated(
|
| 1166 |
+
"Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, "
|
| 1167 |
+
"although still supported. Use examples instead."
|
| 1168 |
+
),
|
| 1169 |
+
] = _Unset,
|
| 1170 |
+
openapi_examples: Annotated[
|
| 1171 |
+
Optional[Dict[str, Example]],
|
| 1172 |
+
Doc(
|
| 1173 |
+
"""
|
| 1174 |
+
OpenAPI-specific examples.
|
| 1175 |
+
|
| 1176 |
+
It will be added to the generated OpenAPI (e.g. visible at `/docs`).
|
| 1177 |
+
|
| 1178 |
+
Swagger UI (that provides the `/docs` interface) has better support for the
|
| 1179 |
+
OpenAPI-specific examples than the JSON Schema `examples`, that's the main
|
| 1180 |
+
use case for this.
|
| 1181 |
+
|
| 1182 |
+
Read more about it in the
|
| 1183 |
+
[FastAPI docs for Declare Request Example Data](https://fastapi.tiangolo.com/tutorial/schema-extra-example/#using-the-openapi_examples-parameter).
|
| 1184 |
+
"""
|
| 1185 |
+
),
|
| 1186 |
+
] = None,
|
| 1187 |
+
deprecated: Annotated[
|
| 1188 |
+
Union[deprecated, str, bool, None],
|
| 1189 |
+
Doc(
|
| 1190 |
+
"""
|
| 1191 |
+
Mark this parameter field as deprecated.
|
| 1192 |
+
|
| 1193 |
+
It will affect the generated OpenAPI (e.g. visible at `/docs`).
|
| 1194 |
+
"""
|
| 1195 |
+
),
|
| 1196 |
+
] = None,
|
| 1197 |
+
include_in_schema: Annotated[
|
| 1198 |
+
bool,
|
| 1199 |
+
Doc(
|
| 1200 |
+
"""
|
| 1201 |
+
To include (or not) this parameter field in the generated OpenAPI.
|
| 1202 |
+
You probably don't need it, but it's available.
|
| 1203 |
+
|
| 1204 |
+
This affects the generated OpenAPI (e.g. visible at `/docs`).
|
| 1205 |
+
"""
|
| 1206 |
+
),
|
| 1207 |
+
] = True,
|
| 1208 |
+
json_schema_extra: Annotated[
|
| 1209 |
+
Union[Dict[str, Any], None],
|
| 1210 |
+
Doc(
|
| 1211 |
+
"""
|
| 1212 |
+
Any additional JSON schema data.
|
| 1213 |
+
"""
|
| 1214 |
+
),
|
| 1215 |
+
] = None,
|
| 1216 |
+
**extra: Annotated[
|
| 1217 |
+
Any,
|
| 1218 |
+
Doc(
|
| 1219 |
+
"""
|
| 1220 |
+
Include extra fields used by the JSON Schema.
|
| 1221 |
+
"""
|
| 1222 |
+
),
|
| 1223 |
+
deprecated(
|
| 1224 |
+
"""
|
| 1225 |
+
The `extra` kwargs is deprecated. Use `json_schema_extra` instead.
|
| 1226 |
+
"""
|
| 1227 |
+
),
|
| 1228 |
+
],
|
| 1229 |
+
) -> Any:
|
| 1230 |
+
return params.Cookie(
|
| 1231 |
+
default=default,
|
| 1232 |
+
default_factory=default_factory,
|
| 1233 |
+
alias=alias,
|
| 1234 |
+
alias_priority=alias_priority,
|
| 1235 |
+
validation_alias=validation_alias,
|
| 1236 |
+
serialization_alias=serialization_alias,
|
| 1237 |
+
title=title,
|
| 1238 |
+
description=description,
|
| 1239 |
+
gt=gt,
|
| 1240 |
+
ge=ge,
|
| 1241 |
+
lt=lt,
|
| 1242 |
+
le=le,
|
| 1243 |
+
min_length=min_length,
|
| 1244 |
+
max_length=max_length,
|
| 1245 |
+
pattern=pattern,
|
| 1246 |
+
regex=regex,
|
| 1247 |
+
discriminator=discriminator,
|
| 1248 |
+
strict=strict,
|
| 1249 |
+
multiple_of=multiple_of,
|
| 1250 |
+
allow_inf_nan=allow_inf_nan,
|
| 1251 |
+
max_digits=max_digits,
|
| 1252 |
+
decimal_places=decimal_places,
|
| 1253 |
+
example=example,
|
| 1254 |
+
examples=examples,
|
| 1255 |
+
openapi_examples=openapi_examples,
|
| 1256 |
+
deprecated=deprecated,
|
| 1257 |
+
include_in_schema=include_in_schema,
|
| 1258 |
+
json_schema_extra=json_schema_extra,
|
| 1259 |
+
**extra,
|
| 1260 |
+
)
|
| 1261 |
+
|
| 1262 |
+
|
| 1263 |
+
def Body( # noqa: N802
|
| 1264 |
+
default: Annotated[
|
| 1265 |
+
Any,
|
| 1266 |
+
Doc(
|
| 1267 |
+
"""
|
| 1268 |
+
Default value if the parameter field is not set.
|
| 1269 |
+
"""
|
| 1270 |
+
),
|
| 1271 |
+
] = Undefined,
|
| 1272 |
+
*,
|
| 1273 |
+
default_factory: Annotated[
|
| 1274 |
+
Union[Callable[[], Any], None],
|
| 1275 |
+
Doc(
|
| 1276 |
+
"""
|
| 1277 |
+
A callable to generate the default value.
|
| 1278 |
+
|
| 1279 |
+
This doesn't affect `Path` parameters as the value is always required.
|
| 1280 |
+
The parameter is available only for compatibility.
|
| 1281 |
+
"""
|
| 1282 |
+
),
|
| 1283 |
+
] = _Unset,
|
| 1284 |
+
embed: Annotated[
|
| 1285 |
+
Union[bool, None],
|
| 1286 |
+
Doc(
|
| 1287 |
+
"""
|
| 1288 |
+
When `embed` is `True`, the parameter will be expected in a JSON body as a
|
| 1289 |
+
key instead of being the JSON body itself.
|
| 1290 |
+
|
| 1291 |
+
This happens automatically when more than one `Body` parameter is declared.
|
| 1292 |
+
|
| 1293 |
+
Read more about it in the
|
| 1294 |
+
[FastAPI docs for Body - Multiple Parameters](https://fastapi.tiangolo.com/tutorial/body-multiple-params/#embed-a-single-body-parameter).
|
| 1295 |
+
"""
|
| 1296 |
+
),
|
| 1297 |
+
] = None,
|
| 1298 |
+
media_type: Annotated[
|
| 1299 |
+
str,
|
| 1300 |
+
Doc(
|
| 1301 |
+
"""
|
| 1302 |
+
The media type of this parameter field. Changing it would affect the
|
| 1303 |
+
generated OpenAPI, but currently it doesn't affect the parsing of the data.
|
| 1304 |
+
"""
|
| 1305 |
+
),
|
| 1306 |
+
] = "application/json",
|
| 1307 |
+
alias: Annotated[
|
| 1308 |
+
Optional[str],
|
| 1309 |
+
Doc(
|
| 1310 |
+
"""
|
| 1311 |
+
An alternative name for the parameter field.
|
| 1312 |
+
|
| 1313 |
+
This will be used to extract the data and for the generated OpenAPI.
|
| 1314 |
+
It is particularly useful when you can't use the name you want because it
|
| 1315 |
+
is a Python reserved keyword or similar.
|
| 1316 |
+
"""
|
| 1317 |
+
),
|
| 1318 |
+
] = None,
|
| 1319 |
+
alias_priority: Annotated[
|
| 1320 |
+
Union[int, None],
|
| 1321 |
+
Doc(
|
| 1322 |
+
"""
|
| 1323 |
+
Priority of the alias. This affects whether an alias generator is used.
|
| 1324 |
+
"""
|
| 1325 |
+
),
|
| 1326 |
+
] = _Unset,
|
| 1327 |
+
# TODO: update when deprecating Pydantic v1, import these types
|
| 1328 |
+
# validation_alias: str | AliasPath | AliasChoices | None
|
| 1329 |
+
validation_alias: Annotated[
|
| 1330 |
+
Union[str, None],
|
| 1331 |
+
Doc(
|
| 1332 |
+
"""
|
| 1333 |
+
'Whitelist' validation step. The parameter field will be the single one
|
| 1334 |
+
allowed by the alias or set of aliases defined.
|
| 1335 |
+
"""
|
| 1336 |
+
),
|
| 1337 |
+
] = None,
|
| 1338 |
+
serialization_alias: Annotated[
|
| 1339 |
+
Union[str, None],
|
| 1340 |
+
Doc(
|
| 1341 |
+
"""
|
| 1342 |
+
'Blacklist' validation step. The vanilla parameter field will be the
|
| 1343 |
+
single one of the alias' or set of aliases' fields and all the other
|
| 1344 |
+
fields will be ignored at serialization time.
|
| 1345 |
+
"""
|
| 1346 |
+
),
|
| 1347 |
+
] = None,
|
| 1348 |
+
title: Annotated[
|
| 1349 |
+
Optional[str],
|
| 1350 |
+
Doc(
|
| 1351 |
+
"""
|
| 1352 |
+
Human-readable title.
|
| 1353 |
+
"""
|
| 1354 |
+
),
|
| 1355 |
+
] = None,
|
| 1356 |
+
description: Annotated[
|
| 1357 |
+
Optional[str],
|
| 1358 |
+
Doc(
|
| 1359 |
+
"""
|
| 1360 |
+
Human-readable description.
|
| 1361 |
+
"""
|
| 1362 |
+
),
|
| 1363 |
+
] = None,
|
| 1364 |
+
gt: Annotated[
|
| 1365 |
+
Optional[float],
|
| 1366 |
+
Doc(
|
| 1367 |
+
"""
|
| 1368 |
+
Greater than. If set, value must be greater than this. Only applicable to
|
| 1369 |
+
numbers.
|
| 1370 |
+
"""
|
| 1371 |
+
),
|
| 1372 |
+
] = None,
|
| 1373 |
+
ge: Annotated[
|
| 1374 |
+
Optional[float],
|
| 1375 |
+
Doc(
|
| 1376 |
+
"""
|
| 1377 |
+
Greater than or equal. If set, value must be greater than or equal to
|
| 1378 |
+
this. Only applicable to numbers.
|
| 1379 |
+
"""
|
| 1380 |
+
),
|
| 1381 |
+
] = None,
|
| 1382 |
+
lt: Annotated[
|
| 1383 |
+
Optional[float],
|
| 1384 |
+
Doc(
|
| 1385 |
+
"""
|
| 1386 |
+
Less than. If set, value must be less than this. Only applicable to numbers.
|
| 1387 |
+
"""
|
| 1388 |
+
),
|
| 1389 |
+
] = None,
|
| 1390 |
+
le: Annotated[
|
| 1391 |
+
Optional[float],
|
| 1392 |
+
Doc(
|
| 1393 |
+
"""
|
| 1394 |
+
Less than or equal. If set, value must be less than or equal to this.
|
| 1395 |
+
Only applicable to numbers.
|
| 1396 |
+
"""
|
| 1397 |
+
),
|
| 1398 |
+
] = None,
|
| 1399 |
+
min_length: Annotated[
|
| 1400 |
+
Optional[int],
|
| 1401 |
+
Doc(
|
| 1402 |
+
"""
|
| 1403 |
+
Minimum length for strings.
|
| 1404 |
+
"""
|
| 1405 |
+
),
|
| 1406 |
+
] = None,
|
| 1407 |
+
max_length: Annotated[
|
| 1408 |
+
Optional[int],
|
| 1409 |
+
Doc(
|
| 1410 |
+
"""
|
| 1411 |
+
Maximum length for strings.
|
| 1412 |
+
"""
|
| 1413 |
+
),
|
| 1414 |
+
] = None,
|
| 1415 |
+
pattern: Annotated[
|
| 1416 |
+
Optional[str],
|
| 1417 |
+
Doc(
|
| 1418 |
+
"""
|
| 1419 |
+
RegEx pattern for strings.
|
| 1420 |
+
"""
|
| 1421 |
+
),
|
| 1422 |
+
] = None,
|
| 1423 |
+
regex: Annotated[
|
| 1424 |
+
Optional[str],
|
| 1425 |
+
Doc(
|
| 1426 |
+
"""
|
| 1427 |
+
RegEx pattern for strings.
|
| 1428 |
+
"""
|
| 1429 |
+
),
|
| 1430 |
+
deprecated(
|
| 1431 |
+
"Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead."
|
| 1432 |
+
),
|
| 1433 |
+
] = None,
|
| 1434 |
+
discriminator: Annotated[
|
| 1435 |
+
Union[str, None],
|
| 1436 |
+
Doc(
|
| 1437 |
+
"""
|
| 1438 |
+
Parameter field name for discriminating the type in a tagged union.
|
| 1439 |
+
"""
|
| 1440 |
+
),
|
| 1441 |
+
] = None,
|
| 1442 |
+
strict: Annotated[
|
| 1443 |
+
Union[bool, None],
|
| 1444 |
+
Doc(
|
| 1445 |
+
"""
|
| 1446 |
+
If `True`, strict validation is applied to the field.
|
| 1447 |
+
"""
|
| 1448 |
+
),
|
| 1449 |
+
] = _Unset,
|
| 1450 |
+
multiple_of: Annotated[
|
| 1451 |
+
Union[float, None],
|
| 1452 |
+
Doc(
|
| 1453 |
+
"""
|
| 1454 |
+
Value must be a multiple of this. Only applicable to numbers.
|
| 1455 |
+
"""
|
| 1456 |
+
),
|
| 1457 |
+
] = _Unset,
|
| 1458 |
+
allow_inf_nan: Annotated[
|
| 1459 |
+
Union[bool, None],
|
| 1460 |
+
Doc(
|
| 1461 |
+
"""
|
| 1462 |
+
Allow `inf`, `-inf`, `nan`. Only applicable to numbers.
|
| 1463 |
+
"""
|
| 1464 |
+
),
|
| 1465 |
+
] = _Unset,
|
| 1466 |
+
max_digits: Annotated[
|
| 1467 |
+
Union[int, None],
|
| 1468 |
+
Doc(
|
| 1469 |
+
"""
|
| 1470 |
+
Maximum number of allow digits for strings.
|
| 1471 |
+
"""
|
| 1472 |
+
),
|
| 1473 |
+
] = _Unset,
|
| 1474 |
+
decimal_places: Annotated[
|
| 1475 |
+
Union[int, None],
|
| 1476 |
+
Doc(
|
| 1477 |
+
"""
|
| 1478 |
+
Maximum number of decimal places allowed for numbers.
|
| 1479 |
+
"""
|
| 1480 |
+
),
|
| 1481 |
+
] = _Unset,
|
| 1482 |
+
examples: Annotated[
|
| 1483 |
+
Optional[List[Any]],
|
| 1484 |
+
Doc(
|
| 1485 |
+
"""
|
| 1486 |
+
Example values for this field.
|
| 1487 |
+
"""
|
| 1488 |
+
),
|
| 1489 |
+
] = None,
|
| 1490 |
+
example: Annotated[
|
| 1491 |
+
Optional[Any],
|
| 1492 |
+
deprecated(
|
| 1493 |
+
"Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, "
|
| 1494 |
+
"although still supported. Use examples instead."
|
| 1495 |
+
),
|
| 1496 |
+
] = _Unset,
|
| 1497 |
+
openapi_examples: Annotated[
|
| 1498 |
+
Optional[Dict[str, Example]],
|
| 1499 |
+
Doc(
|
| 1500 |
+
"""
|
| 1501 |
+
OpenAPI-specific examples.
|
| 1502 |
+
|
| 1503 |
+
It will be added to the generated OpenAPI (e.g. visible at `/docs`).
|
| 1504 |
+
|
| 1505 |
+
Swagger UI (that provides the `/docs` interface) has better support for the
|
| 1506 |
+
OpenAPI-specific examples than the JSON Schema `examples`, that's the main
|
| 1507 |
+
use case for this.
|
| 1508 |
+
|
| 1509 |
+
Read more about it in the
|
| 1510 |
+
[FastAPI docs for Declare Request Example Data](https://fastapi.tiangolo.com/tutorial/schema-extra-example/#using-the-openapi_examples-parameter).
|
| 1511 |
+
"""
|
| 1512 |
+
),
|
| 1513 |
+
] = None,
|
| 1514 |
+
deprecated: Annotated[
|
| 1515 |
+
Union[deprecated, str, bool, None],
|
| 1516 |
+
Doc(
|
| 1517 |
+
"""
|
| 1518 |
+
Mark this parameter field as deprecated.
|
| 1519 |
+
|
| 1520 |
+
It will affect the generated OpenAPI (e.g. visible at `/docs`).
|
| 1521 |
+
"""
|
| 1522 |
+
),
|
| 1523 |
+
] = None,
|
| 1524 |
+
include_in_schema: Annotated[
|
| 1525 |
+
bool,
|
| 1526 |
+
Doc(
|
| 1527 |
+
"""
|
| 1528 |
+
To include (or not) this parameter field in the generated OpenAPI.
|
| 1529 |
+
You probably don't need it, but it's available.
|
| 1530 |
+
|
| 1531 |
+
This affects the generated OpenAPI (e.g. visible at `/docs`).
|
| 1532 |
+
"""
|
| 1533 |
+
),
|
| 1534 |
+
] = True,
|
| 1535 |
+
json_schema_extra: Annotated[
|
| 1536 |
+
Union[Dict[str, Any], None],
|
| 1537 |
+
Doc(
|
| 1538 |
+
"""
|
| 1539 |
+
Any additional JSON schema data.
|
| 1540 |
+
"""
|
| 1541 |
+
),
|
| 1542 |
+
] = None,
|
| 1543 |
+
**extra: Annotated[
|
| 1544 |
+
Any,
|
| 1545 |
+
Doc(
|
| 1546 |
+
"""
|
| 1547 |
+
Include extra fields used by the JSON Schema.
|
| 1548 |
+
"""
|
| 1549 |
+
),
|
| 1550 |
+
deprecated(
|
| 1551 |
+
"""
|
| 1552 |
+
The `extra` kwargs is deprecated. Use `json_schema_extra` instead.
|
| 1553 |
+
"""
|
| 1554 |
+
),
|
| 1555 |
+
],
|
| 1556 |
+
) -> Any:
|
| 1557 |
+
return params.Body(
|
| 1558 |
+
default=default,
|
| 1559 |
+
default_factory=default_factory,
|
| 1560 |
+
embed=embed,
|
| 1561 |
+
media_type=media_type,
|
| 1562 |
+
alias=alias,
|
| 1563 |
+
alias_priority=alias_priority,
|
| 1564 |
+
validation_alias=validation_alias,
|
| 1565 |
+
serialization_alias=serialization_alias,
|
| 1566 |
+
title=title,
|
| 1567 |
+
description=description,
|
| 1568 |
+
gt=gt,
|
| 1569 |
+
ge=ge,
|
| 1570 |
+
lt=lt,
|
| 1571 |
+
le=le,
|
| 1572 |
+
min_length=min_length,
|
| 1573 |
+
max_length=max_length,
|
| 1574 |
+
pattern=pattern,
|
| 1575 |
+
regex=regex,
|
| 1576 |
+
discriminator=discriminator,
|
| 1577 |
+
strict=strict,
|
| 1578 |
+
multiple_of=multiple_of,
|
| 1579 |
+
allow_inf_nan=allow_inf_nan,
|
| 1580 |
+
max_digits=max_digits,
|
| 1581 |
+
decimal_places=decimal_places,
|
| 1582 |
+
example=example,
|
| 1583 |
+
examples=examples,
|
| 1584 |
+
openapi_examples=openapi_examples,
|
| 1585 |
+
deprecated=deprecated,
|
| 1586 |
+
include_in_schema=include_in_schema,
|
| 1587 |
+
json_schema_extra=json_schema_extra,
|
| 1588 |
+
**extra,
|
| 1589 |
+
)
|
| 1590 |
+
|
| 1591 |
+
|
| 1592 |
+
def Form( # noqa: N802
|
| 1593 |
+
default: Annotated[
|
| 1594 |
+
Any,
|
| 1595 |
+
Doc(
|
| 1596 |
+
"""
|
| 1597 |
+
Default value if the parameter field is not set.
|
| 1598 |
+
"""
|
| 1599 |
+
),
|
| 1600 |
+
] = Undefined,
|
| 1601 |
+
*,
|
| 1602 |
+
default_factory: Annotated[
|
| 1603 |
+
Union[Callable[[], Any], None],
|
| 1604 |
+
Doc(
|
| 1605 |
+
"""
|
| 1606 |
+
A callable to generate the default value.
|
| 1607 |
+
|
| 1608 |
+
This doesn't affect `Path` parameters as the value is always required.
|
| 1609 |
+
The parameter is available only for compatibility.
|
| 1610 |
+
"""
|
| 1611 |
+
),
|
| 1612 |
+
] = _Unset,
|
| 1613 |
+
media_type: Annotated[
|
| 1614 |
+
str,
|
| 1615 |
+
Doc(
|
| 1616 |
+
"""
|
| 1617 |
+
The media type of this parameter field. Changing it would affect the
|
| 1618 |
+
generated OpenAPI, but currently it doesn't affect the parsing of the data.
|
| 1619 |
+
"""
|
| 1620 |
+
),
|
| 1621 |
+
] = "application/x-www-form-urlencoded",
|
| 1622 |
+
alias: Annotated[
|
| 1623 |
+
Optional[str],
|
| 1624 |
+
Doc(
|
| 1625 |
+
"""
|
| 1626 |
+
An alternative name for the parameter field.
|
| 1627 |
+
|
| 1628 |
+
This will be used to extract the data and for the generated OpenAPI.
|
| 1629 |
+
It is particularly useful when you can't use the name you want because it
|
| 1630 |
+
is a Python reserved keyword or similar.
|
| 1631 |
+
"""
|
| 1632 |
+
),
|
| 1633 |
+
] = None,
|
| 1634 |
+
alias_priority: Annotated[
|
| 1635 |
+
Union[int, None],
|
| 1636 |
+
Doc(
|
| 1637 |
+
"""
|
| 1638 |
+
Priority of the alias. This affects whether an alias generator is used.
|
| 1639 |
+
"""
|
| 1640 |
+
),
|
| 1641 |
+
] = _Unset,
|
| 1642 |
+
# TODO: update when deprecating Pydantic v1, import these types
|
| 1643 |
+
# validation_alias: str | AliasPath | AliasChoices | None
|
| 1644 |
+
validation_alias: Annotated[
|
| 1645 |
+
Union[str, None],
|
| 1646 |
+
Doc(
|
| 1647 |
+
"""
|
| 1648 |
+
'Whitelist' validation step. The parameter field will be the single one
|
| 1649 |
+
allowed by the alias or set of aliases defined.
|
| 1650 |
+
"""
|
| 1651 |
+
),
|
| 1652 |
+
] = None,
|
| 1653 |
+
serialization_alias: Annotated[
|
| 1654 |
+
Union[str, None],
|
| 1655 |
+
Doc(
|
| 1656 |
+
"""
|
| 1657 |
+
'Blacklist' validation step. The vanilla parameter field will be the
|
| 1658 |
+
single one of the alias' or set of aliases' fields and all the other
|
| 1659 |
+
fields will be ignored at serialization time.
|
| 1660 |
+
"""
|
| 1661 |
+
),
|
| 1662 |
+
] = None,
|
| 1663 |
+
title: Annotated[
|
| 1664 |
+
Optional[str],
|
| 1665 |
+
Doc(
|
| 1666 |
+
"""
|
| 1667 |
+
Human-readable title.
|
| 1668 |
+
"""
|
| 1669 |
+
),
|
| 1670 |
+
] = None,
|
| 1671 |
+
description: Annotated[
|
| 1672 |
+
Optional[str],
|
| 1673 |
+
Doc(
|
| 1674 |
+
"""
|
| 1675 |
+
Human-readable description.
|
| 1676 |
+
"""
|
| 1677 |
+
),
|
| 1678 |
+
] = None,
|
| 1679 |
+
gt: Annotated[
|
| 1680 |
+
Optional[float],
|
| 1681 |
+
Doc(
|
| 1682 |
+
"""
|
| 1683 |
+
Greater than. If set, value must be greater than this. Only applicable to
|
| 1684 |
+
numbers.
|
| 1685 |
+
"""
|
| 1686 |
+
),
|
| 1687 |
+
] = None,
|
| 1688 |
+
ge: Annotated[
|
| 1689 |
+
Optional[float],
|
| 1690 |
+
Doc(
|
| 1691 |
+
"""
|
| 1692 |
+
Greater than or equal. If set, value must be greater than or equal to
|
| 1693 |
+
this. Only applicable to numbers.
|
| 1694 |
+
"""
|
| 1695 |
+
),
|
| 1696 |
+
] = None,
|
| 1697 |
+
lt: Annotated[
|
| 1698 |
+
Optional[float],
|
| 1699 |
+
Doc(
|
| 1700 |
+
"""
|
| 1701 |
+
Less than. If set, value must be less than this. Only applicable to numbers.
|
| 1702 |
+
"""
|
| 1703 |
+
),
|
| 1704 |
+
] = None,
|
| 1705 |
+
le: Annotated[
|
| 1706 |
+
Optional[float],
|
| 1707 |
+
Doc(
|
| 1708 |
+
"""
|
| 1709 |
+
Less than or equal. If set, value must be less than or equal to this.
|
| 1710 |
+
Only applicable to numbers.
|
| 1711 |
+
"""
|
| 1712 |
+
),
|
| 1713 |
+
] = None,
|
| 1714 |
+
min_length: Annotated[
|
| 1715 |
+
Optional[int],
|
| 1716 |
+
Doc(
|
| 1717 |
+
"""
|
| 1718 |
+
Minimum length for strings.
|
| 1719 |
+
"""
|
| 1720 |
+
),
|
| 1721 |
+
] = None,
|
| 1722 |
+
max_length: Annotated[
|
| 1723 |
+
Optional[int],
|
| 1724 |
+
Doc(
|
| 1725 |
+
"""
|
| 1726 |
+
Maximum length for strings.
|
| 1727 |
+
"""
|
| 1728 |
+
),
|
| 1729 |
+
] = None,
|
| 1730 |
+
pattern: Annotated[
|
| 1731 |
+
Optional[str],
|
| 1732 |
+
Doc(
|
| 1733 |
+
"""
|
| 1734 |
+
RegEx pattern for strings.
|
| 1735 |
+
"""
|
| 1736 |
+
),
|
| 1737 |
+
] = None,
|
| 1738 |
+
regex: Annotated[
|
| 1739 |
+
Optional[str],
|
| 1740 |
+
Doc(
|
| 1741 |
+
"""
|
| 1742 |
+
RegEx pattern for strings.
|
| 1743 |
+
"""
|
| 1744 |
+
),
|
| 1745 |
+
deprecated(
|
| 1746 |
+
"Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead."
|
| 1747 |
+
),
|
| 1748 |
+
] = None,
|
| 1749 |
+
discriminator: Annotated[
|
| 1750 |
+
Union[str, None],
|
| 1751 |
+
Doc(
|
| 1752 |
+
"""
|
| 1753 |
+
Parameter field name for discriminating the type in a tagged union.
|
| 1754 |
+
"""
|
| 1755 |
+
),
|
| 1756 |
+
] = None,
|
| 1757 |
+
strict: Annotated[
|
| 1758 |
+
Union[bool, None],
|
| 1759 |
+
Doc(
|
| 1760 |
+
"""
|
| 1761 |
+
If `True`, strict validation is applied to the field.
|
| 1762 |
+
"""
|
| 1763 |
+
),
|
| 1764 |
+
] = _Unset,
|
| 1765 |
+
multiple_of: Annotated[
|
| 1766 |
+
Union[float, None],
|
| 1767 |
+
Doc(
|
| 1768 |
+
"""
|
| 1769 |
+
Value must be a multiple of this. Only applicable to numbers.
|
| 1770 |
+
"""
|
| 1771 |
+
),
|
| 1772 |
+
] = _Unset,
|
| 1773 |
+
allow_inf_nan: Annotated[
|
| 1774 |
+
Union[bool, None],
|
| 1775 |
+
Doc(
|
| 1776 |
+
"""
|
| 1777 |
+
Allow `inf`, `-inf`, `nan`. Only applicable to numbers.
|
| 1778 |
+
"""
|
| 1779 |
+
),
|
| 1780 |
+
] = _Unset,
|
| 1781 |
+
max_digits: Annotated[
|
| 1782 |
+
Union[int, None],
|
| 1783 |
+
Doc(
|
| 1784 |
+
"""
|
| 1785 |
+
Maximum number of allow digits for strings.
|
| 1786 |
+
"""
|
| 1787 |
+
),
|
| 1788 |
+
] = _Unset,
|
| 1789 |
+
decimal_places: Annotated[
|
| 1790 |
+
Union[int, None],
|
| 1791 |
+
Doc(
|
| 1792 |
+
"""
|
| 1793 |
+
Maximum number of decimal places allowed for numbers.
|
| 1794 |
+
"""
|
| 1795 |
+
),
|
| 1796 |
+
] = _Unset,
|
| 1797 |
+
examples: Annotated[
|
| 1798 |
+
Optional[List[Any]],
|
| 1799 |
+
Doc(
|
| 1800 |
+
"""
|
| 1801 |
+
Example values for this field.
|
| 1802 |
+
"""
|
| 1803 |
+
),
|
| 1804 |
+
] = None,
|
| 1805 |
+
example: Annotated[
|
| 1806 |
+
Optional[Any],
|
| 1807 |
+
deprecated(
|
| 1808 |
+
"Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, "
|
| 1809 |
+
"although still supported. Use examples instead."
|
| 1810 |
+
),
|
| 1811 |
+
] = _Unset,
|
| 1812 |
+
openapi_examples: Annotated[
|
| 1813 |
+
Optional[Dict[str, Example]],
|
| 1814 |
+
Doc(
|
| 1815 |
+
"""
|
| 1816 |
+
OpenAPI-specific examples.
|
| 1817 |
+
|
| 1818 |
+
It will be added to the generated OpenAPI (e.g. visible at `/docs`).
|
| 1819 |
+
|
| 1820 |
+
Swagger UI (that provides the `/docs` interface) has better support for the
|
| 1821 |
+
OpenAPI-specific examples than the JSON Schema `examples`, that's the main
|
| 1822 |
+
use case for this.
|
| 1823 |
+
|
| 1824 |
+
Read more about it in the
|
| 1825 |
+
[FastAPI docs for Declare Request Example Data](https://fastapi.tiangolo.com/tutorial/schema-extra-example/#using-the-openapi_examples-parameter).
|
| 1826 |
+
"""
|
| 1827 |
+
),
|
| 1828 |
+
] = None,
|
| 1829 |
+
deprecated: Annotated[
|
| 1830 |
+
Union[deprecated, str, bool, None],
|
| 1831 |
+
Doc(
|
| 1832 |
+
"""
|
| 1833 |
+
Mark this parameter field as deprecated.
|
| 1834 |
+
|
| 1835 |
+
It will affect the generated OpenAPI (e.g. visible at `/docs`).
|
| 1836 |
+
"""
|
| 1837 |
+
),
|
| 1838 |
+
] = None,
|
| 1839 |
+
include_in_schema: Annotated[
|
| 1840 |
+
bool,
|
| 1841 |
+
Doc(
|
| 1842 |
+
"""
|
| 1843 |
+
To include (or not) this parameter field in the generated OpenAPI.
|
| 1844 |
+
You probably don't need it, but it's available.
|
| 1845 |
+
|
| 1846 |
+
This affects the generated OpenAPI (e.g. visible at `/docs`).
|
| 1847 |
+
"""
|
| 1848 |
+
),
|
| 1849 |
+
] = True,
|
| 1850 |
+
json_schema_extra: Annotated[
|
| 1851 |
+
Union[Dict[str, Any], None],
|
| 1852 |
+
Doc(
|
| 1853 |
+
"""
|
| 1854 |
+
Any additional JSON schema data.
|
| 1855 |
+
"""
|
| 1856 |
+
),
|
| 1857 |
+
] = None,
|
| 1858 |
+
**extra: Annotated[
|
| 1859 |
+
Any,
|
| 1860 |
+
Doc(
|
| 1861 |
+
"""
|
| 1862 |
+
Include extra fields used by the JSON Schema.
|
| 1863 |
+
"""
|
| 1864 |
+
),
|
| 1865 |
+
deprecated(
|
| 1866 |
+
"""
|
| 1867 |
+
The `extra` kwargs is deprecated. Use `json_schema_extra` instead.
|
| 1868 |
+
"""
|
| 1869 |
+
),
|
| 1870 |
+
],
|
| 1871 |
+
) -> Any:
|
| 1872 |
+
return params.Form(
|
| 1873 |
+
default=default,
|
| 1874 |
+
default_factory=default_factory,
|
| 1875 |
+
media_type=media_type,
|
| 1876 |
+
alias=alias,
|
| 1877 |
+
alias_priority=alias_priority,
|
| 1878 |
+
validation_alias=validation_alias,
|
| 1879 |
+
serialization_alias=serialization_alias,
|
| 1880 |
+
title=title,
|
| 1881 |
+
description=description,
|
| 1882 |
+
gt=gt,
|
| 1883 |
+
ge=ge,
|
| 1884 |
+
lt=lt,
|
| 1885 |
+
le=le,
|
| 1886 |
+
min_length=min_length,
|
| 1887 |
+
max_length=max_length,
|
| 1888 |
+
pattern=pattern,
|
| 1889 |
+
regex=regex,
|
| 1890 |
+
discriminator=discriminator,
|
| 1891 |
+
strict=strict,
|
| 1892 |
+
multiple_of=multiple_of,
|
| 1893 |
+
allow_inf_nan=allow_inf_nan,
|
| 1894 |
+
max_digits=max_digits,
|
| 1895 |
+
decimal_places=decimal_places,
|
| 1896 |
+
example=example,
|
| 1897 |
+
examples=examples,
|
| 1898 |
+
openapi_examples=openapi_examples,
|
| 1899 |
+
deprecated=deprecated,
|
| 1900 |
+
include_in_schema=include_in_schema,
|
| 1901 |
+
json_schema_extra=json_schema_extra,
|
| 1902 |
+
**extra,
|
| 1903 |
+
)
|
| 1904 |
+
|
| 1905 |
+
|
| 1906 |
+
def File( # noqa: N802
|
| 1907 |
+
default: Annotated[
|
| 1908 |
+
Any,
|
| 1909 |
+
Doc(
|
| 1910 |
+
"""
|
| 1911 |
+
Default value if the parameter field is not set.
|
| 1912 |
+
"""
|
| 1913 |
+
),
|
| 1914 |
+
] = Undefined,
|
| 1915 |
+
*,
|
| 1916 |
+
default_factory: Annotated[
|
| 1917 |
+
Union[Callable[[], Any], None],
|
| 1918 |
+
Doc(
|
| 1919 |
+
"""
|
| 1920 |
+
A callable to generate the default value.
|
| 1921 |
+
|
| 1922 |
+
This doesn't affect `Path` parameters as the value is always required.
|
| 1923 |
+
The parameter is available only for compatibility.
|
| 1924 |
+
"""
|
| 1925 |
+
),
|
| 1926 |
+
] = _Unset,
|
| 1927 |
+
media_type: Annotated[
|
| 1928 |
+
str,
|
| 1929 |
+
Doc(
|
| 1930 |
+
"""
|
| 1931 |
+
The media type of this parameter field. Changing it would affect the
|
| 1932 |
+
generated OpenAPI, but currently it doesn't affect the parsing of the data.
|
| 1933 |
+
"""
|
| 1934 |
+
),
|
| 1935 |
+
] = "multipart/form-data",
|
| 1936 |
+
alias: Annotated[
|
| 1937 |
+
Optional[str],
|
| 1938 |
+
Doc(
|
| 1939 |
+
"""
|
| 1940 |
+
An alternative name for the parameter field.
|
| 1941 |
+
|
| 1942 |
+
This will be used to extract the data and for the generated OpenAPI.
|
| 1943 |
+
It is particularly useful when you can't use the name you want because it
|
| 1944 |
+
is a Python reserved keyword or similar.
|
| 1945 |
+
"""
|
| 1946 |
+
),
|
| 1947 |
+
] = None,
|
| 1948 |
+
alias_priority: Annotated[
|
| 1949 |
+
Union[int, None],
|
| 1950 |
+
Doc(
|
| 1951 |
+
"""
|
| 1952 |
+
Priority of the alias. This affects whether an alias generator is used.
|
| 1953 |
+
"""
|
| 1954 |
+
),
|
| 1955 |
+
] = _Unset,
|
| 1956 |
+
# TODO: update when deprecating Pydantic v1, import these types
|
| 1957 |
+
# validation_alias: str | AliasPath | AliasChoices | None
|
| 1958 |
+
validation_alias: Annotated[
|
| 1959 |
+
Union[str, None],
|
| 1960 |
+
Doc(
|
| 1961 |
+
"""
|
| 1962 |
+
'Whitelist' validation step. The parameter field will be the single one
|
| 1963 |
+
allowed by the alias or set of aliases defined.
|
| 1964 |
+
"""
|
| 1965 |
+
),
|
| 1966 |
+
] = None,
|
| 1967 |
+
serialization_alias: Annotated[
|
| 1968 |
+
Union[str, None],
|
| 1969 |
+
Doc(
|
| 1970 |
+
"""
|
| 1971 |
+
'Blacklist' validation step. The vanilla parameter field will be the
|
| 1972 |
+
single one of the alias' or set of aliases' fields and all the other
|
| 1973 |
+
fields will be ignored at serialization time.
|
| 1974 |
+
"""
|
| 1975 |
+
),
|
| 1976 |
+
] = None,
|
| 1977 |
+
title: Annotated[
|
| 1978 |
+
Optional[str],
|
| 1979 |
+
Doc(
|
| 1980 |
+
"""
|
| 1981 |
+
Human-readable title.
|
| 1982 |
+
"""
|
| 1983 |
+
),
|
| 1984 |
+
] = None,
|
| 1985 |
+
description: Annotated[
|
| 1986 |
+
Optional[str],
|
| 1987 |
+
Doc(
|
| 1988 |
+
"""
|
| 1989 |
+
Human-readable description.
|
| 1990 |
+
"""
|
| 1991 |
+
),
|
| 1992 |
+
] = None,
|
| 1993 |
+
gt: Annotated[
|
| 1994 |
+
Optional[float],
|
| 1995 |
+
Doc(
|
| 1996 |
+
"""
|
| 1997 |
+
Greater than. If set, value must be greater than this. Only applicable to
|
| 1998 |
+
numbers.
|
| 1999 |
+
"""
|
| 2000 |
+
),
|
| 2001 |
+
] = None,
|
| 2002 |
+
ge: Annotated[
|
| 2003 |
+
Optional[float],
|
| 2004 |
+
Doc(
|
| 2005 |
+
"""
|
| 2006 |
+
Greater than or equal. If set, value must be greater than or equal to
|
| 2007 |
+
this. Only applicable to numbers.
|
| 2008 |
+
"""
|
| 2009 |
+
),
|
| 2010 |
+
] = None,
|
| 2011 |
+
lt: Annotated[
|
| 2012 |
+
Optional[float],
|
| 2013 |
+
Doc(
|
| 2014 |
+
"""
|
| 2015 |
+
Less than. If set, value must be less than this. Only applicable to numbers.
|
| 2016 |
+
"""
|
| 2017 |
+
),
|
| 2018 |
+
] = None,
|
| 2019 |
+
le: Annotated[
|
| 2020 |
+
Optional[float],
|
| 2021 |
+
Doc(
|
| 2022 |
+
"""
|
| 2023 |
+
Less than or equal. If set, value must be less than or equal to this.
|
| 2024 |
+
Only applicable to numbers.
|
| 2025 |
+
"""
|
| 2026 |
+
),
|
| 2027 |
+
] = None,
|
| 2028 |
+
min_length: Annotated[
|
| 2029 |
+
Optional[int],
|
| 2030 |
+
Doc(
|
| 2031 |
+
"""
|
| 2032 |
+
Minimum length for strings.
|
| 2033 |
+
"""
|
| 2034 |
+
),
|
| 2035 |
+
] = None,
|
| 2036 |
+
max_length: Annotated[
|
| 2037 |
+
Optional[int],
|
| 2038 |
+
Doc(
|
| 2039 |
+
"""
|
| 2040 |
+
Maximum length for strings.
|
| 2041 |
+
"""
|
| 2042 |
+
),
|
| 2043 |
+
] = None,
|
| 2044 |
+
pattern: Annotated[
|
| 2045 |
+
Optional[str],
|
| 2046 |
+
Doc(
|
| 2047 |
+
"""
|
| 2048 |
+
RegEx pattern for strings.
|
| 2049 |
+
"""
|
| 2050 |
+
),
|
| 2051 |
+
] = None,
|
| 2052 |
+
regex: Annotated[
|
| 2053 |
+
Optional[str],
|
| 2054 |
+
Doc(
|
| 2055 |
+
"""
|
| 2056 |
+
RegEx pattern for strings.
|
| 2057 |
+
"""
|
| 2058 |
+
),
|
| 2059 |
+
deprecated(
|
| 2060 |
+
"Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead."
|
| 2061 |
+
),
|
| 2062 |
+
] = None,
|
| 2063 |
+
discriminator: Annotated[
|
| 2064 |
+
Union[str, None],
|
| 2065 |
+
Doc(
|
| 2066 |
+
"""
|
| 2067 |
+
Parameter field name for discriminating the type in a tagged union.
|
| 2068 |
+
"""
|
| 2069 |
+
),
|
| 2070 |
+
] = None,
|
| 2071 |
+
strict: Annotated[
|
| 2072 |
+
Union[bool, None],
|
| 2073 |
+
Doc(
|
| 2074 |
+
"""
|
| 2075 |
+
If `True`, strict validation is applied to the field.
|
| 2076 |
+
"""
|
| 2077 |
+
),
|
| 2078 |
+
] = _Unset,
|
| 2079 |
+
multiple_of: Annotated[
|
| 2080 |
+
Union[float, None],
|
| 2081 |
+
Doc(
|
| 2082 |
+
"""
|
| 2083 |
+
Value must be a multiple of this. Only applicable to numbers.
|
| 2084 |
+
"""
|
| 2085 |
+
),
|
| 2086 |
+
] = _Unset,
|
| 2087 |
+
allow_inf_nan: Annotated[
|
| 2088 |
+
Union[bool, None],
|
| 2089 |
+
Doc(
|
| 2090 |
+
"""
|
| 2091 |
+
Allow `inf`, `-inf`, `nan`. Only applicable to numbers.
|
| 2092 |
+
"""
|
| 2093 |
+
),
|
| 2094 |
+
] = _Unset,
|
| 2095 |
+
max_digits: Annotated[
|
| 2096 |
+
Union[int, None],
|
| 2097 |
+
Doc(
|
| 2098 |
+
"""
|
| 2099 |
+
Maximum number of allow digits for strings.
|
| 2100 |
+
"""
|
| 2101 |
+
),
|
| 2102 |
+
] = _Unset,
|
| 2103 |
+
decimal_places: Annotated[
|
| 2104 |
+
Union[int, None],
|
| 2105 |
+
Doc(
|
| 2106 |
+
"""
|
| 2107 |
+
Maximum number of decimal places allowed for numbers.
|
| 2108 |
+
"""
|
| 2109 |
+
),
|
| 2110 |
+
] = _Unset,
|
| 2111 |
+
examples: Annotated[
|
| 2112 |
+
Optional[List[Any]],
|
| 2113 |
+
Doc(
|
| 2114 |
+
"""
|
| 2115 |
+
Example values for this field.
|
| 2116 |
+
"""
|
| 2117 |
+
),
|
| 2118 |
+
] = None,
|
| 2119 |
+
example: Annotated[
|
| 2120 |
+
Optional[Any],
|
| 2121 |
+
deprecated(
|
| 2122 |
+
"Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, "
|
| 2123 |
+
"although still supported. Use examples instead."
|
| 2124 |
+
),
|
| 2125 |
+
] = _Unset,
|
| 2126 |
+
openapi_examples: Annotated[
|
| 2127 |
+
Optional[Dict[str, Example]],
|
| 2128 |
+
Doc(
|
| 2129 |
+
"""
|
| 2130 |
+
OpenAPI-specific examples.
|
| 2131 |
+
|
| 2132 |
+
It will be added to the generated OpenAPI (e.g. visible at `/docs`).
|
| 2133 |
+
|
| 2134 |
+
Swagger UI (that provides the `/docs` interface) has better support for the
|
| 2135 |
+
OpenAPI-specific examples than the JSON Schema `examples`, that's the main
|
| 2136 |
+
use case for this.
|
| 2137 |
+
|
| 2138 |
+
Read more about it in the
|
| 2139 |
+
[FastAPI docs for Declare Request Example Data](https://fastapi.tiangolo.com/tutorial/schema-extra-example/#using-the-openapi_examples-parameter).
|
| 2140 |
+
"""
|
| 2141 |
+
),
|
| 2142 |
+
] = None,
|
| 2143 |
+
deprecated: Annotated[
|
| 2144 |
+
Union[deprecated, str, bool, None],
|
| 2145 |
+
Doc(
|
| 2146 |
+
"""
|
| 2147 |
+
Mark this parameter field as deprecated.
|
| 2148 |
+
|
| 2149 |
+
It will affect the generated OpenAPI (e.g. visible at `/docs`).
|
| 2150 |
+
"""
|
| 2151 |
+
),
|
| 2152 |
+
] = None,
|
| 2153 |
+
include_in_schema: Annotated[
|
| 2154 |
+
bool,
|
| 2155 |
+
Doc(
|
| 2156 |
+
"""
|
| 2157 |
+
To include (or not) this parameter field in the generated OpenAPI.
|
| 2158 |
+
You probably don't need it, but it's available.
|
| 2159 |
+
|
| 2160 |
+
This affects the generated OpenAPI (e.g. visible at `/docs`).
|
| 2161 |
+
"""
|
| 2162 |
+
),
|
| 2163 |
+
] = True,
|
| 2164 |
+
json_schema_extra: Annotated[
|
| 2165 |
+
Union[Dict[str, Any], None],
|
| 2166 |
+
Doc(
|
| 2167 |
+
"""
|
| 2168 |
+
Any additional JSON schema data.
|
| 2169 |
+
"""
|
| 2170 |
+
),
|
| 2171 |
+
] = None,
|
| 2172 |
+
**extra: Annotated[
|
| 2173 |
+
Any,
|
| 2174 |
+
Doc(
|
| 2175 |
+
"""
|
| 2176 |
+
Include extra fields used by the JSON Schema.
|
| 2177 |
+
"""
|
| 2178 |
+
),
|
| 2179 |
+
deprecated(
|
| 2180 |
+
"""
|
| 2181 |
+
The `extra` kwargs is deprecated. Use `json_schema_extra` instead.
|
| 2182 |
+
"""
|
| 2183 |
+
),
|
| 2184 |
+
],
|
| 2185 |
+
) -> Any:
|
| 2186 |
+
return params.File(
|
| 2187 |
+
default=default,
|
| 2188 |
+
default_factory=default_factory,
|
| 2189 |
+
media_type=media_type,
|
| 2190 |
+
alias=alias,
|
| 2191 |
+
alias_priority=alias_priority,
|
| 2192 |
+
validation_alias=validation_alias,
|
| 2193 |
+
serialization_alias=serialization_alias,
|
| 2194 |
+
title=title,
|
| 2195 |
+
description=description,
|
| 2196 |
+
gt=gt,
|
| 2197 |
+
ge=ge,
|
| 2198 |
+
lt=lt,
|
| 2199 |
+
le=le,
|
| 2200 |
+
min_length=min_length,
|
| 2201 |
+
max_length=max_length,
|
| 2202 |
+
pattern=pattern,
|
| 2203 |
+
regex=regex,
|
| 2204 |
+
discriminator=discriminator,
|
| 2205 |
+
strict=strict,
|
| 2206 |
+
multiple_of=multiple_of,
|
| 2207 |
+
allow_inf_nan=allow_inf_nan,
|
| 2208 |
+
max_digits=max_digits,
|
| 2209 |
+
decimal_places=decimal_places,
|
| 2210 |
+
example=example,
|
| 2211 |
+
examples=examples,
|
| 2212 |
+
openapi_examples=openapi_examples,
|
| 2213 |
+
deprecated=deprecated,
|
| 2214 |
+
include_in_schema=include_in_schema,
|
| 2215 |
+
json_schema_extra=json_schema_extra,
|
| 2216 |
+
**extra,
|
| 2217 |
+
)
|
| 2218 |
+
|
| 2219 |
+
|
| 2220 |
+
def Depends( # noqa: N802
|
| 2221 |
+
dependency: Annotated[
|
| 2222 |
+
Optional[Callable[..., Any]],
|
| 2223 |
+
Doc(
|
| 2224 |
+
"""
|
| 2225 |
+
A "dependable" callable (like a function).
|
| 2226 |
+
|
| 2227 |
+
Don't call it directly, FastAPI will call it for you, just pass the object
|
| 2228 |
+
directly.
|
| 2229 |
+
"""
|
| 2230 |
+
),
|
| 2231 |
+
] = None,
|
| 2232 |
+
*,
|
| 2233 |
+
use_cache: Annotated[
|
| 2234 |
+
bool,
|
| 2235 |
+
Doc(
|
| 2236 |
+
"""
|
| 2237 |
+
By default, after a dependency is called the first time in a request, if
|
| 2238 |
+
the dependency is declared again for the rest of the request (for example
|
| 2239 |
+
if the dependency is needed by several dependencies), the value will be
|
| 2240 |
+
re-used for the rest of the request.
|
| 2241 |
+
|
| 2242 |
+
Set `use_cache` to `False` to disable this behavior and ensure the
|
| 2243 |
+
dependency is called again (if declared more than once) in the same request.
|
| 2244 |
+
"""
|
| 2245 |
+
),
|
| 2246 |
+
] = True,
|
| 2247 |
+
) -> Any:
|
| 2248 |
+
"""
|
| 2249 |
+
Declare a FastAPI dependency.
|
| 2250 |
+
|
| 2251 |
+
It takes a single "dependable" callable (like a function).
|
| 2252 |
+
|
| 2253 |
+
Don't call it directly, FastAPI will call it for you.
|
| 2254 |
+
|
| 2255 |
+
Read more about it in the
|
| 2256 |
+
[FastAPI docs for Dependencies](https://fastapi.tiangolo.com/tutorial/dependencies/).
|
| 2257 |
+
|
| 2258 |
+
**Example**
|
| 2259 |
+
|
| 2260 |
+
```python
|
| 2261 |
+
from typing import Annotated
|
| 2262 |
+
|
| 2263 |
+
from fastapi import Depends, FastAPI
|
| 2264 |
+
|
| 2265 |
+
app = FastAPI()
|
| 2266 |
+
|
| 2267 |
+
|
| 2268 |
+
async def common_parameters(q: str | None = None, skip: int = 0, limit: int = 100):
|
| 2269 |
+
return {"q": q, "skip": skip, "limit": limit}
|
| 2270 |
+
|
| 2271 |
+
|
| 2272 |
+
@app.get("/items/")
|
| 2273 |
+
async def read_items(commons: Annotated[dict, Depends(common_parameters)]):
|
| 2274 |
+
return commons
|
| 2275 |
+
```
|
| 2276 |
+
"""
|
| 2277 |
+
return params.Depends(dependency=dependency, use_cache=use_cache)
|
| 2278 |
+
|
| 2279 |
+
|
| 2280 |
+
def Security( # noqa: N802
|
| 2281 |
+
dependency: Annotated[
|
| 2282 |
+
Optional[Callable[..., Any]],
|
| 2283 |
+
Doc(
|
| 2284 |
+
"""
|
| 2285 |
+
A "dependable" callable (like a function).
|
| 2286 |
+
|
| 2287 |
+
Don't call it directly, FastAPI will call it for you, just pass the object
|
| 2288 |
+
directly.
|
| 2289 |
+
"""
|
| 2290 |
+
),
|
| 2291 |
+
] = None,
|
| 2292 |
+
*,
|
| 2293 |
+
scopes: Annotated[
|
| 2294 |
+
Optional[Sequence[str]],
|
| 2295 |
+
Doc(
|
| 2296 |
+
"""
|
| 2297 |
+
OAuth2 scopes required for the *path operation* that uses this Security
|
| 2298 |
+
dependency.
|
| 2299 |
+
|
| 2300 |
+
The term "scope" comes from the OAuth2 specification, it seems to be
|
| 2301 |
+
intentionally vague and interpretable. It normally refers to permissions,
|
| 2302 |
+
in cases to roles.
|
| 2303 |
+
|
| 2304 |
+
These scopes are integrated with OpenAPI (and the API docs at `/docs`).
|
| 2305 |
+
So they are visible in the OpenAPI specification.
|
| 2306 |
+
)
|
| 2307 |
+
"""
|
| 2308 |
+
),
|
| 2309 |
+
] = None,
|
| 2310 |
+
use_cache: Annotated[
|
| 2311 |
+
bool,
|
| 2312 |
+
Doc(
|
| 2313 |
+
"""
|
| 2314 |
+
By default, after a dependency is called the first time in a request, if
|
| 2315 |
+
the dependency is declared again for the rest of the request (for example
|
| 2316 |
+
if the dependency is needed by several dependencies), the value will be
|
| 2317 |
+
re-used for the rest of the request.
|
| 2318 |
+
|
| 2319 |
+
Set `use_cache` to `False` to disable this behavior and ensure the
|
| 2320 |
+
dependency is called again (if declared more than once) in the same request.
|
| 2321 |
+
"""
|
| 2322 |
+
),
|
| 2323 |
+
] = True,
|
| 2324 |
+
) -> Any:
|
| 2325 |
+
"""
|
| 2326 |
+
Declare a FastAPI Security dependency.
|
| 2327 |
+
|
| 2328 |
+
The only difference with a regular dependency is that it can declare OAuth2
|
| 2329 |
+
scopes that will be integrated with OpenAPI and the automatic UI docs (by default
|
| 2330 |
+
at `/docs`).
|
| 2331 |
+
|
| 2332 |
+
It takes a single "dependable" callable (like a function).
|
| 2333 |
+
|
| 2334 |
+
Don't call it directly, FastAPI will call it for you.
|
| 2335 |
+
|
| 2336 |
+
Read more about it in the
|
| 2337 |
+
[FastAPI docs for Security](https://fastapi.tiangolo.com/tutorial/security/) and
|
| 2338 |
+
in the
|
| 2339 |
+
[FastAPI docs for OAuth2 scopes](https://fastapi.tiangolo.com/advanced/security/oauth2-scopes/).
|
| 2340 |
+
|
| 2341 |
+
**Example**
|
| 2342 |
+
|
| 2343 |
+
```python
|
| 2344 |
+
from typing import Annotated
|
| 2345 |
+
|
| 2346 |
+
from fastapi import Security, FastAPI
|
| 2347 |
+
|
| 2348 |
+
from .db import User
|
| 2349 |
+
from .security import get_current_active_user
|
| 2350 |
+
|
| 2351 |
+
app = FastAPI()
|
| 2352 |
+
|
| 2353 |
+
@app.get("/users/me/items/")
|
| 2354 |
+
async def read_own_items(
|
| 2355 |
+
current_user: Annotated[User, Security(get_current_active_user, scopes=["items"])]
|
| 2356 |
+
):
|
| 2357 |
+
return [{"item_id": "Foo", "owner": current_user.username}]
|
| 2358 |
+
```
|
| 2359 |
+
"""
|
| 2360 |
+
return params.Security(dependency=dependency, scopes=scopes, use_cache=use_cache)
|
lib/python3.12/site-packages/fastapi/params.py
ADDED
|
@@ -0,0 +1,786 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import warnings
|
| 2 |
+
from enum import Enum
|
| 3 |
+
from typing import Any, Callable, Dict, List, Optional, Sequence, Union
|
| 4 |
+
|
| 5 |
+
from fastapi.openapi.models import Example
|
| 6 |
+
from pydantic.fields import FieldInfo
|
| 7 |
+
from typing_extensions import Annotated, deprecated
|
| 8 |
+
|
| 9 |
+
from ._compat import (
|
| 10 |
+
PYDANTIC_V2,
|
| 11 |
+
PYDANTIC_VERSION_MINOR_TUPLE,
|
| 12 |
+
Undefined,
|
| 13 |
+
)
|
| 14 |
+
|
| 15 |
+
_Unset: Any = Undefined
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
class ParamTypes(Enum):
|
| 19 |
+
query = "query"
|
| 20 |
+
header = "header"
|
| 21 |
+
path = "path"
|
| 22 |
+
cookie = "cookie"
|
| 23 |
+
|
| 24 |
+
|
| 25 |
+
class Param(FieldInfo):
|
| 26 |
+
in_: ParamTypes
|
| 27 |
+
|
| 28 |
+
def __init__(
|
| 29 |
+
self,
|
| 30 |
+
default: Any = Undefined,
|
| 31 |
+
*,
|
| 32 |
+
default_factory: Union[Callable[[], Any], None] = _Unset,
|
| 33 |
+
annotation: Optional[Any] = None,
|
| 34 |
+
alias: Optional[str] = None,
|
| 35 |
+
alias_priority: Union[int, None] = _Unset,
|
| 36 |
+
# TODO: update when deprecating Pydantic v1, import these types
|
| 37 |
+
# validation_alias: str | AliasPath | AliasChoices | None
|
| 38 |
+
validation_alias: Union[str, None] = None,
|
| 39 |
+
serialization_alias: Union[str, None] = None,
|
| 40 |
+
title: Optional[str] = None,
|
| 41 |
+
description: Optional[str] = None,
|
| 42 |
+
gt: Optional[float] = None,
|
| 43 |
+
ge: Optional[float] = None,
|
| 44 |
+
lt: Optional[float] = None,
|
| 45 |
+
le: Optional[float] = None,
|
| 46 |
+
min_length: Optional[int] = None,
|
| 47 |
+
max_length: Optional[int] = None,
|
| 48 |
+
pattern: Optional[str] = None,
|
| 49 |
+
regex: Annotated[
|
| 50 |
+
Optional[str],
|
| 51 |
+
deprecated(
|
| 52 |
+
"Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead."
|
| 53 |
+
),
|
| 54 |
+
] = None,
|
| 55 |
+
discriminator: Union[str, None] = None,
|
| 56 |
+
strict: Union[bool, None] = _Unset,
|
| 57 |
+
multiple_of: Union[float, None] = _Unset,
|
| 58 |
+
allow_inf_nan: Union[bool, None] = _Unset,
|
| 59 |
+
max_digits: Union[int, None] = _Unset,
|
| 60 |
+
decimal_places: Union[int, None] = _Unset,
|
| 61 |
+
examples: Optional[List[Any]] = None,
|
| 62 |
+
example: Annotated[
|
| 63 |
+
Optional[Any],
|
| 64 |
+
deprecated(
|
| 65 |
+
"Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, "
|
| 66 |
+
"although still supported. Use examples instead."
|
| 67 |
+
),
|
| 68 |
+
] = _Unset,
|
| 69 |
+
openapi_examples: Optional[Dict[str, Example]] = None,
|
| 70 |
+
deprecated: Union[deprecated, str, bool, None] = None,
|
| 71 |
+
include_in_schema: bool = True,
|
| 72 |
+
json_schema_extra: Union[Dict[str, Any], None] = None,
|
| 73 |
+
**extra: Any,
|
| 74 |
+
):
|
| 75 |
+
if example is not _Unset:
|
| 76 |
+
warnings.warn(
|
| 77 |
+
"`example` has been deprecated, please use `examples` instead",
|
| 78 |
+
category=DeprecationWarning,
|
| 79 |
+
stacklevel=4,
|
| 80 |
+
)
|
| 81 |
+
self.example = example
|
| 82 |
+
self.include_in_schema = include_in_schema
|
| 83 |
+
self.openapi_examples = openapi_examples
|
| 84 |
+
kwargs = dict(
|
| 85 |
+
default=default,
|
| 86 |
+
default_factory=default_factory,
|
| 87 |
+
alias=alias,
|
| 88 |
+
title=title,
|
| 89 |
+
description=description,
|
| 90 |
+
gt=gt,
|
| 91 |
+
ge=ge,
|
| 92 |
+
lt=lt,
|
| 93 |
+
le=le,
|
| 94 |
+
min_length=min_length,
|
| 95 |
+
max_length=max_length,
|
| 96 |
+
discriminator=discriminator,
|
| 97 |
+
multiple_of=multiple_of,
|
| 98 |
+
allow_inf_nan=allow_inf_nan,
|
| 99 |
+
max_digits=max_digits,
|
| 100 |
+
decimal_places=decimal_places,
|
| 101 |
+
**extra,
|
| 102 |
+
)
|
| 103 |
+
if examples is not None:
|
| 104 |
+
kwargs["examples"] = examples
|
| 105 |
+
if regex is not None:
|
| 106 |
+
warnings.warn(
|
| 107 |
+
"`regex` has been deprecated, please use `pattern` instead",
|
| 108 |
+
category=DeprecationWarning,
|
| 109 |
+
stacklevel=4,
|
| 110 |
+
)
|
| 111 |
+
current_json_schema_extra = json_schema_extra or extra
|
| 112 |
+
if PYDANTIC_VERSION_MINOR_TUPLE < (2, 7):
|
| 113 |
+
self.deprecated = deprecated
|
| 114 |
+
else:
|
| 115 |
+
kwargs["deprecated"] = deprecated
|
| 116 |
+
if PYDANTIC_V2:
|
| 117 |
+
kwargs.update(
|
| 118 |
+
{
|
| 119 |
+
"annotation": annotation,
|
| 120 |
+
"alias_priority": alias_priority,
|
| 121 |
+
"validation_alias": validation_alias,
|
| 122 |
+
"serialization_alias": serialization_alias,
|
| 123 |
+
"strict": strict,
|
| 124 |
+
"json_schema_extra": current_json_schema_extra,
|
| 125 |
+
}
|
| 126 |
+
)
|
| 127 |
+
kwargs["pattern"] = pattern or regex
|
| 128 |
+
else:
|
| 129 |
+
kwargs["regex"] = pattern or regex
|
| 130 |
+
kwargs.update(**current_json_schema_extra)
|
| 131 |
+
use_kwargs = {k: v for k, v in kwargs.items() if v is not _Unset}
|
| 132 |
+
|
| 133 |
+
super().__init__(**use_kwargs)
|
| 134 |
+
|
| 135 |
+
def __repr__(self) -> str:
|
| 136 |
+
return f"{self.__class__.__name__}({self.default})"
|
| 137 |
+
|
| 138 |
+
|
| 139 |
+
class Path(Param):
|
| 140 |
+
in_ = ParamTypes.path
|
| 141 |
+
|
| 142 |
+
def __init__(
|
| 143 |
+
self,
|
| 144 |
+
default: Any = ...,
|
| 145 |
+
*,
|
| 146 |
+
default_factory: Union[Callable[[], Any], None] = _Unset,
|
| 147 |
+
annotation: Optional[Any] = None,
|
| 148 |
+
alias: Optional[str] = None,
|
| 149 |
+
alias_priority: Union[int, None] = _Unset,
|
| 150 |
+
# TODO: update when deprecating Pydantic v1, import these types
|
| 151 |
+
# validation_alias: str | AliasPath | AliasChoices | None
|
| 152 |
+
validation_alias: Union[str, None] = None,
|
| 153 |
+
serialization_alias: Union[str, None] = None,
|
| 154 |
+
title: Optional[str] = None,
|
| 155 |
+
description: Optional[str] = None,
|
| 156 |
+
gt: Optional[float] = None,
|
| 157 |
+
ge: Optional[float] = None,
|
| 158 |
+
lt: Optional[float] = None,
|
| 159 |
+
le: Optional[float] = None,
|
| 160 |
+
min_length: Optional[int] = None,
|
| 161 |
+
max_length: Optional[int] = None,
|
| 162 |
+
pattern: Optional[str] = None,
|
| 163 |
+
regex: Annotated[
|
| 164 |
+
Optional[str],
|
| 165 |
+
deprecated(
|
| 166 |
+
"Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead."
|
| 167 |
+
),
|
| 168 |
+
] = None,
|
| 169 |
+
discriminator: Union[str, None] = None,
|
| 170 |
+
strict: Union[bool, None] = _Unset,
|
| 171 |
+
multiple_of: Union[float, None] = _Unset,
|
| 172 |
+
allow_inf_nan: Union[bool, None] = _Unset,
|
| 173 |
+
max_digits: Union[int, None] = _Unset,
|
| 174 |
+
decimal_places: Union[int, None] = _Unset,
|
| 175 |
+
examples: Optional[List[Any]] = None,
|
| 176 |
+
example: Annotated[
|
| 177 |
+
Optional[Any],
|
| 178 |
+
deprecated(
|
| 179 |
+
"Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, "
|
| 180 |
+
"although still supported. Use examples instead."
|
| 181 |
+
),
|
| 182 |
+
] = _Unset,
|
| 183 |
+
openapi_examples: Optional[Dict[str, Example]] = None,
|
| 184 |
+
deprecated: Union[deprecated, str, bool, None] = None,
|
| 185 |
+
include_in_schema: bool = True,
|
| 186 |
+
json_schema_extra: Union[Dict[str, Any], None] = None,
|
| 187 |
+
**extra: Any,
|
| 188 |
+
):
|
| 189 |
+
assert default is ..., "Path parameters cannot have a default value"
|
| 190 |
+
self.in_ = self.in_
|
| 191 |
+
super().__init__(
|
| 192 |
+
default=default,
|
| 193 |
+
default_factory=default_factory,
|
| 194 |
+
annotation=annotation,
|
| 195 |
+
alias=alias,
|
| 196 |
+
alias_priority=alias_priority,
|
| 197 |
+
validation_alias=validation_alias,
|
| 198 |
+
serialization_alias=serialization_alias,
|
| 199 |
+
title=title,
|
| 200 |
+
description=description,
|
| 201 |
+
gt=gt,
|
| 202 |
+
ge=ge,
|
| 203 |
+
lt=lt,
|
| 204 |
+
le=le,
|
| 205 |
+
min_length=min_length,
|
| 206 |
+
max_length=max_length,
|
| 207 |
+
pattern=pattern,
|
| 208 |
+
regex=regex,
|
| 209 |
+
discriminator=discriminator,
|
| 210 |
+
strict=strict,
|
| 211 |
+
multiple_of=multiple_of,
|
| 212 |
+
allow_inf_nan=allow_inf_nan,
|
| 213 |
+
max_digits=max_digits,
|
| 214 |
+
decimal_places=decimal_places,
|
| 215 |
+
deprecated=deprecated,
|
| 216 |
+
example=example,
|
| 217 |
+
examples=examples,
|
| 218 |
+
openapi_examples=openapi_examples,
|
| 219 |
+
include_in_schema=include_in_schema,
|
| 220 |
+
json_schema_extra=json_schema_extra,
|
| 221 |
+
**extra,
|
| 222 |
+
)
|
| 223 |
+
|
| 224 |
+
|
| 225 |
+
class Query(Param):
|
| 226 |
+
in_ = ParamTypes.query
|
| 227 |
+
|
| 228 |
+
def __init__(
|
| 229 |
+
self,
|
| 230 |
+
default: Any = Undefined,
|
| 231 |
+
*,
|
| 232 |
+
default_factory: Union[Callable[[], Any], None] = _Unset,
|
| 233 |
+
annotation: Optional[Any] = None,
|
| 234 |
+
alias: Optional[str] = None,
|
| 235 |
+
alias_priority: Union[int, None] = _Unset,
|
| 236 |
+
# TODO: update when deprecating Pydantic v1, import these types
|
| 237 |
+
# validation_alias: str | AliasPath | AliasChoices | None
|
| 238 |
+
validation_alias: Union[str, None] = None,
|
| 239 |
+
serialization_alias: Union[str, None] = None,
|
| 240 |
+
title: Optional[str] = None,
|
| 241 |
+
description: Optional[str] = None,
|
| 242 |
+
gt: Optional[float] = None,
|
| 243 |
+
ge: Optional[float] = None,
|
| 244 |
+
lt: Optional[float] = None,
|
| 245 |
+
le: Optional[float] = None,
|
| 246 |
+
min_length: Optional[int] = None,
|
| 247 |
+
max_length: Optional[int] = None,
|
| 248 |
+
pattern: Optional[str] = None,
|
| 249 |
+
regex: Annotated[
|
| 250 |
+
Optional[str],
|
| 251 |
+
deprecated(
|
| 252 |
+
"Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead."
|
| 253 |
+
),
|
| 254 |
+
] = None,
|
| 255 |
+
discriminator: Union[str, None] = None,
|
| 256 |
+
strict: Union[bool, None] = _Unset,
|
| 257 |
+
multiple_of: Union[float, None] = _Unset,
|
| 258 |
+
allow_inf_nan: Union[bool, None] = _Unset,
|
| 259 |
+
max_digits: Union[int, None] = _Unset,
|
| 260 |
+
decimal_places: Union[int, None] = _Unset,
|
| 261 |
+
examples: Optional[List[Any]] = None,
|
| 262 |
+
example: Annotated[
|
| 263 |
+
Optional[Any],
|
| 264 |
+
deprecated(
|
| 265 |
+
"Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, "
|
| 266 |
+
"although still supported. Use examples instead."
|
| 267 |
+
),
|
| 268 |
+
] = _Unset,
|
| 269 |
+
openapi_examples: Optional[Dict[str, Example]] = None,
|
| 270 |
+
deprecated: Union[deprecated, str, bool, None] = None,
|
| 271 |
+
include_in_schema: bool = True,
|
| 272 |
+
json_schema_extra: Union[Dict[str, Any], None] = None,
|
| 273 |
+
**extra: Any,
|
| 274 |
+
):
|
| 275 |
+
super().__init__(
|
| 276 |
+
default=default,
|
| 277 |
+
default_factory=default_factory,
|
| 278 |
+
annotation=annotation,
|
| 279 |
+
alias=alias,
|
| 280 |
+
alias_priority=alias_priority,
|
| 281 |
+
validation_alias=validation_alias,
|
| 282 |
+
serialization_alias=serialization_alias,
|
| 283 |
+
title=title,
|
| 284 |
+
description=description,
|
| 285 |
+
gt=gt,
|
| 286 |
+
ge=ge,
|
| 287 |
+
lt=lt,
|
| 288 |
+
le=le,
|
| 289 |
+
min_length=min_length,
|
| 290 |
+
max_length=max_length,
|
| 291 |
+
pattern=pattern,
|
| 292 |
+
regex=regex,
|
| 293 |
+
discriminator=discriminator,
|
| 294 |
+
strict=strict,
|
| 295 |
+
multiple_of=multiple_of,
|
| 296 |
+
allow_inf_nan=allow_inf_nan,
|
| 297 |
+
max_digits=max_digits,
|
| 298 |
+
decimal_places=decimal_places,
|
| 299 |
+
deprecated=deprecated,
|
| 300 |
+
example=example,
|
| 301 |
+
examples=examples,
|
| 302 |
+
openapi_examples=openapi_examples,
|
| 303 |
+
include_in_schema=include_in_schema,
|
| 304 |
+
json_schema_extra=json_schema_extra,
|
| 305 |
+
**extra,
|
| 306 |
+
)
|
| 307 |
+
|
| 308 |
+
|
| 309 |
+
class Header(Param):
|
| 310 |
+
in_ = ParamTypes.header
|
| 311 |
+
|
| 312 |
+
def __init__(
|
| 313 |
+
self,
|
| 314 |
+
default: Any = Undefined,
|
| 315 |
+
*,
|
| 316 |
+
default_factory: Union[Callable[[], Any], None] = _Unset,
|
| 317 |
+
annotation: Optional[Any] = None,
|
| 318 |
+
alias: Optional[str] = None,
|
| 319 |
+
alias_priority: Union[int, None] = _Unset,
|
| 320 |
+
# TODO: update when deprecating Pydantic v1, import these types
|
| 321 |
+
# validation_alias: str | AliasPath | AliasChoices | None
|
| 322 |
+
validation_alias: Union[str, None] = None,
|
| 323 |
+
serialization_alias: Union[str, None] = None,
|
| 324 |
+
convert_underscores: bool = True,
|
| 325 |
+
title: Optional[str] = None,
|
| 326 |
+
description: Optional[str] = None,
|
| 327 |
+
gt: Optional[float] = None,
|
| 328 |
+
ge: Optional[float] = None,
|
| 329 |
+
lt: Optional[float] = None,
|
| 330 |
+
le: Optional[float] = None,
|
| 331 |
+
min_length: Optional[int] = None,
|
| 332 |
+
max_length: Optional[int] = None,
|
| 333 |
+
pattern: Optional[str] = None,
|
| 334 |
+
regex: Annotated[
|
| 335 |
+
Optional[str],
|
| 336 |
+
deprecated(
|
| 337 |
+
"Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead."
|
| 338 |
+
),
|
| 339 |
+
] = None,
|
| 340 |
+
discriminator: Union[str, None] = None,
|
| 341 |
+
strict: Union[bool, None] = _Unset,
|
| 342 |
+
multiple_of: Union[float, None] = _Unset,
|
| 343 |
+
allow_inf_nan: Union[bool, None] = _Unset,
|
| 344 |
+
max_digits: Union[int, None] = _Unset,
|
| 345 |
+
decimal_places: Union[int, None] = _Unset,
|
| 346 |
+
examples: Optional[List[Any]] = None,
|
| 347 |
+
example: Annotated[
|
| 348 |
+
Optional[Any],
|
| 349 |
+
deprecated(
|
| 350 |
+
"Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, "
|
| 351 |
+
"although still supported. Use examples instead."
|
| 352 |
+
),
|
| 353 |
+
] = _Unset,
|
| 354 |
+
openapi_examples: Optional[Dict[str, Example]] = None,
|
| 355 |
+
deprecated: Union[deprecated, str, bool, None] = None,
|
| 356 |
+
include_in_schema: bool = True,
|
| 357 |
+
json_schema_extra: Union[Dict[str, Any], None] = None,
|
| 358 |
+
**extra: Any,
|
| 359 |
+
):
|
| 360 |
+
self.convert_underscores = convert_underscores
|
| 361 |
+
super().__init__(
|
| 362 |
+
default=default,
|
| 363 |
+
default_factory=default_factory,
|
| 364 |
+
annotation=annotation,
|
| 365 |
+
alias=alias,
|
| 366 |
+
alias_priority=alias_priority,
|
| 367 |
+
validation_alias=validation_alias,
|
| 368 |
+
serialization_alias=serialization_alias,
|
| 369 |
+
title=title,
|
| 370 |
+
description=description,
|
| 371 |
+
gt=gt,
|
| 372 |
+
ge=ge,
|
| 373 |
+
lt=lt,
|
| 374 |
+
le=le,
|
| 375 |
+
min_length=min_length,
|
| 376 |
+
max_length=max_length,
|
| 377 |
+
pattern=pattern,
|
| 378 |
+
regex=regex,
|
| 379 |
+
discriminator=discriminator,
|
| 380 |
+
strict=strict,
|
| 381 |
+
multiple_of=multiple_of,
|
| 382 |
+
allow_inf_nan=allow_inf_nan,
|
| 383 |
+
max_digits=max_digits,
|
| 384 |
+
decimal_places=decimal_places,
|
| 385 |
+
deprecated=deprecated,
|
| 386 |
+
example=example,
|
| 387 |
+
examples=examples,
|
| 388 |
+
openapi_examples=openapi_examples,
|
| 389 |
+
include_in_schema=include_in_schema,
|
| 390 |
+
json_schema_extra=json_schema_extra,
|
| 391 |
+
**extra,
|
| 392 |
+
)
|
| 393 |
+
|
| 394 |
+
|
| 395 |
+
class Cookie(Param):
|
| 396 |
+
in_ = ParamTypes.cookie
|
| 397 |
+
|
| 398 |
+
def __init__(
|
| 399 |
+
self,
|
| 400 |
+
default: Any = Undefined,
|
| 401 |
+
*,
|
| 402 |
+
default_factory: Union[Callable[[], Any], None] = _Unset,
|
| 403 |
+
annotation: Optional[Any] = None,
|
| 404 |
+
alias: Optional[str] = None,
|
| 405 |
+
alias_priority: Union[int, None] = _Unset,
|
| 406 |
+
# TODO: update when deprecating Pydantic v1, import these types
|
| 407 |
+
# validation_alias: str | AliasPath | AliasChoices | None
|
| 408 |
+
validation_alias: Union[str, None] = None,
|
| 409 |
+
serialization_alias: Union[str, None] = None,
|
| 410 |
+
title: Optional[str] = None,
|
| 411 |
+
description: Optional[str] = None,
|
| 412 |
+
gt: Optional[float] = None,
|
| 413 |
+
ge: Optional[float] = None,
|
| 414 |
+
lt: Optional[float] = None,
|
| 415 |
+
le: Optional[float] = None,
|
| 416 |
+
min_length: Optional[int] = None,
|
| 417 |
+
max_length: Optional[int] = None,
|
| 418 |
+
pattern: Optional[str] = None,
|
| 419 |
+
regex: Annotated[
|
| 420 |
+
Optional[str],
|
| 421 |
+
deprecated(
|
| 422 |
+
"Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead."
|
| 423 |
+
),
|
| 424 |
+
] = None,
|
| 425 |
+
discriminator: Union[str, None] = None,
|
| 426 |
+
strict: Union[bool, None] = _Unset,
|
| 427 |
+
multiple_of: Union[float, None] = _Unset,
|
| 428 |
+
allow_inf_nan: Union[bool, None] = _Unset,
|
| 429 |
+
max_digits: Union[int, None] = _Unset,
|
| 430 |
+
decimal_places: Union[int, None] = _Unset,
|
| 431 |
+
examples: Optional[List[Any]] = None,
|
| 432 |
+
example: Annotated[
|
| 433 |
+
Optional[Any],
|
| 434 |
+
deprecated(
|
| 435 |
+
"Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, "
|
| 436 |
+
"although still supported. Use examples instead."
|
| 437 |
+
),
|
| 438 |
+
] = _Unset,
|
| 439 |
+
openapi_examples: Optional[Dict[str, Example]] = None,
|
| 440 |
+
deprecated: Union[deprecated, str, bool, None] = None,
|
| 441 |
+
include_in_schema: bool = True,
|
| 442 |
+
json_schema_extra: Union[Dict[str, Any], None] = None,
|
| 443 |
+
**extra: Any,
|
| 444 |
+
):
|
| 445 |
+
super().__init__(
|
| 446 |
+
default=default,
|
| 447 |
+
default_factory=default_factory,
|
| 448 |
+
annotation=annotation,
|
| 449 |
+
alias=alias,
|
| 450 |
+
alias_priority=alias_priority,
|
| 451 |
+
validation_alias=validation_alias,
|
| 452 |
+
serialization_alias=serialization_alias,
|
| 453 |
+
title=title,
|
| 454 |
+
description=description,
|
| 455 |
+
gt=gt,
|
| 456 |
+
ge=ge,
|
| 457 |
+
lt=lt,
|
| 458 |
+
le=le,
|
| 459 |
+
min_length=min_length,
|
| 460 |
+
max_length=max_length,
|
| 461 |
+
pattern=pattern,
|
| 462 |
+
regex=regex,
|
| 463 |
+
discriminator=discriminator,
|
| 464 |
+
strict=strict,
|
| 465 |
+
multiple_of=multiple_of,
|
| 466 |
+
allow_inf_nan=allow_inf_nan,
|
| 467 |
+
max_digits=max_digits,
|
| 468 |
+
decimal_places=decimal_places,
|
| 469 |
+
deprecated=deprecated,
|
| 470 |
+
example=example,
|
| 471 |
+
examples=examples,
|
| 472 |
+
openapi_examples=openapi_examples,
|
| 473 |
+
include_in_schema=include_in_schema,
|
| 474 |
+
json_schema_extra=json_schema_extra,
|
| 475 |
+
**extra,
|
| 476 |
+
)
|
| 477 |
+
|
| 478 |
+
|
| 479 |
+
class Body(FieldInfo):
|
| 480 |
+
def __init__(
|
| 481 |
+
self,
|
| 482 |
+
default: Any = Undefined,
|
| 483 |
+
*,
|
| 484 |
+
default_factory: Union[Callable[[], Any], None] = _Unset,
|
| 485 |
+
annotation: Optional[Any] = None,
|
| 486 |
+
embed: Union[bool, None] = None,
|
| 487 |
+
media_type: str = "application/json",
|
| 488 |
+
alias: Optional[str] = None,
|
| 489 |
+
alias_priority: Union[int, None] = _Unset,
|
| 490 |
+
# TODO: update when deprecating Pydantic v1, import these types
|
| 491 |
+
# validation_alias: str | AliasPath | AliasChoices | None
|
| 492 |
+
validation_alias: Union[str, None] = None,
|
| 493 |
+
serialization_alias: Union[str, None] = None,
|
| 494 |
+
title: Optional[str] = None,
|
| 495 |
+
description: Optional[str] = None,
|
| 496 |
+
gt: Optional[float] = None,
|
| 497 |
+
ge: Optional[float] = None,
|
| 498 |
+
lt: Optional[float] = None,
|
| 499 |
+
le: Optional[float] = None,
|
| 500 |
+
min_length: Optional[int] = None,
|
| 501 |
+
max_length: Optional[int] = None,
|
| 502 |
+
pattern: Optional[str] = None,
|
| 503 |
+
regex: Annotated[
|
| 504 |
+
Optional[str],
|
| 505 |
+
deprecated(
|
| 506 |
+
"Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead."
|
| 507 |
+
),
|
| 508 |
+
] = None,
|
| 509 |
+
discriminator: Union[str, None] = None,
|
| 510 |
+
strict: Union[bool, None] = _Unset,
|
| 511 |
+
multiple_of: Union[float, None] = _Unset,
|
| 512 |
+
allow_inf_nan: Union[bool, None] = _Unset,
|
| 513 |
+
max_digits: Union[int, None] = _Unset,
|
| 514 |
+
decimal_places: Union[int, None] = _Unset,
|
| 515 |
+
examples: Optional[List[Any]] = None,
|
| 516 |
+
example: Annotated[
|
| 517 |
+
Optional[Any],
|
| 518 |
+
deprecated(
|
| 519 |
+
"Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, "
|
| 520 |
+
"although still supported. Use examples instead."
|
| 521 |
+
),
|
| 522 |
+
] = _Unset,
|
| 523 |
+
openapi_examples: Optional[Dict[str, Example]] = None,
|
| 524 |
+
deprecated: Union[deprecated, str, bool, None] = None,
|
| 525 |
+
include_in_schema: bool = True,
|
| 526 |
+
json_schema_extra: Union[Dict[str, Any], None] = None,
|
| 527 |
+
**extra: Any,
|
| 528 |
+
):
|
| 529 |
+
self.embed = embed
|
| 530 |
+
self.media_type = media_type
|
| 531 |
+
if example is not _Unset:
|
| 532 |
+
warnings.warn(
|
| 533 |
+
"`example` has been deprecated, please use `examples` instead",
|
| 534 |
+
category=DeprecationWarning,
|
| 535 |
+
stacklevel=4,
|
| 536 |
+
)
|
| 537 |
+
self.example = example
|
| 538 |
+
self.include_in_schema = include_in_schema
|
| 539 |
+
self.openapi_examples = openapi_examples
|
| 540 |
+
kwargs = dict(
|
| 541 |
+
default=default,
|
| 542 |
+
default_factory=default_factory,
|
| 543 |
+
alias=alias,
|
| 544 |
+
title=title,
|
| 545 |
+
description=description,
|
| 546 |
+
gt=gt,
|
| 547 |
+
ge=ge,
|
| 548 |
+
lt=lt,
|
| 549 |
+
le=le,
|
| 550 |
+
min_length=min_length,
|
| 551 |
+
max_length=max_length,
|
| 552 |
+
discriminator=discriminator,
|
| 553 |
+
multiple_of=multiple_of,
|
| 554 |
+
allow_inf_nan=allow_inf_nan,
|
| 555 |
+
max_digits=max_digits,
|
| 556 |
+
decimal_places=decimal_places,
|
| 557 |
+
**extra,
|
| 558 |
+
)
|
| 559 |
+
if examples is not None:
|
| 560 |
+
kwargs["examples"] = examples
|
| 561 |
+
if regex is not None:
|
| 562 |
+
warnings.warn(
|
| 563 |
+
"`regex` has been deprecated, please use `pattern` instead",
|
| 564 |
+
category=DeprecationWarning,
|
| 565 |
+
stacklevel=4,
|
| 566 |
+
)
|
| 567 |
+
current_json_schema_extra = json_schema_extra or extra
|
| 568 |
+
if PYDANTIC_VERSION_MINOR_TUPLE < (2, 7):
|
| 569 |
+
self.deprecated = deprecated
|
| 570 |
+
else:
|
| 571 |
+
kwargs["deprecated"] = deprecated
|
| 572 |
+
if PYDANTIC_V2:
|
| 573 |
+
kwargs.update(
|
| 574 |
+
{
|
| 575 |
+
"annotation": annotation,
|
| 576 |
+
"alias_priority": alias_priority,
|
| 577 |
+
"validation_alias": validation_alias,
|
| 578 |
+
"serialization_alias": serialization_alias,
|
| 579 |
+
"strict": strict,
|
| 580 |
+
"json_schema_extra": current_json_schema_extra,
|
| 581 |
+
}
|
| 582 |
+
)
|
| 583 |
+
kwargs["pattern"] = pattern or regex
|
| 584 |
+
else:
|
| 585 |
+
kwargs["regex"] = pattern or regex
|
| 586 |
+
kwargs.update(**current_json_schema_extra)
|
| 587 |
+
|
| 588 |
+
use_kwargs = {k: v for k, v in kwargs.items() if v is not _Unset}
|
| 589 |
+
|
| 590 |
+
super().__init__(**use_kwargs)
|
| 591 |
+
|
| 592 |
+
def __repr__(self) -> str:
|
| 593 |
+
return f"{self.__class__.__name__}({self.default})"
|
| 594 |
+
|
| 595 |
+
|
| 596 |
+
class Form(Body):
|
| 597 |
+
def __init__(
|
| 598 |
+
self,
|
| 599 |
+
default: Any = Undefined,
|
| 600 |
+
*,
|
| 601 |
+
default_factory: Union[Callable[[], Any], None] = _Unset,
|
| 602 |
+
annotation: Optional[Any] = None,
|
| 603 |
+
media_type: str = "application/x-www-form-urlencoded",
|
| 604 |
+
alias: Optional[str] = None,
|
| 605 |
+
alias_priority: Union[int, None] = _Unset,
|
| 606 |
+
# TODO: update when deprecating Pydantic v1, import these types
|
| 607 |
+
# validation_alias: str | AliasPath | AliasChoices | None
|
| 608 |
+
validation_alias: Union[str, None] = None,
|
| 609 |
+
serialization_alias: Union[str, None] = None,
|
| 610 |
+
title: Optional[str] = None,
|
| 611 |
+
description: Optional[str] = None,
|
| 612 |
+
gt: Optional[float] = None,
|
| 613 |
+
ge: Optional[float] = None,
|
| 614 |
+
lt: Optional[float] = None,
|
| 615 |
+
le: Optional[float] = None,
|
| 616 |
+
min_length: Optional[int] = None,
|
| 617 |
+
max_length: Optional[int] = None,
|
| 618 |
+
pattern: Optional[str] = None,
|
| 619 |
+
regex: Annotated[
|
| 620 |
+
Optional[str],
|
| 621 |
+
deprecated(
|
| 622 |
+
"Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead."
|
| 623 |
+
),
|
| 624 |
+
] = None,
|
| 625 |
+
discriminator: Union[str, None] = None,
|
| 626 |
+
strict: Union[bool, None] = _Unset,
|
| 627 |
+
multiple_of: Union[float, None] = _Unset,
|
| 628 |
+
allow_inf_nan: Union[bool, None] = _Unset,
|
| 629 |
+
max_digits: Union[int, None] = _Unset,
|
| 630 |
+
decimal_places: Union[int, None] = _Unset,
|
| 631 |
+
examples: Optional[List[Any]] = None,
|
| 632 |
+
example: Annotated[
|
| 633 |
+
Optional[Any],
|
| 634 |
+
deprecated(
|
| 635 |
+
"Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, "
|
| 636 |
+
"although still supported. Use examples instead."
|
| 637 |
+
),
|
| 638 |
+
] = _Unset,
|
| 639 |
+
openapi_examples: Optional[Dict[str, Example]] = None,
|
| 640 |
+
deprecated: Union[deprecated, str, bool, None] = None,
|
| 641 |
+
include_in_schema: bool = True,
|
| 642 |
+
json_schema_extra: Union[Dict[str, Any], None] = None,
|
| 643 |
+
**extra: Any,
|
| 644 |
+
):
|
| 645 |
+
super().__init__(
|
| 646 |
+
default=default,
|
| 647 |
+
default_factory=default_factory,
|
| 648 |
+
annotation=annotation,
|
| 649 |
+
media_type=media_type,
|
| 650 |
+
alias=alias,
|
| 651 |
+
alias_priority=alias_priority,
|
| 652 |
+
validation_alias=validation_alias,
|
| 653 |
+
serialization_alias=serialization_alias,
|
| 654 |
+
title=title,
|
| 655 |
+
description=description,
|
| 656 |
+
gt=gt,
|
| 657 |
+
ge=ge,
|
| 658 |
+
lt=lt,
|
| 659 |
+
le=le,
|
| 660 |
+
min_length=min_length,
|
| 661 |
+
max_length=max_length,
|
| 662 |
+
pattern=pattern,
|
| 663 |
+
regex=regex,
|
| 664 |
+
discriminator=discriminator,
|
| 665 |
+
strict=strict,
|
| 666 |
+
multiple_of=multiple_of,
|
| 667 |
+
allow_inf_nan=allow_inf_nan,
|
| 668 |
+
max_digits=max_digits,
|
| 669 |
+
decimal_places=decimal_places,
|
| 670 |
+
deprecated=deprecated,
|
| 671 |
+
example=example,
|
| 672 |
+
examples=examples,
|
| 673 |
+
openapi_examples=openapi_examples,
|
| 674 |
+
include_in_schema=include_in_schema,
|
| 675 |
+
json_schema_extra=json_schema_extra,
|
| 676 |
+
**extra,
|
| 677 |
+
)
|
| 678 |
+
|
| 679 |
+
|
| 680 |
+
class File(Form):
|
| 681 |
+
def __init__(
|
| 682 |
+
self,
|
| 683 |
+
default: Any = Undefined,
|
| 684 |
+
*,
|
| 685 |
+
default_factory: Union[Callable[[], Any], None] = _Unset,
|
| 686 |
+
annotation: Optional[Any] = None,
|
| 687 |
+
media_type: str = "multipart/form-data",
|
| 688 |
+
alias: Optional[str] = None,
|
| 689 |
+
alias_priority: Union[int, None] = _Unset,
|
| 690 |
+
# TODO: update when deprecating Pydantic v1, import these types
|
| 691 |
+
# validation_alias: str | AliasPath | AliasChoices | None
|
| 692 |
+
validation_alias: Union[str, None] = None,
|
| 693 |
+
serialization_alias: Union[str, None] = None,
|
| 694 |
+
title: Optional[str] = None,
|
| 695 |
+
description: Optional[str] = None,
|
| 696 |
+
gt: Optional[float] = None,
|
| 697 |
+
ge: Optional[float] = None,
|
| 698 |
+
lt: Optional[float] = None,
|
| 699 |
+
le: Optional[float] = None,
|
| 700 |
+
min_length: Optional[int] = None,
|
| 701 |
+
max_length: Optional[int] = None,
|
| 702 |
+
pattern: Optional[str] = None,
|
| 703 |
+
regex: Annotated[
|
| 704 |
+
Optional[str],
|
| 705 |
+
deprecated(
|
| 706 |
+
"Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead."
|
| 707 |
+
),
|
| 708 |
+
] = None,
|
| 709 |
+
discriminator: Union[str, None] = None,
|
| 710 |
+
strict: Union[bool, None] = _Unset,
|
| 711 |
+
multiple_of: Union[float, None] = _Unset,
|
| 712 |
+
allow_inf_nan: Union[bool, None] = _Unset,
|
| 713 |
+
max_digits: Union[int, None] = _Unset,
|
| 714 |
+
decimal_places: Union[int, None] = _Unset,
|
| 715 |
+
examples: Optional[List[Any]] = None,
|
| 716 |
+
example: Annotated[
|
| 717 |
+
Optional[Any],
|
| 718 |
+
deprecated(
|
| 719 |
+
"Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, "
|
| 720 |
+
"although still supported. Use examples instead."
|
| 721 |
+
),
|
| 722 |
+
] = _Unset,
|
| 723 |
+
openapi_examples: Optional[Dict[str, Example]] = None,
|
| 724 |
+
deprecated: Union[deprecated, str, bool, None] = None,
|
| 725 |
+
include_in_schema: bool = True,
|
| 726 |
+
json_schema_extra: Union[Dict[str, Any], None] = None,
|
| 727 |
+
**extra: Any,
|
| 728 |
+
):
|
| 729 |
+
super().__init__(
|
| 730 |
+
default=default,
|
| 731 |
+
default_factory=default_factory,
|
| 732 |
+
annotation=annotation,
|
| 733 |
+
media_type=media_type,
|
| 734 |
+
alias=alias,
|
| 735 |
+
alias_priority=alias_priority,
|
| 736 |
+
validation_alias=validation_alias,
|
| 737 |
+
serialization_alias=serialization_alias,
|
| 738 |
+
title=title,
|
| 739 |
+
description=description,
|
| 740 |
+
gt=gt,
|
| 741 |
+
ge=ge,
|
| 742 |
+
lt=lt,
|
| 743 |
+
le=le,
|
| 744 |
+
min_length=min_length,
|
| 745 |
+
max_length=max_length,
|
| 746 |
+
pattern=pattern,
|
| 747 |
+
regex=regex,
|
| 748 |
+
discriminator=discriminator,
|
| 749 |
+
strict=strict,
|
| 750 |
+
multiple_of=multiple_of,
|
| 751 |
+
allow_inf_nan=allow_inf_nan,
|
| 752 |
+
max_digits=max_digits,
|
| 753 |
+
decimal_places=decimal_places,
|
| 754 |
+
deprecated=deprecated,
|
| 755 |
+
example=example,
|
| 756 |
+
examples=examples,
|
| 757 |
+
openapi_examples=openapi_examples,
|
| 758 |
+
include_in_schema=include_in_schema,
|
| 759 |
+
json_schema_extra=json_schema_extra,
|
| 760 |
+
**extra,
|
| 761 |
+
)
|
| 762 |
+
|
| 763 |
+
|
| 764 |
+
class Depends:
|
| 765 |
+
def __init__(
|
| 766 |
+
self, dependency: Optional[Callable[..., Any]] = None, *, use_cache: bool = True
|
| 767 |
+
):
|
| 768 |
+
self.dependency = dependency
|
| 769 |
+
self.use_cache = use_cache
|
| 770 |
+
|
| 771 |
+
def __repr__(self) -> str:
|
| 772 |
+
attr = getattr(self.dependency, "__name__", type(self.dependency).__name__)
|
| 773 |
+
cache = "" if self.use_cache else ", use_cache=False"
|
| 774 |
+
return f"{self.__class__.__name__}({attr}{cache})"
|
| 775 |
+
|
| 776 |
+
|
| 777 |
+
class Security(Depends):
|
| 778 |
+
def __init__(
|
| 779 |
+
self,
|
| 780 |
+
dependency: Optional[Callable[..., Any]] = None,
|
| 781 |
+
*,
|
| 782 |
+
scopes: Optional[Sequence[str]] = None,
|
| 783 |
+
use_cache: bool = True,
|
| 784 |
+
):
|
| 785 |
+
super().__init__(dependency=dependency, use_cache=use_cache)
|
| 786 |
+
self.scopes = scopes or []
|
lib/python3.12/site-packages/fastapi/py.typed
ADDED
|
File without changes
|
lib/python3.12/site-packages/fastapi/requests.py
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from starlette.requests import HTTPConnection as HTTPConnection # noqa: F401
|
| 2 |
+
from starlette.requests import Request as Request # noqa: F401
|
lib/python3.12/site-packages/fastapi/responses.py
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from typing import Any
|
| 2 |
+
|
| 3 |
+
from starlette.responses import FileResponse as FileResponse # noqa
|
| 4 |
+
from starlette.responses import HTMLResponse as HTMLResponse # noqa
|
| 5 |
+
from starlette.responses import JSONResponse as JSONResponse # noqa
|
| 6 |
+
from starlette.responses import PlainTextResponse as PlainTextResponse # noqa
|
| 7 |
+
from starlette.responses import RedirectResponse as RedirectResponse # noqa
|
| 8 |
+
from starlette.responses import Response as Response # noqa
|
| 9 |
+
from starlette.responses import StreamingResponse as StreamingResponse # noqa
|
| 10 |
+
|
| 11 |
+
try:
|
| 12 |
+
import ujson
|
| 13 |
+
except ImportError: # pragma: nocover
|
| 14 |
+
ujson = None # type: ignore
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
try:
|
| 18 |
+
import orjson
|
| 19 |
+
except ImportError: # pragma: nocover
|
| 20 |
+
orjson = None # type: ignore
|
| 21 |
+
|
| 22 |
+
|
| 23 |
+
class UJSONResponse(JSONResponse):
|
| 24 |
+
"""
|
| 25 |
+
JSON response using the high-performance ujson library to serialize data to JSON.
|
| 26 |
+
|
| 27 |
+
Read more about it in the
|
| 28 |
+
[FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/).
|
| 29 |
+
"""
|
| 30 |
+
|
| 31 |
+
def render(self, content: Any) -> bytes:
|
| 32 |
+
assert ujson is not None, "ujson must be installed to use UJSONResponse"
|
| 33 |
+
return ujson.dumps(content, ensure_ascii=False).encode("utf-8")
|
| 34 |
+
|
| 35 |
+
|
| 36 |
+
class ORJSONResponse(JSONResponse):
|
| 37 |
+
"""
|
| 38 |
+
JSON response using the high-performance orjson library to serialize data to JSON.
|
| 39 |
+
|
| 40 |
+
Read more about it in the
|
| 41 |
+
[FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/).
|
| 42 |
+
"""
|
| 43 |
+
|
| 44 |
+
def render(self, content: Any) -> bytes:
|
| 45 |
+
assert orjson is not None, "orjson must be installed to use ORJSONResponse"
|
| 46 |
+
return orjson.dumps(
|
| 47 |
+
content, option=orjson.OPT_NON_STR_KEYS | orjson.OPT_SERIALIZE_NUMPY
|
| 48 |
+
)
|
lib/python3.12/site-packages/fastapi/routing.py
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
lib/python3.12/site-packages/fastapi/security/__init__.py
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from .api_key import APIKeyCookie as APIKeyCookie
|
| 2 |
+
from .api_key import APIKeyHeader as APIKeyHeader
|
| 3 |
+
from .api_key import APIKeyQuery as APIKeyQuery
|
| 4 |
+
from .http import HTTPAuthorizationCredentials as HTTPAuthorizationCredentials
|
| 5 |
+
from .http import HTTPBasic as HTTPBasic
|
| 6 |
+
from .http import HTTPBasicCredentials as HTTPBasicCredentials
|
| 7 |
+
from .http import HTTPBearer as HTTPBearer
|
| 8 |
+
from .http import HTTPDigest as HTTPDigest
|
| 9 |
+
from .oauth2 import OAuth2 as OAuth2
|
| 10 |
+
from .oauth2 import OAuth2AuthorizationCodeBearer as OAuth2AuthorizationCodeBearer
|
| 11 |
+
from .oauth2 import OAuth2PasswordBearer as OAuth2PasswordBearer
|
| 12 |
+
from .oauth2 import OAuth2PasswordRequestForm as OAuth2PasswordRequestForm
|
| 13 |
+
from .oauth2 import OAuth2PasswordRequestFormStrict as OAuth2PasswordRequestFormStrict
|
| 14 |
+
from .oauth2 import SecurityScopes as SecurityScopes
|
| 15 |
+
from .open_id_connect_url import OpenIdConnect as OpenIdConnect
|
lib/python3.12/site-packages/fastapi/security/__pycache__/__init__.cpython-312.pyc
ADDED
|
Binary file (851 Bytes). View file
|
|
|
lib/python3.12/site-packages/fastapi/security/__pycache__/api_key.cpython-312.pyc
ADDED
|
Binary file (9.7 kB). View file
|
|
|
lib/python3.12/site-packages/fastapi/security/__pycache__/base.cpython-312.pyc
ADDED
|
Binary file (513 Bytes). View file
|
|
|
lib/python3.12/site-packages/fastapi/security/__pycache__/http.cpython-312.pyc
ADDED
|
Binary file (13.6 kB). View file
|
|
|
lib/python3.12/site-packages/fastapi/security/__pycache__/oauth2.cpython-312.pyc
ADDED
|
Binary file (18.3 kB). View file
|
|
|
lib/python3.12/site-packages/fastapi/security/__pycache__/open_id_connect_url.cpython-312.pyc
ADDED
|
Binary file (3.22 kB). View file
|
|
|
lib/python3.12/site-packages/fastapi/security/__pycache__/utils.cpython-312.pyc
ADDED
|
Binary file (606 Bytes). View file
|
|
|
lib/python3.12/site-packages/fastapi/security/api_key.py
ADDED
|
@@ -0,0 +1,288 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from typing import Optional
|
| 2 |
+
|
| 3 |
+
from fastapi.openapi.models import APIKey, APIKeyIn
|
| 4 |
+
from fastapi.security.base import SecurityBase
|
| 5 |
+
from starlette.exceptions import HTTPException
|
| 6 |
+
from starlette.requests import Request
|
| 7 |
+
from starlette.status import HTTP_403_FORBIDDEN
|
| 8 |
+
from typing_extensions import Annotated, Doc
|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
class APIKeyBase(SecurityBase):
|
| 12 |
+
@staticmethod
|
| 13 |
+
def check_api_key(api_key: Optional[str], auto_error: bool) -> Optional[str]:
|
| 14 |
+
if not api_key:
|
| 15 |
+
if auto_error:
|
| 16 |
+
raise HTTPException(
|
| 17 |
+
status_code=HTTP_403_FORBIDDEN, detail="Not authenticated"
|
| 18 |
+
)
|
| 19 |
+
return None
|
| 20 |
+
return api_key
|
| 21 |
+
|
| 22 |
+
|
| 23 |
+
class APIKeyQuery(APIKeyBase):
|
| 24 |
+
"""
|
| 25 |
+
API key authentication using a query parameter.
|
| 26 |
+
|
| 27 |
+
This defines the name of the query parameter that should be provided in the request
|
| 28 |
+
with the API key and integrates that into the OpenAPI documentation. It extracts
|
| 29 |
+
the key value sent in the query parameter automatically and provides it as the
|
| 30 |
+
dependency result. But it doesn't define how to send that API key to the client.
|
| 31 |
+
|
| 32 |
+
## Usage
|
| 33 |
+
|
| 34 |
+
Create an instance object and use that object as the dependency in `Depends()`.
|
| 35 |
+
|
| 36 |
+
The dependency result will be a string containing the key value.
|
| 37 |
+
|
| 38 |
+
## Example
|
| 39 |
+
|
| 40 |
+
```python
|
| 41 |
+
from fastapi import Depends, FastAPI
|
| 42 |
+
from fastapi.security import APIKeyQuery
|
| 43 |
+
|
| 44 |
+
app = FastAPI()
|
| 45 |
+
|
| 46 |
+
query_scheme = APIKeyQuery(name="api_key")
|
| 47 |
+
|
| 48 |
+
|
| 49 |
+
@app.get("/items/")
|
| 50 |
+
async def read_items(api_key: str = Depends(query_scheme)):
|
| 51 |
+
return {"api_key": api_key}
|
| 52 |
+
```
|
| 53 |
+
"""
|
| 54 |
+
|
| 55 |
+
def __init__(
|
| 56 |
+
self,
|
| 57 |
+
*,
|
| 58 |
+
name: Annotated[
|
| 59 |
+
str,
|
| 60 |
+
Doc("Query parameter name."),
|
| 61 |
+
],
|
| 62 |
+
scheme_name: Annotated[
|
| 63 |
+
Optional[str],
|
| 64 |
+
Doc(
|
| 65 |
+
"""
|
| 66 |
+
Security scheme name.
|
| 67 |
+
|
| 68 |
+
It will be included in the generated OpenAPI (e.g. visible at `/docs`).
|
| 69 |
+
"""
|
| 70 |
+
),
|
| 71 |
+
] = None,
|
| 72 |
+
description: Annotated[
|
| 73 |
+
Optional[str],
|
| 74 |
+
Doc(
|
| 75 |
+
"""
|
| 76 |
+
Security scheme description.
|
| 77 |
+
|
| 78 |
+
It will be included in the generated OpenAPI (e.g. visible at `/docs`).
|
| 79 |
+
"""
|
| 80 |
+
),
|
| 81 |
+
] = None,
|
| 82 |
+
auto_error: Annotated[
|
| 83 |
+
bool,
|
| 84 |
+
Doc(
|
| 85 |
+
"""
|
| 86 |
+
By default, if the query parameter is not provided, `APIKeyQuery` will
|
| 87 |
+
automatically cancel the request and send the client an error.
|
| 88 |
+
|
| 89 |
+
If `auto_error` is set to `False`, when the query parameter is not
|
| 90 |
+
available, instead of erroring out, the dependency result will be
|
| 91 |
+
`None`.
|
| 92 |
+
|
| 93 |
+
This is useful when you want to have optional authentication.
|
| 94 |
+
|
| 95 |
+
It is also useful when you want to have authentication that can be
|
| 96 |
+
provided in one of multiple optional ways (for example, in a query
|
| 97 |
+
parameter or in an HTTP Bearer token).
|
| 98 |
+
"""
|
| 99 |
+
),
|
| 100 |
+
] = True,
|
| 101 |
+
):
|
| 102 |
+
self.model: APIKey = APIKey(
|
| 103 |
+
**{"in": APIKeyIn.query}, # type: ignore[arg-type]
|
| 104 |
+
name=name,
|
| 105 |
+
description=description,
|
| 106 |
+
)
|
| 107 |
+
self.scheme_name = scheme_name or self.__class__.__name__
|
| 108 |
+
self.auto_error = auto_error
|
| 109 |
+
|
| 110 |
+
async def __call__(self, request: Request) -> Optional[str]:
|
| 111 |
+
api_key = request.query_params.get(self.model.name)
|
| 112 |
+
return self.check_api_key(api_key, self.auto_error)
|
| 113 |
+
|
| 114 |
+
|
| 115 |
+
class APIKeyHeader(APIKeyBase):
|
| 116 |
+
"""
|
| 117 |
+
API key authentication using a header.
|
| 118 |
+
|
| 119 |
+
This defines the name of the header that should be provided in the request with
|
| 120 |
+
the API key and integrates that into the OpenAPI documentation. It extracts
|
| 121 |
+
the key value sent in the header automatically and provides it as the dependency
|
| 122 |
+
result. But it doesn't define how to send that key to the client.
|
| 123 |
+
|
| 124 |
+
## Usage
|
| 125 |
+
|
| 126 |
+
Create an instance object and use that object as the dependency in `Depends()`.
|
| 127 |
+
|
| 128 |
+
The dependency result will be a string containing the key value.
|
| 129 |
+
|
| 130 |
+
## Example
|
| 131 |
+
|
| 132 |
+
```python
|
| 133 |
+
from fastapi import Depends, FastAPI
|
| 134 |
+
from fastapi.security import APIKeyHeader
|
| 135 |
+
|
| 136 |
+
app = FastAPI()
|
| 137 |
+
|
| 138 |
+
header_scheme = APIKeyHeader(name="x-key")
|
| 139 |
+
|
| 140 |
+
|
| 141 |
+
@app.get("/items/")
|
| 142 |
+
async def read_items(key: str = Depends(header_scheme)):
|
| 143 |
+
return {"key": key}
|
| 144 |
+
```
|
| 145 |
+
"""
|
| 146 |
+
|
| 147 |
+
def __init__(
|
| 148 |
+
self,
|
| 149 |
+
*,
|
| 150 |
+
name: Annotated[str, Doc("Header name.")],
|
| 151 |
+
scheme_name: Annotated[
|
| 152 |
+
Optional[str],
|
| 153 |
+
Doc(
|
| 154 |
+
"""
|
| 155 |
+
Security scheme name.
|
| 156 |
+
|
| 157 |
+
It will be included in the generated OpenAPI (e.g. visible at `/docs`).
|
| 158 |
+
"""
|
| 159 |
+
),
|
| 160 |
+
] = None,
|
| 161 |
+
description: Annotated[
|
| 162 |
+
Optional[str],
|
| 163 |
+
Doc(
|
| 164 |
+
"""
|
| 165 |
+
Security scheme description.
|
| 166 |
+
|
| 167 |
+
It will be included in the generated OpenAPI (e.g. visible at `/docs`).
|
| 168 |
+
"""
|
| 169 |
+
),
|
| 170 |
+
] = None,
|
| 171 |
+
auto_error: Annotated[
|
| 172 |
+
bool,
|
| 173 |
+
Doc(
|
| 174 |
+
"""
|
| 175 |
+
By default, if the header is not provided, `APIKeyHeader` will
|
| 176 |
+
automatically cancel the request and send the client an error.
|
| 177 |
+
|
| 178 |
+
If `auto_error` is set to `False`, when the header is not available,
|
| 179 |
+
instead of erroring out, the dependency result will be `None`.
|
| 180 |
+
|
| 181 |
+
This is useful when you want to have optional authentication.
|
| 182 |
+
|
| 183 |
+
It is also useful when you want to have authentication that can be
|
| 184 |
+
provided in one of multiple optional ways (for example, in a header or
|
| 185 |
+
in an HTTP Bearer token).
|
| 186 |
+
"""
|
| 187 |
+
),
|
| 188 |
+
] = True,
|
| 189 |
+
):
|
| 190 |
+
self.model: APIKey = APIKey(
|
| 191 |
+
**{"in": APIKeyIn.header}, # type: ignore[arg-type]
|
| 192 |
+
name=name,
|
| 193 |
+
description=description,
|
| 194 |
+
)
|
| 195 |
+
self.scheme_name = scheme_name or self.__class__.__name__
|
| 196 |
+
self.auto_error = auto_error
|
| 197 |
+
|
| 198 |
+
async def __call__(self, request: Request) -> Optional[str]:
|
| 199 |
+
api_key = request.headers.get(self.model.name)
|
| 200 |
+
return self.check_api_key(api_key, self.auto_error)
|
| 201 |
+
|
| 202 |
+
|
| 203 |
+
class APIKeyCookie(APIKeyBase):
|
| 204 |
+
"""
|
| 205 |
+
API key authentication using a cookie.
|
| 206 |
+
|
| 207 |
+
This defines the name of the cookie that should be provided in the request with
|
| 208 |
+
the API key and integrates that into the OpenAPI documentation. It extracts
|
| 209 |
+
the key value sent in the cookie automatically and provides it as the dependency
|
| 210 |
+
result. But it doesn't define how to set that cookie.
|
| 211 |
+
|
| 212 |
+
## Usage
|
| 213 |
+
|
| 214 |
+
Create an instance object and use that object as the dependency in `Depends()`.
|
| 215 |
+
|
| 216 |
+
The dependency result will be a string containing the key value.
|
| 217 |
+
|
| 218 |
+
## Example
|
| 219 |
+
|
| 220 |
+
```python
|
| 221 |
+
from fastapi import Depends, FastAPI
|
| 222 |
+
from fastapi.security import APIKeyCookie
|
| 223 |
+
|
| 224 |
+
app = FastAPI()
|
| 225 |
+
|
| 226 |
+
cookie_scheme = APIKeyCookie(name="session")
|
| 227 |
+
|
| 228 |
+
|
| 229 |
+
@app.get("/items/")
|
| 230 |
+
async def read_items(session: str = Depends(cookie_scheme)):
|
| 231 |
+
return {"session": session}
|
| 232 |
+
```
|
| 233 |
+
"""
|
| 234 |
+
|
| 235 |
+
def __init__(
|
| 236 |
+
self,
|
| 237 |
+
*,
|
| 238 |
+
name: Annotated[str, Doc("Cookie name.")],
|
| 239 |
+
scheme_name: Annotated[
|
| 240 |
+
Optional[str],
|
| 241 |
+
Doc(
|
| 242 |
+
"""
|
| 243 |
+
Security scheme name.
|
| 244 |
+
|
| 245 |
+
It will be included in the generated OpenAPI (e.g. visible at `/docs`).
|
| 246 |
+
"""
|
| 247 |
+
),
|
| 248 |
+
] = None,
|
| 249 |
+
description: Annotated[
|
| 250 |
+
Optional[str],
|
| 251 |
+
Doc(
|
| 252 |
+
"""
|
| 253 |
+
Security scheme description.
|
| 254 |
+
|
| 255 |
+
It will be included in the generated OpenAPI (e.g. visible at `/docs`).
|
| 256 |
+
"""
|
| 257 |
+
),
|
| 258 |
+
] = None,
|
| 259 |
+
auto_error: Annotated[
|
| 260 |
+
bool,
|
| 261 |
+
Doc(
|
| 262 |
+
"""
|
| 263 |
+
By default, if the cookie is not provided, `APIKeyCookie` will
|
| 264 |
+
automatically cancel the request and send the client an error.
|
| 265 |
+
|
| 266 |
+
If `auto_error` is set to `False`, when the cookie is not available,
|
| 267 |
+
instead of erroring out, the dependency result will be `None`.
|
| 268 |
+
|
| 269 |
+
This is useful when you want to have optional authentication.
|
| 270 |
+
|
| 271 |
+
It is also useful when you want to have authentication that can be
|
| 272 |
+
provided in one of multiple optional ways (for example, in a cookie or
|
| 273 |
+
in an HTTP Bearer token).
|
| 274 |
+
"""
|
| 275 |
+
),
|
| 276 |
+
] = True,
|
| 277 |
+
):
|
| 278 |
+
self.model: APIKey = APIKey(
|
| 279 |
+
**{"in": APIKeyIn.cookie}, # type: ignore[arg-type]
|
| 280 |
+
name=name,
|
| 281 |
+
description=description,
|
| 282 |
+
)
|
| 283 |
+
self.scheme_name = scheme_name or self.__class__.__name__
|
| 284 |
+
self.auto_error = auto_error
|
| 285 |
+
|
| 286 |
+
async def __call__(self, request: Request) -> Optional[str]:
|
| 287 |
+
api_key = request.cookies.get(self.model.name)
|
| 288 |
+
return self.check_api_key(api_key, self.auto_error)
|