- FastAPI framework, high performance, easy to learn, fast to code, ready for production -
- - ---- - -**Documentation**: https://fastapi.tiangolo.com - -**Source Code**: https://github.com/fastapi/fastapi - ---- - -FastAPI is a modern, fast (high-performance), web framework for building APIs with Python based on standard Python type hints. - -The key features are: - -* **Fast**: Very high performance, on par with **NodeJS** and **Go** (thanks to Starlette and Pydantic). [One of the fastest Python frameworks available](#performance). -* **Fast to code**: Increase the speed to develop features by about 200% to 300%. * -* **Fewer bugs**: Reduce about 40% of human (developer) induced errors. * -* **Intuitive**: Great editor support. Completion everywhere. Less time debugging. -* **Easy**: Designed to be easy to use and learn. Less time reading docs. -* **Short**: Minimize code duplication. Multiple features from each parameter declaration. Fewer bugs. -* **Robust**: Get production-ready code. With automatic interactive documentation. -* **Standards-based**: Based on (and fully compatible with) the open standards for APIs: OpenAPI (previously known as Swagger) and JSON Schema. - -* estimation based on tests on an internal development team, building production applications. - -## Sponsors - - - -
-
-
-
-
-
-
-
-
-
-
-
-
-Other sponsors
-
-## Opinions
-
-"_[...] I'm using **FastAPI** a ton these days. [...] I'm actually planning to use it for all of my team's **ML services at Microsoft**. Some of them are getting integrated into the core **Windows** product and some **Office** products._"
-
-async def...fastapi dev main.py...email-validator - for email validation.
-
-Used by Starlette:
-
-* httpx - Required if you want to use the `TestClient`.
-* jinja2 - Required if you want to use the default template configuration.
-* python-multipart - Required if you want to support form "parsing", with `request.form()`.
-
-Used by FastAPI / Starlette:
-
-* uvicorn - for the server that loads and serves your application. This includes `uvicorn[standard]`, which includes some dependencies (e.g. `uvloop`) needed for high performance serving.
-* `fastapi-cli` - to provide the `fastapi` command.
-
-### Without `standard` Dependencies
-
-If you don't want to include the `standard` optional dependencies, you can install with `pip install fastapi` instead of `pip install "fastapi[standard]"`.
-
-### Additional Optional Dependencies
-
-There are some additional dependencies you might want to install.
-
-Additional optional Pydantic dependencies:
-
-* pydantic-settings - for settings management.
-* pydantic-extra-types - for extra types to be used with Pydantic.
-
-Additional optional FastAPI dependencies:
-
-* orjson - Required if you want to use `ORJSONResponse`.
-* ujson - Required if you want to use `UJSONResponse`.
-
-## License
-
-This project is licensed under the terms of the MIT license.
diff --git a/backend/pig/Lib/python3.12/site-packages/fastapi-0.115.5.dist-info/RECORD b/backend/pig/Lib/python3.12/site-packages/fastapi-0.115.5.dist-info/RECORD
deleted file mode 100644
index 3f8e770..0000000
--- a/backend/pig/Lib/python3.12/site-packages/fastapi-0.115.5.dist-info/RECORD
+++ /dev/null
@@ -1,97 +0,0 @@
-../../../bin/fastapi,sha256=N9mvST2yNdJFl33odwhfjU7S5puy35gFLg3CgJXc-0s,273
-fastapi-0.115.5.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
-fastapi-0.115.5.dist-info/METADATA,sha256=8IXLQm48i6TD0hGPwT2wDvabW4GRYJMFoGnRm4AILSc,27300
-fastapi-0.115.5.dist-info/RECORD,,
-fastapi-0.115.5.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
-fastapi-0.115.5.dist-info/WHEEL,sha256=thaaA2w1JzcGC48WYufAs8nrYZjJm8LqNfnXFOFyCC4,90
-fastapi-0.115.5.dist-info/entry_points.txt,sha256=GCf-WbIZxyGT4MUmrPGj1cOHYZoGsNPHAvNkT6hnGeA,61
-fastapi-0.115.5.dist-info/licenses/LICENSE,sha256=Tsif_IFIW5f-xYSy1KlhAy7v_oNEU4lP2cEnSQbMdE4,1086
-fastapi/__init__.py,sha256=YJQY54XRlgbczimT8pNac98Wb1yZUfC1iVdnehG937Q,1081
-fastapi/__main__.py,sha256=bKePXLdO4SsVSM6r9SVoLickJDcR2c0cTOxZRKq26YQ,37
-fastapi/__pycache__/__init__.cpython-312.pyc,,
-fastapi/__pycache__/__main__.cpython-312.pyc,,
-fastapi/__pycache__/_compat.cpython-312.pyc,,
-fastapi/__pycache__/applications.cpython-312.pyc,,
-fastapi/__pycache__/background.cpython-312.pyc,,
-fastapi/__pycache__/cli.cpython-312.pyc,,
-fastapi/__pycache__/concurrency.cpython-312.pyc,,
-fastapi/__pycache__/datastructures.cpython-312.pyc,,
-fastapi/__pycache__/encoders.cpython-312.pyc,,
-fastapi/__pycache__/exception_handlers.cpython-312.pyc,,
-fastapi/__pycache__/exceptions.cpython-312.pyc,,
-fastapi/__pycache__/logger.cpython-312.pyc,,
-fastapi/__pycache__/param_functions.cpython-312.pyc,,
-fastapi/__pycache__/params.cpython-312.pyc,,
-fastapi/__pycache__/requests.cpython-312.pyc,,
-fastapi/__pycache__/responses.cpython-312.pyc,,
-fastapi/__pycache__/routing.cpython-312.pyc,,
-fastapi/__pycache__/staticfiles.cpython-312.pyc,,
-fastapi/__pycache__/templating.cpython-312.pyc,,
-fastapi/__pycache__/testclient.cpython-312.pyc,,
-fastapi/__pycache__/types.cpython-312.pyc,,
-fastapi/__pycache__/utils.cpython-312.pyc,,
-fastapi/__pycache__/websockets.cpython-312.pyc,,
-fastapi/_compat.py,sha256=rrpxrPgF5fCUInIKaeVd0scVTFRUkZlHR9puxvTrcB0,24010
-fastapi/applications.py,sha256=Ix-o9pQAWhEDf9J0Q1hZ0nBB1uP72c-Y3oiYzvrwqiM,176316
-fastapi/background.py,sha256=rouLirxUANrcYC824MSMypXL_Qb2HYg2YZqaiEqbEKI,1768
-fastapi/cli.py,sha256=OYhZb0NR_deuT5ofyPF2NoNBzZDNOP8Salef2nk-HqA,418
-fastapi/concurrency.py,sha256=AYLnS4judDUmXsNRICtoKSP0prfYDcS8ehBtYW9JhQQ,1403
-fastapi/datastructures.py,sha256=b2PEz77XGq-u3Ur1Inwk0AGjOsQZO49yF9C7IPJ15cY,5766
-fastapi/dependencies/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
-fastapi/dependencies/__pycache__/__init__.cpython-312.pyc,,
-fastapi/dependencies/__pycache__/models.cpython-312.pyc,,
-fastapi/dependencies/__pycache__/utils.cpython-312.pyc,,
-fastapi/dependencies/models.py,sha256=Pjl6vx-4nZ5Tta9kJa3-RfQKkXtCpS09-FhMgs9eWNs,1507
-fastapi/dependencies/utils.py,sha256=UqN1H0k_4PCnP-nRYNpup1fdIuzEx1F5ZVO6WuVRx4E,35579
-fastapi/encoders.py,sha256=LvwYmFeOz4tVwvgBoC5rvZnbr7hZr73KGrU8O7zSptU,11068
-fastapi/exception_handlers.py,sha256=MBrIOA-ugjJDivIi4rSsUJBdTsjuzN76q4yh0q1COKw,1332
-fastapi/exceptions.py,sha256=taNixuFEXb67lI1bnX1ubq8y8TseJ4yoPlWjyP0fTzk,4969
-fastapi/logger.py,sha256=I9NNi3ov8AcqbsbC9wl1X-hdItKgYt2XTrx1f99Zpl4,54
-fastapi/middleware/__init__.py,sha256=oQDxiFVcc1fYJUOIFvphnK7pTT5kktmfL32QXpBFvvo,58
-fastapi/middleware/__pycache__/__init__.cpython-312.pyc,,
-fastapi/middleware/__pycache__/cors.cpython-312.pyc,,
-fastapi/middleware/__pycache__/gzip.cpython-312.pyc,,
-fastapi/middleware/__pycache__/httpsredirect.cpython-312.pyc,,
-fastapi/middleware/__pycache__/trustedhost.cpython-312.pyc,,
-fastapi/middleware/__pycache__/wsgi.cpython-312.pyc,,
-fastapi/middleware/cors.py,sha256=ynwjWQZoc_vbhzZ3_ZXceoaSrslHFHPdoM52rXr0WUU,79
-fastapi/middleware/gzip.py,sha256=xM5PcsH8QlAimZw4VDvcmTnqQamslThsfe3CVN2voa0,79
-fastapi/middleware/httpsredirect.py,sha256=rL8eXMnmLijwVkH7_400zHri1AekfeBd6D6qs8ix950,115
-fastapi/middleware/trustedhost.py,sha256=eE5XGRxGa7c5zPnMJDGp3BxaL25k5iVQlhnv-Pk0Pss,109
-fastapi/middleware/wsgi.py,sha256=Z3Ue-7wni4lUZMvH3G9ek__acgYdJstbnpZX_HQAboY,79
-fastapi/openapi/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
-fastapi/openapi/__pycache__/__init__.cpython-312.pyc,,
-fastapi/openapi/__pycache__/constants.cpython-312.pyc,,
-fastapi/openapi/__pycache__/docs.cpython-312.pyc,,
-fastapi/openapi/__pycache__/models.cpython-312.pyc,,
-fastapi/openapi/__pycache__/utils.cpython-312.pyc,,
-fastapi/openapi/constants.py,sha256=adGzmis1L1HJRTE3kJ5fmHS_Noq6tIY6pWv_SFzoFDU,153
-fastapi/openapi/docs.py,sha256=XcQq-ZbQdC5sI0gIGu5MoHK1q-OFaqws7-ORTo6sjY4,10348
-fastapi/openapi/models.py,sha256=PqkxQiqcEgjKuhfUIWPZPQcyTcubtUCB3vcObLsB7VE,15397
-fastapi/openapi/utils.py,sha256=vpbAzWpuNaJL_ocBxt4jp0GUUwrDKNB1anyoAx69fhA,23177
-fastapi/param_functions.py,sha256=JHNPLIYvoAwdnZZavIVsxOat8x23fX_Kl33reh7HKl8,64019
-fastapi/params.py,sha256=g450axUBQgQJODdtM7WBxZbQj9Z64inFvadrgHikBbU,28237
-fastapi/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
-fastapi/requests.py,sha256=zayepKFcienBllv3snmWI20Gk0oHNVLU4DDhqXBb4LU,142
-fastapi/responses.py,sha256=QNQQlwpKhQoIPZTTWkpc9d_QGeGZ_aVQPaDV3nQ8m7c,1761
-fastapi/routing.py,sha256=WK06IwZeyRwxkdB4uHZ7JXinxtVOxM8Ke0tqHaDOvYA,176208
-fastapi/security/__init__.py,sha256=bO8pNmxqVRXUjfl2mOKiVZLn0FpBQ61VUYVjmppnbJw,881
-fastapi/security/__pycache__/__init__.cpython-312.pyc,,
-fastapi/security/__pycache__/api_key.cpython-312.pyc,,
-fastapi/security/__pycache__/base.cpython-312.pyc,,
-fastapi/security/__pycache__/http.cpython-312.pyc,,
-fastapi/security/__pycache__/oauth2.cpython-312.pyc,,
-fastapi/security/__pycache__/open_id_connect_url.cpython-312.pyc,,
-fastapi/security/__pycache__/utils.cpython-312.pyc,,
-fastapi/security/api_key.py,sha256=_OqUUjEHG5_MT1IPAhXIGJRCPldTBdSww_DegFy_W8Y,9368
-fastapi/security/base.py,sha256=dl4pvbC-RxjfbWgPtCWd8MVU-7CB2SZ22rJDXVCXO6c,141
-fastapi/security/http.py,sha256=223bAV_d7NjI57Pzhbd_KlQTYlMyr5MoN1TW80rbxF8,13512
-fastapi/security/oauth2.py,sha256=BbXdQ_W2Pm5NIcpHGBSBa1u3t0EBLCgiYdOLfid1t4A,21585
-fastapi/security/open_id_connect_url.py,sha256=8vizZ2tGqEp1ur8SwtVgyHJhGAJ5AqahgcvSpaIioDI,2722
-fastapi/security/utils.py,sha256=bd8T0YM7UQD5ATKucr1bNtAvz_Y3__dVNAv5UebiPvc,293
-fastapi/staticfiles.py,sha256=iirGIt3sdY2QZXd36ijs3Cj-T0FuGFda3cd90kM9Ikw,69
-fastapi/templating.py,sha256=4zsuTWgcjcEainMJFAlW6-gnslm6AgOS1SiiDWfmQxk,76
-fastapi/testclient.py,sha256=nBvaAmX66YldReJNZXPOk1sfuo2Q6hs8bOvIaCep6LQ,66
-fastapi/types.py,sha256=nFb36sK3DSoqoyo7Miwy3meKK5UdFBgkAgLSzQlUVyI,383
-fastapi/utils.py,sha256=y8Bj5ttMaI9tS4D60OUgXqKnktBr99NdYUnHHV9LgoY,7948
-fastapi/websockets.py,sha256=419uncYObEKZG0YcrXscfQQYLSWoE10jqxVMetGdR98,222
diff --git a/backend/pig/Lib/python3.12/site-packages/fastapi-0.115.5.dist-info/REQUESTED b/backend/pig/Lib/python3.12/site-packages/fastapi-0.115.5.dist-info/REQUESTED
deleted file mode 100644
index e69de29..0000000
diff --git a/backend/pig/Lib/python3.12/site-packages/fastapi-0.115.5.dist-info/WHEEL b/backend/pig/Lib/python3.12/site-packages/fastapi-0.115.5.dist-info/WHEEL
deleted file mode 100644
index 64b991e..0000000
--- a/backend/pig/Lib/python3.12/site-packages/fastapi-0.115.5.dist-info/WHEEL
+++ /dev/null
@@ -1,4 +0,0 @@
-Wheel-Version: 1.0
-Generator: pdm-backend (2.4.3)
-Root-Is-Purelib: true
-Tag: py3-none-any
diff --git a/backend/pig/Lib/python3.12/site-packages/fastapi-0.115.5.dist-info/entry_points.txt b/backend/pig/Lib/python3.12/site-packages/fastapi-0.115.5.dist-info/entry_points.txt
deleted file mode 100644
index b81849e..0000000
--- a/backend/pig/Lib/python3.12/site-packages/fastapi-0.115.5.dist-info/entry_points.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-[console_scripts]
-fastapi = fastapi.cli:main
-
-[gui_scripts]
-
diff --git a/backend/pig/Lib/python3.12/site-packages/fastapi-0.115.5.dist-info/licenses/LICENSE b/backend/pig/Lib/python3.12/site-packages/fastapi-0.115.5.dist-info/licenses/LICENSE
deleted file mode 100644
index 3e92463..0000000
--- a/backend/pig/Lib/python3.12/site-packages/fastapi-0.115.5.dist-info/licenses/LICENSE
+++ /dev/null
@@ -1,21 +0,0 @@
-The MIT License (MIT)
-
-Copyright (c) 2018 Sebastián Ramírez
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
diff --git a/backend/pig/Lib/python3.12/site-packages/fastapi/__init__.py b/backend/pig/Lib/python3.12/site-packages/fastapi/__init__.py
deleted file mode 100644
index 12faea9..0000000
--- a/backend/pig/Lib/python3.12/site-packages/fastapi/__init__.py
+++ /dev/null
@@ -1,25 +0,0 @@
-"""FastAPI framework, high performance, easy to learn, fast to code, ready for production"""
-
-__version__ = "0.115.5"
-
-from starlette import status as status
-
-from .applications import FastAPI as FastAPI
-from .background import BackgroundTasks as BackgroundTasks
-from .datastructures import UploadFile as UploadFile
-from .exceptions import HTTPException as HTTPException
-from .exceptions import WebSocketException as WebSocketException
-from .param_functions import Body as Body
-from .param_functions import Cookie as Cookie
-from .param_functions import Depends as Depends
-from .param_functions import File as File
-from .param_functions import Form as Form
-from .param_functions import Header as Header
-from .param_functions import Path as Path
-from .param_functions import Query as Query
-from .param_functions import Security as Security
-from .requests import Request as Request
-from .responses import Response as Response
-from .routing import APIRouter as APIRouter
-from .websockets import WebSocket as WebSocket
-from .websockets import WebSocketDisconnect as WebSocketDisconnect
diff --git a/backend/pig/Lib/python3.12/site-packages/fastapi/__main__.py b/backend/pig/Lib/python3.12/site-packages/fastapi/__main__.py
deleted file mode 100644
index fc36465..0000000
--- a/backend/pig/Lib/python3.12/site-packages/fastapi/__main__.py
+++ /dev/null
@@ -1,3 +0,0 @@
-from fastapi.cli import main
-
-main()
diff --git a/backend/pig/Lib/python3.12/site-packages/fastapi/__pycache__/__init__.cpython-312.pyc b/backend/pig/Lib/python3.12/site-packages/fastapi/__pycache__/__init__.cpython-312.pyc
deleted file mode 100644
index aee7d7b..0000000
Binary files a/backend/pig/Lib/python3.12/site-packages/fastapi/__pycache__/__init__.cpython-312.pyc and /dev/null differ
diff --git a/backend/pig/Lib/python3.12/site-packages/fastapi/__pycache__/__main__.cpython-312.pyc b/backend/pig/Lib/python3.12/site-packages/fastapi/__pycache__/__main__.cpython-312.pyc
deleted file mode 100644
index 965909d..0000000
Binary files a/backend/pig/Lib/python3.12/site-packages/fastapi/__pycache__/__main__.cpython-312.pyc and /dev/null differ
diff --git a/backend/pig/Lib/python3.12/site-packages/fastapi/__pycache__/_compat.cpython-312.pyc b/backend/pig/Lib/python3.12/site-packages/fastapi/__pycache__/_compat.cpython-312.pyc
deleted file mode 100644
index 168a1d3..0000000
Binary files a/backend/pig/Lib/python3.12/site-packages/fastapi/__pycache__/_compat.cpython-312.pyc and /dev/null differ
diff --git a/backend/pig/Lib/python3.12/site-packages/fastapi/__pycache__/applications.cpython-312.pyc b/backend/pig/Lib/python3.12/site-packages/fastapi/__pycache__/applications.cpython-312.pyc
deleted file mode 100644
index 3f53455..0000000
Binary files a/backend/pig/Lib/python3.12/site-packages/fastapi/__pycache__/applications.cpython-312.pyc and /dev/null differ
diff --git a/backend/pig/Lib/python3.12/site-packages/fastapi/__pycache__/background.cpython-312.pyc b/backend/pig/Lib/python3.12/site-packages/fastapi/__pycache__/background.cpython-312.pyc
deleted file mode 100644
index 96291a2..0000000
Binary files a/backend/pig/Lib/python3.12/site-packages/fastapi/__pycache__/background.cpython-312.pyc and /dev/null differ
diff --git a/backend/pig/Lib/python3.12/site-packages/fastapi/__pycache__/cli.cpython-312.pyc b/backend/pig/Lib/python3.12/site-packages/fastapi/__pycache__/cli.cpython-312.pyc
deleted file mode 100644
index 10716bf..0000000
Binary files a/backend/pig/Lib/python3.12/site-packages/fastapi/__pycache__/cli.cpython-312.pyc and /dev/null differ
diff --git a/backend/pig/Lib/python3.12/site-packages/fastapi/__pycache__/concurrency.cpython-312.pyc b/backend/pig/Lib/python3.12/site-packages/fastapi/__pycache__/concurrency.cpython-312.pyc
deleted file mode 100644
index 9464ded..0000000
Binary files a/backend/pig/Lib/python3.12/site-packages/fastapi/__pycache__/concurrency.cpython-312.pyc and /dev/null differ
diff --git a/backend/pig/Lib/python3.12/site-packages/fastapi/__pycache__/datastructures.cpython-312.pyc b/backend/pig/Lib/python3.12/site-packages/fastapi/__pycache__/datastructures.cpython-312.pyc
deleted file mode 100644
index 73ac461..0000000
Binary files a/backend/pig/Lib/python3.12/site-packages/fastapi/__pycache__/datastructures.cpython-312.pyc and /dev/null differ
diff --git a/backend/pig/Lib/python3.12/site-packages/fastapi/__pycache__/encoders.cpython-312.pyc b/backend/pig/Lib/python3.12/site-packages/fastapi/__pycache__/encoders.cpython-312.pyc
deleted file mode 100644
index 7c5ede6..0000000
Binary files a/backend/pig/Lib/python3.12/site-packages/fastapi/__pycache__/encoders.cpython-312.pyc and /dev/null differ
diff --git a/backend/pig/Lib/python3.12/site-packages/fastapi/__pycache__/exception_handlers.cpython-312.pyc b/backend/pig/Lib/python3.12/site-packages/fastapi/__pycache__/exception_handlers.cpython-312.pyc
deleted file mode 100644
index efaafc3..0000000
Binary files a/backend/pig/Lib/python3.12/site-packages/fastapi/__pycache__/exception_handlers.cpython-312.pyc and /dev/null differ
diff --git a/backend/pig/Lib/python3.12/site-packages/fastapi/__pycache__/exceptions.cpython-312.pyc b/backend/pig/Lib/python3.12/site-packages/fastapi/__pycache__/exceptions.cpython-312.pyc
deleted file mode 100644
index 472735d..0000000
Binary files a/backend/pig/Lib/python3.12/site-packages/fastapi/__pycache__/exceptions.cpython-312.pyc and /dev/null differ
diff --git a/backend/pig/Lib/python3.12/site-packages/fastapi/__pycache__/logger.cpython-312.pyc b/backend/pig/Lib/python3.12/site-packages/fastapi/__pycache__/logger.cpython-312.pyc
deleted file mode 100644
index 9406504..0000000
Binary files a/backend/pig/Lib/python3.12/site-packages/fastapi/__pycache__/logger.cpython-312.pyc and /dev/null differ
diff --git a/backend/pig/Lib/python3.12/site-packages/fastapi/__pycache__/param_functions.cpython-312.pyc b/backend/pig/Lib/python3.12/site-packages/fastapi/__pycache__/param_functions.cpython-312.pyc
deleted file mode 100644
index 2ee2fa7..0000000
Binary files a/backend/pig/Lib/python3.12/site-packages/fastapi/__pycache__/param_functions.cpython-312.pyc and /dev/null differ
diff --git a/backend/pig/Lib/python3.12/site-packages/fastapi/__pycache__/params.cpython-312.pyc b/backend/pig/Lib/python3.12/site-packages/fastapi/__pycache__/params.cpython-312.pyc
deleted file mode 100644
index 0cf9593..0000000
Binary files a/backend/pig/Lib/python3.12/site-packages/fastapi/__pycache__/params.cpython-312.pyc and /dev/null differ
diff --git a/backend/pig/Lib/python3.12/site-packages/fastapi/__pycache__/requests.cpython-312.pyc b/backend/pig/Lib/python3.12/site-packages/fastapi/__pycache__/requests.cpython-312.pyc
deleted file mode 100644
index 7218eaa..0000000
Binary files a/backend/pig/Lib/python3.12/site-packages/fastapi/__pycache__/requests.cpython-312.pyc and /dev/null differ
diff --git a/backend/pig/Lib/python3.12/site-packages/fastapi/__pycache__/responses.cpython-312.pyc b/backend/pig/Lib/python3.12/site-packages/fastapi/__pycache__/responses.cpython-312.pyc
deleted file mode 100644
index 3f45afe..0000000
Binary files a/backend/pig/Lib/python3.12/site-packages/fastapi/__pycache__/responses.cpython-312.pyc and /dev/null differ
diff --git a/backend/pig/Lib/python3.12/site-packages/fastapi/__pycache__/routing.cpython-312.pyc b/backend/pig/Lib/python3.12/site-packages/fastapi/__pycache__/routing.cpython-312.pyc
deleted file mode 100644
index 8fcc81b..0000000
Binary files a/backend/pig/Lib/python3.12/site-packages/fastapi/__pycache__/routing.cpython-312.pyc and /dev/null differ
diff --git a/backend/pig/Lib/python3.12/site-packages/fastapi/__pycache__/staticfiles.cpython-312.pyc b/backend/pig/Lib/python3.12/site-packages/fastapi/__pycache__/staticfiles.cpython-312.pyc
deleted file mode 100644
index 6061f09..0000000
Binary files a/backend/pig/Lib/python3.12/site-packages/fastapi/__pycache__/staticfiles.cpython-312.pyc and /dev/null differ
diff --git a/backend/pig/Lib/python3.12/site-packages/fastapi/__pycache__/templating.cpython-312.pyc b/backend/pig/Lib/python3.12/site-packages/fastapi/__pycache__/templating.cpython-312.pyc
deleted file mode 100644
index 399d4b1..0000000
Binary files a/backend/pig/Lib/python3.12/site-packages/fastapi/__pycache__/templating.cpython-312.pyc and /dev/null differ
diff --git a/backend/pig/Lib/python3.12/site-packages/fastapi/__pycache__/testclient.cpython-312.pyc b/backend/pig/Lib/python3.12/site-packages/fastapi/__pycache__/testclient.cpython-312.pyc
deleted file mode 100644
index 2ab9d78..0000000
Binary files a/backend/pig/Lib/python3.12/site-packages/fastapi/__pycache__/testclient.cpython-312.pyc and /dev/null differ
diff --git a/backend/pig/Lib/python3.12/site-packages/fastapi/__pycache__/types.cpython-312.pyc b/backend/pig/Lib/python3.12/site-packages/fastapi/__pycache__/types.cpython-312.pyc
deleted file mode 100644
index 744a50a..0000000
Binary files a/backend/pig/Lib/python3.12/site-packages/fastapi/__pycache__/types.cpython-312.pyc and /dev/null differ
diff --git a/backend/pig/Lib/python3.12/site-packages/fastapi/__pycache__/utils.cpython-312.pyc b/backend/pig/Lib/python3.12/site-packages/fastapi/__pycache__/utils.cpython-312.pyc
deleted file mode 100644
index 1298002..0000000
Binary files a/backend/pig/Lib/python3.12/site-packages/fastapi/__pycache__/utils.cpython-312.pyc and /dev/null differ
diff --git a/backend/pig/Lib/python3.12/site-packages/fastapi/__pycache__/websockets.cpython-312.pyc b/backend/pig/Lib/python3.12/site-packages/fastapi/__pycache__/websockets.cpython-312.pyc
deleted file mode 100644
index 526c63a..0000000
Binary files a/backend/pig/Lib/python3.12/site-packages/fastapi/__pycache__/websockets.cpython-312.pyc and /dev/null differ
diff --git a/backend/pig/Lib/python3.12/site-packages/fastapi/_compat.py b/backend/pig/Lib/python3.12/site-packages/fastapi/_compat.py
deleted file mode 100644
index 2b4d3e7..0000000
--- a/backend/pig/Lib/python3.12/site-packages/fastapi/_compat.py
+++ /dev/null
@@ -1,659 +0,0 @@
-from collections import deque
-from copy import copy
-from dataclasses import dataclass, is_dataclass
-from enum import Enum
-from functools import lru_cache
-from typing import (
- Any,
- Callable,
- Deque,
- Dict,
- FrozenSet,
- List,
- Mapping,
- Sequence,
- Set,
- Tuple,
- Type,
- Union,
-)
-
-from fastapi.exceptions import RequestErrorModel
-from fastapi.types import IncEx, ModelNameMap, UnionType
-from pydantic import BaseModel, create_model
-from pydantic.version import VERSION as P_VERSION
-from starlette.datastructures import UploadFile
-from typing_extensions import Annotated, Literal, get_args, get_origin
-
-# Reassign variable to make it reexported for mypy
-PYDANTIC_VERSION = P_VERSION
-PYDANTIC_VERSION_MINOR_TUPLE = tuple(int(x) for x in PYDANTIC_VERSION.split(".")[:2])
-PYDANTIC_V2 = PYDANTIC_VERSION_MINOR_TUPLE[0] == 2
-
-
-sequence_annotation_to_type = {
- Sequence: list,
- List: list,
- list: list,
- Tuple: tuple,
- tuple: tuple,
- Set: set,
- set: set,
- FrozenSet: frozenset,
- frozenset: frozenset,
- Deque: deque,
- deque: deque,
-}
-
-sequence_types = tuple(sequence_annotation_to_type.keys())
-
-if PYDANTIC_V2:
- from pydantic import PydanticSchemaGenerationError as PydanticSchemaGenerationError
- from pydantic import TypeAdapter
- from pydantic import ValidationError as ValidationError
- from pydantic._internal._schema_generation_shared import ( # type: ignore[attr-defined]
- GetJsonSchemaHandler as GetJsonSchemaHandler,
- )
- from pydantic._internal._typing_extra import eval_type_lenient
- from pydantic._internal._utils import lenient_issubclass as lenient_issubclass
- from pydantic.fields import FieldInfo
- from pydantic.json_schema import GenerateJsonSchema as GenerateJsonSchema
- from pydantic.json_schema import JsonSchemaValue as JsonSchemaValue
- from pydantic_core import CoreSchema as CoreSchema
- from pydantic_core import PydanticUndefined, PydanticUndefinedType
- from pydantic_core import Url as Url
-
- try:
- from pydantic_core.core_schema import (
- with_info_plain_validator_function as with_info_plain_validator_function,
- )
- except ImportError: # pragma: no cover
- from pydantic_core.core_schema import (
- general_plain_validator_function as with_info_plain_validator_function, # noqa: F401
- )
-
- RequiredParam = PydanticUndefined
- Undefined = PydanticUndefined
- UndefinedType = PydanticUndefinedType
- evaluate_forwardref = eval_type_lenient
- Validator = Any
-
- class BaseConfig:
- pass
-
- class ErrorWrapper(Exception):
- pass
-
- @dataclass
- class ModelField:
- field_info: FieldInfo
- name: str
- mode: Literal["validation", "serialization"] = "validation"
-
- @property
- def alias(self) -> str:
- a = self.field_info.alias
- return a if a is not None else self.name
-
- @property
- def required(self) -> bool:
- return self.field_info.is_required()
-
- @property
- def default(self) -> Any:
- return self.get_default()
-
- @property
- def type_(self) -> Any:
- return self.field_info.annotation
-
- def __post_init__(self) -> None:
- self._type_adapter: TypeAdapter[Any] = TypeAdapter(
- Annotated[self.field_info.annotation, self.field_info]
- )
-
- def get_default(self) -> Any:
- if self.field_info.is_required():
- return Undefined
- return self.field_info.get_default(call_default_factory=True)
-
- def validate(
- self,
- value: Any,
- values: Dict[str, Any] = {}, # noqa: B006
- *,
- loc: Tuple[Union[int, str], ...] = (),
- ) -> Tuple[Any, Union[List[Dict[str, Any]], None]]:
- try:
- return (
- self._type_adapter.validate_python(value, from_attributes=True),
- None,
- )
- except ValidationError as exc:
- return None, _regenerate_error_with_loc(
- errors=exc.errors(include_url=False), loc_prefix=loc
- )
-
- def serialize(
- self,
- value: Any,
- *,
- mode: Literal["json", "python"] = "json",
- include: Union[IncEx, None] = None,
- exclude: Union[IncEx, None] = None,
- by_alias: bool = True,
- exclude_unset: bool = False,
- exclude_defaults: bool = False,
- exclude_none: bool = False,
- ) -> Any:
- # What calls this code passes a value that already called
- # self._type_adapter.validate_python(value)
- return self._type_adapter.dump_python(
- value,
- mode=mode,
- include=include,
- exclude=exclude,
- by_alias=by_alias,
- exclude_unset=exclude_unset,
- exclude_defaults=exclude_defaults,
- exclude_none=exclude_none,
- )
-
- def __hash__(self) -> int:
- # Each ModelField is unique for our purposes, to allow making a dict from
- # ModelField to its JSON Schema.
- return id(self)
-
- def get_annotation_from_field_info(
- annotation: Any, field_info: FieldInfo, field_name: str
- ) -> Any:
- return annotation
-
- def _normalize_errors(errors: Sequence[Any]) -> List[Dict[str, Any]]:
- return errors # type: ignore[return-value]
-
- def _model_rebuild(model: Type[BaseModel]) -> None:
- model.model_rebuild()
-
- def _model_dump(
- model: BaseModel, mode: Literal["json", "python"] = "json", **kwargs: Any
- ) -> Any:
- return model.model_dump(mode=mode, **kwargs)
-
- def _get_model_config(model: BaseModel) -> Any:
- return model.model_config
-
- def get_schema_from_model_field(
- *,
- field: ModelField,
- schema_generator: GenerateJsonSchema,
- model_name_map: ModelNameMap,
- field_mapping: Dict[
- Tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue
- ],
- separate_input_output_schemas: bool = True,
- ) -> Dict[str, Any]:
- override_mode: Union[Literal["validation"], None] = (
- None if separate_input_output_schemas else "validation"
- )
- # This expects that GenerateJsonSchema was already used to generate the definitions
- json_schema = field_mapping[(field, override_mode or field.mode)]
- if "$ref" not in json_schema:
- # TODO remove when deprecating Pydantic v1
- # Ref: https://github.com/pydantic/pydantic/blob/d61792cc42c80b13b23e3ffa74bc37ec7c77f7d1/pydantic/schema.py#L207
- json_schema["title"] = (
- field.field_info.title or field.alias.title().replace("_", " ")
- )
- return json_schema
-
- def get_compat_model_name_map(fields: List[ModelField]) -> ModelNameMap:
- return {}
-
- def get_definitions(
- *,
- fields: List[ModelField],
- schema_generator: GenerateJsonSchema,
- model_name_map: ModelNameMap,
- separate_input_output_schemas: bool = True,
- ) -> Tuple[
- Dict[
- Tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue
- ],
- Dict[str, Dict[str, Any]],
- ]:
- override_mode: Union[Literal["validation"], None] = (
- None if separate_input_output_schemas else "validation"
- )
- inputs = [
- (field, override_mode or field.mode, field._type_adapter.core_schema)
- for field in fields
- ]
- field_mapping, definitions = schema_generator.generate_definitions(
- inputs=inputs
- )
- return field_mapping, definitions # type: ignore[return-value]
-
- def is_scalar_field(field: ModelField) -> bool:
- from fastapi import params
-
- return field_annotation_is_scalar(
- field.field_info.annotation
- ) and not isinstance(field.field_info, params.Body)
-
- def is_sequence_field(field: ModelField) -> bool:
- return field_annotation_is_sequence(field.field_info.annotation)
-
- def is_scalar_sequence_field(field: ModelField) -> bool:
- return field_annotation_is_scalar_sequence(field.field_info.annotation)
-
- def is_bytes_field(field: ModelField) -> bool:
- return is_bytes_or_nonable_bytes_annotation(field.type_)
-
- def is_bytes_sequence_field(field: ModelField) -> bool:
- return is_bytes_sequence_annotation(field.type_)
-
- def copy_field_info(*, field_info: FieldInfo, annotation: Any) -> FieldInfo:
- cls = type(field_info)
- merged_field_info = cls.from_annotation(annotation)
- new_field_info = copy(field_info)
- new_field_info.metadata = merged_field_info.metadata
- new_field_info.annotation = merged_field_info.annotation
- return new_field_info
-
- def serialize_sequence_value(*, field: ModelField, value: Any) -> Sequence[Any]:
- origin_type = (
- get_origin(field.field_info.annotation) or field.field_info.annotation
- )
- assert issubclass(origin_type, sequence_types) # type: ignore[arg-type]
- return sequence_annotation_to_type[origin_type](value) # type: ignore[no-any-return]
-
- def get_missing_field_error(loc: Tuple[str, ...]) -> Dict[str, Any]:
- error = ValidationError.from_exception_data(
- "Field required", [{"type": "missing", "loc": loc, "input": {}}]
- ).errors(include_url=False)[0]
- error["input"] = None
- return error # type: ignore[return-value]
-
- def create_body_model(
- *, fields: Sequence[ModelField], model_name: str
- ) -> Type[BaseModel]:
- field_params = {f.name: (f.field_info.annotation, f.field_info) for f in fields}
- BodyModel: Type[BaseModel] = create_model(model_name, **field_params) # type: ignore[call-overload]
- return BodyModel
-
- def get_model_fields(model: Type[BaseModel]) -> List[ModelField]:
- return [
- ModelField(field_info=field_info, name=name)
- for name, field_info in model.model_fields.items()
- ]
-
-else:
- from fastapi.openapi.constants import REF_PREFIX as REF_PREFIX
- from pydantic import AnyUrl as Url # noqa: F401
- from pydantic import ( # type: ignore[assignment]
- BaseConfig as BaseConfig, # noqa: F401
- )
- from pydantic import ValidationError as ValidationError # noqa: F401
- from pydantic.class_validators import ( # type: ignore[no-redef]
- Validator as Validator, # noqa: F401
- )
- from pydantic.error_wrappers import ( # type: ignore[no-redef]
- ErrorWrapper as ErrorWrapper, # noqa: F401
- )
- from pydantic.errors import MissingError
- from pydantic.fields import ( # type: ignore[attr-defined]
- SHAPE_FROZENSET,
- SHAPE_LIST,
- SHAPE_SEQUENCE,
- SHAPE_SET,
- SHAPE_SINGLETON,
- SHAPE_TUPLE,
- SHAPE_TUPLE_ELLIPSIS,
- )
- from pydantic.fields import FieldInfo as FieldInfo
- from pydantic.fields import ( # type: ignore[no-redef,attr-defined]
- ModelField as ModelField, # noqa: F401
- )
-
- # Keeping old "Required" functionality from Pydantic V1, without
- # shadowing typing.Required.
- RequiredParam: Any = Ellipsis # type: ignore[no-redef]
- from pydantic.fields import ( # type: ignore[no-redef,attr-defined]
- Undefined as Undefined,
- )
- from pydantic.fields import ( # type: ignore[no-redef, attr-defined]
- UndefinedType as UndefinedType, # noqa: F401
- )
- from pydantic.schema import (
- field_schema,
- get_flat_models_from_fields,
- get_model_name_map,
- model_process_schema,
- )
- from pydantic.schema import ( # type: ignore[no-redef] # noqa: F401
- get_annotation_from_field_info as get_annotation_from_field_info,
- )
- from pydantic.typing import ( # type: ignore[no-redef]
- evaluate_forwardref as evaluate_forwardref, # noqa: F401
- )
- from pydantic.utils import ( # type: ignore[no-redef]
- lenient_issubclass as lenient_issubclass, # noqa: F401
- )
-
- GetJsonSchemaHandler = Any # type: ignore[assignment,misc]
- JsonSchemaValue = Dict[str, Any] # type: ignore[misc]
- CoreSchema = Any # type: ignore[assignment,misc]
-
- sequence_shapes = {
- SHAPE_LIST,
- SHAPE_SET,
- SHAPE_FROZENSET,
- SHAPE_TUPLE,
- SHAPE_SEQUENCE,
- SHAPE_TUPLE_ELLIPSIS,
- }
- sequence_shape_to_type = {
- SHAPE_LIST: list,
- SHAPE_SET: set,
- SHAPE_TUPLE: tuple,
- SHAPE_SEQUENCE: list,
- SHAPE_TUPLE_ELLIPSIS: list,
- }
-
- @dataclass
- class GenerateJsonSchema: # type: ignore[no-redef]
- ref_template: str
-
- class PydanticSchemaGenerationError(Exception): # type: ignore[no-redef]
- pass
-
- def with_info_plain_validator_function( # type: ignore[misc]
- function: Callable[..., Any],
- *,
- ref: Union[str, None] = None,
- metadata: Any = None,
- serialization: Any = None,
- ) -> Any:
- return {}
-
- def get_model_definitions(
- *,
- flat_models: Set[Union[Type[BaseModel], Type[Enum]]],
- model_name_map: Dict[Union[Type[BaseModel], Type[Enum]], str],
- ) -> Dict[str, Any]:
- definitions: Dict[str, Dict[str, Any]] = {}
- for model in flat_models:
- m_schema, m_definitions, m_nested_models = model_process_schema(
- model, model_name_map=model_name_map, ref_prefix=REF_PREFIX
- )
- definitions.update(m_definitions)
- model_name = model_name_map[model]
- if "description" in m_schema:
- m_schema["description"] = m_schema["description"].split("\f")[0]
- definitions[model_name] = m_schema
- return definitions
-
- def is_pv1_scalar_field(field: ModelField) -> bool:
- from fastapi import params
-
- field_info = field.field_info
- if not (
- field.shape == SHAPE_SINGLETON # type: ignore[attr-defined]
- and not lenient_issubclass(field.type_, BaseModel)
- and not lenient_issubclass(field.type_, dict)
- and not field_annotation_is_sequence(field.type_)
- and not is_dataclass(field.type_)
- and not isinstance(field_info, params.Body)
- ):
- return False
- if field.sub_fields: # type: ignore[attr-defined]
- if not all(
- is_pv1_scalar_field(f)
- for f in field.sub_fields # type: ignore[attr-defined]
- ):
- return False
- return True
-
- def is_pv1_scalar_sequence_field(field: ModelField) -> bool:
- if (field.shape in sequence_shapes) and not lenient_issubclass( # type: ignore[attr-defined]
- field.type_, BaseModel
- ):
- if field.sub_fields is not None: # type: ignore[attr-defined]
- for sub_field in field.sub_fields: # type: ignore[attr-defined]
- if not is_pv1_scalar_field(sub_field):
- return False
- return True
- if _annotation_is_sequence(field.type_):
- return True
- return False
-
- def _normalize_errors(errors: Sequence[Any]) -> List[Dict[str, Any]]:
- use_errors: List[Any] = []
- for error in errors:
- if isinstance(error, ErrorWrapper):
- new_errors = ValidationError( # type: ignore[call-arg]
- errors=[error], model=RequestErrorModel
- ).errors()
- use_errors.extend(new_errors)
- elif isinstance(error, list):
- use_errors.extend(_normalize_errors(error))
- else:
- use_errors.append(error)
- return use_errors
-
- def _model_rebuild(model: Type[BaseModel]) -> None:
- model.update_forward_refs()
-
- def _model_dump(
- model: BaseModel, mode: Literal["json", "python"] = "json", **kwargs: Any
- ) -> Any:
- return model.dict(**kwargs)
-
- def _get_model_config(model: BaseModel) -> Any:
- return model.__config__ # type: ignore[attr-defined]
-
- def get_schema_from_model_field(
- *,
- field: ModelField,
- schema_generator: GenerateJsonSchema,
- model_name_map: ModelNameMap,
- field_mapping: Dict[
- Tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue
- ],
- separate_input_output_schemas: bool = True,
- ) -> Dict[str, Any]:
- # This expects that GenerateJsonSchema was already used to generate the definitions
- return field_schema( # type: ignore[no-any-return]
- field, model_name_map=model_name_map, ref_prefix=REF_PREFIX
- )[0]
-
- def get_compat_model_name_map(fields: List[ModelField]) -> ModelNameMap:
- models = get_flat_models_from_fields(fields, known_models=set())
- return get_model_name_map(models) # type: ignore[no-any-return]
-
- def get_definitions(
- *,
- fields: List[ModelField],
- schema_generator: GenerateJsonSchema,
- model_name_map: ModelNameMap,
- separate_input_output_schemas: bool = True,
- ) -> Tuple[
- Dict[
- Tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue
- ],
- Dict[str, Dict[str, Any]],
- ]:
- models = get_flat_models_from_fields(fields, known_models=set())
- return {}, get_model_definitions(
- flat_models=models, model_name_map=model_name_map
- )
-
- def is_scalar_field(field: ModelField) -> bool:
- return is_pv1_scalar_field(field)
-
- def is_sequence_field(field: ModelField) -> bool:
- return field.shape in sequence_shapes or _annotation_is_sequence(field.type_) # type: ignore[attr-defined]
-
- def is_scalar_sequence_field(field: ModelField) -> bool:
- return is_pv1_scalar_sequence_field(field)
-
- def is_bytes_field(field: ModelField) -> bool:
- return lenient_issubclass(field.type_, bytes)
-
- def is_bytes_sequence_field(field: ModelField) -> bool:
- return field.shape in sequence_shapes and lenient_issubclass(field.type_, bytes) # type: ignore[attr-defined]
-
- def copy_field_info(*, field_info: FieldInfo, annotation: Any) -> FieldInfo:
- return copy(field_info)
-
- def serialize_sequence_value(*, field: ModelField, value: Any) -> Sequence[Any]:
- return sequence_shape_to_type[field.shape](value) # type: ignore[no-any-return,attr-defined]
-
- def get_missing_field_error(loc: Tuple[str, ...]) -> Dict[str, Any]:
- missing_field_error = ErrorWrapper(MissingError(), loc=loc) # type: ignore[call-arg]
- new_error = ValidationError([missing_field_error], RequestErrorModel)
- return new_error.errors()[0] # type: ignore[return-value]
-
- def create_body_model(
- *, fields: Sequence[ModelField], model_name: str
- ) -> Type[BaseModel]:
- BodyModel = create_model(model_name)
- for f in fields:
- BodyModel.__fields__[f.name] = f # type: ignore[index]
- return BodyModel
-
- def get_model_fields(model: Type[BaseModel]) -> List[ModelField]:
- return list(model.__fields__.values()) # type: ignore[attr-defined]
-
-
-def _regenerate_error_with_loc(
- *, errors: Sequence[Any], loc_prefix: Tuple[Union[str, int], ...]
-) -> List[Dict[str, Any]]:
- updated_loc_errors: List[Any] = [
- {**err, "loc": loc_prefix + err.get("loc", ())}
- for err in _normalize_errors(errors)
- ]
-
- return updated_loc_errors
-
-
-def _annotation_is_sequence(annotation: Union[Type[Any], None]) -> bool:
- if lenient_issubclass(annotation, (str, bytes)):
- return False
- return lenient_issubclass(annotation, sequence_types)
-
-
-def field_annotation_is_sequence(annotation: Union[Type[Any], None]) -> bool:
- origin = get_origin(annotation)
- if origin is Union or origin is UnionType:
- for arg in get_args(annotation):
- if field_annotation_is_sequence(arg):
- return True
- return False
- return _annotation_is_sequence(annotation) or _annotation_is_sequence(
- get_origin(annotation)
- )
-
-
-def value_is_sequence(value: Any) -> bool:
- return isinstance(value, sequence_types) and not isinstance(value, (str, bytes)) # type: ignore[arg-type]
-
-
-def _annotation_is_complex(annotation: Union[Type[Any], None]) -> bool:
- return (
- lenient_issubclass(annotation, (BaseModel, Mapping, UploadFile))
- or _annotation_is_sequence(annotation)
- or is_dataclass(annotation)
- )
-
-
-def field_annotation_is_complex(annotation: Union[Type[Any], None]) -> bool:
- origin = get_origin(annotation)
- if origin is Union or origin is UnionType:
- return any(field_annotation_is_complex(arg) for arg in get_args(annotation))
-
- return (
- _annotation_is_complex(annotation)
- or _annotation_is_complex(origin)
- or hasattr(origin, "__pydantic_core_schema__")
- or hasattr(origin, "__get_pydantic_core_schema__")
- )
-
-
-def field_annotation_is_scalar(annotation: Any) -> bool:
- # handle Ellipsis here to make tuple[int, ...] work nicely
- return annotation is Ellipsis or not field_annotation_is_complex(annotation)
-
-
-def field_annotation_is_scalar_sequence(annotation: Union[Type[Any], None]) -> bool:
- origin = get_origin(annotation)
- if origin is Union or origin is UnionType:
- at_least_one_scalar_sequence = False
- for arg in get_args(annotation):
- if field_annotation_is_scalar_sequence(arg):
- at_least_one_scalar_sequence = True
- continue
- elif not field_annotation_is_scalar(arg):
- return False
- return at_least_one_scalar_sequence
- return field_annotation_is_sequence(annotation) and all(
- field_annotation_is_scalar(sub_annotation)
- for sub_annotation in get_args(annotation)
- )
-
-
-def is_bytes_or_nonable_bytes_annotation(annotation: Any) -> bool:
- if lenient_issubclass(annotation, bytes):
- return True
- origin = get_origin(annotation)
- if origin is Union or origin is UnionType:
- for arg in get_args(annotation):
- if lenient_issubclass(arg, bytes):
- return True
- return False
-
-
-def is_uploadfile_or_nonable_uploadfile_annotation(annotation: Any) -> bool:
- if lenient_issubclass(annotation, UploadFile):
- return True
- origin = get_origin(annotation)
- if origin is Union or origin is UnionType:
- for arg in get_args(annotation):
- if lenient_issubclass(arg, UploadFile):
- return True
- return False
-
-
-def is_bytes_sequence_annotation(annotation: Any) -> bool:
- origin = get_origin(annotation)
- if origin is Union or origin is UnionType:
- at_least_one = False
- for arg in get_args(annotation):
- if is_bytes_sequence_annotation(arg):
- at_least_one = True
- continue
- return at_least_one
- return field_annotation_is_sequence(annotation) and all(
- is_bytes_or_nonable_bytes_annotation(sub_annotation)
- for sub_annotation in get_args(annotation)
- )
-
-
-def is_uploadfile_sequence_annotation(annotation: Any) -> bool:
- origin = get_origin(annotation)
- if origin is Union or origin is UnionType:
- at_least_one = False
- for arg in get_args(annotation):
- if is_uploadfile_sequence_annotation(arg):
- at_least_one = True
- continue
- return at_least_one
- return field_annotation_is_sequence(annotation) and all(
- is_uploadfile_or_nonable_uploadfile_annotation(sub_annotation)
- for sub_annotation in get_args(annotation)
- )
-
-
-@lru_cache
-def get_cached_model_fields(model: Type[BaseModel]) -> List[ModelField]:
- return get_model_fields(model)
diff --git a/backend/pig/Lib/python3.12/site-packages/fastapi/applications.py b/backend/pig/Lib/python3.12/site-packages/fastapi/applications.py
deleted file mode 100644
index 6d427cd..0000000
--- a/backend/pig/Lib/python3.12/site-packages/fastapi/applications.py
+++ /dev/null
@@ -1,4585 +0,0 @@
-from enum import Enum
-from typing import (
- Any,
- Awaitable,
- Callable,
- Coroutine,
- Dict,
- List,
- Optional,
- Sequence,
- Type,
- TypeVar,
- Union,
-)
-
-from fastapi import routing
-from fastapi.datastructures import Default, DefaultPlaceholder
-from fastapi.exception_handlers import (
- http_exception_handler,
- request_validation_exception_handler,
- websocket_request_validation_exception_handler,
-)
-from fastapi.exceptions import RequestValidationError, WebSocketRequestValidationError
-from fastapi.logger import logger
-from fastapi.openapi.docs import (
- get_redoc_html,
- get_swagger_ui_html,
- get_swagger_ui_oauth2_redirect_html,
-)
-from fastapi.openapi.utils import get_openapi
-from fastapi.params import Depends
-from fastapi.types import DecoratedCallable, IncEx
-from fastapi.utils import generate_unique_id
-from starlette.applications import Starlette
-from starlette.datastructures import State
-from starlette.exceptions import HTTPException
-from starlette.middleware import Middleware
-from starlette.middleware.base import BaseHTTPMiddleware
-from starlette.requests import Request
-from starlette.responses import HTMLResponse, JSONResponse, Response
-from starlette.routing import BaseRoute
-from starlette.types import ASGIApp, Lifespan, Receive, Scope, Send
-from typing_extensions import Annotated, Doc, deprecated
-
-AppType = TypeVar("AppType", bound="FastAPI")
-
-
-class FastAPI(Starlette):
- """
- `FastAPI` app class, the main entrypoint to use FastAPI.
-
- Read more in the
- [FastAPI docs for First Steps](https://fastapi.tiangolo.com/tutorial/first-steps/).
-
- ## Example
-
- ```python
- from fastapi import FastAPI
-
- app = FastAPI()
- ```
- """
-
- def __init__(
- self: AppType,
- *,
- debug: Annotated[
- bool,
- Doc(
- """
- Boolean indicating if debug tracebacks should be returned on server
- errors.
-
- Read more in the
- [Starlette docs for Applications](https://www.starlette.io/applications/#instantiating-the-application).
- """
- ),
- ] = False,
- routes: Annotated[
- Optional[List[BaseRoute]],
- Doc(
- """
- **Note**: you probably shouldn't use this parameter, it is inherited
- from Starlette and supported for compatibility.
-
- ---
-
- A list of routes to serve incoming HTTP and WebSocket requests.
- """
- ),
- deprecated(
- """
- You normally wouldn't use this parameter with FastAPI, it is inherited
- from Starlette and supported for compatibility.
-
- In FastAPI, you normally would use the *path operation methods*,
- like `app.get()`, `app.post()`, etc.
- """
- ),
- ] = None,
- title: Annotated[
- str,
- Doc(
- """
- The title of the API.
-
- It will be added to the generated OpenAPI (e.g. visible at `/docs`).
-
- Read more in the
- [FastAPI docs for Metadata and Docs URLs](https://fastapi.tiangolo.com/tutorial/metadata/#metadata-for-api).
-
- **Example**
-
- ```python
- from fastapi import FastAPI
-
- app = FastAPI(title="ChimichangApp")
- ```
- """
- ),
- ] = "FastAPI",
- summary: Annotated[
- Optional[str],
- Doc(
- """
- A short summary of the API.
-
- It will be added to the generated OpenAPI (e.g. visible at `/docs`).
-
- Read more in the
- [FastAPI docs for Metadata and Docs URLs](https://fastapi.tiangolo.com/tutorial/metadata/#metadata-for-api).
-
- **Example**
-
- ```python
- from fastapi import FastAPI
-
- app = FastAPI(summary="Deadpond's favorite app. Nuff said.")
- ```
- """
- ),
- ] = None,
- description: Annotated[
- str,
- Doc(
- '''
- A description of the API. Supports Markdown (using
- [CommonMark syntax](https://commonmark.org/)).
-
- It will be added to the generated OpenAPI (e.g. visible at `/docs`).
-
- Read more in the
- [FastAPI docs for Metadata and Docs URLs](https://fastapi.tiangolo.com/tutorial/metadata/#metadata-for-api).
-
- **Example**
-
- ```python
- from fastapi import FastAPI
-
- app = FastAPI(
- description="""
- ChimichangApp API helps you do awesome stuff. 🚀
-
- ## Items
-
- You can **read items**.
-
- ## Users
-
- You will be able to:
-
- * **Create users** (_not implemented_).
- * **Read users** (_not implemented_).
-
- """
- )
- ```
- '''
- ),
- ] = "",
- version: Annotated[
- str,
- Doc(
- """
- The version of the API.
-
- **Note** This is the version of your application, not the version of
- the OpenAPI specification nor the version of FastAPI being used.
-
- It will be added to the generated OpenAPI (e.g. visible at `/docs`).
-
- Read more in the
- [FastAPI docs for Metadata and Docs URLs](https://fastapi.tiangolo.com/tutorial/metadata/#metadata-for-api).
-
- **Example**
-
- ```python
- from fastapi import FastAPI
-
- app = FastAPI(version="0.0.1")
- ```
- """
- ),
- ] = "0.1.0",
- openapi_url: Annotated[
- Optional[str],
- Doc(
- """
- The URL where the OpenAPI schema will be served from.
-
- If you set it to `None`, no OpenAPI schema will be served publicly, and
- the default automatic endpoints `/docs` and `/redoc` will also be
- disabled.
-
- Read more in the
- [FastAPI docs for Metadata and Docs URLs](https://fastapi.tiangolo.com/tutorial/metadata/#openapi-url).
-
- **Example**
-
- ```python
- from fastapi import FastAPI
-
- app = FastAPI(openapi_url="/api/v1/openapi.json")
- ```
- """
- ),
- ] = "/openapi.json",
- openapi_tags: Annotated[
- Optional[List[Dict[str, Any]]],
- Doc(
- """
- A list of tags used by OpenAPI, these are the same `tags` you can set
- in the *path operations*, like:
-
- * `@app.get("/users/", tags=["users"])`
- * `@app.get("/items/", tags=["items"])`
-
- The order of the tags can be used to specify the order shown in
- tools like Swagger UI, used in the automatic path `/docs`.
-
- It's not required to specify all the tags used.
-
- The tags that are not declared MAY be organized randomly or based
- on the tools' logic. Each tag name in the list MUST be unique.
-
- The value of each item is a `dict` containing:
-
- * `name`: The name of the tag.
- * `description`: A short description of the tag.
- [CommonMark syntax](https://commonmark.org/) MAY be used for rich
- text representation.
- * `externalDocs`: Additional external documentation for this tag. If
- provided, it would contain a `dict` with:
- * `description`: A short description of the target documentation.
- [CommonMark syntax](https://commonmark.org/) MAY be used for
- rich text representation.
- * `url`: The URL for the target documentation. Value MUST be in
- the form of a URL.
-
- Read more in the
- [FastAPI docs for Metadata and Docs URLs](https://fastapi.tiangolo.com/tutorial/metadata/#metadata-for-tags).
-
- **Example**
-
- ```python
- from fastapi import FastAPI
-
- tags_metadata = [
- {
- "name": "users",
- "description": "Operations with users. The **login** logic is also here.",
- },
- {
- "name": "items",
- "description": "Manage items. So _fancy_ they have their own docs.",
- "externalDocs": {
- "description": "Items external docs",
- "url": "https://fastapi.tiangolo.com/",
- },
- },
- ]
-
- app = FastAPI(openapi_tags=tags_metadata)
- ```
- """
- ),
- ] = None,
- servers: Annotated[
- Optional[List[Dict[str, Union[str, Any]]]],
- Doc(
- """
- A `list` of `dict`s with connectivity information to a target server.
-
- You would use it, for example, if your application is served from
- different domains and you want to use the same Swagger UI in the
- browser to interact with each of them (instead of having multiple
- browser tabs open). Or if you want to leave fixed the possible URLs.
-
- If the servers `list` is not provided, or is an empty `list`, the
- default value would be a `dict` with a `url` value of `/`.
-
- Each item in the `list` is a `dict` containing:
-
- * `url`: A URL to the target host. This URL supports Server Variables
- and MAY be relative, to indicate that the host location is relative
- to the location where the OpenAPI document is being served. Variable
- substitutions will be made when a variable is named in `{`brackets`}`.
- * `description`: An optional string describing the host designated by
- the URL. [CommonMark syntax](https://commonmark.org/) MAY be used for
- rich text representation.
- * `variables`: A `dict` between a variable name and its value. The value
- is used for substitution in the server's URL template.
-
- Read more in the
- [FastAPI docs for Behind a Proxy](https://fastapi.tiangolo.com/advanced/behind-a-proxy/#additional-servers).
-
- **Example**
-
- ```python
- from fastapi import FastAPI
-
- app = FastAPI(
- servers=[
- {"url": "https://stag.example.com", "description": "Staging environment"},
- {"url": "https://prod.example.com", "description": "Production environment"},
- ]
- )
- ```
- """
- ),
- ] = None,
- dependencies: Annotated[
- Optional[Sequence[Depends]],
- Doc(
- """
- A list of global dependencies, they will be applied to each
- *path operation*, including in sub-routers.
-
- Read more about it in the
- [FastAPI docs for Global Dependencies](https://fastapi.tiangolo.com/tutorial/dependencies/global-dependencies/).
-
- **Example**
-
- ```python
- from fastapi import Depends, FastAPI
-
- from .dependencies import func_dep_1, func_dep_2
-
- app = FastAPI(dependencies=[Depends(func_dep_1), Depends(func_dep_2)])
- ```
- """
- ),
- ] = None,
- default_response_class: Annotated[
- Type[Response],
- Doc(
- """
- The default response class to be used.
-
- Read more in the
- [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#default-response-class).
-
- **Example**
-
- ```python
- from fastapi import FastAPI
- from fastapi.responses import ORJSONResponse
-
- app = FastAPI(default_response_class=ORJSONResponse)
- ```
- """
- ),
- ] = Default(JSONResponse),
- redirect_slashes: Annotated[
- bool,
- Doc(
- """
- Whether to detect and redirect slashes in URLs when the client doesn't
- use the same format.
-
- **Example**
-
- ```python
- from fastapi import FastAPI
-
- app = FastAPI(redirect_slashes=True) # the default
-
- @app.get("/items/")
- async def read_items():
- return [{"item_id": "Foo"}]
- ```
-
- With this app, if a client goes to `/items` (without a trailing slash),
- they will be automatically redirected with an HTTP status code of 307
- to `/items/`.
- """
- ),
- ] = True,
- docs_url: Annotated[
- Optional[str],
- Doc(
- """
- The path to the automatic interactive API documentation.
- It is handled in the browser by Swagger UI.
-
- The default URL is `/docs`. You can disable it by setting it to `None`.
-
- If `openapi_url` is set to `None`, this will be automatically disabled.
-
- Read more in the
- [FastAPI docs for Metadata and Docs URLs](https://fastapi.tiangolo.com/tutorial/metadata/#docs-urls).
-
- **Example**
-
- ```python
- from fastapi import FastAPI
-
- app = FastAPI(docs_url="/documentation", redoc_url=None)
- ```
- """
- ),
- ] = "/docs",
- redoc_url: Annotated[
- Optional[str],
- Doc(
- """
- The path to the alternative automatic interactive API documentation
- provided by ReDoc.
-
- The default URL is `/redoc`. You can disable it by setting it to `None`.
-
- If `openapi_url` is set to `None`, this will be automatically disabled.
-
- Read more in the
- [FastAPI docs for Metadata and Docs URLs](https://fastapi.tiangolo.com/tutorial/metadata/#docs-urls).
-
- **Example**
-
- ```python
- from fastapi import FastAPI
-
- app = FastAPI(docs_url="/documentation", redoc_url="redocumentation")
- ```
- """
- ),
- ] = "/redoc",
- swagger_ui_oauth2_redirect_url: Annotated[
- Optional[str],
- Doc(
- """
- The OAuth2 redirect endpoint for the Swagger UI.
-
- By default it is `/docs/oauth2-redirect`.
-
- This is only used if you use OAuth2 (with the "Authorize" button)
- with Swagger UI.
- """
- ),
- ] = "/docs/oauth2-redirect",
- swagger_ui_init_oauth: Annotated[
- Optional[Dict[str, Any]],
- Doc(
- """
- OAuth2 configuration for the Swagger UI, by default shown at `/docs`.
-
- Read more about the available configuration options in the
- [Swagger UI docs](https://swagger.io/docs/open-source-tools/swagger-ui/usage/oauth2/).
- """
- ),
- ] = None,
- middleware: Annotated[
- Optional[Sequence[Middleware]],
- Doc(
- """
- List of middleware to be added when creating the application.
-
- In FastAPI you would normally do this with `app.add_middleware()`
- instead.
-
- Read more in the
- [FastAPI docs for Middleware](https://fastapi.tiangolo.com/tutorial/middleware/).
- """
- ),
- ] = None,
- exception_handlers: Annotated[
- Optional[
- Dict[
- Union[int, Type[Exception]],
- Callable[[Request, Any], Coroutine[Any, Any, Response]],
- ]
- ],
- Doc(
- """
- A dictionary with handlers for exceptions.
-
- In FastAPI, you would normally use the decorator
- `@app.exception_handler()`.
-
- Read more in the
- [FastAPI docs for Handling Errors](https://fastapi.tiangolo.com/tutorial/handling-errors/).
- """
- ),
- ] = None,
- on_startup: Annotated[
- Optional[Sequence[Callable[[], Any]]],
- Doc(
- """
- A list of startup event handler functions.
-
- You should instead use the `lifespan` handlers.
-
- Read more in the [FastAPI docs for `lifespan`](https://fastapi.tiangolo.com/advanced/events/).
- """
- ),
- ] = None,
- on_shutdown: Annotated[
- Optional[Sequence[Callable[[], Any]]],
- Doc(
- """
- A list of shutdown event handler functions.
-
- You should instead use the `lifespan` handlers.
-
- Read more in the
- [FastAPI docs for `lifespan`](https://fastapi.tiangolo.com/advanced/events/).
- """
- ),
- ] = None,
- lifespan: Annotated[
- Optional[Lifespan[AppType]],
- Doc(
- """
- A `Lifespan` context manager handler. This replaces `startup` and
- `shutdown` functions with a single context manager.
-
- Read more in the
- [FastAPI docs for `lifespan`](https://fastapi.tiangolo.com/advanced/events/).
- """
- ),
- ] = None,
- terms_of_service: Annotated[
- Optional[str],
- Doc(
- """
- A URL to the Terms of Service for your API.
-
- It will be added to the generated OpenAPI (e.g. visible at `/docs`).
-
- Read more at the
- [FastAPI docs for Metadata and Docs URLs](https://fastapi.tiangolo.com/tutorial/metadata/#metadata-for-api).
-
- **Example**
-
- ```python
- app = FastAPI(terms_of_service="http://example.com/terms/")
- ```
- """
- ),
- ] = None,
- contact: Annotated[
- Optional[Dict[str, Union[str, Any]]],
- Doc(
- """
- A dictionary with the contact information for the exposed API.
-
- It can contain several fields.
-
- * `name`: (`str`) The name of the contact person/organization.
- * `url`: (`str`) A URL pointing to the contact information. MUST be in
- the format of a URL.
- * `email`: (`str`) The email address of the contact person/organization.
- MUST be in the format of an email address.
-
- It will be added to the generated OpenAPI (e.g. visible at `/docs`).
-
- Read more at the
- [FastAPI docs for Metadata and Docs URLs](https://fastapi.tiangolo.com/tutorial/metadata/#metadata-for-api).
-
- **Example**
-
- ```python
- app = FastAPI(
- contact={
- "name": "Deadpoolio the Amazing",
- "url": "http://x-force.example.com/contact/",
- "email": "dp@x-force.example.com",
- }
- )
- ```
- """
- ),
- ] = None,
- license_info: Annotated[
- Optional[Dict[str, Union[str, Any]]],
- Doc(
- """
- A dictionary with the license information for the exposed API.
-
- It can contain several fields.
-
- * `name`: (`str`) **REQUIRED** (if a `license_info` is set). The
- license name used for the API.
- * `identifier`: (`str`) An [SPDX](https://spdx.dev/) license expression
- for the API. The `identifier` field is mutually exclusive of the `url`
- field. Available since OpenAPI 3.1.0, FastAPI 0.99.0.
- * `url`: (`str`) A URL to the license used for the API. This MUST be
- the format of a URL.
-
- It will be added to the generated OpenAPI (e.g. visible at `/docs`).
-
- Read more at the
- [FastAPI docs for Metadata and Docs URLs](https://fastapi.tiangolo.com/tutorial/metadata/#metadata-for-api).
-
- **Example**
-
- ```python
- app = FastAPI(
- license_info={
- "name": "Apache 2.0",
- "url": "https://www.apache.org/licenses/LICENSE-2.0.html",
- }
- )
- ```
- """
- ),
- ] = None,
- openapi_prefix: Annotated[
- str,
- Doc(
- """
- A URL prefix for the OpenAPI URL.
- """
- ),
- deprecated(
- """
- "openapi_prefix" has been deprecated in favor of "root_path", which
- follows more closely the ASGI standard, is simpler, and more
- automatic.
- """
- ),
- ] = "",
- root_path: Annotated[
- str,
- Doc(
- """
- A path prefix handled by a proxy that is not seen by the application
- but is seen by external clients, which affects things like Swagger UI.
-
- Read more about it at the
- [FastAPI docs for Behind a Proxy](https://fastapi.tiangolo.com/advanced/behind-a-proxy/).
-
- **Example**
-
- ```python
- from fastapi import FastAPI
-
- app = FastAPI(root_path="/api/v1")
- ```
- """
- ),
- ] = "",
- root_path_in_servers: Annotated[
- bool,
- Doc(
- """
- To disable automatically generating the URLs in the `servers` field
- in the autogenerated OpenAPI using the `root_path`.
-
- Read more about it in the
- [FastAPI docs for Behind a Proxy](https://fastapi.tiangolo.com/advanced/behind-a-proxy/#disable-automatic-server-from-root_path).
-
- **Example**
-
- ```python
- from fastapi import FastAPI
-
- app = FastAPI(root_path_in_servers=False)
- ```
- """
- ),
- ] = True,
- responses: Annotated[
- Optional[Dict[Union[int, str], Dict[str, Any]]],
- Doc(
- """
- Additional responses to be shown in OpenAPI.
-
- It will be added to the generated OpenAPI (e.g. visible at `/docs`).
-
- Read more about it in the
- [FastAPI docs for Additional Responses in OpenAPI](https://fastapi.tiangolo.com/advanced/additional-responses/).
-
- And in the
- [FastAPI docs for Bigger Applications](https://fastapi.tiangolo.com/tutorial/bigger-applications/#include-an-apirouter-with-a-custom-prefix-tags-responses-and-dependencies).
- """
- ),
- ] = None,
- callbacks: Annotated[
- Optional[List[BaseRoute]],
- Doc(
- """
- OpenAPI callbacks that should apply to all *path operations*.
-
- It will be added to the generated OpenAPI (e.g. visible at `/docs`).
-
- Read more about it in the
- [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/).
- """
- ),
- ] = None,
- webhooks: Annotated[
- Optional[routing.APIRouter],
- Doc(
- """
- Add OpenAPI webhooks. This is similar to `callbacks` but it doesn't
- depend on specific *path operations*.
-
- It will be added to the generated OpenAPI (e.g. visible at `/docs`).
-
- **Note**: This is available since OpenAPI 3.1.0, FastAPI 0.99.0.
-
- Read more about it in the
- [FastAPI docs for OpenAPI Webhooks](https://fastapi.tiangolo.com/advanced/openapi-webhooks/).
- """
- ),
- ] = None,
- deprecated: Annotated[
- Optional[bool],
- Doc(
- """
- Mark all *path operations* as deprecated. You probably don't need it,
- but it's available.
-
- It will be added to the generated OpenAPI (e.g. visible at `/docs`).
-
- Read more about it in the
- [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
- """
- ),
- ] = None,
- include_in_schema: Annotated[
- bool,
- Doc(
- """
- To include (or not) all the *path operations* in the generated OpenAPI.
- You probably don't need it, but it's available.
-
- This affects the generated OpenAPI (e.g. visible at `/docs`).
-
- Read more about it in the
- [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi).
- """
- ),
- ] = True,
- swagger_ui_parameters: Annotated[
- Optional[Dict[str, Any]],
- Doc(
- """
- Parameters to configure Swagger UI, the autogenerated interactive API
- documentation (by default at `/docs`).
-
- Read more about it in the
- [FastAPI docs about how to Configure Swagger UI](https://fastapi.tiangolo.com/how-to/configure-swagger-ui/).
- """
- ),
- ] = None,
- generate_unique_id_function: Annotated[
- Callable[[routing.APIRoute], str],
- Doc(
- """
- Customize the function used to generate unique IDs for the *path
- operations* shown in the generated OpenAPI.
-
- This is particularly useful when automatically generating clients or
- SDKs for your API.
-
- Read more about it in the
- [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
- """
- ),
- ] = Default(generate_unique_id),
- separate_input_output_schemas: Annotated[
- bool,
- Doc(
- """
- Whether to generate separate OpenAPI schemas for request body and
- response body when the results would be more precise.
-
- This is particularly useful when automatically generating clients.
-
- For example, if you have a model like:
-
- ```python
- from pydantic import BaseModel
-
- class Item(BaseModel):
- name: str
- tags: list[str] = []
- ```
-
- When `Item` is used for input, a request body, `tags` is not required,
- the client doesn't have to provide it.
-
- But when using `Item` for output, for a response body, `tags` is always
- available because it has a default value, even if it's just an empty
- list. So, the client should be able to always expect it.
-
- In this case, there would be two different schemas, one for input and
- another one for output.
- """
- ),
- ] = True,
- **extra: Annotated[
- Any,
- Doc(
- """
- Extra keyword arguments to be stored in the app, not used by FastAPI
- anywhere.
- """
- ),
- ],
- ) -> None:
- self.debug = debug
- self.title = title
- self.summary = summary
- self.description = description
- self.version = version
- self.terms_of_service = terms_of_service
- self.contact = contact
- self.license_info = license_info
- self.openapi_url = openapi_url
- self.openapi_tags = openapi_tags
- self.root_path_in_servers = root_path_in_servers
- self.docs_url = docs_url
- self.redoc_url = redoc_url
- self.swagger_ui_oauth2_redirect_url = swagger_ui_oauth2_redirect_url
- self.swagger_ui_init_oauth = swagger_ui_init_oauth
- self.swagger_ui_parameters = swagger_ui_parameters
- self.servers = servers or []
- self.separate_input_output_schemas = separate_input_output_schemas
- self.extra = extra
- self.openapi_version: Annotated[
- str,
- Doc(
- """
- The version string of OpenAPI.
-
- FastAPI will generate OpenAPI version 3.1.0, and will output that as
- the OpenAPI version. But some tools, even though they might be
- compatible with OpenAPI 3.1.0, might not recognize it as a valid.
-
- So you could override this value to trick those tools into using
- the generated OpenAPI. Have in mind that this is a hack. But if you
- avoid using features added in OpenAPI 3.1.0, it might work for your
- use case.
-
- This is not passed as a parameter to the `FastAPI` class to avoid
- giving the false idea that FastAPI would generate a different OpenAPI
- schema. It is only available as an attribute.
-
- **Example**
-
- ```python
- from fastapi import FastAPI
-
- app = FastAPI()
-
- app.openapi_version = "3.0.2"
- ```
- """
- ),
- ] = "3.1.0"
- self.openapi_schema: Optional[Dict[str, Any]] = None
- if self.openapi_url:
- assert self.title, "A title must be provided for OpenAPI, e.g.: 'My API'"
- assert self.version, "A version must be provided for OpenAPI, e.g.: '2.1.0'"
- # TODO: remove when discarding the openapi_prefix parameter
- if openapi_prefix:
- logger.warning(
- '"openapi_prefix" has been deprecated in favor of "root_path", which '
- "follows more closely the ASGI standard, is simpler, and more "
- "automatic. Check the docs at "
- "https://fastapi.tiangolo.com/advanced/sub-applications/"
- )
- self.webhooks: Annotated[
- routing.APIRouter,
- Doc(
- """
- The `app.webhooks` attribute is an `APIRouter` with the *path
- operations* that will be used just for documentation of webhooks.
-
- Read more about it in the
- [FastAPI docs for OpenAPI Webhooks](https://fastapi.tiangolo.com/advanced/openapi-webhooks/).
- """
- ),
- ] = webhooks or routing.APIRouter()
- self.root_path = root_path or openapi_prefix
- self.state: Annotated[
- State,
- Doc(
- """
- A state object for the application. This is the same object for the
- entire application, it doesn't change from request to request.
-
- You normally wouldn't use this in FastAPI, for most of the cases you
- would instead use FastAPI dependencies.
-
- This is simply inherited from Starlette.
-
- Read more about it in the
- [Starlette docs for Applications](https://www.starlette.io/applications/#storing-state-on-the-app-instance).
- """
- ),
- ] = State()
- self.dependency_overrides: Annotated[
- Dict[Callable[..., Any], Callable[..., Any]],
- Doc(
- """
- A dictionary with overrides for the dependencies.
-
- Each key is the original dependency callable, and the value is the
- actual dependency that should be called.
-
- This is for testing, to replace expensive dependencies with testing
- versions.
-
- Read more about it in the
- [FastAPI docs for Testing Dependencies with Overrides](https://fastapi.tiangolo.com/advanced/testing-dependencies/).
- """
- ),
- ] = {}
- self.router: routing.APIRouter = routing.APIRouter(
- routes=routes,
- redirect_slashes=redirect_slashes,
- dependency_overrides_provider=self,
- on_startup=on_startup,
- on_shutdown=on_shutdown,
- lifespan=lifespan,
- default_response_class=default_response_class,
- dependencies=dependencies,
- callbacks=callbacks,
- deprecated=deprecated,
- include_in_schema=include_in_schema,
- responses=responses,
- generate_unique_id_function=generate_unique_id_function,
- )
- self.exception_handlers: Dict[
- Any, Callable[[Request, Any], Union[Response, Awaitable[Response]]]
- ] = {} if exception_handlers is None else dict(exception_handlers)
- self.exception_handlers.setdefault(HTTPException, http_exception_handler)
- self.exception_handlers.setdefault(
- RequestValidationError, request_validation_exception_handler
- )
- self.exception_handlers.setdefault(
- WebSocketRequestValidationError,
- # Starlette still has incorrect type specification for the handlers
- websocket_request_validation_exception_handler, # type: ignore
- )
-
- self.user_middleware: List[Middleware] = (
- [] if middleware is None else list(middleware)
- )
- self.middleware_stack: Union[ASGIApp, None] = None
- self.setup()
-
- def openapi(self) -> Dict[str, Any]:
- """
- Generate the OpenAPI schema of the application. This is called by FastAPI
- internally.
-
- The first time it is called it stores the result in the attribute
- `app.openapi_schema`, and next times it is called, it just returns that same
- result. To avoid the cost of generating the schema every time.
-
- If you need to modify the generated OpenAPI schema, you could modify it.
-
- Read more in the
- [FastAPI docs for OpenAPI](https://fastapi.tiangolo.com/how-to/extending-openapi/).
- """
- if not self.openapi_schema:
- self.openapi_schema = get_openapi(
- title=self.title,
- version=self.version,
- openapi_version=self.openapi_version,
- summary=self.summary,
- description=self.description,
- terms_of_service=self.terms_of_service,
- contact=self.contact,
- license_info=self.license_info,
- routes=self.routes,
- webhooks=self.webhooks.routes,
- tags=self.openapi_tags,
- servers=self.servers,
- separate_input_output_schemas=self.separate_input_output_schemas,
- )
- return self.openapi_schema
-
- def setup(self) -> None:
- if self.openapi_url:
- urls = (server_data.get("url") for server_data in self.servers)
- server_urls = {url for url in urls if url}
-
- async def openapi(req: Request) -> JSONResponse:
- root_path = req.scope.get("root_path", "").rstrip("/")
- if root_path not in server_urls:
- if root_path and self.root_path_in_servers:
- self.servers.insert(0, {"url": root_path})
- server_urls.add(root_path)
- return JSONResponse(self.openapi())
-
- self.add_route(self.openapi_url, openapi, include_in_schema=False)
- if self.openapi_url and self.docs_url:
-
- async def swagger_ui_html(req: Request) -> HTMLResponse:
- root_path = req.scope.get("root_path", "").rstrip("/")
- openapi_url = root_path + self.openapi_url
- oauth2_redirect_url = self.swagger_ui_oauth2_redirect_url
- if oauth2_redirect_url:
- oauth2_redirect_url = root_path + oauth2_redirect_url
- return get_swagger_ui_html(
- openapi_url=openapi_url,
- title=f"{self.title} - Swagger UI",
- oauth2_redirect_url=oauth2_redirect_url,
- init_oauth=self.swagger_ui_init_oauth,
- swagger_ui_parameters=self.swagger_ui_parameters,
- )
-
- self.add_route(self.docs_url, swagger_ui_html, include_in_schema=False)
-
- if self.swagger_ui_oauth2_redirect_url:
-
- async def swagger_ui_redirect(req: Request) -> HTMLResponse:
- return get_swagger_ui_oauth2_redirect_html()
-
- self.add_route(
- self.swagger_ui_oauth2_redirect_url,
- swagger_ui_redirect,
- include_in_schema=False,
- )
- if self.openapi_url and self.redoc_url:
-
- async def redoc_html(req: Request) -> HTMLResponse:
- root_path = req.scope.get("root_path", "").rstrip("/")
- openapi_url = root_path + self.openapi_url
- return get_redoc_html(
- openapi_url=openapi_url, title=f"{self.title} - ReDoc"
- )
-
- self.add_route(self.redoc_url, redoc_html, include_in_schema=False)
-
- async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:
- if self.root_path:
- scope["root_path"] = self.root_path
- await super().__call__(scope, receive, send)
-
- def add_api_route(
- self,
- path: str,
- endpoint: Callable[..., Any],
- *,
- response_model: Any = Default(None),
- status_code: Optional[int] = None,
- tags: Optional[List[Union[str, Enum]]] = None,
- dependencies: Optional[Sequence[Depends]] = None,
- summary: Optional[str] = None,
- description: Optional[str] = None,
- response_description: str = "Successful Response",
- responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None,
- deprecated: Optional[bool] = None,
- methods: Optional[List[str]] = None,
- operation_id: Optional[str] = None,
- response_model_include: Optional[IncEx] = None,
- response_model_exclude: Optional[IncEx] = None,
- response_model_by_alias: bool = True,
- response_model_exclude_unset: bool = False,
- response_model_exclude_defaults: bool = False,
- response_model_exclude_none: bool = False,
- include_in_schema: bool = True,
- response_class: Union[Type[Response], DefaultPlaceholder] = Default(
- JSONResponse
- ),
- name: Optional[str] = None,
- openapi_extra: Optional[Dict[str, Any]] = None,
- generate_unique_id_function: Callable[[routing.APIRoute], str] = Default(
- generate_unique_id
- ),
- ) -> None:
- self.router.add_api_route(
- path,
- endpoint=endpoint,
- response_model=response_model,
- status_code=status_code,
- tags=tags,
- dependencies=dependencies,
- summary=summary,
- description=description,
- response_description=response_description,
- responses=responses,
- deprecated=deprecated,
- methods=methods,
- operation_id=operation_id,
- response_model_include=response_model_include,
- response_model_exclude=response_model_exclude,
- response_model_by_alias=response_model_by_alias,
- response_model_exclude_unset=response_model_exclude_unset,
- response_model_exclude_defaults=response_model_exclude_defaults,
- response_model_exclude_none=response_model_exclude_none,
- include_in_schema=include_in_schema,
- response_class=response_class,
- name=name,
- openapi_extra=openapi_extra,
- generate_unique_id_function=generate_unique_id_function,
- )
-
- def api_route(
- self,
- path: str,
- *,
- response_model: Any = Default(None),
- status_code: Optional[int] = None,
- tags: Optional[List[Union[str, Enum]]] = None,
- dependencies: Optional[Sequence[Depends]] = None,
- summary: Optional[str] = None,
- description: Optional[str] = None,
- response_description: str = "Successful Response",
- responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None,
- deprecated: Optional[bool] = None,
- methods: Optional[List[str]] = None,
- operation_id: Optional[str] = None,
- response_model_include: Optional[IncEx] = None,
- response_model_exclude: Optional[IncEx] = None,
- response_model_by_alias: bool = True,
- response_model_exclude_unset: bool = False,
- response_model_exclude_defaults: bool = False,
- response_model_exclude_none: bool = False,
- include_in_schema: bool = True,
- response_class: Type[Response] = Default(JSONResponse),
- name: Optional[str] = None,
- openapi_extra: Optional[Dict[str, Any]] = None,
- generate_unique_id_function: Callable[[routing.APIRoute], str] = Default(
- generate_unique_id
- ),
- ) -> Callable[[DecoratedCallable], DecoratedCallable]:
- def decorator(func: DecoratedCallable) -> DecoratedCallable:
- self.router.add_api_route(
- path,
- func,
- response_model=response_model,
- status_code=status_code,
- tags=tags,
- dependencies=dependencies,
- summary=summary,
- description=description,
- response_description=response_description,
- responses=responses,
- deprecated=deprecated,
- methods=methods,
- operation_id=operation_id,
- response_model_include=response_model_include,
- response_model_exclude=response_model_exclude,
- response_model_by_alias=response_model_by_alias,
- response_model_exclude_unset=response_model_exclude_unset,
- response_model_exclude_defaults=response_model_exclude_defaults,
- response_model_exclude_none=response_model_exclude_none,
- include_in_schema=include_in_schema,
- response_class=response_class,
- name=name,
- openapi_extra=openapi_extra,
- generate_unique_id_function=generate_unique_id_function,
- )
- return func
-
- return decorator
-
- def add_api_websocket_route(
- self,
- path: str,
- endpoint: Callable[..., Any],
- name: Optional[str] = None,
- *,
- dependencies: Optional[Sequence[Depends]] = None,
- ) -> None:
- self.router.add_api_websocket_route(
- path,
- endpoint,
- name=name,
- dependencies=dependencies,
- )
-
- def websocket(
- self,
- path: Annotated[
- str,
- Doc(
- """
- WebSocket path.
- """
- ),
- ],
- name: Annotated[
- Optional[str],
- Doc(
- """
- A name for the WebSocket. Only used internally.
- """
- ),
- ] = None,
- *,
- dependencies: Annotated[
- Optional[Sequence[Depends]],
- Doc(
- """
- A list of dependencies (using `Depends()`) to be used for this
- WebSocket.
-
- Read more about it in the
- [FastAPI docs for WebSockets](https://fastapi.tiangolo.com/advanced/websockets/).
- """
- ),
- ] = None,
- ) -> Callable[[DecoratedCallable], DecoratedCallable]:
- """
- Decorate a WebSocket function.
-
- Read more about it in the
- [FastAPI docs for WebSockets](https://fastapi.tiangolo.com/advanced/websockets/).
-
- **Example**
-
- ```python
- from fastapi import FastAPI, WebSocket
-
- app = FastAPI()
-
- @app.websocket("/ws")
- async def websocket_endpoint(websocket: WebSocket):
- await websocket.accept()
- while True:
- data = await websocket.receive_text()
- await websocket.send_text(f"Message text was: {data}")
- ```
- """
-
- def decorator(func: DecoratedCallable) -> DecoratedCallable:
- self.add_api_websocket_route(
- path,
- func,
- name=name,
- dependencies=dependencies,
- )
- return func
-
- return decorator
-
- def include_router(
- self,
- router: Annotated[routing.APIRouter, Doc("The `APIRouter` to include.")],
- *,
- prefix: Annotated[str, Doc("An optional path prefix for the router.")] = "",
- tags: Annotated[
- Optional[List[Union[str, Enum]]],
- Doc(
- """
- A list of tags to be applied to all the *path operations* in this
- router.
-
- It will be added to the generated OpenAPI (e.g. visible at `/docs`).
-
- Read more about it in the
- [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
- """
- ),
- ] = None,
- dependencies: Annotated[
- Optional[Sequence[Depends]],
- Doc(
- """
- A list of dependencies (using `Depends()`) to be applied to all the
- *path operations* in this router.
-
- Read more about it in the
- [FastAPI docs for Bigger Applications - Multiple Files](https://fastapi.tiangolo.com/tutorial/bigger-applications/#include-an-apirouter-with-a-custom-prefix-tags-responses-and-dependencies).
-
- **Example**
-
- ```python
- from fastapi import Depends, FastAPI
-
- from .dependencies import get_token_header
- from .internal import admin
-
- app = FastAPI()
-
- app.include_router(
- admin.router,
- dependencies=[Depends(get_token_header)],
- )
- ```
- """
- ),
- ] = None,
- responses: Annotated[
- Optional[Dict[Union[int, str], Dict[str, Any]]],
- Doc(
- """
- Additional responses to be shown in OpenAPI.
-
- It will be added to the generated OpenAPI (e.g. visible at `/docs`).
-
- Read more about it in the
- [FastAPI docs for Additional Responses in OpenAPI](https://fastapi.tiangolo.com/advanced/additional-responses/).
-
- And in the
- [FastAPI docs for Bigger Applications](https://fastapi.tiangolo.com/tutorial/bigger-applications/#include-an-apirouter-with-a-custom-prefix-tags-responses-and-dependencies).
- """
- ),
- ] = None,
- deprecated: Annotated[
- Optional[bool],
- Doc(
- """
- Mark all the *path operations* in this router as deprecated.
-
- It will be added to the generated OpenAPI (e.g. visible at `/docs`).
-
- **Example**
-
- ```python
- from fastapi import FastAPI
-
- from .internal import old_api
-
- app = FastAPI()
-
- app.include_router(
- old_api.router,
- deprecated=True,
- )
- ```
- """
- ),
- ] = None,
- include_in_schema: Annotated[
- bool,
- Doc(
- """
- Include (or not) all the *path operations* in this router in the
- generated OpenAPI schema.
-
- This affects the generated OpenAPI (e.g. visible at `/docs`).
-
- **Example**
-
- ```python
- from fastapi import FastAPI
-
- from .internal import old_api
-
- app = FastAPI()
-
- app.include_router(
- old_api.router,
- include_in_schema=False,
- )
- ```
- """
- ),
- ] = True,
- default_response_class: Annotated[
- Type[Response],
- Doc(
- """
- Default response class to be used for the *path operations* in this
- router.
-
- Read more in the
- [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#default-response-class).
-
- **Example**
-
- ```python
- from fastapi import FastAPI
- from fastapi.responses import ORJSONResponse
-
- from .internal import old_api
-
- app = FastAPI()
-
- app.include_router(
- old_api.router,
- default_response_class=ORJSONResponse,
- )
- ```
- """
- ),
- ] = Default(JSONResponse),
- callbacks: Annotated[
- Optional[List[BaseRoute]],
- Doc(
- """
- List of *path operations* that will be used as OpenAPI callbacks.
-
- This is only for OpenAPI documentation, the callbacks won't be used
- directly.
-
- It will be added to the generated OpenAPI (e.g. visible at `/docs`).
-
- Read more about it in the
- [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/).
- """
- ),
- ] = None,
- generate_unique_id_function: Annotated[
- Callable[[routing.APIRoute], str],
- Doc(
- """
- Customize the function used to generate unique IDs for the *path
- operations* shown in the generated OpenAPI.
-
- This is particularly useful when automatically generating clients or
- SDKs for your API.
-
- Read more about it in the
- [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
- """
- ),
- ] = Default(generate_unique_id),
- ) -> None:
- """
- Include an `APIRouter` in the same app.
-
- Read more about it in the
- [FastAPI docs for Bigger Applications](https://fastapi.tiangolo.com/tutorial/bigger-applications/).
-
- ## Example
-
- ```python
- from fastapi import FastAPI
-
- from .users import users_router
-
- app = FastAPI()
-
- app.include_router(users_router)
- ```
- """
- self.router.include_router(
- router,
- prefix=prefix,
- tags=tags,
- dependencies=dependencies,
- responses=responses,
- deprecated=deprecated,
- include_in_schema=include_in_schema,
- default_response_class=default_response_class,
- callbacks=callbacks,
- generate_unique_id_function=generate_unique_id_function,
- )
-
- def get(
- self,
- path: Annotated[
- str,
- Doc(
- """
- The URL path to be used for this *path operation*.
-
- For example, in `http://example.com/items`, the path is `/items`.
- """
- ),
- ],
- *,
- response_model: Annotated[
- Any,
- Doc(
- """
- The type to use for the response.
-
- It could be any valid Pydantic *field* type. So, it doesn't have to
- be a Pydantic model, it could be other things, like a `list`, `dict`,
- etc.
-
- It will be used for:
-
- * Documentation: the generated OpenAPI (and the UI at `/docs`) will
- show it as the response (JSON Schema).
- * Serialization: you could return an arbitrary object and the
- `response_model` would be used to serialize that object into the
- corresponding JSON.
- * Filtering: the JSON sent to the client will only contain the data
- (fields) defined in the `response_model`. If you returned an object
- that contains an attribute `password` but the `response_model` does
- not include that field, the JSON sent to the client would not have
- that `password`.
- * Validation: whatever you return will be serialized with the
- `response_model`, converting any data as necessary to generate the
- corresponding JSON. But if the data in the object returned is not
- valid, that would mean a violation of the contract with the client,
- so it's an error from the API developer. So, FastAPI will raise an
- error and return a 500 error code (Internal Server Error).
-
- Read more about it in the
- [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/).
- """
- ),
- ] = Default(None),
- status_code: Annotated[
- Optional[int],
- Doc(
- """
- The default status code to be used for the response.
-
- You could override the status code by returning a response directly.
-
- Read more about it in the
- [FastAPI docs for Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/).
- """
- ),
- ] = None,
- tags: Annotated[
- Optional[List[Union[str, Enum]]],
- Doc(
- """
- A list of tags to be applied to the *path operation*.
-
- It will be added to the generated OpenAPI (e.g. visible at `/docs`).
-
- Read more about it in the
- [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#tags).
- """
- ),
- ] = None,
- dependencies: Annotated[
- Optional[Sequence[Depends]],
- Doc(
- """
- A list of dependencies (using `Depends()`) to be applied to the
- *path operation*.
-
- Read more about it in the
- [FastAPI docs for Dependencies in path operation decorators](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-path-operation-decorators/).
- """
- ),
- ] = None,
- summary: Annotated[
- Optional[str],
- Doc(
- """
- A summary for the *path operation*.
-
- It will be added to the generated OpenAPI (e.g. visible at `/docs`).
-
- Read more about it in the
- [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
- """
- ),
- ] = None,
- description: Annotated[
- Optional[str],
- Doc(
- """
- A description for the *path operation*.
-
- If not provided, it will be extracted automatically from the docstring
- of the *path operation function*.
-
- It can contain Markdown.
-
- It will be added to the generated OpenAPI (e.g. visible at `/docs`).
-
- Read more about it in the
- [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
- """
- ),
- ] = None,
- response_description: Annotated[
- str,
- Doc(
- """
- The description for the default response.
-
- It will be added to the generated OpenAPI (e.g. visible at `/docs`).
- """
- ),
- ] = "Successful Response",
- responses: Annotated[
- Optional[Dict[Union[int, str], Dict[str, Any]]],
- Doc(
- """
- Additional responses that could be returned by this *path operation*.
-
- It will be added to the generated OpenAPI (e.g. visible at `/docs`).
- """
- ),
- ] = None,
- deprecated: Annotated[
- Optional[bool],
- Doc(
- """
- Mark this *path operation* as deprecated.
-
- It will be added to the generated OpenAPI (e.g. visible at `/docs`).
- """
- ),
- ] = None,
- operation_id: Annotated[
- Optional[str],
- Doc(
- """
- Custom operation ID to be used by this *path operation*.
-
- By default, it is generated automatically.
-
- If you provide a custom operation ID, you need to make sure it is
- unique for the whole API.
-
- You can customize the
- operation ID generation with the parameter
- `generate_unique_id_function` in the `FastAPI` class.
-
- Read more about it in the
- [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
- """
- ),
- ] = None,
- response_model_include: Annotated[
- Optional[IncEx],
- Doc(
- """
- Configuration passed to Pydantic to include only certain fields in the
- response data.
-
- Read more about it in the
- [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
- """
- ),
- ] = None,
- response_model_exclude: Annotated[
- Optional[IncEx],
- Doc(
- """
- Configuration passed to Pydantic to exclude certain fields in the
- response data.
-
- Read more about it in the
- [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
- """
- ),
- ] = None,
- response_model_by_alias: Annotated[
- bool,
- Doc(
- """
- Configuration passed to Pydantic to define if the response model
- should be serialized by alias when an alias is used.
-
- Read more about it in the
- [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
- """
- ),
- ] = True,
- response_model_exclude_unset: Annotated[
- bool,
- Doc(
- """
- Configuration passed to Pydantic to define if the response data
- should have all the fields, including the ones that were not set and
- have their default values. This is different from
- `response_model_exclude_defaults` in that if the fields are set,
- they will be included in the response, even if the value is the same
- as the default.
-
- When `True`, default values are omitted from the response.
-
- Read more about it in the
- [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter).
- """
- ),
- ] = False,
- response_model_exclude_defaults: Annotated[
- bool,
- Doc(
- """
- Configuration passed to Pydantic to define if the response data
- should have all the fields, including the ones that have the same value
- as the default. This is different from `response_model_exclude_unset`
- in that if the fields are set but contain the same default values,
- they will be excluded from the response.
-
- When `True`, default values are omitted from the response.
-
- Read more about it in the
- [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter).
- """
- ),
- ] = False,
- response_model_exclude_none: Annotated[
- bool,
- Doc(
- """
- Configuration passed to Pydantic to define if the response data should
- exclude fields set to `None`.
-
- This is much simpler (less smart) than `response_model_exclude_unset`
- and `response_model_exclude_defaults`. You probably want to use one of
- those two instead of this one, as those allow returning `None` values
- when it makes sense.
-
- Read more about it in the
- [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_exclude_none).
- """
- ),
- ] = False,
- include_in_schema: Annotated[
- bool,
- Doc(
- """
- Include this *path operation* in the generated OpenAPI schema.
-
- This affects the generated OpenAPI (e.g. visible at `/docs`).
-
- Read more about it in the
- [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi).
- """
- ),
- ] = True,
- response_class: Annotated[
- Type[Response],
- Doc(
- """
- Response class to be used for this *path operation*.
-
- This will not be used if you return a response directly.
-
- Read more about it in the
- [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse).
- """
- ),
- ] = Default(JSONResponse),
- name: Annotated[
- Optional[str],
- Doc(
- """
- Name for this *path operation*. Only used internally.
- """
- ),
- ] = None,
- callbacks: Annotated[
- Optional[List[BaseRoute]],
- Doc(
- """
- List of *path operations* that will be used as OpenAPI callbacks.
-
- This is only for OpenAPI documentation, the callbacks won't be used
- directly.
-
- It will be added to the generated OpenAPI (e.g. visible at `/docs`).
-
- Read more about it in the
- [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/).
- """
- ),
- ] = None,
- openapi_extra: Annotated[
- Optional[Dict[str, Any]],
- Doc(
- """
- Extra metadata to be included in the OpenAPI schema for this *path
- operation*.
-
- Read more about it in the
- [FastAPI docs for Path Operation Advanced Configuration](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#custom-openapi-path-operation-schema).
- """
- ),
- ] = None,
- generate_unique_id_function: Annotated[
- Callable[[routing.APIRoute], str],
- Doc(
- """
- Customize the function used to generate unique IDs for the *path
- operations* shown in the generated OpenAPI.
-
- This is particularly useful when automatically generating clients or
- SDKs for your API.
-
- Read more about it in the
- [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
- """
- ),
- ] = Default(generate_unique_id),
- ) -> Callable[[DecoratedCallable], DecoratedCallable]:
- """
- Add a *path operation* using an HTTP GET operation.
-
- ## Example
-
- ```python
- from fastapi import FastAPI
-
- app = FastAPI()
-
- @app.get("/items/")
- def read_items():
- return [{"name": "Empanada"}, {"name": "Arepa"}]
- ```
- """
- return self.router.get(
- path,
- response_model=response_model,
- status_code=status_code,
- tags=tags,
- dependencies=dependencies,
- summary=summary,
- description=description,
- response_description=response_description,
- responses=responses,
- deprecated=deprecated,
- operation_id=operation_id,
- response_model_include=response_model_include,
- response_model_exclude=response_model_exclude,
- response_model_by_alias=response_model_by_alias,
- response_model_exclude_unset=response_model_exclude_unset,
- response_model_exclude_defaults=response_model_exclude_defaults,
- response_model_exclude_none=response_model_exclude_none,
- include_in_schema=include_in_schema,
- response_class=response_class,
- name=name,
- callbacks=callbacks,
- openapi_extra=openapi_extra,
- generate_unique_id_function=generate_unique_id_function,
- )
-
- def put(
- self,
- path: Annotated[
- str,
- Doc(
- """
- The URL path to be used for this *path operation*.
-
- For example, in `http://example.com/items`, the path is `/items`.
- """
- ),
- ],
- *,
- response_model: Annotated[
- Any,
- Doc(
- """
- The type to use for the response.
-
- It could be any valid Pydantic *field* type. So, it doesn't have to
- be a Pydantic model, it could be other things, like a `list`, `dict`,
- etc.
-
- It will be used for:
-
- * Documentation: the generated OpenAPI (and the UI at `/docs`) will
- show it as the response (JSON Schema).
- * Serialization: you could return an arbitrary object and the
- `response_model` would be used to serialize that object into the
- corresponding JSON.
- * Filtering: the JSON sent to the client will only contain the data
- (fields) defined in the `response_model`. If you returned an object
- that contains an attribute `password` but the `response_model` does
- not include that field, the JSON sent to the client would not have
- that `password`.
- * Validation: whatever you return will be serialized with the
- `response_model`, converting any data as necessary to generate the
- corresponding JSON. But if the data in the object returned is not
- valid, that would mean a violation of the contract with the client,
- so it's an error from the API developer. So, FastAPI will raise an
- error and return a 500 error code (Internal Server Error).
-
- Read more about it in the
- [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/).
- """
- ),
- ] = Default(None),
- status_code: Annotated[
- Optional[int],
- Doc(
- """
- The default status code to be used for the response.
-
- You could override the status code by returning a response directly.
-
- Read more about it in the
- [FastAPI docs for Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/).
- """
- ),
- ] = None,
- tags: Annotated[
- Optional[List[Union[str, Enum]]],
- Doc(
- """
- A list of tags to be applied to the *path operation*.
-
- It will be added to the generated OpenAPI (e.g. visible at `/docs`).
-
- Read more about it in the
- [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#tags).
- """
- ),
- ] = None,
- dependencies: Annotated[
- Optional[Sequence[Depends]],
- Doc(
- """
- A list of dependencies (using `Depends()`) to be applied to the
- *path operation*.
-
- Read more about it in the
- [FastAPI docs for Dependencies in path operation decorators](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-path-operation-decorators/).
- """
- ),
- ] = None,
- summary: Annotated[
- Optional[str],
- Doc(
- """
- A summary for the *path operation*.
-
- It will be added to the generated OpenAPI (e.g. visible at `/docs`).
-
- Read more about it in the
- [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
- """
- ),
- ] = None,
- description: Annotated[
- Optional[str],
- Doc(
- """
- A description for the *path operation*.
-
- If not provided, it will be extracted automatically from the docstring
- of the *path operation function*.
-
- It can contain Markdown.
-
- It will be added to the generated OpenAPI (e.g. visible at `/docs`).
-
- Read more about it in the
- [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
- """
- ),
- ] = None,
- response_description: Annotated[
- str,
- Doc(
- """
- The description for the default response.
-
- It will be added to the generated OpenAPI (e.g. visible at `/docs`).
- """
- ),
- ] = "Successful Response",
- responses: Annotated[
- Optional[Dict[Union[int, str], Dict[str, Any]]],
- Doc(
- """
- Additional responses that could be returned by this *path operation*.
-
- It will be added to the generated OpenAPI (e.g. visible at `/docs`).
- """
- ),
- ] = None,
- deprecated: Annotated[
- Optional[bool],
- Doc(
- """
- Mark this *path operation* as deprecated.
-
- It will be added to the generated OpenAPI (e.g. visible at `/docs`).
- """
- ),
- ] = None,
- operation_id: Annotated[
- Optional[str],
- Doc(
- """
- Custom operation ID to be used by this *path operation*.
-
- By default, it is generated automatically.
-
- If you provide a custom operation ID, you need to make sure it is
- unique for the whole API.
-
- You can customize the
- operation ID generation with the parameter
- `generate_unique_id_function` in the `FastAPI` class.
-
- Read more about it in the
- [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
- """
- ),
- ] = None,
- response_model_include: Annotated[
- Optional[IncEx],
- Doc(
- """
- Configuration passed to Pydantic to include only certain fields in the
- response data.
-
- Read more about it in the
- [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
- """
- ),
- ] = None,
- response_model_exclude: Annotated[
- Optional[IncEx],
- Doc(
- """
- Configuration passed to Pydantic to exclude certain fields in the
- response data.
-
- Read more about it in the
- [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
- """
- ),
- ] = None,
- response_model_by_alias: Annotated[
- bool,
- Doc(
- """
- Configuration passed to Pydantic to define if the response model
- should be serialized by alias when an alias is used.
-
- Read more about it in the
- [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
- """
- ),
- ] = True,
- response_model_exclude_unset: Annotated[
- bool,
- Doc(
- """
- Configuration passed to Pydantic to define if the response data
- should have all the fields, including the ones that were not set and
- have their default values. This is different from
- `response_model_exclude_defaults` in that if the fields are set,
- they will be included in the response, even if the value is the same
- as the default.
-
- When `True`, default values are omitted from the response.
-
- Read more about it in the
- [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter).
- """
- ),
- ] = False,
- response_model_exclude_defaults: Annotated[
- bool,
- Doc(
- """
- Configuration passed to Pydantic to define if the response data
- should have all the fields, including the ones that have the same value
- as the default. This is different from `response_model_exclude_unset`
- in that if the fields are set but contain the same default values,
- they will be excluded from the response.
-
- When `True`, default values are omitted from the response.
-
- Read more about it in the
- [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter).
- """
- ),
- ] = False,
- response_model_exclude_none: Annotated[
- bool,
- Doc(
- """
- Configuration passed to Pydantic to define if the response data should
- exclude fields set to `None`.
-
- This is much simpler (less smart) than `response_model_exclude_unset`
- and `response_model_exclude_defaults`. You probably want to use one of
- those two instead of this one, as those allow returning `None` values
- when it makes sense.
-
- Read more about it in the
- [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_exclude_none).
- """
- ),
- ] = False,
- include_in_schema: Annotated[
- bool,
- Doc(
- """
- Include this *path operation* in the generated OpenAPI schema.
-
- This affects the generated OpenAPI (e.g. visible at `/docs`).
-
- Read more about it in the
- [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi).
- """
- ),
- ] = True,
- response_class: Annotated[
- Type[Response],
- Doc(
- """
- Response class to be used for this *path operation*.
-
- This will not be used if you return a response directly.
-
- Read more about it in the
- [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse).
- """
- ),
- ] = Default(JSONResponse),
- name: Annotated[
- Optional[str],
- Doc(
- """
- Name for this *path operation*. Only used internally.
- """
- ),
- ] = None,
- callbacks: Annotated[
- Optional[List[BaseRoute]],
- Doc(
- """
- List of *path operations* that will be used as OpenAPI callbacks.
-
- This is only for OpenAPI documentation, the callbacks won't be used
- directly.
-
- It will be added to the generated OpenAPI (e.g. visible at `/docs`).
-
- Read more about it in the
- [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/).
- """
- ),
- ] = None,
- openapi_extra: Annotated[
- Optional[Dict[str, Any]],
- Doc(
- """
- Extra metadata to be included in the OpenAPI schema for this *path
- operation*.
-
- Read more about it in the
- [FastAPI docs for Path Operation Advanced Configuration](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#custom-openapi-path-operation-schema).
- """
- ),
- ] = None,
- generate_unique_id_function: Annotated[
- Callable[[routing.APIRoute], str],
- Doc(
- """
- Customize the function used to generate unique IDs for the *path
- operations* shown in the generated OpenAPI.
-
- This is particularly useful when automatically generating clients or
- SDKs for your API.
-
- Read more about it in the
- [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
- """
- ),
- ] = Default(generate_unique_id),
- ) -> Callable[[DecoratedCallable], DecoratedCallable]:
- """
- Add a *path operation* using an HTTP PUT operation.
-
- ## Example
-
- ```python
- from fastapi import FastAPI
- from pydantic import BaseModel
-
- class Item(BaseModel):
- name: str
- description: str | None = None
-
- app = FastAPI()
-
- @app.put("/items/{item_id}")
- def replace_item(item_id: str, item: Item):
- return {"message": "Item replaced", "id": item_id}
- ```
- """
- return self.router.put(
- path,
- response_model=response_model,
- status_code=status_code,
- tags=tags,
- dependencies=dependencies,
- summary=summary,
- description=description,
- response_description=response_description,
- responses=responses,
- deprecated=deprecated,
- operation_id=operation_id,
- response_model_include=response_model_include,
- response_model_exclude=response_model_exclude,
- response_model_by_alias=response_model_by_alias,
- response_model_exclude_unset=response_model_exclude_unset,
- response_model_exclude_defaults=response_model_exclude_defaults,
- response_model_exclude_none=response_model_exclude_none,
- include_in_schema=include_in_schema,
- response_class=response_class,
- name=name,
- callbacks=callbacks,
- openapi_extra=openapi_extra,
- generate_unique_id_function=generate_unique_id_function,
- )
-
- def post(
- self,
- path: Annotated[
- str,
- Doc(
- """
- The URL path to be used for this *path operation*.
-
- For example, in `http://example.com/items`, the path is `/items`.
- """
- ),
- ],
- *,
- response_model: Annotated[
- Any,
- Doc(
- """
- The type to use for the response.
-
- It could be any valid Pydantic *field* type. So, it doesn't have to
- be a Pydantic model, it could be other things, like a `list`, `dict`,
- etc.
-
- It will be used for:
-
- * Documentation: the generated OpenAPI (and the UI at `/docs`) will
- show it as the response (JSON Schema).
- * Serialization: you could return an arbitrary object and the
- `response_model` would be used to serialize that object into the
- corresponding JSON.
- * Filtering: the JSON sent to the client will only contain the data
- (fields) defined in the `response_model`. If you returned an object
- that contains an attribute `password` but the `response_model` does
- not include that field, the JSON sent to the client would not have
- that `password`.
- * Validation: whatever you return will be serialized with the
- `response_model`, converting any data as necessary to generate the
- corresponding JSON. But if the data in the object returned is not
- valid, that would mean a violation of the contract with the client,
- so it's an error from the API developer. So, FastAPI will raise an
- error and return a 500 error code (Internal Server Error).
-
- Read more about it in the
- [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/).
- """
- ),
- ] = Default(None),
- status_code: Annotated[
- Optional[int],
- Doc(
- """
- The default status code to be used for the response.
-
- You could override the status code by returning a response directly.
-
- Read more about it in the
- [FastAPI docs for Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/).
- """
- ),
- ] = None,
- tags: Annotated[
- Optional[List[Union[str, Enum]]],
- Doc(
- """
- A list of tags to be applied to the *path operation*.
-
- It will be added to the generated OpenAPI (e.g. visible at `/docs`).
-
- Read more about it in the
- [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#tags).
- """
- ),
- ] = None,
- dependencies: Annotated[
- Optional[Sequence[Depends]],
- Doc(
- """
- A list of dependencies (using `Depends()`) to be applied to the
- *path operation*.
-
- Read more about it in the
- [FastAPI docs for Dependencies in path operation decorators](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-path-operation-decorators/).
- """
- ),
- ] = None,
- summary: Annotated[
- Optional[str],
- Doc(
- """
- A summary for the *path operation*.
-
- It will be added to the generated OpenAPI (e.g. visible at `/docs`).
-
- Read more about it in the
- [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
- """
- ),
- ] = None,
- description: Annotated[
- Optional[str],
- Doc(
- """
- A description for the *path operation*.
-
- If not provided, it will be extracted automatically from the docstring
- of the *path operation function*.
-
- It can contain Markdown.
-
- It will be added to the generated OpenAPI (e.g. visible at `/docs`).
-
- Read more about it in the
- [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
- """
- ),
- ] = None,
- response_description: Annotated[
- str,
- Doc(
- """
- The description for the default response.
-
- It will be added to the generated OpenAPI (e.g. visible at `/docs`).
- """
- ),
- ] = "Successful Response",
- responses: Annotated[
- Optional[Dict[Union[int, str], Dict[str, Any]]],
- Doc(
- """
- Additional responses that could be returned by this *path operation*.
-
- It will be added to the generated OpenAPI (e.g. visible at `/docs`).
- """
- ),
- ] = None,
- deprecated: Annotated[
- Optional[bool],
- Doc(
- """
- Mark this *path operation* as deprecated.
-
- It will be added to the generated OpenAPI (e.g. visible at `/docs`).
- """
- ),
- ] = None,
- operation_id: Annotated[
- Optional[str],
- Doc(
- """
- Custom operation ID to be used by this *path operation*.
-
- By default, it is generated automatically.
-
- If you provide a custom operation ID, you need to make sure it is
- unique for the whole API.
-
- You can customize the
- operation ID generation with the parameter
- `generate_unique_id_function` in the `FastAPI` class.
-
- Read more about it in the
- [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
- """
- ),
- ] = None,
- response_model_include: Annotated[
- Optional[IncEx],
- Doc(
- """
- Configuration passed to Pydantic to include only certain fields in the
- response data.
-
- Read more about it in the
- [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
- """
- ),
- ] = None,
- response_model_exclude: Annotated[
- Optional[IncEx],
- Doc(
- """
- Configuration passed to Pydantic to exclude certain fields in the
- response data.
-
- Read more about it in the
- [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
- """
- ),
- ] = None,
- response_model_by_alias: Annotated[
- bool,
- Doc(
- """
- Configuration passed to Pydantic to define if the response model
- should be serialized by alias when an alias is used.
-
- Read more about it in the
- [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
- """
- ),
- ] = True,
- response_model_exclude_unset: Annotated[
- bool,
- Doc(
- """
- Configuration passed to Pydantic to define if the response data
- should have all the fields, including the ones that were not set and
- have their default values. This is different from
- `response_model_exclude_defaults` in that if the fields are set,
- they will be included in the response, even if the value is the same
- as the default.
-
- When `True`, default values are omitted from the response.
-
- Read more about it in the
- [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter).
- """
- ),
- ] = False,
- response_model_exclude_defaults: Annotated[
- bool,
- Doc(
- """
- Configuration passed to Pydantic to define if the response data
- should have all the fields, including the ones that have the same value
- as the default. This is different from `response_model_exclude_unset`
- in that if the fields are set but contain the same default values,
- they will be excluded from the response.
-
- When `True`, default values are omitted from the response.
-
- Read more about it in the
- [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter).
- """
- ),
- ] = False,
- response_model_exclude_none: Annotated[
- bool,
- Doc(
- """
- Configuration passed to Pydantic to define if the response data should
- exclude fields set to `None`.
-
- This is much simpler (less smart) than `response_model_exclude_unset`
- and `response_model_exclude_defaults`. You probably want to use one of
- those two instead of this one, as those allow returning `None` values
- when it makes sense.
-
- Read more about it in the
- [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_exclude_none).
- """
- ),
- ] = False,
- include_in_schema: Annotated[
- bool,
- Doc(
- """
- Include this *path operation* in the generated OpenAPI schema.
-
- This affects the generated OpenAPI (e.g. visible at `/docs`).
-
- Read more about it in the
- [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi).
- """
- ),
- ] = True,
- response_class: Annotated[
- Type[Response],
- Doc(
- """
- Response class to be used for this *path operation*.
-
- This will not be used if you return a response directly.
-
- Read more about it in the
- [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse).
- """
- ),
- ] = Default(JSONResponse),
- name: Annotated[
- Optional[str],
- Doc(
- """
- Name for this *path operation*. Only used internally.
- """
- ),
- ] = None,
- callbacks: Annotated[
- Optional[List[BaseRoute]],
- Doc(
- """
- List of *path operations* that will be used as OpenAPI callbacks.
-
- This is only for OpenAPI documentation, the callbacks won't be used
- directly.
-
- It will be added to the generated OpenAPI (e.g. visible at `/docs`).
-
- Read more about it in the
- [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/).
- """
- ),
- ] = None,
- openapi_extra: Annotated[
- Optional[Dict[str, Any]],
- Doc(
- """
- Extra metadata to be included in the OpenAPI schema for this *path
- operation*.
-
- Read more about it in the
- [FastAPI docs for Path Operation Advanced Configuration](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#custom-openapi-path-operation-schema).
- """
- ),
- ] = None,
- generate_unique_id_function: Annotated[
- Callable[[routing.APIRoute], str],
- Doc(
- """
- Customize the function used to generate unique IDs for the *path
- operations* shown in the generated OpenAPI.
-
- This is particularly useful when automatically generating clients or
- SDKs for your API.
-
- Read more about it in the
- [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
- """
- ),
- ] = Default(generate_unique_id),
- ) -> Callable[[DecoratedCallable], DecoratedCallable]:
- """
- Add a *path operation* using an HTTP POST operation.
-
- ## Example
-
- ```python
- from fastapi import FastAPI
- from pydantic import BaseModel
-
- class Item(BaseModel):
- name: str
- description: str | None = None
-
- app = FastAPI()
-
- @app.post("/items/")
- def create_item(item: Item):
- return {"message": "Item created"}
- ```
- """
- return self.router.post(
- path,
- response_model=response_model,
- status_code=status_code,
- tags=tags,
- dependencies=dependencies,
- summary=summary,
- description=description,
- response_description=response_description,
- responses=responses,
- deprecated=deprecated,
- operation_id=operation_id,
- response_model_include=response_model_include,
- response_model_exclude=response_model_exclude,
- response_model_by_alias=response_model_by_alias,
- response_model_exclude_unset=response_model_exclude_unset,
- response_model_exclude_defaults=response_model_exclude_defaults,
- response_model_exclude_none=response_model_exclude_none,
- include_in_schema=include_in_schema,
- response_class=response_class,
- name=name,
- callbacks=callbacks,
- openapi_extra=openapi_extra,
- generate_unique_id_function=generate_unique_id_function,
- )
-
- def delete(
- self,
- path: Annotated[
- str,
- Doc(
- """
- The URL path to be used for this *path operation*.
-
- For example, in `http://example.com/items`, the path is `/items`.
- """
- ),
- ],
- *,
- response_model: Annotated[
- Any,
- Doc(
- """
- The type to use for the response.
-
- It could be any valid Pydantic *field* type. So, it doesn't have to
- be a Pydantic model, it could be other things, like a `list`, `dict`,
- etc.
-
- It will be used for:
-
- * Documentation: the generated OpenAPI (and the UI at `/docs`) will
- show it as the response (JSON Schema).
- * Serialization: you could return an arbitrary object and the
- `response_model` would be used to serialize that object into the
- corresponding JSON.
- * Filtering: the JSON sent to the client will only contain the data
- (fields) defined in the `response_model`. If you returned an object
- that contains an attribute `password` but the `response_model` does
- not include that field, the JSON sent to the client would not have
- that `password`.
- * Validation: whatever you return will be serialized with the
- `response_model`, converting any data as necessary to generate the
- corresponding JSON. But if the data in the object returned is not
- valid, that would mean a violation of the contract with the client,
- so it's an error from the API developer. So, FastAPI will raise an
- error and return a 500 error code (Internal Server Error).
-
- Read more about it in the
- [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/).
- """
- ),
- ] = Default(None),
- status_code: Annotated[
- Optional[int],
- Doc(
- """
- The default status code to be used for the response.
-
- You could override the status code by returning a response directly.
-
- Read more about it in the
- [FastAPI docs for Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/).
- """
- ),
- ] = None,
- tags: Annotated[
- Optional[List[Union[str, Enum]]],
- Doc(
- """
- A list of tags to be applied to the *path operation*.
-
- It will be added to the generated OpenAPI (e.g. visible at `/docs`).
-
- Read more about it in the
- [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#tags).
- """
- ),
- ] = None,
- dependencies: Annotated[
- Optional[Sequence[Depends]],
- Doc(
- """
- A list of dependencies (using `Depends()`) to be applied to the
- *path operation*.
-
- Read more about it in the
- [FastAPI docs for Dependencies in path operation decorators](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-path-operation-decorators/).
- """
- ),
- ] = None,
- summary: Annotated[
- Optional[str],
- Doc(
- """
- A summary for the *path operation*.
-
- It will be added to the generated OpenAPI (e.g. visible at `/docs`).
-
- Read more about it in the
- [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
- """
- ),
- ] = None,
- description: Annotated[
- Optional[str],
- Doc(
- """
- A description for the *path operation*.
-
- If not provided, it will be extracted automatically from the docstring
- of the *path operation function*.
-
- It can contain Markdown.
-
- It will be added to the generated OpenAPI (e.g. visible at `/docs`).
-
- Read more about it in the
- [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
- """
- ),
- ] = None,
- response_description: Annotated[
- str,
- Doc(
- """
- The description for the default response.
-
- It will be added to the generated OpenAPI (e.g. visible at `/docs`).
- """
- ),
- ] = "Successful Response",
- responses: Annotated[
- Optional[Dict[Union[int, str], Dict[str, Any]]],
- Doc(
- """
- Additional responses that could be returned by this *path operation*.
-
- It will be added to the generated OpenAPI (e.g. visible at `/docs`).
- """
- ),
- ] = None,
- deprecated: Annotated[
- Optional[bool],
- Doc(
- """
- Mark this *path operation* as deprecated.
-
- It will be added to the generated OpenAPI (e.g. visible at `/docs`).
- """
- ),
- ] = None,
- operation_id: Annotated[
- Optional[str],
- Doc(
- """
- Custom operation ID to be used by this *path operation*.
-
- By default, it is generated automatically.
-
- If you provide a custom operation ID, you need to make sure it is
- unique for the whole API.
-
- You can customize the
- operation ID generation with the parameter
- `generate_unique_id_function` in the `FastAPI` class.
-
- Read more about it in the
- [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
- """
- ),
- ] = None,
- response_model_include: Annotated[
- Optional[IncEx],
- Doc(
- """
- Configuration passed to Pydantic to include only certain fields in the
- response data.
-
- Read more about it in the
- [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
- """
- ),
- ] = None,
- response_model_exclude: Annotated[
- Optional[IncEx],
- Doc(
- """
- Configuration passed to Pydantic to exclude certain fields in the
- response data.
-
- Read more about it in the
- [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
- """
- ),
- ] = None,
- response_model_by_alias: Annotated[
- bool,
- Doc(
- """
- Configuration passed to Pydantic to define if the response model
- should be serialized by alias when an alias is used.
-
- Read more about it in the
- [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
- """
- ),
- ] = True,
- response_model_exclude_unset: Annotated[
- bool,
- Doc(
- """
- Configuration passed to Pydantic to define if the response data
- should have all the fields, including the ones that were not set and
- have their default values. This is different from
- `response_model_exclude_defaults` in that if the fields are set,
- they will be included in the response, even if the value is the same
- as the default.
-
- When `True`, default values are omitted from the response.
-
- Read more about it in the
- [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter).
- """
- ),
- ] = False,
- response_model_exclude_defaults: Annotated[
- bool,
- Doc(
- """
- Configuration passed to Pydantic to define if the response data
- should have all the fields, including the ones that have the same value
- as the default. This is different from `response_model_exclude_unset`
- in that if the fields are set but contain the same default values,
- they will be excluded from the response.
-
- When `True`, default values are omitted from the response.
-
- Read more about it in the
- [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter).
- """
- ),
- ] = False,
- response_model_exclude_none: Annotated[
- bool,
- Doc(
- """
- Configuration passed to Pydantic to define if the response data should
- exclude fields set to `None`.
-
- This is much simpler (less smart) than `response_model_exclude_unset`
- and `response_model_exclude_defaults`. You probably want to use one of
- those two instead of this one, as those allow returning `None` values
- when it makes sense.
-
- Read more about it in the
- [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_exclude_none).
- """
- ),
- ] = False,
- include_in_schema: Annotated[
- bool,
- Doc(
- """
- Include this *path operation* in the generated OpenAPI schema.
-
- This affects the generated OpenAPI (e.g. visible at `/docs`).
-
- Read more about it in the
- [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi).
- """
- ),
- ] = True,
- response_class: Annotated[
- Type[Response],
- Doc(
- """
- Response class to be used for this *path operation*.
-
- This will not be used if you return a response directly.
-
- Read more about it in the
- [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse).
- """
- ),
- ] = Default(JSONResponse),
- name: Annotated[
- Optional[str],
- Doc(
- """
- Name for this *path operation*. Only used internally.
- """
- ),
- ] = None,
- callbacks: Annotated[
- Optional[List[BaseRoute]],
- Doc(
- """
- List of *path operations* that will be used as OpenAPI callbacks.
-
- This is only for OpenAPI documentation, the callbacks won't be used
- directly.
-
- It will be added to the generated OpenAPI (e.g. visible at `/docs`).
-
- Read more about it in the
- [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/).
- """
- ),
- ] = None,
- openapi_extra: Annotated[
- Optional[Dict[str, Any]],
- Doc(
- """
- Extra metadata to be included in the OpenAPI schema for this *path
- operation*.
-
- Read more about it in the
- [FastAPI docs for Path Operation Advanced Configuration](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#custom-openapi-path-operation-schema).
- """
- ),
- ] = None,
- generate_unique_id_function: Annotated[
- Callable[[routing.APIRoute], str],
- Doc(
- """
- Customize the function used to generate unique IDs for the *path
- operations* shown in the generated OpenAPI.
-
- This is particularly useful when automatically generating clients or
- SDKs for your API.
-
- Read more about it in the
- [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
- """
- ),
- ] = Default(generate_unique_id),
- ) -> Callable[[DecoratedCallable], DecoratedCallable]:
- """
- Add a *path operation* using an HTTP DELETE operation.
-
- ## Example
-
- ```python
- from fastapi import FastAPI
-
- app = FastAPI()
-
- @app.delete("/items/{item_id}")
- def delete_item(item_id: str):
- return {"message": "Item deleted"}
- ```
- """
- return self.router.delete(
- path,
- response_model=response_model,
- status_code=status_code,
- tags=tags,
- dependencies=dependencies,
- summary=summary,
- description=description,
- response_description=response_description,
- responses=responses,
- deprecated=deprecated,
- operation_id=operation_id,
- response_model_include=response_model_include,
- response_model_exclude=response_model_exclude,
- response_model_by_alias=response_model_by_alias,
- response_model_exclude_unset=response_model_exclude_unset,
- response_model_exclude_defaults=response_model_exclude_defaults,
- response_model_exclude_none=response_model_exclude_none,
- include_in_schema=include_in_schema,
- response_class=response_class,
- name=name,
- callbacks=callbacks,
- openapi_extra=openapi_extra,
- generate_unique_id_function=generate_unique_id_function,
- )
-
- def options(
- self,
- path: Annotated[
- str,
- Doc(
- """
- The URL path to be used for this *path operation*.
-
- For example, in `http://example.com/items`, the path is `/items`.
- """
- ),
- ],
- *,
- response_model: Annotated[
- Any,
- Doc(
- """
- The type to use for the response.
-
- It could be any valid Pydantic *field* type. So, it doesn't have to
- be a Pydantic model, it could be other things, like a `list`, `dict`,
- etc.
-
- It will be used for:
-
- * Documentation: the generated OpenAPI (and the UI at `/docs`) will
- show it as the response (JSON Schema).
- * Serialization: you could return an arbitrary object and the
- `response_model` would be used to serialize that object into the
- corresponding JSON.
- * Filtering: the JSON sent to the client will only contain the data
- (fields) defined in the `response_model`. If you returned an object
- that contains an attribute `password` but the `response_model` does
- not include that field, the JSON sent to the client would not have
- that `password`.
- * Validation: whatever you return will be serialized with the
- `response_model`, converting any data as necessary to generate the
- corresponding JSON. But if the data in the object returned is not
- valid, that would mean a violation of the contract with the client,
- so it's an error from the API developer. So, FastAPI will raise an
- error and return a 500 error code (Internal Server Error).
-
- Read more about it in the
- [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/).
- """
- ),
- ] = Default(None),
- status_code: Annotated[
- Optional[int],
- Doc(
- """
- The default status code to be used for the response.
-
- You could override the status code by returning a response directly.
-
- Read more about it in the
- [FastAPI docs for Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/).
- """
- ),
- ] = None,
- tags: Annotated[
- Optional[List[Union[str, Enum]]],
- Doc(
- """
- A list of tags to be applied to the *path operation*.
-
- It will be added to the generated OpenAPI (e.g. visible at `/docs`).
-
- Read more about it in the
- [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#tags).
- """
- ),
- ] = None,
- dependencies: Annotated[
- Optional[Sequence[Depends]],
- Doc(
- """
- A list of dependencies (using `Depends()`) to be applied to the
- *path operation*.
-
- Read more about it in the
- [FastAPI docs for Dependencies in path operation decorators](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-path-operation-decorators/).
- """
- ),
- ] = None,
- summary: Annotated[
- Optional[str],
- Doc(
- """
- A summary for the *path operation*.
-
- It will be added to the generated OpenAPI (e.g. visible at `/docs`).
-
- Read more about it in the
- [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
- """
- ),
- ] = None,
- description: Annotated[
- Optional[str],
- Doc(
- """
- A description for the *path operation*.
-
- If not provided, it will be extracted automatically from the docstring
- of the *path operation function*.
-
- It can contain Markdown.
-
- It will be added to the generated OpenAPI (e.g. visible at `/docs`).
-
- Read more about it in the
- [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
- """
- ),
- ] = None,
- response_description: Annotated[
- str,
- Doc(
- """
- The description for the default response.
-
- It will be added to the generated OpenAPI (e.g. visible at `/docs`).
- """
- ),
- ] = "Successful Response",
- responses: Annotated[
- Optional[Dict[Union[int, str], Dict[str, Any]]],
- Doc(
- """
- Additional responses that could be returned by this *path operation*.
-
- It will be added to the generated OpenAPI (e.g. visible at `/docs`).
- """
- ),
- ] = None,
- deprecated: Annotated[
- Optional[bool],
- Doc(
- """
- Mark this *path operation* as deprecated.
-
- It will be added to the generated OpenAPI (e.g. visible at `/docs`).
- """
- ),
- ] = None,
- operation_id: Annotated[
- Optional[str],
- Doc(
- """
- Custom operation ID to be used by this *path operation*.
-
- By default, it is generated automatically.
-
- If you provide a custom operation ID, you need to make sure it is
- unique for the whole API.
-
- You can customize the
- operation ID generation with the parameter
- `generate_unique_id_function` in the `FastAPI` class.
-
- Read more about it in the
- [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
- """
- ),
- ] = None,
- response_model_include: Annotated[
- Optional[IncEx],
- Doc(
- """
- Configuration passed to Pydantic to include only certain fields in the
- response data.
-
- Read more about it in the
- [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
- """
- ),
- ] = None,
- response_model_exclude: Annotated[
- Optional[IncEx],
- Doc(
- """
- Configuration passed to Pydantic to exclude certain fields in the
- response data.
-
- Read more about it in the
- [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
- """
- ),
- ] = None,
- response_model_by_alias: Annotated[
- bool,
- Doc(
- """
- Configuration passed to Pydantic to define if the response model
- should be serialized by alias when an alias is used.
-
- Read more about it in the
- [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
- """
- ),
- ] = True,
- response_model_exclude_unset: Annotated[
- bool,
- Doc(
- """
- Configuration passed to Pydantic to define if the response data
- should have all the fields, including the ones that were not set and
- have their default values. This is different from
- `response_model_exclude_defaults` in that if the fields are set,
- they will be included in the response, even if the value is the same
- as the default.
-
- When `True`, default values are omitted from the response.
-
- Read more about it in the
- [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter).
- """
- ),
- ] = False,
- response_model_exclude_defaults: Annotated[
- bool,
- Doc(
- """
- Configuration passed to Pydantic to define if the response data
- should have all the fields, including the ones that have the same value
- as the default. This is different from `response_model_exclude_unset`
- in that if the fields are set but contain the same default values,
- they will be excluded from the response.
-
- When `True`, default values are omitted from the response.
-
- Read more about it in the
- [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter).
- """
- ),
- ] = False,
- response_model_exclude_none: Annotated[
- bool,
- Doc(
- """
- Configuration passed to Pydantic to define if the response data should
- exclude fields set to `None`.
-
- This is much simpler (less smart) than `response_model_exclude_unset`
- and `response_model_exclude_defaults`. You probably want to use one of
- those two instead of this one, as those allow returning `None` values
- when it makes sense.
-
- Read more about it in the
- [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_exclude_none).
- """
- ),
- ] = False,
- include_in_schema: Annotated[
- bool,
- Doc(
- """
- Include this *path operation* in the generated OpenAPI schema.
-
- This affects the generated OpenAPI (e.g. visible at `/docs`).
-
- Read more about it in the
- [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi).
- """
- ),
- ] = True,
- response_class: Annotated[
- Type[Response],
- Doc(
- """
- Response class to be used for this *path operation*.
-
- This will not be used if you return a response directly.
-
- Read more about it in the
- [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse).
- """
- ),
- ] = Default(JSONResponse),
- name: Annotated[
- Optional[str],
- Doc(
- """
- Name for this *path operation*. Only used internally.
- """
- ),
- ] = None,
- callbacks: Annotated[
- Optional[List[BaseRoute]],
- Doc(
- """
- List of *path operations* that will be used as OpenAPI callbacks.
-
- This is only for OpenAPI documentation, the callbacks won't be used
- directly.
-
- It will be added to the generated OpenAPI (e.g. visible at `/docs`).
-
- Read more about it in the
- [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/).
- """
- ),
- ] = None,
- openapi_extra: Annotated[
- Optional[Dict[str, Any]],
- Doc(
- """
- Extra metadata to be included in the OpenAPI schema for this *path
- operation*.
-
- Read more about it in the
- [FastAPI docs for Path Operation Advanced Configuration](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#custom-openapi-path-operation-schema).
- """
- ),
- ] = None,
- generate_unique_id_function: Annotated[
- Callable[[routing.APIRoute], str],
- Doc(
- """
- Customize the function used to generate unique IDs for the *path
- operations* shown in the generated OpenAPI.
-
- This is particularly useful when automatically generating clients or
- SDKs for your API.
-
- Read more about it in the
- [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
- """
- ),
- ] = Default(generate_unique_id),
- ) -> Callable[[DecoratedCallable], DecoratedCallable]:
- """
- Add a *path operation* using an HTTP OPTIONS operation.
-
- ## Example
-
- ```python
- from fastapi import FastAPI
-
- app = FastAPI()
-
- @app.options("/items/")
- def get_item_options():
- return {"additions": ["Aji", "Guacamole"]}
- ```
- """
- return self.router.options(
- path,
- response_model=response_model,
- status_code=status_code,
- tags=tags,
- dependencies=dependencies,
- summary=summary,
- description=description,
- response_description=response_description,
- responses=responses,
- deprecated=deprecated,
- operation_id=operation_id,
- response_model_include=response_model_include,
- response_model_exclude=response_model_exclude,
- response_model_by_alias=response_model_by_alias,
- response_model_exclude_unset=response_model_exclude_unset,
- response_model_exclude_defaults=response_model_exclude_defaults,
- response_model_exclude_none=response_model_exclude_none,
- include_in_schema=include_in_schema,
- response_class=response_class,
- name=name,
- callbacks=callbacks,
- openapi_extra=openapi_extra,
- generate_unique_id_function=generate_unique_id_function,
- )
-
- def head(
- self,
- path: Annotated[
- str,
- Doc(
- """
- The URL path to be used for this *path operation*.
-
- For example, in `http://example.com/items`, the path is `/items`.
- """
- ),
- ],
- *,
- response_model: Annotated[
- Any,
- Doc(
- """
- The type to use for the response.
-
- It could be any valid Pydantic *field* type. So, it doesn't have to
- be a Pydantic model, it could be other things, like a `list`, `dict`,
- etc.
-
- It will be used for:
-
- * Documentation: the generated OpenAPI (and the UI at `/docs`) will
- show it as the response (JSON Schema).
- * Serialization: you could return an arbitrary object and the
- `response_model` would be used to serialize that object into the
- corresponding JSON.
- * Filtering: the JSON sent to the client will only contain the data
- (fields) defined in the `response_model`. If you returned an object
- that contains an attribute `password` but the `response_model` does
- not include that field, the JSON sent to the client would not have
- that `password`.
- * Validation: whatever you return will be serialized with the
- `response_model`, converting any data as necessary to generate the
- corresponding JSON. But if the data in the object returned is not
- valid, that would mean a violation of the contract with the client,
- so it's an error from the API developer. So, FastAPI will raise an
- error and return a 500 error code (Internal Server Error).
-
- Read more about it in the
- [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/).
- """
- ),
- ] = Default(None),
- status_code: Annotated[
- Optional[int],
- Doc(
- """
- The default status code to be used for the response.
-
- You could override the status code by returning a response directly.
-
- Read more about it in the
- [FastAPI docs for Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/).
- """
- ),
- ] = None,
- tags: Annotated[
- Optional[List[Union[str, Enum]]],
- Doc(
- """
- A list of tags to be applied to the *path operation*.
-
- It will be added to the generated OpenAPI (e.g. visible at `/docs`).
-
- Read more about it in the
- [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#tags).
- """
- ),
- ] = None,
- dependencies: Annotated[
- Optional[Sequence[Depends]],
- Doc(
- """
- A list of dependencies (using `Depends()`) to be applied to the
- *path operation*.
-
- Read more about it in the
- [FastAPI docs for Dependencies in path operation decorators](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-path-operation-decorators/).
- """
- ),
- ] = None,
- summary: Annotated[
- Optional[str],
- Doc(
- """
- A summary for the *path operation*.
-
- It will be added to the generated OpenAPI (e.g. visible at `/docs`).
-
- Read more about it in the
- [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
- """
- ),
- ] = None,
- description: Annotated[
- Optional[str],
- Doc(
- """
- A description for the *path operation*.
-
- If not provided, it will be extracted automatically from the docstring
- of the *path operation function*.
-
- It can contain Markdown.
-
- It will be added to the generated OpenAPI (e.g. visible at `/docs`).
-
- Read more about it in the
- [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
- """
- ),
- ] = None,
- response_description: Annotated[
- str,
- Doc(
- """
- The description for the default response.
-
- It will be added to the generated OpenAPI (e.g. visible at `/docs`).
- """
- ),
- ] = "Successful Response",
- responses: Annotated[
- Optional[Dict[Union[int, str], Dict[str, Any]]],
- Doc(
- """
- Additional responses that could be returned by this *path operation*.
-
- It will be added to the generated OpenAPI (e.g. visible at `/docs`).
- """
- ),
- ] = None,
- deprecated: Annotated[
- Optional[bool],
- Doc(
- """
- Mark this *path operation* as deprecated.
-
- It will be added to the generated OpenAPI (e.g. visible at `/docs`).
- """
- ),
- ] = None,
- operation_id: Annotated[
- Optional[str],
- Doc(
- """
- Custom operation ID to be used by this *path operation*.
-
- By default, it is generated automatically.
-
- If you provide a custom operation ID, you need to make sure it is
- unique for the whole API.
-
- You can customize the
- operation ID generation with the parameter
- `generate_unique_id_function` in the `FastAPI` class.
-
- Read more about it in the
- [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
- """
- ),
- ] = None,
- response_model_include: Annotated[
- Optional[IncEx],
- Doc(
- """
- Configuration passed to Pydantic to include only certain fields in the
- response data.
-
- Read more about it in the
- [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
- """
- ),
- ] = None,
- response_model_exclude: Annotated[
- Optional[IncEx],
- Doc(
- """
- Configuration passed to Pydantic to exclude certain fields in the
- response data.
-
- Read more about it in the
- [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
- """
- ),
- ] = None,
- response_model_by_alias: Annotated[
- bool,
- Doc(
- """
- Configuration passed to Pydantic to define if the response model
- should be serialized by alias when an alias is used.
-
- Read more about it in the
- [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
- """
- ),
- ] = True,
- response_model_exclude_unset: Annotated[
- bool,
- Doc(
- """
- Configuration passed to Pydantic to define if the response data
- should have all the fields, including the ones that were not set and
- have their default values. This is different from
- `response_model_exclude_defaults` in that if the fields are set,
- they will be included in the response, even if the value is the same
- as the default.
-
- When `True`, default values are omitted from the response.
-
- Read more about it in the
- [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter).
- """
- ),
- ] = False,
- response_model_exclude_defaults: Annotated[
- bool,
- Doc(
- """
- Configuration passed to Pydantic to define if the response data
- should have all the fields, including the ones that have the same value
- as the default. This is different from `response_model_exclude_unset`
- in that if the fields are set but contain the same default values,
- they will be excluded from the response.
-
- When `True`, default values are omitted from the response.
-
- Read more about it in the
- [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter).
- """
- ),
- ] = False,
- response_model_exclude_none: Annotated[
- bool,
- Doc(
- """
- Configuration passed to Pydantic to define if the response data should
- exclude fields set to `None`.
-
- This is much simpler (less smart) than `response_model_exclude_unset`
- and `response_model_exclude_defaults`. You probably want to use one of
- those two instead of this one, as those allow returning `None` values
- when it makes sense.
-
- Read more about it in the
- [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_exclude_none).
- """
- ),
- ] = False,
- include_in_schema: Annotated[
- bool,
- Doc(
- """
- Include this *path operation* in the generated OpenAPI schema.
-
- This affects the generated OpenAPI (e.g. visible at `/docs`).
-
- Read more about it in the
- [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi).
- """
- ),
- ] = True,
- response_class: Annotated[
- Type[Response],
- Doc(
- """
- Response class to be used for this *path operation*.
-
- This will not be used if you return a response directly.
-
- Read more about it in the
- [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse).
- """
- ),
- ] = Default(JSONResponse),
- name: Annotated[
- Optional[str],
- Doc(
- """
- Name for this *path operation*. Only used internally.
- """
- ),
- ] = None,
- callbacks: Annotated[
- Optional[List[BaseRoute]],
- Doc(
- """
- List of *path operations* that will be used as OpenAPI callbacks.
-
- This is only for OpenAPI documentation, the callbacks won't be used
- directly.
-
- It will be added to the generated OpenAPI (e.g. visible at `/docs`).
-
- Read more about it in the
- [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/).
- """
- ),
- ] = None,
- openapi_extra: Annotated[
- Optional[Dict[str, Any]],
- Doc(
- """
- Extra metadata to be included in the OpenAPI schema for this *path
- operation*.
-
- Read more about it in the
- [FastAPI docs for Path Operation Advanced Configuration](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#custom-openapi-path-operation-schema).
- """
- ),
- ] = None,
- generate_unique_id_function: Annotated[
- Callable[[routing.APIRoute], str],
- Doc(
- """
- Customize the function used to generate unique IDs for the *path
- operations* shown in the generated OpenAPI.
-
- This is particularly useful when automatically generating clients or
- SDKs for your API.
-
- Read more about it in the
- [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
- """
- ),
- ] = Default(generate_unique_id),
- ) -> Callable[[DecoratedCallable], DecoratedCallable]:
- """
- Add a *path operation* using an HTTP HEAD operation.
-
- ## Example
-
- ```python
- from fastapi import FastAPI, Response
-
- app = FastAPI()
-
- @app.head("/items/", status_code=204)
- def get_items_headers(response: Response):
- response.headers["X-Cat-Dog"] = "Alone in the world"
- ```
- """
- return self.router.head(
- path,
- response_model=response_model,
- status_code=status_code,
- tags=tags,
- dependencies=dependencies,
- summary=summary,
- description=description,
- response_description=response_description,
- responses=responses,
- deprecated=deprecated,
- operation_id=operation_id,
- response_model_include=response_model_include,
- response_model_exclude=response_model_exclude,
- response_model_by_alias=response_model_by_alias,
- response_model_exclude_unset=response_model_exclude_unset,
- response_model_exclude_defaults=response_model_exclude_defaults,
- response_model_exclude_none=response_model_exclude_none,
- include_in_schema=include_in_schema,
- response_class=response_class,
- name=name,
- callbacks=callbacks,
- openapi_extra=openapi_extra,
- generate_unique_id_function=generate_unique_id_function,
- )
-
- def patch(
- self,
- path: Annotated[
- str,
- Doc(
- """
- The URL path to be used for this *path operation*.
-
- For example, in `http://example.com/items`, the path is `/items`.
- """
- ),
- ],
- *,
- response_model: Annotated[
- Any,
- Doc(
- """
- The type to use for the response.
-
- It could be any valid Pydantic *field* type. So, it doesn't have to
- be a Pydantic model, it could be other things, like a `list`, `dict`,
- etc.
-
- It will be used for:
-
- * Documentation: the generated OpenAPI (and the UI at `/docs`) will
- show it as the response (JSON Schema).
- * Serialization: you could return an arbitrary object and the
- `response_model` would be used to serialize that object into the
- corresponding JSON.
- * Filtering: the JSON sent to the client will only contain the data
- (fields) defined in the `response_model`. If you returned an object
- that contains an attribute `password` but the `response_model` does
- not include that field, the JSON sent to the client would not have
- that `password`.
- * Validation: whatever you return will be serialized with the
- `response_model`, converting any data as necessary to generate the
- corresponding JSON. But if the data in the object returned is not
- valid, that would mean a violation of the contract with the client,
- so it's an error from the API developer. So, FastAPI will raise an
- error and return a 500 error code (Internal Server Error).
-
- Read more about it in the
- [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/).
- """
- ),
- ] = Default(None),
- status_code: Annotated[
- Optional[int],
- Doc(
- """
- The default status code to be used for the response.
-
- You could override the status code by returning a response directly.
-
- Read more about it in the
- [FastAPI docs for Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/).
- """
- ),
- ] = None,
- tags: Annotated[
- Optional[List[Union[str, Enum]]],
- Doc(
- """
- A list of tags to be applied to the *path operation*.
-
- It will be added to the generated OpenAPI (e.g. visible at `/docs`).
-
- Read more about it in the
- [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#tags).
- """
- ),
- ] = None,
- dependencies: Annotated[
- Optional[Sequence[Depends]],
- Doc(
- """
- A list of dependencies (using `Depends()`) to be applied to the
- *path operation*.
-
- Read more about it in the
- [FastAPI docs for Dependencies in path operation decorators](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-path-operation-decorators/).
- """
- ),
- ] = None,
- summary: Annotated[
- Optional[str],
- Doc(
- """
- A summary for the *path operation*.
-
- It will be added to the generated OpenAPI (e.g. visible at `/docs`).
-
- Read more about it in the
- [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
- """
- ),
- ] = None,
- description: Annotated[
- Optional[str],
- Doc(
- """
- A description for the *path operation*.
-
- If not provided, it will be extracted automatically from the docstring
- of the *path operation function*.
-
- It can contain Markdown.
-
- It will be added to the generated OpenAPI (e.g. visible at `/docs`).
-
- Read more about it in the
- [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
- """
- ),
- ] = None,
- response_description: Annotated[
- str,
- Doc(
- """
- The description for the default response.
-
- It will be added to the generated OpenAPI (e.g. visible at `/docs`).
- """
- ),
- ] = "Successful Response",
- responses: Annotated[
- Optional[Dict[Union[int, str], Dict[str, Any]]],
- Doc(
- """
- Additional responses that could be returned by this *path operation*.
-
- It will be added to the generated OpenAPI (e.g. visible at `/docs`).
- """
- ),
- ] = None,
- deprecated: Annotated[
- Optional[bool],
- Doc(
- """
- Mark this *path operation* as deprecated.
-
- It will be added to the generated OpenAPI (e.g. visible at `/docs`).
- """
- ),
- ] = None,
- operation_id: Annotated[
- Optional[str],
- Doc(
- """
- Custom operation ID to be used by this *path operation*.
-
- By default, it is generated automatically.
-
- If you provide a custom operation ID, you need to make sure it is
- unique for the whole API.
-
- You can customize the
- operation ID generation with the parameter
- `generate_unique_id_function` in the `FastAPI` class.
-
- Read more about it in the
- [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
- """
- ),
- ] = None,
- response_model_include: Annotated[
- Optional[IncEx],
- Doc(
- """
- Configuration passed to Pydantic to include only certain fields in the
- response data.
-
- Read more about it in the
- [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
- """
- ),
- ] = None,
- response_model_exclude: Annotated[
- Optional[IncEx],
- Doc(
- """
- Configuration passed to Pydantic to exclude certain fields in the
- response data.
-
- Read more about it in the
- [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
- """
- ),
- ] = None,
- response_model_by_alias: Annotated[
- bool,
- Doc(
- """
- Configuration passed to Pydantic to define if the response model
- should be serialized by alias when an alias is used.
-
- Read more about it in the
- [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
- """
- ),
- ] = True,
- response_model_exclude_unset: Annotated[
- bool,
- Doc(
- """
- Configuration passed to Pydantic to define if the response data
- should have all the fields, including the ones that were not set and
- have their default values. This is different from
- `response_model_exclude_defaults` in that if the fields are set,
- they will be included in the response, even if the value is the same
- as the default.
-
- When `True`, default values are omitted from the response.
-
- Read more about it in the
- [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter).
- """
- ),
- ] = False,
- response_model_exclude_defaults: Annotated[
- bool,
- Doc(
- """
- Configuration passed to Pydantic to define if the response data
- should have all the fields, including the ones that have the same value
- as the default. This is different from `response_model_exclude_unset`
- in that if the fields are set but contain the same default values,
- they will be excluded from the response.
-
- When `True`, default values are omitted from the response.
-
- Read more about it in the
- [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter).
- """
- ),
- ] = False,
- response_model_exclude_none: Annotated[
- bool,
- Doc(
- """
- Configuration passed to Pydantic to define if the response data should
- exclude fields set to `None`.
-
- This is much simpler (less smart) than `response_model_exclude_unset`
- and `response_model_exclude_defaults`. You probably want to use one of
- those two instead of this one, as those allow returning `None` values
- when it makes sense.
-
- Read more about it in the
- [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_exclude_none).
- """
- ),
- ] = False,
- include_in_schema: Annotated[
- bool,
- Doc(
- """
- Include this *path operation* in the generated OpenAPI schema.
-
- This affects the generated OpenAPI (e.g. visible at `/docs`).
-
- Read more about it in the
- [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi).
- """
- ),
- ] = True,
- response_class: Annotated[
- Type[Response],
- Doc(
- """
- Response class to be used for this *path operation*.
-
- This will not be used if you return a response directly.
-
- Read more about it in the
- [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse).
- """
- ),
- ] = Default(JSONResponse),
- name: Annotated[
- Optional[str],
- Doc(
- """
- Name for this *path operation*. Only used internally.
- """
- ),
- ] = None,
- callbacks: Annotated[
- Optional[List[BaseRoute]],
- Doc(
- """
- List of *path operations* that will be used as OpenAPI callbacks.
-
- This is only for OpenAPI documentation, the callbacks won't be used
- directly.
-
- It will be added to the generated OpenAPI (e.g. visible at `/docs`).
-
- Read more about it in the
- [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/).
- """
- ),
- ] = None,
- openapi_extra: Annotated[
- Optional[Dict[str, Any]],
- Doc(
- """
- Extra metadata to be included in the OpenAPI schema for this *path
- operation*.
-
- Read more about it in the
- [FastAPI docs for Path Operation Advanced Configuration](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#custom-openapi-path-operation-schema).
- """
- ),
- ] = None,
- generate_unique_id_function: Annotated[
- Callable[[routing.APIRoute], str],
- Doc(
- """
- Customize the function used to generate unique IDs for the *path
- operations* shown in the generated OpenAPI.
-
- This is particularly useful when automatically generating clients or
- SDKs for your API.
-
- Read more about it in the
- [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
- """
- ),
- ] = Default(generate_unique_id),
- ) -> Callable[[DecoratedCallable], DecoratedCallable]:
- """
- Add a *path operation* using an HTTP PATCH operation.
-
- ## Example
-
- ```python
- from fastapi import FastAPI
- from pydantic import BaseModel
-
- class Item(BaseModel):
- name: str
- description: str | None = None
-
- app = FastAPI()
-
- @app.patch("/items/")
- def update_item(item: Item):
- return {"message": "Item updated in place"}
- ```
- """
- return self.router.patch(
- path,
- response_model=response_model,
- status_code=status_code,
- tags=tags,
- dependencies=dependencies,
- summary=summary,
- description=description,
- response_description=response_description,
- responses=responses,
- deprecated=deprecated,
- operation_id=operation_id,
- response_model_include=response_model_include,
- response_model_exclude=response_model_exclude,
- response_model_by_alias=response_model_by_alias,
- response_model_exclude_unset=response_model_exclude_unset,
- response_model_exclude_defaults=response_model_exclude_defaults,
- response_model_exclude_none=response_model_exclude_none,
- include_in_schema=include_in_schema,
- response_class=response_class,
- name=name,
- callbacks=callbacks,
- openapi_extra=openapi_extra,
- generate_unique_id_function=generate_unique_id_function,
- )
-
- def trace(
- self,
- path: Annotated[
- str,
- Doc(
- """
- The URL path to be used for this *path operation*.
-
- For example, in `http://example.com/items`, the path is `/items`.
- """
- ),
- ],
- *,
- response_model: Annotated[
- Any,
- Doc(
- """
- The type to use for the response.
-
- It could be any valid Pydantic *field* type. So, it doesn't have to
- be a Pydantic model, it could be other things, like a `list`, `dict`,
- etc.
-
- It will be used for:
-
- * Documentation: the generated OpenAPI (and the UI at `/docs`) will
- show it as the response (JSON Schema).
- * Serialization: you could return an arbitrary object and the
- `response_model` would be used to serialize that object into the
- corresponding JSON.
- * Filtering: the JSON sent to the client will only contain the data
- (fields) defined in the `response_model`. If you returned an object
- that contains an attribute `password` but the `response_model` does
- not include that field, the JSON sent to the client would not have
- that `password`.
- * Validation: whatever you return will be serialized with the
- `response_model`, converting any data as necessary to generate the
- corresponding JSON. But if the data in the object returned is not
- valid, that would mean a violation of the contract with the client,
- so it's an error from the API developer. So, FastAPI will raise an
- error and return a 500 error code (Internal Server Error).
-
- Read more about it in the
- [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/).
- """
- ),
- ] = Default(None),
- status_code: Annotated[
- Optional[int],
- Doc(
- """
- The default status code to be used for the response.
-
- You could override the status code by returning a response directly.
-
- Read more about it in the
- [FastAPI docs for Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/).
- """
- ),
- ] = None,
- tags: Annotated[
- Optional[List[Union[str, Enum]]],
- Doc(
- """
- A list of tags to be applied to the *path operation*.
-
- It will be added to the generated OpenAPI (e.g. visible at `/docs`).
-
- Read more about it in the
- [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#tags).
- """
- ),
- ] = None,
- dependencies: Annotated[
- Optional[Sequence[Depends]],
- Doc(
- """
- A list of dependencies (using `Depends()`) to be applied to the
- *path operation*.
-
- Read more about it in the
- [FastAPI docs for Dependencies in path operation decorators](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-path-operation-decorators/).
- """
- ),
- ] = None,
- summary: Annotated[
- Optional[str],
- Doc(
- """
- A summary for the *path operation*.
-
- It will be added to the generated OpenAPI (e.g. visible at `/docs`).
-
- Read more about it in the
- [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
- """
- ),
- ] = None,
- description: Annotated[
- Optional[str],
- Doc(
- """
- A description for the *path operation*.
-
- If not provided, it will be extracted automatically from the docstring
- of the *path operation function*.
-
- It can contain Markdown.
-
- It will be added to the generated OpenAPI (e.g. visible at `/docs`).
-
- Read more about it in the
- [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
- """
- ),
- ] = None,
- response_description: Annotated[
- str,
- Doc(
- """
- The description for the default response.
-
- It will be added to the generated OpenAPI (e.g. visible at `/docs`).
- """
- ),
- ] = "Successful Response",
- responses: Annotated[
- Optional[Dict[Union[int, str], Dict[str, Any]]],
- Doc(
- """
- Additional responses that could be returned by this *path operation*.
-
- It will be added to the generated OpenAPI (e.g. visible at `/docs`).
- """
- ),
- ] = None,
- deprecated: Annotated[
- Optional[bool],
- Doc(
- """
- Mark this *path operation* as deprecated.
-
- It will be added to the generated OpenAPI (e.g. visible at `/docs`).
- """
- ),
- ] = None,
- operation_id: Annotated[
- Optional[str],
- Doc(
- """
- Custom operation ID to be used by this *path operation*.
-
- By default, it is generated automatically.
-
- If you provide a custom operation ID, you need to make sure it is
- unique for the whole API.
-
- You can customize the
- operation ID generation with the parameter
- `generate_unique_id_function` in the `FastAPI` class.
-
- Read more about it in the
- [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
- """
- ),
- ] = None,
- response_model_include: Annotated[
- Optional[IncEx],
- Doc(
- """
- Configuration passed to Pydantic to include only certain fields in the
- response data.
-
- Read more about it in the
- [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
- """
- ),
- ] = None,
- response_model_exclude: Annotated[
- Optional[IncEx],
- Doc(
- """
- Configuration passed to Pydantic to exclude certain fields in the
- response data.
-
- Read more about it in the
- [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
- """
- ),
- ] = None,
- response_model_by_alias: Annotated[
- bool,
- Doc(
- """
- Configuration passed to Pydantic to define if the response model
- should be serialized by alias when an alias is used.
-
- Read more about it in the
- [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
- """
- ),
- ] = True,
- response_model_exclude_unset: Annotated[
- bool,
- Doc(
- """
- Configuration passed to Pydantic to define if the response data
- should have all the fields, including the ones that were not set and
- have their default values. This is different from
- `response_model_exclude_defaults` in that if the fields are set,
- they will be included in the response, even if the value is the same
- as the default.
-
- When `True`, default values are omitted from the response.
-
- Read more about it in the
- [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter).
- """
- ),
- ] = False,
- response_model_exclude_defaults: Annotated[
- bool,
- Doc(
- """
- Configuration passed to Pydantic to define if the response data
- should have all the fields, including the ones that have the same value
- as the default. This is different from `response_model_exclude_unset`
- in that if the fields are set but contain the same default values,
- they will be excluded from the response.
-
- When `True`, default values are omitted from the response.
-
- Read more about it in the
- [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter).
- """
- ),
- ] = False,
- response_model_exclude_none: Annotated[
- bool,
- Doc(
- """
- Configuration passed to Pydantic to define if the response data should
- exclude fields set to `None`.
-
- This is much simpler (less smart) than `response_model_exclude_unset`
- and `response_model_exclude_defaults`. You probably want to use one of
- those two instead of this one, as those allow returning `None` values
- when it makes sense.
-
- Read more about it in the
- [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_exclude_none).
- """
- ),
- ] = False,
- include_in_schema: Annotated[
- bool,
- Doc(
- """
- Include this *path operation* in the generated OpenAPI schema.
-
- This affects the generated OpenAPI (e.g. visible at `/docs`).
-
- Read more about it in the
- [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi).
- """
- ),
- ] = True,
- response_class: Annotated[
- Type[Response],
- Doc(
- """
- Response class to be used for this *path operation*.
-
- This will not be used if you return a response directly.
-
- Read more about it in the
- [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse).
- """
- ),
- ] = Default(JSONResponse),
- name: Annotated[
- Optional[str],
- Doc(
- """
- Name for this *path operation*. Only used internally.
- """
- ),
- ] = None,
- callbacks: Annotated[
- Optional[List[BaseRoute]],
- Doc(
- """
- List of *path operations* that will be used as OpenAPI callbacks.
-
- This is only for OpenAPI documentation, the callbacks won't be used
- directly.
-
- It will be added to the generated OpenAPI (e.g. visible at `/docs`).
-
- Read more about it in the
- [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/).
- """
- ),
- ] = None,
- openapi_extra: Annotated[
- Optional[Dict[str, Any]],
- Doc(
- """
- Extra metadata to be included in the OpenAPI schema for this *path
- operation*.
-
- Read more about it in the
- [FastAPI docs for Path Operation Advanced Configuration](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#custom-openapi-path-operation-schema).
- """
- ),
- ] = None,
- generate_unique_id_function: Annotated[
- Callable[[routing.APIRoute], str],
- Doc(
- """
- Customize the function used to generate unique IDs for the *path
- operations* shown in the generated OpenAPI.
-
- This is particularly useful when automatically generating clients or
- SDKs for your API.
-
- Read more about it in the
- [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
- """
- ),
- ] = Default(generate_unique_id),
- ) -> Callable[[DecoratedCallable], DecoratedCallable]:
- """
- Add a *path operation* using an HTTP TRACE operation.
-
- ## Example
-
- ```python
- from fastapi import FastAPI
-
- app = FastAPI()
-
- @app.put("/items/{item_id}")
- def trace_item(item_id: str):
- return None
- ```
- """
- return self.router.trace(
- path,
- response_model=response_model,
- status_code=status_code,
- tags=tags,
- dependencies=dependencies,
- summary=summary,
- description=description,
- response_description=response_description,
- responses=responses,
- deprecated=deprecated,
- operation_id=operation_id,
- response_model_include=response_model_include,
- response_model_exclude=response_model_exclude,
- response_model_by_alias=response_model_by_alias,
- response_model_exclude_unset=response_model_exclude_unset,
- response_model_exclude_defaults=response_model_exclude_defaults,
- response_model_exclude_none=response_model_exclude_none,
- include_in_schema=include_in_schema,
- response_class=response_class,
- name=name,
- callbacks=callbacks,
- openapi_extra=openapi_extra,
- generate_unique_id_function=generate_unique_id_function,
- )
-
- def websocket_route(
- self, path: str, name: Union[str, None] = None
- ) -> Callable[[DecoratedCallable], DecoratedCallable]:
- def decorator(func: DecoratedCallable) -> DecoratedCallable:
- self.router.add_websocket_route(path, func, name=name)
- return func
-
- return decorator
-
- @deprecated(
- """
- on_event is deprecated, use lifespan event handlers instead.
-
- Read more about it in the
- [FastAPI docs for Lifespan Events](https://fastapi.tiangolo.com/advanced/events/).
- """
- )
- def on_event(
- self,
- event_type: Annotated[
- str,
- Doc(
- """
- The type of event. `startup` or `shutdown`.
- """
- ),
- ],
- ) -> Callable[[DecoratedCallable], DecoratedCallable]:
- """
- Add an event handler for the application.
-
- `on_event` is deprecated, use `lifespan` event handlers instead.
-
- Read more about it in the
- [FastAPI docs for Lifespan Events](https://fastapi.tiangolo.com/advanced/events/#alternative-events-deprecated).
- """
- return self.router.on_event(event_type)
-
- def middleware(
- self,
- middleware_type: Annotated[
- str,
- Doc(
- """
- The type of middleware. Currently only supports `http`.
- """
- ),
- ],
- ) -> Callable[[DecoratedCallable], DecoratedCallable]:
- """
- Add a middleware to the application.
-
- Read more about it in the
- [FastAPI docs for Middleware](https://fastapi.tiangolo.com/tutorial/middleware/).
-
- ## Example
-
- ```python
- import time
-
- from fastapi import FastAPI, Request
-
- app = FastAPI()
-
-
- @app.middleware("http")
- async def add_process_time_header(request: Request, call_next):
- start_time = time.time()
- response = await call_next(request)
- process_time = time.time() - start_time
- response.headers["X-Process-Time"] = str(process_time)
- return response
- ```
- """
-
- def decorator(func: DecoratedCallable) -> DecoratedCallable:
- self.add_middleware(BaseHTTPMiddleware, dispatch=func)
- return func
-
- return decorator
-
- def exception_handler(
- self,
- exc_class_or_status_code: Annotated[
- Union[int, Type[Exception]],
- Doc(
- """
- The Exception class this would handle, or a status code.
- """
- ),
- ],
- ) -> Callable[[DecoratedCallable], DecoratedCallable]:
- """
- Add an exception handler to the app.
-
- Read more about it in the
- [FastAPI docs for Handling Errors](https://fastapi.tiangolo.com/tutorial/handling-errors/).
-
- ## Example
-
- ```python
- from fastapi import FastAPI, Request
- from fastapi.responses import JSONResponse
-
-
- class UnicornException(Exception):
- def __init__(self, name: str):
- self.name = name
-
-
- app = FastAPI()
-
-
- @app.exception_handler(UnicornException)
- async def unicorn_exception_handler(request: Request, exc: UnicornException):
- return JSONResponse(
- status_code=418,
- content={"message": f"Oops! {exc.name} did something. There goes a rainbow..."},
- )
- ```
- """
-
- def decorator(func: DecoratedCallable) -> DecoratedCallable:
- self.add_exception_handler(exc_class_or_status_code, func)
- return func
-
- return decorator
diff --git a/backend/pig/Lib/python3.12/site-packages/fastapi/background.py b/backend/pig/Lib/python3.12/site-packages/fastapi/background.py
deleted file mode 100644
index 203578a..0000000
--- a/backend/pig/Lib/python3.12/site-packages/fastapi/background.py
+++ /dev/null
@@ -1,59 +0,0 @@
-from typing import Any, Callable
-
-from starlette.background import BackgroundTasks as StarletteBackgroundTasks
-from typing_extensions import Annotated, Doc, ParamSpec
-
-P = ParamSpec("P")
-
-
-class BackgroundTasks(StarletteBackgroundTasks):
- """
- A collection of background tasks that will be called after a response has been
- sent to the client.
-
- Read more about it in the
- [FastAPI docs for Background Tasks](https://fastapi.tiangolo.com/tutorial/background-tasks/).
-
- ## Example
-
- ```python
- from fastapi import BackgroundTasks, FastAPI
-
- app = FastAPI()
-
-
- def write_notification(email: str, message=""):
- with open("log.txt", mode="w") as email_file:
- content = f"notification for {email}: {message}"
- email_file.write(content)
-
-
- @app.post("/send-notification/{email}")
- async def send_notification(email: str, background_tasks: BackgroundTasks):
- background_tasks.add_task(write_notification, email, message="some notification")
- return {"message": "Notification sent in the background"}
- ```
- """
-
- def add_task(
- self,
- func: Annotated[
- Callable[P, Any],
- Doc(
- """
- The function to call after the response is sent.
-
- It can be a regular `def` function or an `async def` function.
- """
- ),
- ],
- *args: P.args,
- **kwargs: P.kwargs,
- ) -> None:
- """
- Add a function to be called in the background after the response is sent.
-
- Read more about it in the
- [FastAPI docs for Background Tasks](https://fastapi.tiangolo.com/tutorial/background-tasks/).
- """
- return super().add_task(func, *args, **kwargs)
diff --git a/backend/pig/Lib/python3.12/site-packages/fastapi/cli.py b/backend/pig/Lib/python3.12/site-packages/fastapi/cli.py
deleted file mode 100644
index 8d3301e..0000000
--- a/backend/pig/Lib/python3.12/site-packages/fastapi/cli.py
+++ /dev/null
@@ -1,13 +0,0 @@
-try:
- from fastapi_cli.cli import main as cli_main
-
-except ImportError: # pragma: no cover
- cli_main = None # type: ignore
-
-
-def main() -> None:
- if not cli_main: # type: ignore[truthy-function]
- message = 'To use the fastapi command, please install "fastapi[standard]":\n\n\tpip install "fastapi[standard]"\n'
- print(message)
- raise RuntimeError(message) # noqa: B904
- cli_main()
diff --git a/backend/pig/Lib/python3.12/site-packages/fastapi/concurrency.py b/backend/pig/Lib/python3.12/site-packages/fastapi/concurrency.py
deleted file mode 100644
index 894bd3e..0000000
--- a/backend/pig/Lib/python3.12/site-packages/fastapi/concurrency.py
+++ /dev/null
@@ -1,39 +0,0 @@
-from contextlib import asynccontextmanager as asynccontextmanager
-from typing import AsyncGenerator, ContextManager, TypeVar
-
-import anyio
-from anyio import CapacityLimiter
-from starlette.concurrency import iterate_in_threadpool as iterate_in_threadpool # noqa
-from starlette.concurrency import run_in_threadpool as run_in_threadpool # noqa
-from starlette.concurrency import ( # noqa
- run_until_first_complete as run_until_first_complete,
-)
-
-_T = TypeVar("_T")
-
-
-@asynccontextmanager
-async def contextmanager_in_threadpool(
- cm: ContextManager[_T],
-) -> AsyncGenerator[_T, None]:
- # blocking __exit__ from running waiting on a free thread
- # can create race conditions/deadlocks if the context manager itself
- # has its own internal pool (e.g. a database connection pool)
- # to avoid this we let __exit__ run without a capacity limit
- # since we're creating a new limiter for each call, any non-zero limit
- # works (1 is arbitrary)
- exit_limiter = CapacityLimiter(1)
- try:
- yield await run_in_threadpool(cm.__enter__)
- except Exception as e:
- ok = bool(
- await anyio.to_thread.run_sync(
- cm.__exit__, type(e), e, None, limiter=exit_limiter
- )
- )
- if not ok:
- raise e
- else:
- await anyio.to_thread.run_sync(
- cm.__exit__, None, None, None, limiter=exit_limiter
- )
diff --git a/backend/pig/Lib/python3.12/site-packages/fastapi/datastructures.py b/backend/pig/Lib/python3.12/site-packages/fastapi/datastructures.py
deleted file mode 100644
index cf8406b..0000000
--- a/backend/pig/Lib/python3.12/site-packages/fastapi/datastructures.py
+++ /dev/null
@@ -1,204 +0,0 @@
-from typing import (
- Any,
- BinaryIO,
- Callable,
- Dict,
- Iterable,
- Optional,
- Type,
- TypeVar,
- cast,
-)
-
-from fastapi._compat import (
- PYDANTIC_V2,
- CoreSchema,
- GetJsonSchemaHandler,
- JsonSchemaValue,
- with_info_plain_validator_function,
-)
-from starlette.datastructures import URL as URL # noqa: F401
-from starlette.datastructures import Address as Address # noqa: F401
-from starlette.datastructures import FormData as FormData # noqa: F401
-from starlette.datastructures import Headers as Headers # noqa: F401
-from starlette.datastructures import QueryParams as QueryParams # noqa: F401
-from starlette.datastructures import State as State # noqa: F401
-from starlette.datastructures import UploadFile as StarletteUploadFile
-from typing_extensions import Annotated, Doc
-
-
-class UploadFile(StarletteUploadFile):
- """
- A file uploaded in a request.
-
- Define it as a *path operation function* (or dependency) parameter.
-
- If you are using a regular `def` function, you can use the `upload_file.file`
- attribute to access the raw standard Python file (blocking, not async), useful and
- needed for non-async code.
-
- Read more about it in the
- [FastAPI docs for Request Files](https://fastapi.tiangolo.com/tutorial/request-files/).
-
- ## Example
-
- ```python
- from typing import Annotated
-
- from fastapi import FastAPI, File, UploadFile
-
- app = FastAPI()
-
-
- @app.post("/files/")
- async def create_file(file: Annotated[bytes, File()]):
- return {"file_size": len(file)}
-
-
- @app.post("/uploadfile/")
- async def create_upload_file(file: UploadFile):
- return {"filename": file.filename}
- ```
- """
-
- file: Annotated[
- BinaryIO,
- Doc("The standard Python file object (non-async)."),
- ]
- filename: Annotated[Optional[str], Doc("The original file name.")]
- size: Annotated[Optional[int], Doc("The size of the file in bytes.")]
- headers: Annotated[Headers, Doc("The headers of the request.")]
- content_type: Annotated[
- Optional[str], Doc("The content type of the request, from the headers.")
- ]
-
- async def write(
- self,
- data: Annotated[
- bytes,
- Doc(
- """
- The bytes to write to the file.
- """
- ),
- ],
- ) -> None:
- """
- Write some bytes to the file.
-
- You normally wouldn't use this from a file you read in a request.
-
- To be awaitable, compatible with async, this is run in threadpool.
- """
- return await super().write(data)
-
- async def read(
- self,
- size: Annotated[
- int,
- Doc(
- """
- The number of bytes to read from the file.
- """
- ),
- ] = -1,
- ) -> bytes:
- """
- Read some bytes from the file.
-
- To be awaitable, compatible with async, this is run in threadpool.
- """
- return await super().read(size)
-
- async def seek(
- self,
- offset: Annotated[
- int,
- Doc(
- """
- The position in bytes to seek to in the file.
- """
- ),
- ],
- ) -> None:
- """
- Move to a position in the file.
-
- Any next read or write will be done from that position.
-
- To be awaitable, compatible with async, this is run in threadpool.
- """
- return await super().seek(offset)
-
- async def close(self) -> None:
- """
- Close the file.
-
- To be awaitable, compatible with async, this is run in threadpool.
- """
- return await super().close()
-
- @classmethod
- def __get_validators__(cls: Type["UploadFile"]) -> Iterable[Callable[..., Any]]:
- yield cls.validate
-
- @classmethod
- def validate(cls: Type["UploadFile"], v: Any) -> Any:
- if not isinstance(v, StarletteUploadFile):
- raise ValueError(f"Expected UploadFile, received: {type(v)}")
- return v
-
- @classmethod
- def _validate(cls, __input_value: Any, _: Any) -> "UploadFile":
- if not isinstance(__input_value, StarletteUploadFile):
- raise ValueError(f"Expected UploadFile, received: {type(__input_value)}")
- return cast(UploadFile, __input_value)
-
- if not PYDANTIC_V2:
-
- @classmethod
- def __modify_schema__(cls, field_schema: Dict[str, Any]) -> None:
- field_schema.update({"type": "string", "format": "binary"})
-
- @classmethod
- def __get_pydantic_json_schema__(
- cls, core_schema: CoreSchema, handler: GetJsonSchemaHandler
- ) -> JsonSchemaValue:
- return {"type": "string", "format": "binary"}
-
- @classmethod
- def __get_pydantic_core_schema__(
- cls, source: Type[Any], handler: Callable[[Any], CoreSchema]
- ) -> CoreSchema:
- return with_info_plain_validator_function(cls._validate)
-
-
-class DefaultPlaceholder:
- """
- You shouldn't use this class directly.
-
- It's used internally to recognize when a default value has been overwritten, even
- if the overridden default value was truthy.
- """
-
- def __init__(self, value: Any):
- self.value = value
-
- def __bool__(self) -> bool:
- return bool(self.value)
-
- def __eq__(self, o: object) -> bool:
- return isinstance(o, DefaultPlaceholder) and o.value == self.value
-
-
-DefaultType = TypeVar("DefaultType")
-
-
-def Default(value: DefaultType) -> DefaultType:
- """
- You shouldn't use this function directly.
-
- It's used internally to recognize when a default value has been overwritten, even
- if the overridden default value was truthy.
- """
- return DefaultPlaceholder(value) # type: ignore
diff --git a/backend/pig/Lib/python3.12/site-packages/fastapi/dependencies/__init__.py b/backend/pig/Lib/python3.12/site-packages/fastapi/dependencies/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/backend/pig/Lib/python3.12/site-packages/fastapi/dependencies/__pycache__/__init__.cpython-312.pyc b/backend/pig/Lib/python3.12/site-packages/fastapi/dependencies/__pycache__/__init__.cpython-312.pyc
deleted file mode 100644
index 92d23fe..0000000
Binary files a/backend/pig/Lib/python3.12/site-packages/fastapi/dependencies/__pycache__/__init__.cpython-312.pyc and /dev/null differ
diff --git a/backend/pig/Lib/python3.12/site-packages/fastapi/dependencies/__pycache__/models.cpython-312.pyc b/backend/pig/Lib/python3.12/site-packages/fastapi/dependencies/__pycache__/models.cpython-312.pyc
deleted file mode 100644
index 1d2312f..0000000
Binary files a/backend/pig/Lib/python3.12/site-packages/fastapi/dependencies/__pycache__/models.cpython-312.pyc and /dev/null differ
diff --git a/backend/pig/Lib/python3.12/site-packages/fastapi/dependencies/__pycache__/utils.cpython-312.pyc b/backend/pig/Lib/python3.12/site-packages/fastapi/dependencies/__pycache__/utils.cpython-312.pyc
deleted file mode 100644
index c14bc4c..0000000
Binary files a/backend/pig/Lib/python3.12/site-packages/fastapi/dependencies/__pycache__/utils.cpython-312.pyc and /dev/null differ
diff --git a/backend/pig/Lib/python3.12/site-packages/fastapi/dependencies/models.py b/backend/pig/Lib/python3.12/site-packages/fastapi/dependencies/models.py
deleted file mode 100644
index 418c117..0000000
--- a/backend/pig/Lib/python3.12/site-packages/fastapi/dependencies/models.py
+++ /dev/null
@@ -1,37 +0,0 @@
-from dataclasses import dataclass, field
-from typing import Any, Callable, List, Optional, Sequence, Tuple
-
-from fastapi._compat import ModelField
-from fastapi.security.base import SecurityBase
-
-
-@dataclass
-class SecurityRequirement:
- security_scheme: SecurityBase
- scopes: Optional[Sequence[str]] = None
-
-
-@dataclass
-class Dependant:
- path_params: List[ModelField] = field(default_factory=list)
- query_params: List[ModelField] = field(default_factory=list)
- header_params: List[ModelField] = field(default_factory=list)
- cookie_params: List[ModelField] = field(default_factory=list)
- body_params: List[ModelField] = field(default_factory=list)
- dependencies: List["Dependant"] = field(default_factory=list)
- security_requirements: List[SecurityRequirement] = field(default_factory=list)
- name: Optional[str] = None
- call: Optional[Callable[..., Any]] = None
- request_param_name: Optional[str] = None
- websocket_param_name: Optional[str] = None
- http_connection_param_name: Optional[str] = None
- response_param_name: Optional[str] = None
- background_tasks_param_name: Optional[str] = None
- security_scopes_param_name: Optional[str] = None
- security_scopes: Optional[List[str]] = None
- use_cache: bool = True
- path: Optional[str] = None
- cache_key: Tuple[Optional[Callable[..., Any]], Tuple[str, ...]] = field(init=False)
-
- def __post_init__(self) -> None:
- self.cache_key = (self.call, tuple(sorted(set(self.security_scopes or []))))
diff --git a/backend/pig/Lib/python3.12/site-packages/fastapi/dependencies/utils.py b/backend/pig/Lib/python3.12/site-packages/fastapi/dependencies/utils.py
deleted file mode 100644
index e2866b4..0000000
--- a/backend/pig/Lib/python3.12/site-packages/fastapi/dependencies/utils.py
+++ /dev/null
@@ -1,972 +0,0 @@
-import inspect
-from contextlib import AsyncExitStack, contextmanager
-from copy import copy, deepcopy
-from dataclasses import dataclass
-from typing import (
- Any,
- Callable,
- Coroutine,
- Dict,
- ForwardRef,
- List,
- Mapping,
- Optional,
- Sequence,
- Tuple,
- Type,
- Union,
- cast,
-)
-
-import anyio
-from fastapi import params
-from fastapi._compat import (
- PYDANTIC_V2,
- ErrorWrapper,
- ModelField,
- RequiredParam,
- Undefined,
- _regenerate_error_with_loc,
- copy_field_info,
- create_body_model,
- evaluate_forwardref,
- field_annotation_is_scalar,
- get_annotation_from_field_info,
- get_cached_model_fields,
- get_missing_field_error,
- is_bytes_field,
- is_bytes_sequence_field,
- is_scalar_field,
- is_scalar_sequence_field,
- is_sequence_field,
- is_uploadfile_or_nonable_uploadfile_annotation,
- is_uploadfile_sequence_annotation,
- lenient_issubclass,
- sequence_types,
- serialize_sequence_value,
- value_is_sequence,
-)
-from fastapi.background import BackgroundTasks
-from fastapi.concurrency import (
- asynccontextmanager,
- contextmanager_in_threadpool,
-)
-from fastapi.dependencies.models import Dependant, SecurityRequirement
-from fastapi.logger import logger
-from fastapi.security.base import SecurityBase
-from fastapi.security.oauth2 import OAuth2, SecurityScopes
-from fastapi.security.open_id_connect_url import OpenIdConnect
-from fastapi.utils import create_model_field, get_path_param_names
-from pydantic import BaseModel
-from pydantic.fields import FieldInfo
-from starlette.background import BackgroundTasks as StarletteBackgroundTasks
-from starlette.concurrency import run_in_threadpool
-from starlette.datastructures import (
- FormData,
- Headers,
- ImmutableMultiDict,
- QueryParams,
- UploadFile,
-)
-from starlette.requests import HTTPConnection, Request
-from starlette.responses import Response
-from starlette.websockets import WebSocket
-from typing_extensions import Annotated, get_args, get_origin
-
-multipart_not_installed_error = (
- 'Form data requires "python-multipart" to be installed. \n'
- 'You can install "python-multipart" with: \n\n'
- "pip install python-multipart\n"
-)
-multipart_incorrect_install_error = (
- 'Form data requires "python-multipart" to be installed. '
- 'It seems you installed "multipart" instead. \n'
- 'You can remove "multipart" with: \n\n'
- "pip uninstall multipart\n\n"
- 'And then install "python-multipart" with: \n\n'
- "pip install python-multipart\n"
-)
-
-
-def ensure_multipart_is_installed() -> None:
- try:
- from python_multipart import __version__
-
- # Import an attribute that can be mocked/deleted in testing
- assert __version__ > "0.0.12"
- except (ImportError, AssertionError):
- try:
- # __version__ is available in both multiparts, and can be mocked
- from multipart import __version__ # type: ignore[no-redef,import-untyped]
-
- assert __version__
- try:
- # parse_options_header is only available in the right multipart
- from multipart.multipart import ( # type: ignore[import-untyped]
- parse_options_header,
- )
-
- assert parse_options_header
- except ImportError:
- logger.error(multipart_incorrect_install_error)
- raise RuntimeError(multipart_incorrect_install_error) from None
- except ImportError:
- logger.error(multipart_not_installed_error)
- raise RuntimeError(multipart_not_installed_error) from None
-
-
-def get_param_sub_dependant(
- *,
- param_name: str,
- depends: params.Depends,
- path: str,
- security_scopes: Optional[List[str]] = None,
-) -> Dependant:
- assert depends.dependency
- return get_sub_dependant(
- depends=depends,
- dependency=depends.dependency,
- path=path,
- name=param_name,
- security_scopes=security_scopes,
- )
-
-
-def get_parameterless_sub_dependant(*, depends: params.Depends, path: str) -> Dependant:
- assert callable(
- depends.dependency
- ), "A parameter-less dependency must have a callable dependency"
- return get_sub_dependant(depends=depends, dependency=depends.dependency, path=path)
-
-
-def get_sub_dependant(
- *,
- depends: params.Depends,
- dependency: Callable[..., Any],
- path: str,
- name: Optional[str] = None,
- security_scopes: Optional[List[str]] = None,
-) -> Dependant:
- security_requirement = None
- security_scopes = security_scopes or []
- if isinstance(depends, params.Security):
- dependency_scopes = depends.scopes
- security_scopes.extend(dependency_scopes)
- if isinstance(dependency, SecurityBase):
- use_scopes: List[str] = []
- if isinstance(dependency, (OAuth2, OpenIdConnect)):
- use_scopes = security_scopes
- security_requirement = SecurityRequirement(
- security_scheme=dependency, scopes=use_scopes
- )
- sub_dependant = get_dependant(
- path=path,
- call=dependency,
- name=name,
- security_scopes=security_scopes,
- use_cache=depends.use_cache,
- )
- if security_requirement:
- sub_dependant.security_requirements.append(security_requirement)
- return sub_dependant
-
-
-CacheKey = Tuple[Optional[Callable[..., Any]], Tuple[str, ...]]
-
-
-def get_flat_dependant(
- dependant: Dependant,
- *,
- skip_repeats: bool = False,
- visited: Optional[List[CacheKey]] = None,
-) -> Dependant:
- if visited is None:
- visited = []
- visited.append(dependant.cache_key)
-
- flat_dependant = Dependant(
- path_params=dependant.path_params.copy(),
- query_params=dependant.query_params.copy(),
- header_params=dependant.header_params.copy(),
- cookie_params=dependant.cookie_params.copy(),
- body_params=dependant.body_params.copy(),
- security_requirements=dependant.security_requirements.copy(),
- use_cache=dependant.use_cache,
- path=dependant.path,
- )
- for sub_dependant in dependant.dependencies:
- if skip_repeats and sub_dependant.cache_key in visited:
- continue
- flat_sub = get_flat_dependant(
- sub_dependant, skip_repeats=skip_repeats, visited=visited
- )
- flat_dependant.path_params.extend(flat_sub.path_params)
- flat_dependant.query_params.extend(flat_sub.query_params)
- flat_dependant.header_params.extend(flat_sub.header_params)
- flat_dependant.cookie_params.extend(flat_sub.cookie_params)
- flat_dependant.body_params.extend(flat_sub.body_params)
- flat_dependant.security_requirements.extend(flat_sub.security_requirements)
- return flat_dependant
-
-
-def _get_flat_fields_from_params(fields: List[ModelField]) -> List[ModelField]:
- if not fields:
- return fields
- first_field = fields[0]
- if len(fields) == 1 and lenient_issubclass(first_field.type_, BaseModel):
- fields_to_extract = get_cached_model_fields(first_field.type_)
- return fields_to_extract
- return fields
-
-
-def get_flat_params(dependant: Dependant) -> List[ModelField]:
- flat_dependant = get_flat_dependant(dependant, skip_repeats=True)
- path_params = _get_flat_fields_from_params(flat_dependant.path_params)
- query_params = _get_flat_fields_from_params(flat_dependant.query_params)
- header_params = _get_flat_fields_from_params(flat_dependant.header_params)
- cookie_params = _get_flat_fields_from_params(flat_dependant.cookie_params)
- return path_params + query_params + header_params + cookie_params
-
-
-def get_typed_signature(call: Callable[..., Any]) -> inspect.Signature:
- signature = inspect.signature(call)
- globalns = getattr(call, "__globals__", {})
- typed_params = [
- inspect.Parameter(
- name=param.name,
- kind=param.kind,
- default=param.default,
- annotation=get_typed_annotation(param.annotation, globalns),
- )
- for param in signature.parameters.values()
- ]
- typed_signature = inspect.Signature(typed_params)
- return typed_signature
-
-
-def get_typed_annotation(annotation: Any, globalns: Dict[str, Any]) -> Any:
- if isinstance(annotation, str):
- annotation = ForwardRef(annotation)
- annotation = evaluate_forwardref(annotation, globalns, globalns)
- return annotation
-
-
-def get_typed_return_annotation(call: Callable[..., Any]) -> Any:
- signature = inspect.signature(call)
- annotation = signature.return_annotation
-
- if annotation is inspect.Signature.empty:
- return None
-
- globalns = getattr(call, "__globals__", {})
- return get_typed_annotation(annotation, globalns)
-
-
-def get_dependant(
- *,
- path: str,
- call: Callable[..., Any],
- name: Optional[str] = None,
- security_scopes: Optional[List[str]] = None,
- use_cache: bool = True,
-) -> Dependant:
- path_param_names = get_path_param_names(path)
- endpoint_signature = get_typed_signature(call)
- signature_params = endpoint_signature.parameters
- dependant = Dependant(
- call=call,
- name=name,
- path=path,
- security_scopes=security_scopes,
- use_cache=use_cache,
- )
- for param_name, param in signature_params.items():
- is_path_param = param_name in path_param_names
- param_details = analyze_param(
- param_name=param_name,
- annotation=param.annotation,
- value=param.default,
- is_path_param=is_path_param,
- )
- if param_details.depends is not None:
- sub_dependant = get_param_sub_dependant(
- param_name=param_name,
- depends=param_details.depends,
- path=path,
- security_scopes=security_scopes,
- )
- dependant.dependencies.append(sub_dependant)
- continue
- if add_non_field_param_to_dependency(
- param_name=param_name,
- type_annotation=param_details.type_annotation,
- dependant=dependant,
- ):
- assert (
- param_details.field is None
- ), f"Cannot specify multiple FastAPI annotations for {param_name!r}"
- continue
- assert param_details.field is not None
- if isinstance(param_details.field.field_info, params.Body):
- dependant.body_params.append(param_details.field)
- else:
- add_param_to_fields(field=param_details.field, dependant=dependant)
- return dependant
-
-
-def add_non_field_param_to_dependency(
- *, param_name: str, type_annotation: Any, dependant: Dependant
-) -> Optional[bool]:
- if lenient_issubclass(type_annotation, Request):
- dependant.request_param_name = param_name
- return True
- elif lenient_issubclass(type_annotation, WebSocket):
- dependant.websocket_param_name = param_name
- return True
- elif lenient_issubclass(type_annotation, HTTPConnection):
- dependant.http_connection_param_name = param_name
- return True
- elif lenient_issubclass(type_annotation, Response):
- dependant.response_param_name = param_name
- return True
- elif lenient_issubclass(type_annotation, StarletteBackgroundTasks):
- dependant.background_tasks_param_name = param_name
- return True
- elif lenient_issubclass(type_annotation, SecurityScopes):
- dependant.security_scopes_param_name = param_name
- return True
- return None
-
-
-@dataclass
-class ParamDetails:
- type_annotation: Any
- depends: Optional[params.Depends]
- field: Optional[ModelField]
-
-
-def analyze_param(
- *,
- param_name: str,
- annotation: Any,
- value: Any,
- is_path_param: bool,
-) -> ParamDetails:
- field_info = None
- depends = None
- type_annotation: Any = Any
- use_annotation: Any = Any
- if annotation is not inspect.Signature.empty:
- use_annotation = annotation
- type_annotation = annotation
- # Extract Annotated info
- if get_origin(use_annotation) is Annotated:
- annotated_args = get_args(annotation)
- type_annotation = annotated_args[0]
- fastapi_annotations = [
- arg
- for arg in annotated_args[1:]
- if isinstance(arg, (FieldInfo, params.Depends))
- ]
- fastapi_specific_annotations = [
- arg
- for arg in fastapi_annotations
- if isinstance(arg, (params.Param, params.Body, params.Depends))
- ]
- if fastapi_specific_annotations:
- fastapi_annotation: Union[FieldInfo, params.Depends, None] = (
- fastapi_specific_annotations[-1]
- )
- else:
- fastapi_annotation = None
- # Set default for Annotated FieldInfo
- if isinstance(fastapi_annotation, FieldInfo):
- # Copy `field_info` because we mutate `field_info.default` below.
- field_info = copy_field_info(
- field_info=fastapi_annotation, annotation=use_annotation
- )
- assert (
- field_info.default is Undefined or field_info.default is RequiredParam
- ), (
- f"`{field_info.__class__.__name__}` default value cannot be set in"
- f" `Annotated` for {param_name!r}. Set the default value with `=` instead."
- )
- if value is not inspect.Signature.empty:
- assert not is_path_param, "Path parameters cannot have default values"
- field_info.default = value
- else:
- field_info.default = RequiredParam
- # Get Annotated Depends
- elif isinstance(fastapi_annotation, params.Depends):
- depends = fastapi_annotation
- # Get Depends from default value
- if isinstance(value, params.Depends):
- assert depends is None, (
- "Cannot specify `Depends` in `Annotated` and default value"
- f" together for {param_name!r}"
- )
- assert field_info is None, (
- "Cannot specify a FastAPI annotation in `Annotated` and `Depends` as a"
- f" default value together for {param_name!r}"
- )
- depends = value
- # Get FieldInfo from default value
- elif isinstance(value, FieldInfo):
- assert field_info is None, (
- "Cannot specify FastAPI annotations in `Annotated` and default value"
- f" together for {param_name!r}"
- )
- field_info = value
- if PYDANTIC_V2:
- field_info.annotation = type_annotation
-
- # Get Depends from type annotation
- if depends is not None and depends.dependency is None:
- # Copy `depends` before mutating it
- depends = copy(depends)
- depends.dependency = type_annotation
-
- # Handle non-param type annotations like Request
- if lenient_issubclass(
- type_annotation,
- (
- Request,
- WebSocket,
- HTTPConnection,
- Response,
- StarletteBackgroundTasks,
- SecurityScopes,
- ),
- ):
- assert depends is None, f"Cannot specify `Depends` for type {type_annotation!r}"
- assert (
- field_info is None
- ), f"Cannot specify FastAPI annotation for type {type_annotation!r}"
- # Handle default assignations, neither field_info nor depends was not found in Annotated nor default value
- elif field_info is None and depends is None:
- default_value = value if value is not inspect.Signature.empty else RequiredParam
- if is_path_param:
- # We might check here that `default_value is RequiredParam`, but the fact is that the same
- # parameter might sometimes be a path parameter and sometimes not. See
- # `tests/test_infer_param_optionality.py` for an example.
- field_info = params.Path(annotation=use_annotation)
- elif is_uploadfile_or_nonable_uploadfile_annotation(
- type_annotation
- ) or is_uploadfile_sequence_annotation(type_annotation):
- field_info = params.File(annotation=use_annotation, default=default_value)
- elif not field_annotation_is_scalar(annotation=type_annotation):
- field_info = params.Body(annotation=use_annotation, default=default_value)
- else:
- field_info = params.Query(annotation=use_annotation, default=default_value)
-
- field = None
- # It's a field_info, not a dependency
- if field_info is not None:
- # Handle field_info.in_
- if is_path_param:
- assert isinstance(field_info, params.Path), (
- f"Cannot use `{field_info.__class__.__name__}` for path param"
- f" {param_name!r}"
- )
- elif (
- isinstance(field_info, params.Param)
- and getattr(field_info, "in_", None) is None
- ):
- field_info.in_ = params.ParamTypes.query
- use_annotation_from_field_info = get_annotation_from_field_info(
- use_annotation,
- field_info,
- param_name,
- )
- if isinstance(field_info, params.Form):
- ensure_multipart_is_installed()
- if not field_info.alias and getattr(field_info, "convert_underscores", None):
- alias = param_name.replace("_", "-")
- else:
- alias = field_info.alias or param_name
- field_info.alias = alias
- field = create_model_field(
- name=param_name,
- type_=use_annotation_from_field_info,
- default=field_info.default,
- alias=alias,
- required=field_info.default in (RequiredParam, Undefined),
- field_info=field_info,
- )
- if is_path_param:
- assert is_scalar_field(
- field=field
- ), "Path params must be of one of the supported types"
- elif isinstance(field_info, params.Query):
- assert (
- is_scalar_field(field)
- or is_scalar_sequence_field(field)
- or (
- lenient_issubclass(field.type_, BaseModel)
- # For Pydantic v1
- and getattr(field, "shape", 1) == 1
- )
- )
-
- return ParamDetails(type_annotation=type_annotation, depends=depends, field=field)
-
-
-def add_param_to_fields(*, field: ModelField, dependant: Dependant) -> None:
- field_info = field.field_info
- field_info_in = getattr(field_info, "in_", None)
- if field_info_in == params.ParamTypes.path:
- dependant.path_params.append(field)
- elif field_info_in == params.ParamTypes.query:
- dependant.query_params.append(field)
- elif field_info_in == params.ParamTypes.header:
- dependant.header_params.append(field)
- else:
- assert (
- field_info_in == params.ParamTypes.cookie
- ), f"non-body parameters must be in path, query, header or cookie: {field.name}"
- dependant.cookie_params.append(field)
-
-
-def is_coroutine_callable(call: Callable[..., Any]) -> bool:
- if inspect.isroutine(call):
- return inspect.iscoroutinefunction(call)
- if inspect.isclass(call):
- return False
- dunder_call = getattr(call, "__call__", None) # noqa: B004
- return inspect.iscoroutinefunction(dunder_call)
-
-
-def is_async_gen_callable(call: Callable[..., Any]) -> bool:
- if inspect.isasyncgenfunction(call):
- return True
- dunder_call = getattr(call, "__call__", None) # noqa: B004
- return inspect.isasyncgenfunction(dunder_call)
-
-
-def is_gen_callable(call: Callable[..., Any]) -> bool:
- if inspect.isgeneratorfunction(call):
- return True
- dunder_call = getattr(call, "__call__", None) # noqa: B004
- return inspect.isgeneratorfunction(dunder_call)
-
-
-async def solve_generator(
- *, call: Callable[..., Any], stack: AsyncExitStack, sub_values: Dict[str, Any]
-) -> Any:
- if is_gen_callable(call):
- cm = contextmanager_in_threadpool(contextmanager(call)(**sub_values))
- elif is_async_gen_callable(call):
- cm = asynccontextmanager(call)(**sub_values)
- return await stack.enter_async_context(cm)
-
-
-@dataclass
-class SolvedDependency:
- values: Dict[str, Any]
- errors: List[Any]
- background_tasks: Optional[StarletteBackgroundTasks]
- response: Response
- dependency_cache: Dict[Tuple[Callable[..., Any], Tuple[str]], Any]
-
-
-async def solve_dependencies(
- *,
- request: Union[Request, WebSocket],
- dependant: Dependant,
- body: Optional[Union[Dict[str, Any], FormData]] = None,
- background_tasks: Optional[StarletteBackgroundTasks] = None,
- response: Optional[Response] = None,
- dependency_overrides_provider: Optional[Any] = None,
- dependency_cache: Optional[Dict[Tuple[Callable[..., Any], Tuple[str]], Any]] = None,
- async_exit_stack: AsyncExitStack,
- embed_body_fields: bool,
-) -> SolvedDependency:
- values: Dict[str, Any] = {}
- errors: List[Any] = []
- if response is None:
- response = Response()
- del response.headers["content-length"]
- response.status_code = None # type: ignore
- dependency_cache = dependency_cache or {}
- sub_dependant: Dependant
- for sub_dependant in dependant.dependencies:
- sub_dependant.call = cast(Callable[..., Any], sub_dependant.call)
- sub_dependant.cache_key = cast(
- Tuple[Callable[..., Any], Tuple[str]], sub_dependant.cache_key
- )
- call = sub_dependant.call
- use_sub_dependant = sub_dependant
- if (
- dependency_overrides_provider
- and dependency_overrides_provider.dependency_overrides
- ):
- original_call = sub_dependant.call
- call = getattr(
- dependency_overrides_provider, "dependency_overrides", {}
- ).get(original_call, original_call)
- use_path: str = sub_dependant.path # type: ignore
- use_sub_dependant = get_dependant(
- path=use_path,
- call=call,
- name=sub_dependant.name,
- security_scopes=sub_dependant.security_scopes,
- )
-
- solved_result = await solve_dependencies(
- request=request,
- dependant=use_sub_dependant,
- body=body,
- background_tasks=background_tasks,
- response=response,
- dependency_overrides_provider=dependency_overrides_provider,
- dependency_cache=dependency_cache,
- async_exit_stack=async_exit_stack,
- embed_body_fields=embed_body_fields,
- )
- background_tasks = solved_result.background_tasks
- dependency_cache.update(solved_result.dependency_cache)
- if solved_result.errors:
- errors.extend(solved_result.errors)
- continue
- if sub_dependant.use_cache and sub_dependant.cache_key in dependency_cache:
- solved = dependency_cache[sub_dependant.cache_key]
- elif is_gen_callable(call) or is_async_gen_callable(call):
- solved = await solve_generator(
- call=call, stack=async_exit_stack, sub_values=solved_result.values
- )
- elif is_coroutine_callable(call):
- solved = await call(**solved_result.values)
- else:
- solved = await run_in_threadpool(call, **solved_result.values)
- if sub_dependant.name is not None:
- values[sub_dependant.name] = solved
- if sub_dependant.cache_key not in dependency_cache:
- dependency_cache[sub_dependant.cache_key] = solved
- path_values, path_errors = request_params_to_args(
- dependant.path_params, request.path_params
- )
- query_values, query_errors = request_params_to_args(
- dependant.query_params, request.query_params
- )
- header_values, header_errors = request_params_to_args(
- dependant.header_params, request.headers
- )
- cookie_values, cookie_errors = request_params_to_args(
- dependant.cookie_params, request.cookies
- )
- values.update(path_values)
- values.update(query_values)
- values.update(header_values)
- values.update(cookie_values)
- errors += path_errors + query_errors + header_errors + cookie_errors
- if dependant.body_params:
- (
- body_values,
- body_errors,
- ) = await request_body_to_args( # body_params checked above
- body_fields=dependant.body_params,
- received_body=body,
- embed_body_fields=embed_body_fields,
- )
- values.update(body_values)
- errors.extend(body_errors)
- if dependant.http_connection_param_name:
- values[dependant.http_connection_param_name] = request
- if dependant.request_param_name and isinstance(request, Request):
- values[dependant.request_param_name] = request
- elif dependant.websocket_param_name and isinstance(request, WebSocket):
- values[dependant.websocket_param_name] = request
- if dependant.background_tasks_param_name:
- if background_tasks is None:
- background_tasks = BackgroundTasks()
- values[dependant.background_tasks_param_name] = background_tasks
- if dependant.response_param_name:
- values[dependant.response_param_name] = response
- if dependant.security_scopes_param_name:
- values[dependant.security_scopes_param_name] = SecurityScopes(
- scopes=dependant.security_scopes
- )
- return SolvedDependency(
- values=values,
- errors=errors,
- background_tasks=background_tasks,
- response=response,
- dependency_cache=dependency_cache,
- )
-
-
-def _validate_value_with_model_field(
- *, field: ModelField, value: Any, values: Dict[str, Any], loc: Tuple[str, ...]
-) -> Tuple[Any, List[Any]]:
- if value is None:
- if field.required:
- return None, [get_missing_field_error(loc=loc)]
- else:
- return deepcopy(field.default), []
- v_, errors_ = field.validate(value, values, loc=loc)
- if isinstance(errors_, ErrorWrapper):
- return None, [errors_]
- elif isinstance(errors_, list):
- new_errors = _regenerate_error_with_loc(errors=errors_, loc_prefix=())
- return None, new_errors
- else:
- return v_, []
-
-
-def _get_multidict_value(
- field: ModelField, values: Mapping[str, Any], alias: Union[str, None] = None
-) -> Any:
- alias = alias or field.alias
- if is_sequence_field(field) and isinstance(values, (ImmutableMultiDict, Headers)):
- value = values.getlist(alias)
- else:
- value = values.get(alias, None)
- if (
- value is None
- or (
- isinstance(field.field_info, params.Form)
- and isinstance(value, str) # For type checks
- and value == ""
- )
- or (is_sequence_field(field) and len(value) == 0)
- ):
- if field.required:
- return
- else:
- return deepcopy(field.default)
- return value
-
-
-def request_params_to_args(
- fields: Sequence[ModelField],
- received_params: Union[Mapping[str, Any], QueryParams, Headers],
-) -> Tuple[Dict[str, Any], List[Any]]:
- values: Dict[str, Any] = {}
- errors: List[Dict[str, Any]] = []
-
- if not fields:
- return values, errors
-
- first_field = fields[0]
- fields_to_extract = fields
- single_not_embedded_field = False
- if len(fields) == 1 and lenient_issubclass(first_field.type_, BaseModel):
- fields_to_extract = get_cached_model_fields(first_field.type_)
- single_not_embedded_field = True
-
- params_to_process: Dict[str, Any] = {}
-
- processed_keys = set()
-
- for field in fields_to_extract:
- alias = None
- if isinstance(received_params, Headers):
- # Handle fields extracted from a Pydantic Model for a header, each field
- # doesn't have a FieldInfo of type Header with the default convert_underscores=True
- convert_underscores = getattr(field.field_info, "convert_underscores", True)
- if convert_underscores:
- alias = (
- field.alias
- if field.alias != field.name
- else field.name.replace("_", "-")
- )
- value = _get_multidict_value(field, received_params, alias=alias)
- if value is not None:
- params_to_process[field.name] = value
- processed_keys.add(alias or field.alias)
- processed_keys.add(field.name)
-
- for key, value in received_params.items():
- if key not in processed_keys:
- params_to_process[key] = value
-
- if single_not_embedded_field:
- field_info = first_field.field_info
- assert isinstance(
- field_info, params.Param
- ), "Params must be subclasses of Param"
- loc: Tuple[str, ...] = (field_info.in_.value,)
- v_, errors_ = _validate_value_with_model_field(
- field=first_field, value=params_to_process, values=values, loc=loc
- )
- return {first_field.name: v_}, errors_
-
- for field in fields:
- value = _get_multidict_value(field, received_params)
- field_info = field.field_info
- assert isinstance(
- field_info, params.Param
- ), "Params must be subclasses of Param"
- loc = (field_info.in_.value, field.alias)
- v_, errors_ = _validate_value_with_model_field(
- field=field, value=value, values=values, loc=loc
- )
- if errors_:
- errors.extend(errors_)
- else:
- values[field.name] = v_
- return values, errors
-
-
-def _should_embed_body_fields(fields: List[ModelField]) -> bool:
- if not fields:
- return False
- # More than one dependency could have the same field, it would show up as multiple
- # fields but it's the same one, so count them by name
- body_param_names_set = {field.name for field in fields}
- # A top level field has to be a single field, not multiple
- if len(body_param_names_set) > 1:
- return True
- first_field = fields[0]
- # If it explicitly specifies it is embedded, it has to be embedded
- if getattr(first_field.field_info, "embed", None):
- return True
- # If it's a Form (or File) field, it has to be a BaseModel to be top level
- # otherwise it has to be embedded, so that the key value pair can be extracted
- if isinstance(first_field.field_info, params.Form) and not lenient_issubclass(
- first_field.type_, BaseModel
- ):
- return True
- return False
-
-
-async def _extract_form_body(
- body_fields: List[ModelField],
- received_body: FormData,
-) -> Dict[str, Any]:
- values = {}
- first_field = body_fields[0]
- first_field_info = first_field.field_info
-
- for field in body_fields:
- value = _get_multidict_value(field, received_body)
- if (
- isinstance(first_field_info, params.File)
- and is_bytes_field(field)
- and isinstance(value, UploadFile)
- ):
- value = await value.read()
- elif (
- is_bytes_sequence_field(field)
- and isinstance(first_field_info, params.File)
- and value_is_sequence(value)
- ):
- # For types
- assert isinstance(value, sequence_types) # type: ignore[arg-type]
- results: List[Union[bytes, str]] = []
-
- async def process_fn(
- fn: Callable[[], Coroutine[Any, Any, Any]],
- ) -> None:
- result = await fn()
- results.append(result) # noqa: B023
-
- async with anyio.create_task_group() as tg:
- for sub_value in value:
- tg.start_soon(process_fn, sub_value.read)
- value = serialize_sequence_value(field=field, value=results)
- if value is not None:
- values[field.alias] = value
- for key, value in received_body.items():
- if key not in values:
- values[key] = value
- return values
-
-
-async def request_body_to_args(
- body_fields: List[ModelField],
- received_body: Optional[Union[Dict[str, Any], FormData]],
- embed_body_fields: bool,
-) -> Tuple[Dict[str, Any], List[Dict[str, Any]]]:
- values: Dict[str, Any] = {}
- errors: List[Dict[str, Any]] = []
- assert body_fields, "request_body_to_args() should be called with fields"
- single_not_embedded_field = len(body_fields) == 1 and not embed_body_fields
- first_field = body_fields[0]
- body_to_process = received_body
-
- fields_to_extract: List[ModelField] = body_fields
-
- if single_not_embedded_field and lenient_issubclass(first_field.type_, BaseModel):
- fields_to_extract = get_cached_model_fields(first_field.type_)
-
- if isinstance(received_body, FormData):
- body_to_process = await _extract_form_body(fields_to_extract, received_body)
-
- if single_not_embedded_field:
- loc: Tuple[str, ...] = ("body",)
- v_, errors_ = _validate_value_with_model_field(
- field=first_field, value=body_to_process, values=values, loc=loc
- )
- return {first_field.name: v_}, errors_
- for field in body_fields:
- loc = ("body", field.alias)
- value: Optional[Any] = None
- if body_to_process is not None:
- try:
- value = body_to_process.get(field.alias)
- # If the received body is a list, not a dict
- except AttributeError:
- errors.append(get_missing_field_error(loc))
- continue
- v_, errors_ = _validate_value_with_model_field(
- field=field, value=value, values=values, loc=loc
- )
- if errors_:
- errors.extend(errors_)
- else:
- values[field.name] = v_
- return values, errors
-
-
-def get_body_field(
- *, flat_dependant: Dependant, name: str, embed_body_fields: bool
-) -> Optional[ModelField]:
- """
- Get a ModelField representing the request body for a path operation, combining
- all body parameters into a single field if necessary.
-
- Used to check if it's form data (with `isinstance(body_field, params.Form)`)
- or JSON and to generate the JSON Schema for a request body.
-
- This is **not** used to validate/parse the request body, that's done with each
- individual body parameter.
- """
- if not flat_dependant.body_params:
- return None
- first_param = flat_dependant.body_params[0]
- if not embed_body_fields:
- return first_param
- model_name = "Body_" + name
- BodyModel = create_body_model(
- fields=flat_dependant.body_params, model_name=model_name
- )
- required = any(True for f in flat_dependant.body_params if f.required)
- BodyFieldInfo_kwargs: Dict[str, Any] = {
- "annotation": BodyModel,
- "alias": "body",
- }
- if not required:
- BodyFieldInfo_kwargs["default"] = None
- if any(isinstance(f.field_info, params.File) for f in flat_dependant.body_params):
- BodyFieldInfo: Type[params.Body] = params.File
- elif any(isinstance(f.field_info, params.Form) for f in flat_dependant.body_params):
- BodyFieldInfo = params.Form
- else:
- BodyFieldInfo = params.Body
-
- body_param_media_types = [
- f.field_info.media_type
- for f in flat_dependant.body_params
- if isinstance(f.field_info, params.Body)
- ]
- if len(set(body_param_media_types)) == 1:
- BodyFieldInfo_kwargs["media_type"] = body_param_media_types[0]
- final_field = create_model_field(
- name="body",
- type_=BodyModel,
- required=required,
- alias="body",
- field_info=BodyFieldInfo(**BodyFieldInfo_kwargs),
- )
- return final_field
diff --git a/backend/pig/Lib/python3.12/site-packages/fastapi/encoders.py b/backend/pig/Lib/python3.12/site-packages/fastapi/encoders.py
deleted file mode 100644
index 451ea07..0000000
--- a/backend/pig/Lib/python3.12/site-packages/fastapi/encoders.py
+++ /dev/null
@@ -1,343 +0,0 @@
-import dataclasses
-import datetime
-from collections import defaultdict, deque
-from decimal import Decimal
-from enum import Enum
-from ipaddress import (
- IPv4Address,
- IPv4Interface,
- IPv4Network,
- IPv6Address,
- IPv6Interface,
- IPv6Network,
-)
-from pathlib import Path, PurePath
-from re import Pattern
-from types import GeneratorType
-from typing import Any, Callable, Dict, List, Optional, Tuple, Type, Union
-from uuid import UUID
-
-from fastapi.types import IncEx
-from pydantic import BaseModel
-from pydantic.color import Color
-from pydantic.networks import AnyUrl, NameEmail
-from pydantic.types import SecretBytes, SecretStr
-from typing_extensions import Annotated, Doc
-
-from ._compat import PYDANTIC_V2, UndefinedType, Url, _model_dump
-
-
-# Taken from Pydantic v1 as is
-def isoformat(o: Union[datetime.date, datetime.time]) -> str:
- return o.isoformat()
-
-
-# Taken from Pydantic v1 as is
-# TODO: pv2 should this return strings instead?
-def decimal_encoder(dec_value: Decimal) -> Union[int, float]:
- """
- Encodes a Decimal as int of there's no exponent, otherwise float
-
- This is useful when we use ConstrainedDecimal to represent Numeric(x,0)
- where a integer (but not int typed) is used. Encoding this as a float
- results in failed round-tripping between encode and parse.
- Our Id type is a prime example of this.
-
- >>> decimal_encoder(Decimal("1.0"))
- 1.0
-
- >>> decimal_encoder(Decimal("1"))
- 1
- """
- if dec_value.as_tuple().exponent >= 0: # type: ignore[operator]
- return int(dec_value)
- else:
- return float(dec_value)
-
-
-ENCODERS_BY_TYPE: Dict[Type[Any], Callable[[Any], Any]] = {
- bytes: lambda o: o.decode(),
- Color: str,
- datetime.date: isoformat,
- datetime.datetime: isoformat,
- datetime.time: isoformat,
- datetime.timedelta: lambda td: td.total_seconds(),
- Decimal: decimal_encoder,
- Enum: lambda o: o.value,
- frozenset: list,
- deque: list,
- GeneratorType: list,
- IPv4Address: str,
- IPv4Interface: str,
- IPv4Network: str,
- IPv6Address: str,
- IPv6Interface: str,
- IPv6Network: str,
- NameEmail: str,
- Path: str,
- Pattern: lambda o: o.pattern,
- SecretBytes: str,
- SecretStr: str,
- set: list,
- UUID: str,
- Url: str,
- AnyUrl: str,
-}
-
-
-def generate_encoders_by_class_tuples(
- type_encoder_map: Dict[Any, Callable[[Any], Any]],
-) -> Dict[Callable[[Any], Any], Tuple[Any, ...]]:
- encoders_by_class_tuples: Dict[Callable[[Any], Any], Tuple[Any, ...]] = defaultdict(
- tuple
- )
- for type_, encoder in type_encoder_map.items():
- encoders_by_class_tuples[encoder] += (type_,)
- return encoders_by_class_tuples
-
-
-encoders_by_class_tuples = generate_encoders_by_class_tuples(ENCODERS_BY_TYPE)
-
-
-def jsonable_encoder(
- obj: Annotated[
- Any,
- Doc(
- """
- The input object to convert to JSON.
- """
- ),
- ],
- include: Annotated[
- Optional[IncEx],
- Doc(
- """
- Pydantic's `include` parameter, passed to Pydantic models to set the
- fields to include.
- """
- ),
- ] = None,
- exclude: Annotated[
- Optional[IncEx],
- Doc(
- """
- Pydantic's `exclude` parameter, passed to Pydantic models to set the
- fields to exclude.
- """
- ),
- ] = None,
- by_alias: Annotated[
- bool,
- Doc(
- """
- Pydantic's `by_alias` parameter, passed to Pydantic models to define if
- the output should use the alias names (when provided) or the Python
- attribute names. In an API, if you set an alias, it's probably because you
- want to use it in the result, so you probably want to leave this set to
- `True`.
- """
- ),
- ] = True,
- exclude_unset: Annotated[
- bool,
- Doc(
- """
- Pydantic's `exclude_unset` parameter, passed to Pydantic models to define
- if it should exclude from the output the fields that were not explicitly
- set (and that only had their default values).
- """
- ),
- ] = False,
- exclude_defaults: Annotated[
- bool,
- Doc(
- """
- Pydantic's `exclude_defaults` parameter, passed to Pydantic models to define
- if it should exclude from the output the fields that had the same default
- value, even when they were explicitly set.
- """
- ),
- ] = False,
- exclude_none: Annotated[
- bool,
- Doc(
- """
- Pydantic's `exclude_none` parameter, passed to Pydantic models to define
- if it should exclude from the output any fields that have a `None` value.
- """
- ),
- ] = False,
- custom_encoder: Annotated[
- Optional[Dict[Any, Callable[[Any], Any]]],
- Doc(
- """
- Pydantic's `custom_encoder` parameter, passed to Pydantic models to define
- a custom encoder.
- """
- ),
- ] = None,
- sqlalchemy_safe: Annotated[
- bool,
- Doc(
- """
- Exclude from the output any fields that start with the name `_sa`.
-
- This is mainly a hack for compatibility with SQLAlchemy objects, they
- store internal SQLAlchemy-specific state in attributes named with `_sa`,
- and those objects can't (and shouldn't be) serialized to JSON.
- """
- ),
- ] = True,
-) -> Any:
- """
- Convert any object to something that can be encoded in JSON.
-
- This is used internally by FastAPI to make sure anything you return can be
- encoded as JSON before it is sent to the client.
-
- You can also use it yourself, for example to convert objects before saving them
- in a database that supports only JSON.
-
- Read more about it in the
- [FastAPI docs for JSON Compatible Encoder](https://fastapi.tiangolo.com/tutorial/encoder/).
- """
- custom_encoder = custom_encoder or {}
- if custom_encoder:
- if type(obj) in custom_encoder:
- return custom_encoder[type(obj)](obj)
- else:
- for encoder_type, encoder_instance in custom_encoder.items():
- if isinstance(obj, encoder_type):
- return encoder_instance(obj)
- if include is not None and not isinstance(include, (set, dict)):
- include = set(include)
- if exclude is not None and not isinstance(exclude, (set, dict)):
- exclude = set(exclude)
- if isinstance(obj, BaseModel):
- # TODO: remove when deprecating Pydantic v1
- encoders: Dict[Any, Any] = {}
- if not PYDANTIC_V2:
- encoders = getattr(obj.__config__, "json_encoders", {}) # type: ignore[attr-defined]
- if custom_encoder:
- encoders.update(custom_encoder)
- obj_dict = _model_dump(
- obj,
- mode="json",
- include=include,
- exclude=exclude,
- by_alias=by_alias,
- exclude_unset=exclude_unset,
- exclude_none=exclude_none,
- exclude_defaults=exclude_defaults,
- )
- if "__root__" in obj_dict:
- obj_dict = obj_dict["__root__"]
- return jsonable_encoder(
- obj_dict,
- exclude_none=exclude_none,
- exclude_defaults=exclude_defaults,
- # TODO: remove when deprecating Pydantic v1
- custom_encoder=encoders,
- sqlalchemy_safe=sqlalchemy_safe,
- )
- if dataclasses.is_dataclass(obj):
- obj_dict = dataclasses.asdict(obj)
- return jsonable_encoder(
- obj_dict,
- include=include,
- exclude=exclude,
- by_alias=by_alias,
- exclude_unset=exclude_unset,
- exclude_defaults=exclude_defaults,
- exclude_none=exclude_none,
- custom_encoder=custom_encoder,
- sqlalchemy_safe=sqlalchemy_safe,
- )
- if isinstance(obj, Enum):
- return obj.value
- if isinstance(obj, PurePath):
- return str(obj)
- if isinstance(obj, (str, int, float, type(None))):
- return obj
- if isinstance(obj, UndefinedType):
- return None
- if isinstance(obj, dict):
- encoded_dict = {}
- allowed_keys = set(obj.keys())
- if include is not None:
- allowed_keys &= set(include)
- if exclude is not None:
- allowed_keys -= set(exclude)
- for key, value in obj.items():
- if (
- (
- not sqlalchemy_safe
- or (not isinstance(key, str))
- or (not key.startswith("_sa"))
- )
- and (value is not None or not exclude_none)
- and key in allowed_keys
- ):
- encoded_key = jsonable_encoder(
- key,
- by_alias=by_alias,
- exclude_unset=exclude_unset,
- exclude_none=exclude_none,
- custom_encoder=custom_encoder,
- sqlalchemy_safe=sqlalchemy_safe,
- )
- encoded_value = jsonable_encoder(
- value,
- by_alias=by_alias,
- exclude_unset=exclude_unset,
- exclude_none=exclude_none,
- custom_encoder=custom_encoder,
- sqlalchemy_safe=sqlalchemy_safe,
- )
- encoded_dict[encoded_key] = encoded_value
- return encoded_dict
- if isinstance(obj, (list, set, frozenset, GeneratorType, tuple, deque)):
- encoded_list = []
- for item in obj:
- encoded_list.append(
- jsonable_encoder(
- item,
- include=include,
- exclude=exclude,
- by_alias=by_alias,
- exclude_unset=exclude_unset,
- exclude_defaults=exclude_defaults,
- exclude_none=exclude_none,
- custom_encoder=custom_encoder,
- sqlalchemy_safe=sqlalchemy_safe,
- )
- )
- return encoded_list
-
- if type(obj) in ENCODERS_BY_TYPE:
- return ENCODERS_BY_TYPE[type(obj)](obj)
- for encoder, classes_tuple in encoders_by_class_tuples.items():
- if isinstance(obj, classes_tuple):
- return encoder(obj)
-
- try:
- data = dict(obj)
- except Exception as e:
- errors: List[Exception] = []
- errors.append(e)
- try:
- data = vars(obj)
- except Exception as e:
- errors.append(e)
- raise ValueError(errors) from e
- return jsonable_encoder(
- data,
- include=include,
- exclude=exclude,
- by_alias=by_alias,
- exclude_unset=exclude_unset,
- exclude_defaults=exclude_defaults,
- exclude_none=exclude_none,
- custom_encoder=custom_encoder,
- sqlalchemy_safe=sqlalchemy_safe,
- )
diff --git a/backend/pig/Lib/python3.12/site-packages/fastapi/exception_handlers.py b/backend/pig/Lib/python3.12/site-packages/fastapi/exception_handlers.py
deleted file mode 100644
index 6c2ba7f..0000000
--- a/backend/pig/Lib/python3.12/site-packages/fastapi/exception_handlers.py
+++ /dev/null
@@ -1,34 +0,0 @@
-from fastapi.encoders import jsonable_encoder
-from fastapi.exceptions import RequestValidationError, WebSocketRequestValidationError
-from fastapi.utils import is_body_allowed_for_status_code
-from fastapi.websockets import WebSocket
-from starlette.exceptions import HTTPException
-from starlette.requests import Request
-from starlette.responses import JSONResponse, Response
-from starlette.status import HTTP_422_UNPROCESSABLE_ENTITY, WS_1008_POLICY_VIOLATION
-
-
-async def http_exception_handler(request: Request, exc: HTTPException) -> Response:
- headers = getattr(exc, "headers", None)
- if not is_body_allowed_for_status_code(exc.status_code):
- return Response(status_code=exc.status_code, headers=headers)
- return JSONResponse(
- {"detail": exc.detail}, status_code=exc.status_code, headers=headers
- )
-
-
-async def request_validation_exception_handler(
- request: Request, exc: RequestValidationError
-) -> JSONResponse:
- return JSONResponse(
- status_code=HTTP_422_UNPROCESSABLE_ENTITY,
- content={"detail": jsonable_encoder(exc.errors())},
- )
-
-
-async def websocket_request_validation_exception_handler(
- websocket: WebSocket, exc: WebSocketRequestValidationError
-) -> None:
- await websocket.close(
- code=WS_1008_POLICY_VIOLATION, reason=jsonable_encoder(exc.errors())
- )
diff --git a/backend/pig/Lib/python3.12/site-packages/fastapi/exceptions.py b/backend/pig/Lib/python3.12/site-packages/fastapi/exceptions.py
deleted file mode 100644
index 44d4ada..0000000
--- a/backend/pig/Lib/python3.12/site-packages/fastapi/exceptions.py
+++ /dev/null
@@ -1,176 +0,0 @@
-from typing import Any, Dict, Optional, Sequence, Type, Union
-
-from pydantic import BaseModel, create_model
-from starlette.exceptions import HTTPException as StarletteHTTPException
-from starlette.exceptions import WebSocketException as StarletteWebSocketException
-from typing_extensions import Annotated, Doc
-
-
-class HTTPException(StarletteHTTPException):
- """
- An HTTP exception you can raise in your own code to show errors to the client.
-
- This is for client errors, invalid authentication, invalid data, etc. Not for server
- errors in your code.
-
- Read more about it in the
- [FastAPI docs for Handling Errors](https://fastapi.tiangolo.com/tutorial/handling-errors/).
-
- ## Example
-
- ```python
- from fastapi import FastAPI, HTTPException
-
- app = FastAPI()
-
- items = {"foo": "The Foo Wrestlers"}
-
-
- @app.get("/items/{item_id}")
- async def read_item(item_id: str):
- if item_id not in items:
- raise HTTPException(status_code=404, detail="Item not found")
- return {"item": items[item_id]}
- ```
- """
-
- def __init__(
- self,
- status_code: Annotated[
- int,
- Doc(
- """
- HTTP status code to send to the client.
- """
- ),
- ],
- detail: Annotated[
- Any,
- Doc(
- """
- Any data to be sent to the client in the `detail` key of the JSON
- response.
- """
- ),
- ] = None,
- headers: Annotated[
- Optional[Dict[str, str]],
- Doc(
- """
- Any headers to send to the client in the response.
- """
- ),
- ] = None,
- ) -> None:
- super().__init__(status_code=status_code, detail=detail, headers=headers)
-
-
-class WebSocketException(StarletteWebSocketException):
- """
- A WebSocket exception you can raise in your own code to show errors to the client.
-
- This is for client errors, invalid authentication, invalid data, etc. Not for server
- errors in your code.
-
- Read more about it in the
- [FastAPI docs for WebSockets](https://fastapi.tiangolo.com/advanced/websockets/).
-
- ## Example
-
- ```python
- from typing import Annotated
-
- from fastapi import (
- Cookie,
- FastAPI,
- WebSocket,
- WebSocketException,
- status,
- )
-
- app = FastAPI()
-
- @app.websocket("/items/{item_id}/ws")
- async def websocket_endpoint(
- *,
- websocket: WebSocket,
- session: Annotated[str | None, Cookie()] = None,
- item_id: str,
- ):
- if session is None:
- raise WebSocketException(code=status.WS_1008_POLICY_VIOLATION)
- await websocket.accept()
- while True:
- data = await websocket.receive_text()
- await websocket.send_text(f"Session cookie is: {session}")
- await websocket.send_text(f"Message text was: {data}, for item ID: {item_id}")
- ```
- """
-
- def __init__(
- self,
- code: Annotated[
- int,
- Doc(
- """
- A closing code from the
- [valid codes defined in the specification](https://datatracker.ietf.org/doc/html/rfc6455#section-7.4.1).
- """
- ),
- ],
- reason: Annotated[
- Union[str, None],
- Doc(
- """
- The reason to close the WebSocket connection.
-
- It is UTF-8-encoded data. The interpretation of the reason is up to the
- application, it is not specified by the WebSocket specification.
-
- It could contain text that could be human-readable or interpretable
- by the client code, etc.
- """
- ),
- ] = None,
- ) -> None:
- super().__init__(code=code, reason=reason)
-
-
-RequestErrorModel: Type[BaseModel] = create_model("Request")
-WebSocketErrorModel: Type[BaseModel] = create_model("WebSocket")
-
-
-class FastAPIError(RuntimeError):
- """
- A generic, FastAPI-specific error.
- """
-
-
-class ValidationException(Exception):
- def __init__(self, errors: Sequence[Any]) -> None:
- self._errors = errors
-
- def errors(self) -> Sequence[Any]:
- return self._errors
-
-
-class RequestValidationError(ValidationException):
- def __init__(self, errors: Sequence[Any], *, body: Any = None) -> None:
- super().__init__(errors)
- self.body = body
-
-
-class WebSocketRequestValidationError(ValidationException):
- pass
-
-
-class ResponseValidationError(ValidationException):
- def __init__(self, errors: Sequence[Any], *, body: Any = None) -> None:
- super().__init__(errors)
- self.body = body
-
- def __str__(self) -> str:
- message = f"{len(self._errors)} validation errors:\n"
- for err in self._errors:
- message += f" {err}\n"
- return message
diff --git a/backend/pig/Lib/python3.12/site-packages/fastapi/logger.py b/backend/pig/Lib/python3.12/site-packages/fastapi/logger.py
deleted file mode 100644
index 5b2c4ad..0000000
--- a/backend/pig/Lib/python3.12/site-packages/fastapi/logger.py
+++ /dev/null
@@ -1,3 +0,0 @@
-import logging
-
-logger = logging.getLogger("fastapi")
diff --git a/backend/pig/Lib/python3.12/site-packages/fastapi/middleware/__init__.py b/backend/pig/Lib/python3.12/site-packages/fastapi/middleware/__init__.py
deleted file mode 100644
index 620296d..0000000
--- a/backend/pig/Lib/python3.12/site-packages/fastapi/middleware/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-from starlette.middleware import Middleware as Middleware
diff --git a/backend/pig/Lib/python3.12/site-packages/fastapi/middleware/__pycache__/__init__.cpython-312.pyc b/backend/pig/Lib/python3.12/site-packages/fastapi/middleware/__pycache__/__init__.cpython-312.pyc
deleted file mode 100644
index 635f875..0000000
Binary files a/backend/pig/Lib/python3.12/site-packages/fastapi/middleware/__pycache__/__init__.cpython-312.pyc and /dev/null differ
diff --git a/backend/pig/Lib/python3.12/site-packages/fastapi/middleware/__pycache__/cors.cpython-312.pyc b/backend/pig/Lib/python3.12/site-packages/fastapi/middleware/__pycache__/cors.cpython-312.pyc
deleted file mode 100644
index 8f0779c..0000000
Binary files a/backend/pig/Lib/python3.12/site-packages/fastapi/middleware/__pycache__/cors.cpython-312.pyc and /dev/null differ
diff --git a/backend/pig/Lib/python3.12/site-packages/fastapi/middleware/__pycache__/gzip.cpython-312.pyc b/backend/pig/Lib/python3.12/site-packages/fastapi/middleware/__pycache__/gzip.cpython-312.pyc
deleted file mode 100644
index 5bfa527..0000000
Binary files a/backend/pig/Lib/python3.12/site-packages/fastapi/middleware/__pycache__/gzip.cpython-312.pyc and /dev/null differ
diff --git a/backend/pig/Lib/python3.12/site-packages/fastapi/middleware/__pycache__/httpsredirect.cpython-312.pyc b/backend/pig/Lib/python3.12/site-packages/fastapi/middleware/__pycache__/httpsredirect.cpython-312.pyc
deleted file mode 100644
index 291455b..0000000
Binary files a/backend/pig/Lib/python3.12/site-packages/fastapi/middleware/__pycache__/httpsredirect.cpython-312.pyc and /dev/null differ
diff --git a/backend/pig/Lib/python3.12/site-packages/fastapi/middleware/__pycache__/trustedhost.cpython-312.pyc b/backend/pig/Lib/python3.12/site-packages/fastapi/middleware/__pycache__/trustedhost.cpython-312.pyc
deleted file mode 100644
index c583a68..0000000
Binary files a/backend/pig/Lib/python3.12/site-packages/fastapi/middleware/__pycache__/trustedhost.cpython-312.pyc and /dev/null differ
diff --git a/backend/pig/Lib/python3.12/site-packages/fastapi/middleware/__pycache__/wsgi.cpython-312.pyc b/backend/pig/Lib/python3.12/site-packages/fastapi/middleware/__pycache__/wsgi.cpython-312.pyc
deleted file mode 100644
index 76f1a4d..0000000
Binary files a/backend/pig/Lib/python3.12/site-packages/fastapi/middleware/__pycache__/wsgi.cpython-312.pyc and /dev/null differ
diff --git a/backend/pig/Lib/python3.12/site-packages/fastapi/middleware/cors.py b/backend/pig/Lib/python3.12/site-packages/fastapi/middleware/cors.py
deleted file mode 100644
index 8dfaad0..0000000
--- a/backend/pig/Lib/python3.12/site-packages/fastapi/middleware/cors.py
+++ /dev/null
@@ -1 +0,0 @@
-from starlette.middleware.cors import CORSMiddleware as CORSMiddleware # noqa
diff --git a/backend/pig/Lib/python3.12/site-packages/fastapi/middleware/gzip.py b/backend/pig/Lib/python3.12/site-packages/fastapi/middleware/gzip.py
deleted file mode 100644
index bbeb2cc..0000000
--- a/backend/pig/Lib/python3.12/site-packages/fastapi/middleware/gzip.py
+++ /dev/null
@@ -1 +0,0 @@
-from starlette.middleware.gzip import GZipMiddleware as GZipMiddleware # noqa
diff --git a/backend/pig/Lib/python3.12/site-packages/fastapi/middleware/httpsredirect.py b/backend/pig/Lib/python3.12/site-packages/fastapi/middleware/httpsredirect.py
deleted file mode 100644
index b7a3d8e..0000000
--- a/backend/pig/Lib/python3.12/site-packages/fastapi/middleware/httpsredirect.py
+++ /dev/null
@@ -1,3 +0,0 @@
-from starlette.middleware.httpsredirect import ( # noqa
- HTTPSRedirectMiddleware as HTTPSRedirectMiddleware,
-)
diff --git a/backend/pig/Lib/python3.12/site-packages/fastapi/middleware/trustedhost.py b/backend/pig/Lib/python3.12/site-packages/fastapi/middleware/trustedhost.py
deleted file mode 100644
index 08d7e03..0000000
--- a/backend/pig/Lib/python3.12/site-packages/fastapi/middleware/trustedhost.py
+++ /dev/null
@@ -1,3 +0,0 @@
-from starlette.middleware.trustedhost import ( # noqa
- TrustedHostMiddleware as TrustedHostMiddleware,
-)
diff --git a/backend/pig/Lib/python3.12/site-packages/fastapi/middleware/wsgi.py b/backend/pig/Lib/python3.12/site-packages/fastapi/middleware/wsgi.py
deleted file mode 100644
index c4c6a79..0000000
--- a/backend/pig/Lib/python3.12/site-packages/fastapi/middleware/wsgi.py
+++ /dev/null
@@ -1 +0,0 @@
-from starlette.middleware.wsgi import WSGIMiddleware as WSGIMiddleware # noqa
diff --git a/backend/pig/Lib/python3.12/site-packages/fastapi/openapi/__init__.py b/backend/pig/Lib/python3.12/site-packages/fastapi/openapi/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/backend/pig/Lib/python3.12/site-packages/fastapi/openapi/__pycache__/__init__.cpython-312.pyc b/backend/pig/Lib/python3.12/site-packages/fastapi/openapi/__pycache__/__init__.cpython-312.pyc
deleted file mode 100644
index 237622a..0000000
Binary files a/backend/pig/Lib/python3.12/site-packages/fastapi/openapi/__pycache__/__init__.cpython-312.pyc and /dev/null differ
diff --git a/backend/pig/Lib/python3.12/site-packages/fastapi/openapi/__pycache__/constants.cpython-312.pyc b/backend/pig/Lib/python3.12/site-packages/fastapi/openapi/__pycache__/constants.cpython-312.pyc
deleted file mode 100644
index aae2fb0..0000000
Binary files a/backend/pig/Lib/python3.12/site-packages/fastapi/openapi/__pycache__/constants.cpython-312.pyc and /dev/null differ
diff --git a/backend/pig/Lib/python3.12/site-packages/fastapi/openapi/__pycache__/docs.cpython-312.pyc b/backend/pig/Lib/python3.12/site-packages/fastapi/openapi/__pycache__/docs.cpython-312.pyc
deleted file mode 100644
index 2dd1f64..0000000
Binary files a/backend/pig/Lib/python3.12/site-packages/fastapi/openapi/__pycache__/docs.cpython-312.pyc and /dev/null differ
diff --git a/backend/pig/Lib/python3.12/site-packages/fastapi/openapi/__pycache__/models.cpython-312.pyc b/backend/pig/Lib/python3.12/site-packages/fastapi/openapi/__pycache__/models.cpython-312.pyc
deleted file mode 100644
index 6202e66..0000000
Binary files a/backend/pig/Lib/python3.12/site-packages/fastapi/openapi/__pycache__/models.cpython-312.pyc and /dev/null differ
diff --git a/backend/pig/Lib/python3.12/site-packages/fastapi/openapi/__pycache__/utils.cpython-312.pyc b/backend/pig/Lib/python3.12/site-packages/fastapi/openapi/__pycache__/utils.cpython-312.pyc
deleted file mode 100644
index 9d9d58b..0000000
Binary files a/backend/pig/Lib/python3.12/site-packages/fastapi/openapi/__pycache__/utils.cpython-312.pyc and /dev/null differ
diff --git a/backend/pig/Lib/python3.12/site-packages/fastapi/openapi/constants.py b/backend/pig/Lib/python3.12/site-packages/fastapi/openapi/constants.py
deleted file mode 100644
index d724ee3..0000000
--- a/backend/pig/Lib/python3.12/site-packages/fastapi/openapi/constants.py
+++ /dev/null
@@ -1,3 +0,0 @@
-METHODS_WITH_BODY = {"GET", "HEAD", "POST", "PUT", "DELETE", "PATCH"}
-REF_PREFIX = "#/components/schemas/"
-REF_TEMPLATE = "#/components/schemas/{model}"
diff --git a/backend/pig/Lib/python3.12/site-packages/fastapi/openapi/docs.py b/backend/pig/Lib/python3.12/site-packages/fastapi/openapi/docs.py
deleted file mode 100644
index c2ec358..0000000
--- a/backend/pig/Lib/python3.12/site-packages/fastapi/openapi/docs.py
+++ /dev/null
@@ -1,344 +0,0 @@
-import json
-from typing import Any, Dict, Optional
-
-from fastapi.encoders import jsonable_encoder
-from starlette.responses import HTMLResponse
-from typing_extensions import Annotated, Doc
-
-swagger_ui_default_parameters: Annotated[
- Dict[str, Any],
- Doc(
- """
- Default configurations for Swagger UI.
-
- You can use it as a template to add any other configurations needed.
- """
- ),
-] = {
- "dom_id": "#swagger-ui",
- "layout": "BaseLayout",
- "deepLinking": True,
- "showExtensions": True,
- "showCommonExtensions": True,
-}
-
-
-def get_swagger_ui_html(
- *,
- openapi_url: Annotated[
- str,
- Doc(
- """
- The OpenAPI URL that Swagger UI should load and use.
-
- This is normally done automatically by FastAPI using the default URL
- `/openapi.json`.
- """
- ),
- ],
- title: Annotated[
- str,
- Doc(
- """
- The HTML `Q" - format_p = format_i if self.e_ident_class == self.ELFCLASS32 else format_q - self.e_type = unpack(format_h) - self.e_machine = unpack(format_h) - self.e_version = unpack(format_i) - self.e_entry = unpack(format_p) - self.e_phoff = unpack(format_p) - self.e_shoff = unpack(format_p) - self.e_flags = unpack(format_i) - self.e_ehsize = unpack(format_h) - self.e_phentsize = unpack(format_h) - self.e_phnum = unpack(format_h) - self.e_shentsize = unpack(format_h) - self.e_shnum = unpack(format_h) - self.e_shstrndx = unpack(format_h) - - -def _get_elf_header() -> Optional[_ELFFileHeader]: - try: - with open(sys.executable, "rb") as f: - elf_header = _ELFFileHeader(f) - except (OSError, TypeError, _ELFFileHeader._InvalidELFFileHeader): - return None - return elf_header - - -def _is_linux_armhf() -> bool: - # hard-float ABI can be detected from the ELF header of the running - # process - # https://static.docs.arm.com/ihi0044/g/aaelf32.pdf - elf_header = _get_elf_header() - if elf_header is None: - return False - result = elf_header.e_ident_class == elf_header.ELFCLASS32 - result &= elf_header.e_ident_data == elf_header.ELFDATA2LSB - result &= elf_header.e_machine == elf_header.EM_ARM - result &= ( - elf_header.e_flags & elf_header.EF_ARM_ABIMASK - ) == elf_header.EF_ARM_ABI_VER5 - result &= ( - elf_header.e_flags & elf_header.EF_ARM_ABI_FLOAT_HARD - ) == elf_header.EF_ARM_ABI_FLOAT_HARD - return result - - -def _is_linux_i686() -> bool: - elf_header = _get_elf_header() - if elf_header is None: - return False - result = elf_header.e_ident_class == elf_header.ELFCLASS32 - result &= elf_header.e_ident_data == elf_header.ELFDATA2LSB - result &= elf_header.e_machine == elf_header.EM_386 - return result - - -def _have_compatible_abi(arch: str) -> bool: - if arch == "armv7l": - return _is_linux_armhf() - if arch == "i686": - return _is_linux_i686() - return arch in {"x86_64", "aarch64", "ppc64", "ppc64le", "s390x"} - - -# If glibc ever changes its major version, we need to know what the last -# minor version was, so we can build the complete list of all versions. -# For now, guess what the highest minor version might be, assume it will -# be 50 for testing. Once this actually happens, update the dictionary -# with the actual value. -_LAST_GLIBC_MINOR: Dict[int, int] = collections.defaultdict(lambda: 50) - - -class _GLibCVersion(NamedTuple): - major: int - minor: int - - -def _glibc_version_string_confstr() -> Optional[str]: - """ - Primary implementation of glibc_version_string using os.confstr. - """ - # os.confstr is quite a bit faster than ctypes.DLL. It's also less likely - # to be broken or missing. This strategy is used in the standard library - # platform module. - # https://github.com/python/cpython/blob/fcf1d003bf4f0100c/Lib/platform.py#L175-L183 - try: - # os.confstr("CS_GNU_LIBC_VERSION") returns a string like "glibc 2.17". - version_string = os.confstr("CS_GNU_LIBC_VERSION") - assert version_string is not None - _, version = version_string.split() - except (AssertionError, AttributeError, OSError, ValueError): - # os.confstr() or CS_GNU_LIBC_VERSION not available (or a bad value)... - return None - return version - - -def _glibc_version_string_ctypes() -> Optional[str]: - """ - Fallback implementation of glibc_version_string using ctypes. - """ - try: - import ctypes - except ImportError: - return None - - # ctypes.CDLL(None) internally calls dlopen(NULL), and as the dlopen - # manpage says, "If filename is NULL, then the returned handle is for the - # main program". This way we can let the linker do the work to figure out - # which libc our process is actually using. - # - # We must also handle the special case where the executable is not a - # dynamically linked executable. This can occur when using musl libc, - # for example. In this situation, dlopen() will error, leading to an - # OSError. Interestingly, at least in the case of musl, there is no - # errno set on the OSError. The single string argument used to construct - # OSError comes from libc itself and is therefore not portable to - # hard code here. In any case, failure to call dlopen() means we - # can proceed, so we bail on our attempt. - try: - process_namespace = ctypes.CDLL(None) - except OSError: - return None - - try: - gnu_get_libc_version = process_namespace.gnu_get_libc_version - except AttributeError: - # Symbol doesn't exist -> therefore, we are not linked to - # glibc. - return None - - # Call gnu_get_libc_version, which returns a string like "2.5" - gnu_get_libc_version.restype = ctypes.c_char_p - version_str: str = gnu_get_libc_version() - # py2 / py3 compatibility: - if not isinstance(version_str, str): - version_str = version_str.decode("ascii") - - return version_str - - -def _glibc_version_string() -> Optional[str]: - """Returns glibc version string, or None if not using glibc.""" - return _glibc_version_string_confstr() or _glibc_version_string_ctypes() - - -def _parse_glibc_version(version_str: str) -> Tuple[int, int]: - """Parse glibc version. - - We use a regexp instead of str.split because we want to discard any - random junk that might come after the minor version -- this might happen - in patched/forked versions of glibc (e.g. Linaro's version of glibc - uses version strings like "2.20-2014.11"). See gh-3588. - """ - m = re.match(r"(?P[0-9]+)\.(?P [0-9]+)", version_str) - if not m: - warnings.warn( - "Expected glibc version with 2 components major.minor," - " got: %s" % version_str, - RuntimeWarning, - ) - return -1, -1 - return int(m.group("major")), int(m.group("minor")) - - -@functools.lru_cache() -def _get_glibc_version() -> Tuple[int, int]: - version_str = _glibc_version_string() - if version_str is None: - return (-1, -1) - return _parse_glibc_version(version_str) - - -# From PEP 513, PEP 600 -def _is_compatible(name: str, arch: str, version: _GLibCVersion) -> bool: - sys_glibc = _get_glibc_version() - if sys_glibc < version: - return False - # Check for presence of _manylinux module. - try: - import _manylinux # noqa - except ImportError: - return True - if hasattr(_manylinux, "manylinux_compatible"): - result = _manylinux.manylinux_compatible(version[0], version[1], arch) - if result is not None: - return bool(result) - return True - if version == _GLibCVersion(2, 5): - if hasattr(_manylinux, "manylinux1_compatible"): - return bool(_manylinux.manylinux1_compatible) - if version == _GLibCVersion(2, 12): - if hasattr(_manylinux, "manylinux2010_compatible"): - return bool(_manylinux.manylinux2010_compatible) - if version == _GLibCVersion(2, 17): - if hasattr(_manylinux, "manylinux2014_compatible"): - return bool(_manylinux.manylinux2014_compatible) - return True - - -_LEGACY_MANYLINUX_MAP = { - # CentOS 7 w/ glibc 2.17 (PEP 599) - (2, 17): "manylinux2014", - # CentOS 6 w/ glibc 2.12 (PEP 571) - (2, 12): "manylinux2010", - # CentOS 5 w/ glibc 2.5 (PEP 513) - (2, 5): "manylinux1", -} - - -def platform_tags(linux: str, arch: str) -> Iterator[str]: - if not _have_compatible_abi(arch): - return - # Oldest glibc to be supported regardless of architecture is (2, 17). - too_old_glibc2 = _GLibCVersion(2, 16) - if arch in {"x86_64", "i686"}: - # On x86/i686 also oldest glibc to be supported is (2, 5). - too_old_glibc2 = _GLibCVersion(2, 4) - current_glibc = _GLibCVersion(*_get_glibc_version()) - glibc_max_list = [current_glibc] - # We can assume compatibility across glibc major versions. - # https://sourceware.org/bugzilla/show_bug.cgi?id=24636 - # - # Build a list of maximum glibc versions so that we can - # output the canonical list of all glibc from current_glibc - # down to too_old_glibc2, including all intermediary versions. - for glibc_major in range(current_glibc.major - 1, 1, -1): - glibc_minor = _LAST_GLIBC_MINOR[glibc_major] - glibc_max_list.append(_GLibCVersion(glibc_major, glibc_minor)) - for glibc_max in glibc_max_list: - if glibc_max.major == too_old_glibc2.major: - min_minor = too_old_glibc2.minor - else: - # For other glibc major versions oldest supported is (x, 0). - min_minor = -1 - for glibc_minor in range(glibc_max.minor, min_minor, -1): - glibc_version = _GLibCVersion(glibc_max.major, glibc_minor) - tag = "manylinux_{}_{}".format(*glibc_version) - if _is_compatible(tag, arch, glibc_version): - yield linux.replace("linux", tag) - # Handle the legacy manylinux1, manylinux2010, manylinux2014 tags. - if glibc_version in _LEGACY_MANYLINUX_MAP: - legacy_tag = _LEGACY_MANYLINUX_MAP[glibc_version] - if _is_compatible(legacy_tag, arch, glibc_version): - yield linux.replace("linux", legacy_tag) diff --git a/backend/pig/Lib/python3.12/site-packages/pip/_vendor/packaging/_musllinux.py b/backend/pig/Lib/python3.12/site-packages/pip/_vendor/packaging/_musllinux.py deleted file mode 100644 index 8ac3059..0000000 --- a/backend/pig/Lib/python3.12/site-packages/pip/_vendor/packaging/_musllinux.py +++ /dev/null @@ -1,136 +0,0 @@ -"""PEP 656 support. - -This module implements logic to detect if the currently running Python is -linked against musl, and what musl version is used. -""" - -import contextlib -import functools -import operator -import os -import re -import struct -import subprocess -import sys -from typing import IO, Iterator, NamedTuple, Optional, Tuple - - -def _read_unpacked(f: IO[bytes], fmt: str) -> Tuple[int, ...]: - return struct.unpack(fmt, f.read(struct.calcsize(fmt))) - - -def _parse_ld_musl_from_elf(f: IO[bytes]) -> Optional[str]: - """Detect musl libc location by parsing the Python executable. - - Based on: https://gist.github.com/lyssdod/f51579ae8d93c8657a5564aefc2ffbca - ELF header: https://refspecs.linuxfoundation.org/elf/gabi4+/ch4.eheader.html - """ - f.seek(0) - try: - ident = _read_unpacked(f, "16B") - except struct.error: - return None - if ident[:4] != tuple(b"\x7fELF"): # Invalid magic, not ELF. - return None - f.seek(struct.calcsize("HHI"), 1) # Skip file type, machine, and version. - - try: - # e_fmt: Format for program header. - # p_fmt: Format for section header. - # p_idx: Indexes to find p_type, p_offset, and p_filesz. - e_fmt, p_fmt, p_idx = { - 1: ("IIIIHHH", "IIIIIIII", (0, 1, 4)), # 32-bit. - 2: ("QQQIHHH", "IIQQQQQQ", (0, 2, 5)), # 64-bit. - }[ident[4]] - except KeyError: - return None - else: - p_get = operator.itemgetter(*p_idx) - - # Find the interpreter section and return its content. - try: - _, e_phoff, _, _, _, e_phentsize, e_phnum = _read_unpacked(f, e_fmt) - except struct.error: - return None - for i in range(e_phnum + 1): - f.seek(e_phoff + e_phentsize * i) - try: - p_type, p_offset, p_filesz = p_get(_read_unpacked(f, p_fmt)) - except struct.error: - return None - if p_type != 3: # Not PT_INTERP. - continue - f.seek(p_offset) - interpreter = os.fsdecode(f.read(p_filesz)).strip("\0") - if "musl" not in interpreter: - return None - return interpreter - return None - - -class _MuslVersion(NamedTuple): - major: int - minor: int - - -def _parse_musl_version(output: str) -> Optional[_MuslVersion]: - lines = [n for n in (n.strip() for n in output.splitlines()) if n] - if len(lines) < 2 or lines[0][:4] != "musl": - return None - m = re.match(r"Version (\d+)\.(\d+)", lines[1]) - if not m: - return None - return _MuslVersion(major=int(m.group(1)), minor=int(m.group(2))) - - -@functools.lru_cache() -def _get_musl_version(executable: str) -> Optional[_MuslVersion]: - """Detect currently-running musl runtime version. - - This is done by checking the specified executable's dynamic linking - information, and invoking the loader to parse its output for a version - string. If the loader is musl, the output would be something like:: - - musl libc (x86_64) - Version 1.2.2 - Dynamic Program Loader - """ - with contextlib.ExitStack() as stack: - try: - f = stack.enter_context(open(executable, "rb")) - except OSError: - return None - ld = _parse_ld_musl_from_elf(f) - if not ld: - return None - proc = subprocess.run([ld], stderr=subprocess.PIPE, universal_newlines=True) - return _parse_musl_version(proc.stderr) - - -def platform_tags(arch: str) -> Iterator[str]: - """Generate musllinux tags compatible to the current platform. - - :param arch: Should be the part of platform tag after the ``linux_`` - prefix, e.g. ``x86_64``. The ``linux_`` prefix is assumed as a - prerequisite for the current platform to be musllinux-compatible. - - :returns: An iterator of compatible musllinux tags. - """ - sys_musl = _get_musl_version(sys.executable) - if sys_musl is None: # Python not dynamically linked against musl. - return - for minor in range(sys_musl.minor, -1, -1): - yield f"musllinux_{sys_musl.major}_{minor}_{arch}" - - -if __name__ == "__main__": # pragma: no cover - import sysconfig - - plat = sysconfig.get_platform() - assert plat.startswith("linux-"), "not linux" - - print("plat:", plat) - print("musl:", _get_musl_version(sys.executable)) - print("tags:", end=" ") - for t in platform_tags(re.sub(r"[.-]", "_", plat.split("-", 1)[-1])): - print(t, end="\n ") diff --git a/backend/pig/Lib/python3.12/site-packages/pip/_vendor/packaging/_structures.py b/backend/pig/Lib/python3.12/site-packages/pip/_vendor/packaging/_structures.py deleted file mode 100644 index 90a6465..0000000 --- a/backend/pig/Lib/python3.12/site-packages/pip/_vendor/packaging/_structures.py +++ /dev/null @@ -1,61 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - - -class InfinityType: - def __repr__(self) -> str: - return "Infinity" - - def __hash__(self) -> int: - return hash(repr(self)) - - def __lt__(self, other: object) -> bool: - return False - - def __le__(self, other: object) -> bool: - return False - - def __eq__(self, other: object) -> bool: - return isinstance(other, self.__class__) - - def __gt__(self, other: object) -> bool: - return True - - def __ge__(self, other: object) -> bool: - return True - - def __neg__(self: object) -> "NegativeInfinityType": - return NegativeInfinity - - -Infinity = InfinityType() - - -class NegativeInfinityType: - def __repr__(self) -> str: - return "-Infinity" - - def __hash__(self) -> int: - return hash(repr(self)) - - def __lt__(self, other: object) -> bool: - return True - - def __le__(self, other: object) -> bool: - return True - - def __eq__(self, other: object) -> bool: - return isinstance(other, self.__class__) - - def __gt__(self, other: object) -> bool: - return False - - def __ge__(self, other: object) -> bool: - return False - - def __neg__(self: object) -> InfinityType: - return Infinity - - -NegativeInfinity = NegativeInfinityType() diff --git a/backend/pig/Lib/python3.12/site-packages/pip/_vendor/packaging/markers.py b/backend/pig/Lib/python3.12/site-packages/pip/_vendor/packaging/markers.py deleted file mode 100644 index 540e7a4..0000000 --- a/backend/pig/Lib/python3.12/site-packages/pip/_vendor/packaging/markers.py +++ /dev/null @@ -1,304 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -import operator -import os -import platform -import sys -from typing import Any, Callable, Dict, List, Optional, Tuple, Union - -from pip._vendor.pyparsing import ( # noqa: N817 - Forward, - Group, - Literal as L, - ParseException, - ParseResults, - QuotedString, - ZeroOrMore, - stringEnd, - stringStart, -) - -from .specifiers import InvalidSpecifier, Specifier - -__all__ = [ - "InvalidMarker", - "UndefinedComparison", - "UndefinedEnvironmentName", - "Marker", - "default_environment", -] - -Operator = Callable[[str, str], bool] - - -class InvalidMarker(ValueError): - """ - An invalid marker was found, users should refer to PEP 508. - """ - - -class UndefinedComparison(ValueError): - """ - An invalid operation was attempted on a value that doesn't support it. - """ - - -class UndefinedEnvironmentName(ValueError): - """ - A name was attempted to be used that does not exist inside of the - environment. - """ - - -class Node: - def __init__(self, value: Any) -> None: - self.value = value - - def __str__(self) -> str: - return str(self.value) - - def __repr__(self) -> str: - return f"<{self.__class__.__name__}('{self}')>" - - def serialize(self) -> str: - raise NotImplementedError - - -class Variable(Node): - def serialize(self) -> str: - return str(self) - - -class Value(Node): - def serialize(self) -> str: - return f'"{self}"' - - -class Op(Node): - def serialize(self) -> str: - return str(self) - - -VARIABLE = ( - L("implementation_version") - | L("platform_python_implementation") - | L("implementation_name") - | L("python_full_version") - | L("platform_release") - | L("platform_version") - | L("platform_machine") - | L("platform_system") - | L("python_version") - | L("sys_platform") - | L("os_name") - | L("os.name") # PEP-345 - | L("sys.platform") # PEP-345 - | L("platform.version") # PEP-345 - | L("platform.machine") # PEP-345 - | L("platform.python_implementation") # PEP-345 - | L("python_implementation") # undocumented setuptools legacy - | L("extra") # PEP-508 -) -ALIASES = { - "os.name": "os_name", - "sys.platform": "sys_platform", - "platform.version": "platform_version", - "platform.machine": "platform_machine", - "platform.python_implementation": "platform_python_implementation", - "python_implementation": "platform_python_implementation", -} -VARIABLE.setParseAction(lambda s, l, t: Variable(ALIASES.get(t[0], t[0]))) - -VERSION_CMP = ( - L("===") | L("==") | L(">=") | L("<=") | L("!=") | L("~=") | L(">") | L("<") -) - -MARKER_OP = VERSION_CMP | L("not in") | L("in") -MARKER_OP.setParseAction(lambda s, l, t: Op(t[0])) - -MARKER_VALUE = QuotedString("'") | QuotedString('"') -MARKER_VALUE.setParseAction(lambda s, l, t: Value(t[0])) - -BOOLOP = L("and") | L("or") - -MARKER_VAR = VARIABLE | MARKER_VALUE - -MARKER_ITEM = Group(MARKER_VAR + MARKER_OP + MARKER_VAR) -MARKER_ITEM.setParseAction(lambda s, l, t: tuple(t[0])) - -LPAREN = L("(").suppress() -RPAREN = L(")").suppress() - -MARKER_EXPR = Forward() -MARKER_ATOM = MARKER_ITEM | Group(LPAREN + MARKER_EXPR + RPAREN) -MARKER_EXPR << MARKER_ATOM + ZeroOrMore(BOOLOP + MARKER_EXPR) - -MARKER = stringStart + MARKER_EXPR + stringEnd - - -def _coerce_parse_result(results: Union[ParseResults, List[Any]]) -> List[Any]: - if isinstance(results, ParseResults): - return [_coerce_parse_result(i) for i in results] - else: - return results - - -def _format_marker( - marker: Union[List[str], Tuple[Node, ...], str], first: Optional[bool] = True -) -> str: - - assert isinstance(marker, (list, tuple, str)) - - # Sometimes we have a structure like [[...]] which is a single item list - # where the single item is itself it's own list. In that case we want skip - # the rest of this function so that we don't get extraneous () on the - # outside. - if ( - isinstance(marker, list) - and len(marker) == 1 - and isinstance(marker[0], (list, tuple)) - ): - return _format_marker(marker[0]) - - if isinstance(marker, list): - inner = (_format_marker(m, first=False) for m in marker) - if first: - return " ".join(inner) - else: - return "(" + " ".join(inner) + ")" - elif isinstance(marker, tuple): - return " ".join([m.serialize() for m in marker]) - else: - return marker - - -_operators: Dict[str, Operator] = { - "in": lambda lhs, rhs: lhs in rhs, - "not in": lambda lhs, rhs: lhs not in rhs, - "<": operator.lt, - "<=": operator.le, - "==": operator.eq, - "!=": operator.ne, - ">=": operator.ge, - ">": operator.gt, -} - - -def _eval_op(lhs: str, op: Op, rhs: str) -> bool: - try: - spec = Specifier("".join([op.serialize(), rhs])) - except InvalidSpecifier: - pass - else: - return spec.contains(lhs) - - oper: Optional[Operator] = _operators.get(op.serialize()) - if oper is None: - raise UndefinedComparison(f"Undefined {op!r} on {lhs!r} and {rhs!r}.") - - return oper(lhs, rhs) - - -class Undefined: - pass - - -_undefined = Undefined() - - -def _get_env(environment: Dict[str, str], name: str) -> str: - value: Union[str, Undefined] = environment.get(name, _undefined) - - if isinstance(value, Undefined): - raise UndefinedEnvironmentName( - f"{name!r} does not exist in evaluation environment." - ) - - return value - - -def _evaluate_markers(markers: List[Any], environment: Dict[str, str]) -> bool: - groups: List[List[bool]] = [[]] - - for marker in markers: - assert isinstance(marker, (list, tuple, str)) - - if isinstance(marker, list): - groups[-1].append(_evaluate_markers(marker, environment)) - elif isinstance(marker, tuple): - lhs, op, rhs = marker - - if isinstance(lhs, Variable): - lhs_value = _get_env(environment, lhs.value) - rhs_value = rhs.value - else: - lhs_value = lhs.value - rhs_value = _get_env(environment, rhs.value) - - groups[-1].append(_eval_op(lhs_value, op, rhs_value)) - else: - assert marker in ["and", "or"] - if marker == "or": - groups.append([]) - - return any(all(item) for item in groups) - - -def format_full_version(info: "sys._version_info") -> str: - version = "{0.major}.{0.minor}.{0.micro}".format(info) - kind = info.releaselevel - if kind != "final": - version += kind[0] + str(info.serial) - return version - - -def default_environment() -> Dict[str, str]: - iver = format_full_version(sys.implementation.version) - implementation_name = sys.implementation.name - return { - "implementation_name": implementation_name, - "implementation_version": iver, - "os_name": os.name, - "platform_machine": platform.machine(), - "platform_release": platform.release(), - "platform_system": platform.system(), - "platform_version": platform.version(), - "python_full_version": platform.python_version(), - "platform_python_implementation": platform.python_implementation(), - "python_version": ".".join(platform.python_version_tuple()[:2]), - "sys_platform": sys.platform, - } - - -class Marker: - def __init__(self, marker: str) -> None: - try: - self._markers = _coerce_parse_result(MARKER.parseString(marker)) - except ParseException as e: - raise InvalidMarker( - f"Invalid marker: {marker!r}, parse error at " - f"{marker[e.loc : e.loc + 8]!r}" - ) - - def __str__(self) -> str: - return _format_marker(self._markers) - - def __repr__(self) -> str: - return f" " - - def evaluate(self, environment: Optional[Dict[str, str]] = None) -> bool: - """Evaluate a marker. - - Return the boolean from evaluating the given marker against the - environment. environment is an optional argument to override all or - part of the determined environment. - - The environment is determined from the current Python process. - """ - current_environment = default_environment() - if environment is not None: - current_environment.update(environment) - - return _evaluate_markers(self._markers, current_environment) diff --git a/backend/pig/Lib/python3.12/site-packages/pip/_vendor/packaging/py.typed b/backend/pig/Lib/python3.12/site-packages/pip/_vendor/packaging/py.typed deleted file mode 100644 index e69de29..0000000 diff --git a/backend/pig/Lib/python3.12/site-packages/pip/_vendor/packaging/requirements.py b/backend/pig/Lib/python3.12/site-packages/pip/_vendor/packaging/requirements.py deleted file mode 100644 index 1eab7dd..0000000 --- a/backend/pig/Lib/python3.12/site-packages/pip/_vendor/packaging/requirements.py +++ /dev/null @@ -1,146 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -import re -import string -import urllib.parse -from typing import List, Optional as TOptional, Set - -from pip._vendor.pyparsing import ( # noqa - Combine, - Literal as L, - Optional, - ParseException, - Regex, - Word, - ZeroOrMore, - originalTextFor, - stringEnd, - stringStart, -) - -from .markers import MARKER_EXPR, Marker -from .specifiers import LegacySpecifier, Specifier, SpecifierSet - - -class InvalidRequirement(ValueError): - """ - An invalid requirement was found, users should refer to PEP 508. - """ - - -ALPHANUM = Word(string.ascii_letters + string.digits) - -LBRACKET = L("[").suppress() -RBRACKET = L("]").suppress() -LPAREN = L("(").suppress() -RPAREN = L(")").suppress() -COMMA = L(",").suppress() -SEMICOLON = L(";").suppress() -AT = L("@").suppress() - -PUNCTUATION = Word("-_.") -IDENTIFIER_END = ALPHANUM | (ZeroOrMore(PUNCTUATION) + ALPHANUM) -IDENTIFIER = Combine(ALPHANUM + ZeroOrMore(IDENTIFIER_END)) - -NAME = IDENTIFIER("name") -EXTRA = IDENTIFIER - -URI = Regex(r"[^ ]+")("url") -URL = AT + URI - -EXTRAS_LIST = EXTRA + ZeroOrMore(COMMA + EXTRA) -EXTRAS = (LBRACKET + Optional(EXTRAS_LIST) + RBRACKET)("extras") - -VERSION_PEP440 = Regex(Specifier._regex_str, re.VERBOSE | re.IGNORECASE) -VERSION_LEGACY = Regex(LegacySpecifier._regex_str, re.VERBOSE | re.IGNORECASE) - -VERSION_ONE = VERSION_PEP440 ^ VERSION_LEGACY -VERSION_MANY = Combine( - VERSION_ONE + ZeroOrMore(COMMA + VERSION_ONE), joinString=",", adjacent=False -)("_raw_spec") -_VERSION_SPEC = Optional((LPAREN + VERSION_MANY + RPAREN) | VERSION_MANY) -_VERSION_SPEC.setParseAction(lambda s, l, t: t._raw_spec or "") - -VERSION_SPEC = originalTextFor(_VERSION_SPEC)("specifier") -VERSION_SPEC.setParseAction(lambda s, l, t: t[1]) - -MARKER_EXPR = originalTextFor(MARKER_EXPR())("marker") -MARKER_EXPR.setParseAction( - lambda s, l, t: Marker(s[t._original_start : t._original_end]) -) -MARKER_SEPARATOR = SEMICOLON -MARKER = MARKER_SEPARATOR + MARKER_EXPR - -VERSION_AND_MARKER = VERSION_SPEC + Optional(MARKER) -URL_AND_MARKER = URL + Optional(MARKER) - -NAMED_REQUIREMENT = NAME + Optional(EXTRAS) + (URL_AND_MARKER | VERSION_AND_MARKER) - -REQUIREMENT = stringStart + NAMED_REQUIREMENT + stringEnd -# pyparsing isn't thread safe during initialization, so we do it eagerly, see -# issue #104 -REQUIREMENT.parseString("x[]") - - -class Requirement: - """Parse a requirement. - - Parse a given requirement string into its parts, such as name, specifier, - URL, and extras. Raises InvalidRequirement on a badly-formed requirement - string. - """ - - # TODO: Can we test whether something is contained within a requirement? - # If so how do we do that? Do we need to test against the _name_ of - # the thing as well as the version? What about the markers? - # TODO: Can we normalize the name and extra name? - - def __init__(self, requirement_string: str) -> None: - try: - req = REQUIREMENT.parseString(requirement_string) - except ParseException as e: - raise InvalidRequirement( - f'Parse error at "{ requirement_string[e.loc : e.loc + 8]!r}": {e.msg}' - ) - - self.name: str = req.name - if req.url: - parsed_url = urllib.parse.urlparse(req.url) - if parsed_url.scheme == "file": - if urllib.parse.urlunparse(parsed_url) != req.url: - raise InvalidRequirement("Invalid URL given") - elif not (parsed_url.scheme and parsed_url.netloc) or ( - not parsed_url.scheme and not parsed_url.netloc - ): - raise InvalidRequirement(f"Invalid URL: {req.url}") - self.url: TOptional[str] = req.url - else: - self.url = None - self.extras: Set[str] = set(req.extras.asList() if req.extras else []) - self.specifier: SpecifierSet = SpecifierSet(req.specifier) - self.marker: TOptional[Marker] = req.marker if req.marker else None - - def __str__(self) -> str: - parts: List[str] = [self.name] - - if self.extras: - formatted_extras = ",".join(sorted(self.extras)) - parts.append(f"[{formatted_extras}]") - - if self.specifier: - parts.append(str(self.specifier)) - - if self.url: - parts.append(f"@ {self.url}") - if self.marker: - parts.append(" ") - - if self.marker: - parts.append(f"; {self.marker}") - - return "".join(parts) - - def __repr__(self) -> str: - return f" " diff --git a/backend/pig/Lib/python3.12/site-packages/pip/_vendor/packaging/specifiers.py b/backend/pig/Lib/python3.12/site-packages/pip/_vendor/packaging/specifiers.py deleted file mode 100644 index 0e218a6..0000000 --- a/backend/pig/Lib/python3.12/site-packages/pip/_vendor/packaging/specifiers.py +++ /dev/null @@ -1,802 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -import abc -import functools -import itertools -import re -import warnings -from typing import ( - Callable, - Dict, - Iterable, - Iterator, - List, - Optional, - Pattern, - Set, - Tuple, - TypeVar, - Union, -) - -from .utils import canonicalize_version -from .version import LegacyVersion, Version, parse - -ParsedVersion = Union[Version, LegacyVersion] -UnparsedVersion = Union[Version, LegacyVersion, str] -VersionTypeVar = TypeVar("VersionTypeVar", bound=UnparsedVersion) -CallableOperator = Callable[[ParsedVersion, str], bool] - - -class InvalidSpecifier(ValueError): - """ - An invalid specifier was found, users should refer to PEP 440. - """ - - -class BaseSpecifier(metaclass=abc.ABCMeta): - @abc.abstractmethod - def __str__(self) -> str: - """ - Returns the str representation of this Specifier like object. This - should be representative of the Specifier itself. - """ - - @abc.abstractmethod - def __hash__(self) -> int: - """ - Returns a hash value for this Specifier like object. - """ - - @abc.abstractmethod - def __eq__(self, other: object) -> bool: - """ - Returns a boolean representing whether or not the two Specifier like - objects are equal. - """ - - @abc.abstractproperty - def prereleases(self) -> Optional[bool]: - """ - Returns whether or not pre-releases as a whole are allowed by this - specifier. - """ - - @prereleases.setter - def prereleases(self, value: bool) -> None: - """ - Sets whether or not pre-releases as a whole are allowed by this - specifier. - """ - - @abc.abstractmethod - def contains(self, item: str, prereleases: Optional[bool] = None) -> bool: - """ - Determines if the given item is contained within this specifier. - """ - - @abc.abstractmethod - def filter( - self, iterable: Iterable[VersionTypeVar], prereleases: Optional[bool] = None - ) -> Iterable[VersionTypeVar]: - """ - Takes an iterable of items and filters them so that only items which - are contained within this specifier are allowed in it. - """ - - -class _IndividualSpecifier(BaseSpecifier): - - _operators: Dict[str, str] = {} - _regex: Pattern[str] - - def __init__(self, spec: str = "", prereleases: Optional[bool] = None) -> None: - match = self._regex.search(spec) - if not match: - raise InvalidSpecifier(f"Invalid specifier: '{spec}'") - - self._spec: Tuple[str, str] = ( - match.group("operator").strip(), - match.group("version").strip(), - ) - - # Store whether or not this Specifier should accept prereleases - self._prereleases = prereleases - - def __repr__(self) -> str: - pre = ( - f", prereleases={self.prereleases!r}" - if self._prereleases is not None - else "" - ) - - return f"<{self.__class__.__name__}({str(self)!r}{pre})>" - - def __str__(self) -> str: - return "{}{}".format(*self._spec) - - @property - def _canonical_spec(self) -> Tuple[str, str]: - return self._spec[0], canonicalize_version(self._spec[1]) - - def __hash__(self) -> int: - return hash(self._canonical_spec) - - def __eq__(self, other: object) -> bool: - if isinstance(other, str): - try: - other = self.__class__(str(other)) - except InvalidSpecifier: - return NotImplemented - elif not isinstance(other, self.__class__): - return NotImplemented - - return self._canonical_spec == other._canonical_spec - - def _get_operator(self, op: str) -> CallableOperator: - operator_callable: CallableOperator = getattr( - self, f"_compare_{self._operators[op]}" - ) - return operator_callable - - def _coerce_version(self, version: UnparsedVersion) -> ParsedVersion: - if not isinstance(version, (LegacyVersion, Version)): - version = parse(version) - return version - - @property - def operator(self) -> str: - return self._spec[0] - - @property - def version(self) -> str: - return self._spec[1] - - @property - def prereleases(self) -> Optional[bool]: - return self._prereleases - - @prereleases.setter - def prereleases(self, value: bool) -> None: - self._prereleases = value - - def __contains__(self, item: str) -> bool: - return self.contains(item) - - def contains( - self, item: UnparsedVersion, prereleases: Optional[bool] = None - ) -> bool: - - # Determine if prereleases are to be allowed or not. - if prereleases is None: - prereleases = self.prereleases - - # Normalize item to a Version or LegacyVersion, this allows us to have - # a shortcut for ``"2.0" in Specifier(">=2") - normalized_item = self._coerce_version(item) - - # Determine if we should be supporting prereleases in this specifier - # or not, if we do not support prereleases than we can short circuit - # logic if this version is a prereleases. - if normalized_item.is_prerelease and not prereleases: - return False - - # Actually do the comparison to determine if this item is contained - # within this Specifier or not. - operator_callable: CallableOperator = self._get_operator(self.operator) - return operator_callable(normalized_item, self.version) - - def filter( - self, iterable: Iterable[VersionTypeVar], prereleases: Optional[bool] = None - ) -> Iterable[VersionTypeVar]: - - yielded = False - found_prereleases = [] - - kw = {"prereleases": prereleases if prereleases is not None else True} - - # Attempt to iterate over all the values in the iterable and if any of - # them match, yield them. - for version in iterable: - parsed_version = self._coerce_version(version) - - if self.contains(parsed_version, **kw): - # If our version is a prerelease, and we were not set to allow - # prereleases, then we'll store it for later in case nothing - # else matches this specifier. - if parsed_version.is_prerelease and not ( - prereleases or self.prereleases - ): - found_prereleases.append(version) - # Either this is not a prerelease, or we should have been - # accepting prereleases from the beginning. - else: - yielded = True - yield version - - # Now that we've iterated over everything, determine if we've yielded - # any values, and if we have not and we have any prereleases stored up - # then we will go ahead and yield the prereleases. - if not yielded and found_prereleases: - for version in found_prereleases: - yield version - - -class LegacySpecifier(_IndividualSpecifier): - - _regex_str = r""" - (?P (==|!=|<=|>=|<|>)) - \s* - (?P - [^,;\s)]* # Since this is a "legacy" specifier, and the version - # string can be just about anything, we match everything - # except for whitespace, a semi-colon for marker support, - # a closing paren since versions can be enclosed in - # them, and a comma since it's a version separator. - ) - """ - - _regex = re.compile(r"^\s*" + _regex_str + r"\s*$", re.VERBOSE | re.IGNORECASE) - - _operators = { - "==": "equal", - "!=": "not_equal", - "<=": "less_than_equal", - ">=": "greater_than_equal", - "<": "less_than", - ">": "greater_than", - } - - def __init__(self, spec: str = "", prereleases: Optional[bool] = None) -> None: - super().__init__(spec, prereleases) - - warnings.warn( - "Creating a LegacyVersion has been deprecated and will be " - "removed in the next major release", - DeprecationWarning, - ) - - def _coerce_version(self, version: UnparsedVersion) -> LegacyVersion: - if not isinstance(version, LegacyVersion): - version = LegacyVersion(str(version)) - return version - - def _compare_equal(self, prospective: LegacyVersion, spec: str) -> bool: - return prospective == self._coerce_version(spec) - - def _compare_not_equal(self, prospective: LegacyVersion, spec: str) -> bool: - return prospective != self._coerce_version(spec) - - def _compare_less_than_equal(self, prospective: LegacyVersion, spec: str) -> bool: - return prospective <= self._coerce_version(spec) - - def _compare_greater_than_equal( - self, prospective: LegacyVersion, spec: str - ) -> bool: - return prospective >= self._coerce_version(spec) - - def _compare_less_than(self, prospective: LegacyVersion, spec: str) -> bool: - return prospective < self._coerce_version(spec) - - def _compare_greater_than(self, prospective: LegacyVersion, spec: str) -> bool: - return prospective > self._coerce_version(spec) - - -def _require_version_compare( - fn: Callable[["Specifier", ParsedVersion, str], bool] -) -> Callable[["Specifier", ParsedVersion, str], bool]: - @functools.wraps(fn) - def wrapped(self: "Specifier", prospective: ParsedVersion, spec: str) -> bool: - if not isinstance(prospective, Version): - return False - return fn(self, prospective, spec) - - return wrapped - - -class Specifier(_IndividualSpecifier): - - _regex_str = r""" - (?P (~=|==|!=|<=|>=|<|>|===)) - (?P - (?: - # The identity operators allow for an escape hatch that will - # do an exact string match of the version you wish to install. - # This will not be parsed by PEP 440 and we cannot determine - # any semantic meaning from it. This operator is discouraged - # but included entirely as an escape hatch. - (?<====) # Only match for the identity operator - \s* - [^\s]* # We just match everything, except for whitespace - # since we are only testing for strict identity. - ) - | - (?: - # The (non)equality operators allow for wild card and local - # versions to be specified so we have to define these two - # operators separately to enable that. - (?<===|!=) # Only match for equals and not equals - - \s* - v? - (?:[0-9]+!)? # epoch - [0-9]+(?:\.[0-9]+)* # release - (?: # pre release - [-_\.]? - (a|b|c|rc|alpha|beta|pre|preview) - [-_\.]? - [0-9]* - )? - (?: # post release - (?:-[0-9]+)|(?:[-_\.]?(post|rev|r)[-_\.]?[0-9]*) - )? - - # You cannot use a wild card and a dev or local version - # together so group them with a | and make them optional. - (?: - (?:[-_\.]?dev[-_\.]?[0-9]*)? # dev release - (?:\+[a-z0-9]+(?:[-_\.][a-z0-9]+)*)? # local - | - \.\* # Wild card syntax of .* - )? - ) - | - (?: - # The compatible operator requires at least two digits in the - # release segment. - (?<=~=) # Only match for the compatible operator - - \s* - v? - (?:[0-9]+!)? # epoch - [0-9]+(?:\.[0-9]+)+ # release (We have a + instead of a *) - (?: # pre release - [-_\.]? - (a|b|c|rc|alpha|beta|pre|preview) - [-_\.]? - [0-9]* - )? - (?: # post release - (?:-[0-9]+)|(?:[-_\.]?(post|rev|r)[-_\.]?[0-9]*) - )? - (?:[-_\.]?dev[-_\.]?[0-9]*)? # dev release - ) - | - (?: - # All other operators only allow a sub set of what the - # (non)equality operators do. Specifically they do not allow - # local versions to be specified nor do they allow the prefix - # matching wild cards. - (?=": "greater_than_equal", - "<": "less_than", - ">": "greater_than", - "===": "arbitrary", - } - - @_require_version_compare - def _compare_compatible(self, prospective: ParsedVersion, spec: str) -> bool: - - # Compatible releases have an equivalent combination of >= and ==. That - # is that ~=2.2 is equivalent to >=2.2,==2.*. This allows us to - # implement this in terms of the other specifiers instead of - # implementing it ourselves. The only thing we need to do is construct - # the other specifiers. - - # We want everything but the last item in the version, but we want to - # ignore suffix segments. - prefix = ".".join( - list(itertools.takewhile(_is_not_suffix, _version_split(spec)))[:-1] - ) - - # Add the prefix notation to the end of our string - prefix += ".*" - - return self._get_operator(">=")(prospective, spec) and self._get_operator("==")( - prospective, prefix - ) - - @_require_version_compare - def _compare_equal(self, prospective: ParsedVersion, spec: str) -> bool: - - # We need special logic to handle prefix matching - if spec.endswith(".*"): - # In the case of prefix matching we want to ignore local segment. - prospective = Version(prospective.public) - # Split the spec out by dots, and pretend that there is an implicit - # dot in between a release segment and a pre-release segment. - split_spec = _version_split(spec[:-2]) # Remove the trailing .* - - # Split the prospective version out by dots, and pretend that there - # is an implicit dot in between a release segment and a pre-release - # segment. - split_prospective = _version_split(str(prospective)) - - # Shorten the prospective version to be the same length as the spec - # so that we can determine if the specifier is a prefix of the - # prospective version or not. - shortened_prospective = split_prospective[: len(split_spec)] - - # Pad out our two sides with zeros so that they both equal the same - # length. - padded_spec, padded_prospective = _pad_version( - split_spec, shortened_prospective - ) - - return padded_prospective == padded_spec - else: - # Convert our spec string into a Version - spec_version = Version(spec) - - # If the specifier does not have a local segment, then we want to - # act as if the prospective version also does not have a local - # segment. - if not spec_version.local: - prospective = Version(prospective.public) - - return prospective == spec_version - - @_require_version_compare - def _compare_not_equal(self, prospective: ParsedVersion, spec: str) -> bool: - return not self._compare_equal(prospective, spec) - - @_require_version_compare - def _compare_less_than_equal(self, prospective: ParsedVersion, spec: str) -> bool: - - # NB: Local version identifiers are NOT permitted in the version - # specifier, so local version labels can be universally removed from - # the prospective version. - return Version(prospective.public) <= Version(spec) - - @_require_version_compare - def _compare_greater_than_equal( - self, prospective: ParsedVersion, spec: str - ) -> bool: - - # NB: Local version identifiers are NOT permitted in the version - # specifier, so local version labels can be universally removed from - # the prospective version. - return Version(prospective.public) >= Version(spec) - - @_require_version_compare - def _compare_less_than(self, prospective: ParsedVersion, spec_str: str) -> bool: - - # Convert our spec to a Version instance, since we'll want to work with - # it as a version. - spec = Version(spec_str) - - # Check to see if the prospective version is less than the spec - # version. If it's not we can short circuit and just return False now - # instead of doing extra unneeded work. - if not prospective < spec: - return False - - # This special case is here so that, unless the specifier itself - # includes is a pre-release version, that we do not accept pre-release - # versions for the version mentioned in the specifier (e.g. <3.1 should - # not match 3.1.dev0, but should match 3.0.dev0). - if not spec.is_prerelease and prospective.is_prerelease: - if Version(prospective.base_version) == Version(spec.base_version): - return False - - # If we've gotten to here, it means that prospective version is both - # less than the spec version *and* it's not a pre-release of the same - # version in the spec. - return True - - @_require_version_compare - def _compare_greater_than(self, prospective: ParsedVersion, spec_str: str) -> bool: - - # Convert our spec to a Version instance, since we'll want to work with - # it as a version. - spec = Version(spec_str) - - # Check to see if the prospective version is greater than the spec - # version. If it's not we can short circuit and just return False now - # instead of doing extra unneeded work. - if not prospective > spec: - return False - - # This special case is here so that, unless the specifier itself - # includes is a post-release version, that we do not accept - # post-release versions for the version mentioned in the specifier - # (e.g. >3.1 should not match 3.0.post0, but should match 3.2.post0). - if not spec.is_postrelease and prospective.is_postrelease: - if Version(prospective.base_version) == Version(spec.base_version): - return False - - # Ensure that we do not allow a local version of the version mentioned - # in the specifier, which is technically greater than, to match. - if prospective.local is not None: - if Version(prospective.base_version) == Version(spec.base_version): - return False - - # If we've gotten to here, it means that prospective version is both - # greater than the spec version *and* it's not a pre-release of the - # same version in the spec. - return True - - def _compare_arbitrary(self, prospective: Version, spec: str) -> bool: - return str(prospective).lower() == str(spec).lower() - - @property - def prereleases(self) -> bool: - - # If there is an explicit prereleases set for this, then we'll just - # blindly use that. - if self._prereleases is not None: - return self._prereleases - - # Look at all of our specifiers and determine if they are inclusive - # operators, and if they are if they are including an explicit - # prerelease. - operator, version = self._spec - if operator in ["==", ">=", "<=", "~=", "==="]: - # The == specifier can include a trailing .*, if it does we - # want to remove before parsing. - if operator == "==" and version.endswith(".*"): - version = version[:-2] - - # Parse the version, and if it is a pre-release than this - # specifier allows pre-releases. - if parse(version).is_prerelease: - return True - - return False - - @prereleases.setter - def prereleases(self, value: bool) -> None: - self._prereleases = value - - -_prefix_regex = re.compile(r"^([0-9]+)((?:a|b|c|rc)[0-9]+)$") - - -def _version_split(version: str) -> List[str]: - result: List[str] = [] - for item in version.split("."): - match = _prefix_regex.search(item) - if match: - result.extend(match.groups()) - else: - result.append(item) - return result - - -def _is_not_suffix(segment: str) -> bool: - return not any( - segment.startswith(prefix) for prefix in ("dev", "a", "b", "rc", "post") - ) - - -def _pad_version(left: List[str], right: List[str]) -> Tuple[List[str], List[str]]: - left_split, right_split = [], [] - - # Get the release segment of our versions - left_split.append(list(itertools.takewhile(lambda x: x.isdigit(), left))) - right_split.append(list(itertools.takewhile(lambda x: x.isdigit(), right))) - - # Get the rest of our versions - left_split.append(left[len(left_split[0]) :]) - right_split.append(right[len(right_split[0]) :]) - - # Insert our padding - left_split.insert(1, ["0"] * max(0, len(right_split[0]) - len(left_split[0]))) - right_split.insert(1, ["0"] * max(0, len(left_split[0]) - len(right_split[0]))) - - return (list(itertools.chain(*left_split)), list(itertools.chain(*right_split))) - - -class SpecifierSet(BaseSpecifier): - def __init__( - self, specifiers: str = "", prereleases: Optional[bool] = None - ) -> None: - - # Split on , to break each individual specifier into it's own item, and - # strip each item to remove leading/trailing whitespace. - split_specifiers = [s.strip() for s in specifiers.split(",") if s.strip()] - - # Parsed each individual specifier, attempting first to make it a - # Specifier and falling back to a LegacySpecifier. - parsed: Set[_IndividualSpecifier] = set() - for specifier in split_specifiers: - try: - parsed.add(Specifier(specifier)) - except InvalidSpecifier: - parsed.add(LegacySpecifier(specifier)) - - # Turn our parsed specifiers into a frozen set and save them for later. - self._specs = frozenset(parsed) - - # Store our prereleases value so we can use it later to determine if - # we accept prereleases or not. - self._prereleases = prereleases - - def __repr__(self) -> str: - pre = ( - f", prereleases={self.prereleases!r}" - if self._prereleases is not None - else "" - ) - - return f" " - - def __str__(self) -> str: - return ",".join(sorted(str(s) for s in self._specs)) - - def __hash__(self) -> int: - return hash(self._specs) - - def __and__(self, other: Union["SpecifierSet", str]) -> "SpecifierSet": - if isinstance(other, str): - other = SpecifierSet(other) - elif not isinstance(other, SpecifierSet): - return NotImplemented - - specifier = SpecifierSet() - specifier._specs = frozenset(self._specs | other._specs) - - if self._prereleases is None and other._prereleases is not None: - specifier._prereleases = other._prereleases - elif self._prereleases is not None and other._prereleases is None: - specifier._prereleases = self._prereleases - elif self._prereleases == other._prereleases: - specifier._prereleases = self._prereleases - else: - raise ValueError( - "Cannot combine SpecifierSets with True and False prerelease " - "overrides." - ) - - return specifier - - def __eq__(self, other: object) -> bool: - if isinstance(other, (str, _IndividualSpecifier)): - other = SpecifierSet(str(other)) - elif not isinstance(other, SpecifierSet): - return NotImplemented - - return self._specs == other._specs - - def __len__(self) -> int: - return len(self._specs) - - def __iter__(self) -> Iterator[_IndividualSpecifier]: - return iter(self._specs) - - @property - def prereleases(self) -> Optional[bool]: - - # If we have been given an explicit prerelease modifier, then we'll - # pass that through here. - if self._prereleases is not None: - return self._prereleases - - # If we don't have any specifiers, and we don't have a forced value, - # then we'll just return None since we don't know if this should have - # pre-releases or not. - if not self._specs: - return None - - # Otherwise we'll see if any of the given specifiers accept - # prereleases, if any of them do we'll return True, otherwise False. - return any(s.prereleases for s in self._specs) - - @prereleases.setter - def prereleases(self, value: bool) -> None: - self._prereleases = value - - def __contains__(self, item: UnparsedVersion) -> bool: - return self.contains(item) - - def contains( - self, item: UnparsedVersion, prereleases: Optional[bool] = None - ) -> bool: - - # Ensure that our item is a Version or LegacyVersion instance. - if not isinstance(item, (LegacyVersion, Version)): - item = parse(item) - - # Determine if we're forcing a prerelease or not, if we're not forcing - # one for this particular filter call, then we'll use whatever the - # SpecifierSet thinks for whether or not we should support prereleases. - if prereleases is None: - prereleases = self.prereleases - - # We can determine if we're going to allow pre-releases by looking to - # see if any of the underlying items supports them. If none of them do - # and this item is a pre-release then we do not allow it and we can - # short circuit that here. - # Note: This means that 1.0.dev1 would not be contained in something - # like >=1.0.devabc however it would be in >=1.0.debabc,>0.0.dev0 - if not prereleases and item.is_prerelease: - return False - - # We simply dispatch to the underlying specs here to make sure that the - # given version is contained within all of them. - # Note: This use of all() here means that an empty set of specifiers - # will always return True, this is an explicit design decision. - return all(s.contains(item, prereleases=prereleases) for s in self._specs) - - def filter( - self, iterable: Iterable[VersionTypeVar], prereleases: Optional[bool] = None - ) -> Iterable[VersionTypeVar]: - - # Determine if we're forcing a prerelease or not, if we're not forcing - # one for this particular filter call, then we'll use whatever the - # SpecifierSet thinks for whether or not we should support prereleases. - if prereleases is None: - prereleases = self.prereleases - - # If we have any specifiers, then we want to wrap our iterable in the - # filter method for each one, this will act as a logical AND amongst - # each specifier. - if self._specs: - for spec in self._specs: - iterable = spec.filter(iterable, prereleases=bool(prereleases)) - return iterable - # If we do not have any specifiers, then we need to have a rough filter - # which will filter out any pre-releases, unless there are no final - # releases, and which will filter out LegacyVersion in general. - else: - filtered: List[VersionTypeVar] = [] - found_prereleases: List[VersionTypeVar] = [] - - item: UnparsedVersion - parsed_version: Union[Version, LegacyVersion] - - for item in iterable: - # Ensure that we some kind of Version class for this item. - if not isinstance(item, (LegacyVersion, Version)): - parsed_version = parse(item) - else: - parsed_version = item - - # Filter out any item which is parsed as a LegacyVersion - if isinstance(parsed_version, LegacyVersion): - continue - - # Store any item which is a pre-release for later unless we've - # already found a final version or we are accepting prereleases - if parsed_version.is_prerelease and not prereleases: - if not filtered: - found_prereleases.append(item) - else: - filtered.append(item) - - # If we've found no items except for pre-releases, then we'll go - # ahead and use the pre-releases - if not filtered and found_prereleases and prereleases is None: - return found_prereleases - - return filtered diff --git a/backend/pig/Lib/python3.12/site-packages/pip/_vendor/packaging/tags.py b/backend/pig/Lib/python3.12/site-packages/pip/_vendor/packaging/tags.py deleted file mode 100644 index 9a3d25a..0000000 --- a/backend/pig/Lib/python3.12/site-packages/pip/_vendor/packaging/tags.py +++ /dev/null @@ -1,487 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -import logging -import platform -import sys -import sysconfig -from importlib.machinery import EXTENSION_SUFFIXES -from typing import ( - Dict, - FrozenSet, - Iterable, - Iterator, - List, - Optional, - Sequence, - Tuple, - Union, - cast, -) - -from . import _manylinux, _musllinux - -logger = logging.getLogger(__name__) - -PythonVersion = Sequence[int] -MacVersion = Tuple[int, int] - -INTERPRETER_SHORT_NAMES: Dict[str, str] = { - "python": "py", # Generic. - "cpython": "cp", - "pypy": "pp", - "ironpython": "ip", - "jython": "jy", -} - - -_32_BIT_INTERPRETER = sys.maxsize <= 2 ** 32 - - -class Tag: - """ - A representation of the tag triple for a wheel. - - Instances are considered immutable and thus are hashable. Equality checking - is also supported. - """ - - __slots__ = ["_interpreter", "_abi", "_platform", "_hash"] - - def __init__(self, interpreter: str, abi: str, platform: str) -> None: - self._interpreter = interpreter.lower() - self._abi = abi.lower() - self._platform = platform.lower() - # The __hash__ of every single element in a Set[Tag] will be evaluated each time - # that a set calls its `.disjoint()` method, which may be called hundreds of - # times when scanning a page of links for packages with tags matching that - # Set[Tag]. Pre-computing the value here produces significant speedups for - # downstream consumers. - self._hash = hash((self._interpreter, self._abi, self._platform)) - - @property - def interpreter(self) -> str: - return self._interpreter - - @property - def abi(self) -> str: - return self._abi - - @property - def platform(self) -> str: - return self._platform - - def __eq__(self, other: object) -> bool: - if not isinstance(other, Tag): - return NotImplemented - - return ( - (self._hash == other._hash) # Short-circuit ASAP for perf reasons. - and (self._platform == other._platform) - and (self._abi == other._abi) - and (self._interpreter == other._interpreter) - ) - - def __hash__(self) -> int: - return self._hash - - def __str__(self) -> str: - return f"{self._interpreter}-{self._abi}-{self._platform}" - - def __repr__(self) -> str: - return f"<{self} @ {id(self)}>" - - -def parse_tag(tag: str) -> FrozenSet[Tag]: - """ - Parses the provided tag (e.g. `py3-none-any`) into a frozenset of Tag instances. - - Returning a set is required due to the possibility that the tag is a - compressed tag set. - """ - tags = set() - interpreters, abis, platforms = tag.split("-") - for interpreter in interpreters.split("."): - for abi in abis.split("."): - for platform_ in platforms.split("."): - tags.add(Tag(interpreter, abi, platform_)) - return frozenset(tags) - - -def _get_config_var(name: str, warn: bool = False) -> Union[int, str, None]: - value = sysconfig.get_config_var(name) - if value is None and warn: - logger.debug( - "Config variable '%s' is unset, Python ABI tag may be incorrect", name - ) - return value - - -def _normalize_string(string: str) -> str: - return string.replace(".", "_").replace("-", "_") - - -def _abi3_applies(python_version: PythonVersion) -> bool: - """ - Determine if the Python version supports abi3. - - PEP 384 was first implemented in Python 3.2. - """ - return len(python_version) > 1 and tuple(python_version) >= (3, 2) - - -def _cpython_abis(py_version: PythonVersion, warn: bool = False) -> List[str]: - py_version = tuple(py_version) # To allow for version comparison. - abis = [] - version = _version_nodot(py_version[:2]) - debug = pymalloc = ucs4 = "" - with_debug = _get_config_var("Py_DEBUG", warn) - has_refcount = hasattr(sys, "gettotalrefcount") - # Windows doesn't set Py_DEBUG, so checking for support of debug-compiled - # extension modules is the best option. - # https://github.com/pypa/pip/issues/3383#issuecomment-173267692 - has_ext = "_d.pyd" in EXTENSION_SUFFIXES - if with_debug or (with_debug is None and (has_refcount or has_ext)): - debug = "d" - if py_version < (3, 8): - with_pymalloc = _get_config_var("WITH_PYMALLOC", warn) - if with_pymalloc or with_pymalloc is None: - pymalloc = "m" - if py_version < (3, 3): - unicode_size = _get_config_var("Py_UNICODE_SIZE", warn) - if unicode_size == 4 or ( - unicode_size is None and sys.maxunicode == 0x10FFFF - ): - ucs4 = "u" - elif debug: - # Debug builds can also load "normal" extension modules. - # We can also assume no UCS-4 or pymalloc requirement. - abis.append(f"cp{version}") - abis.insert( - 0, - "cp{version}{debug}{pymalloc}{ucs4}".format( - version=version, debug=debug, pymalloc=pymalloc, ucs4=ucs4 - ), - ) - return abis - - -def cpython_tags( - python_version: Optional[PythonVersion] = None, - abis: Optional[Iterable[str]] = None, - platforms: Optional[Iterable[str]] = None, - *, - warn: bool = False, -) -> Iterator[Tag]: - """ - Yields the tags for a CPython interpreter. - - The tags consist of: - - cp - - - - cp -abi3- - - cp -none- - - cp -abi3- # Older Python versions down to 3.2. - - If python_version only specifies a major version then user-provided ABIs and - the 'none' ABItag will be used. - - If 'abi3' or 'none' are specified in 'abis' then they will be yielded at - their normal position and not at the beginning. - """ - if not python_version: - python_version = sys.version_info[:2] - - interpreter = f"cp{_version_nodot(python_version[:2])}" - - if abis is None: - if len(python_version) > 1: - abis = _cpython_abis(python_version, warn) - else: - abis = [] - abis = list(abis) - # 'abi3' and 'none' are explicitly handled later. - for explicit_abi in ("abi3", "none"): - try: - abis.remove(explicit_abi) - except ValueError: - pass - - platforms = list(platforms or platform_tags()) - for abi in abis: - for platform_ in platforms: - yield Tag(interpreter, abi, platform_) - if _abi3_applies(python_version): - yield from (Tag(interpreter, "abi3", platform_) for platform_ in platforms) - yield from (Tag(interpreter, "none", platform_) for platform_ in platforms) - - if _abi3_applies(python_version): - for minor_version in range(python_version[1] - 1, 1, -1): - for platform_ in platforms: - interpreter = "cp{version}".format( - version=_version_nodot((python_version[0], minor_version)) - ) - yield Tag(interpreter, "abi3", platform_) - - -def _generic_abi() -> Iterator[str]: - abi = sysconfig.get_config_var("SOABI") - if abi: - yield _normalize_string(abi) - - -def generic_tags( - interpreter: Optional[str] = None, - abis: Optional[Iterable[str]] = None, - platforms: Optional[Iterable[str]] = None, - *, - warn: bool = False, -) -> Iterator[Tag]: - """ - Yields the tags for a generic interpreter. - - The tags consist of: - - - - - - The "none" ABI will be added if it was not explicitly provided. - """ - if not interpreter: - interp_name = interpreter_name() - interp_version = interpreter_version(warn=warn) - interpreter = "".join([interp_name, interp_version]) - if abis is None: - abis = _generic_abi() - platforms = list(platforms or platform_tags()) - abis = list(abis) - if "none" not in abis: - abis.append("none") - for abi in abis: - for platform_ in platforms: - yield Tag(interpreter, abi, platform_) - - -def _py_interpreter_range(py_version: PythonVersion) -> Iterator[str]: - """ - Yields Python versions in descending order. - - After the latest version, the major-only version will be yielded, and then - all previous versions of that major version. - """ - if len(py_version) > 1: - yield f"py{_version_nodot(py_version[:2])}" - yield f"py{py_version[0]}" - if len(py_version) > 1: - for minor in range(py_version[1] - 1, -1, -1): - yield f"py{_version_nodot((py_version[0], minor))}" - - -def compatible_tags( - python_version: Optional[PythonVersion] = None, - interpreter: Optional[str] = None, - platforms: Optional[Iterable[str]] = None, -) -> Iterator[Tag]: - """ - Yields the sequence of tags that are compatible with a specific version of Python. - - The tags consist of: - - py*-none- - - -none-any # ... if `interpreter` is provided. - - py*-none-any - """ - if not python_version: - python_version = sys.version_info[:2] - platforms = list(platforms or platform_tags()) - for version in _py_interpreter_range(python_version): - for platform_ in platforms: - yield Tag(version, "none", platform_) - if interpreter: - yield Tag(interpreter, "none", "any") - for version in _py_interpreter_range(python_version): - yield Tag(version, "none", "any") - - -def _mac_arch(arch: str, is_32bit: bool = _32_BIT_INTERPRETER) -> str: - if not is_32bit: - return arch - - if arch.startswith("ppc"): - return "ppc" - - return "i386" - - -def _mac_binary_formats(version: MacVersion, cpu_arch: str) -> List[str]: - formats = [cpu_arch] - if cpu_arch == "x86_64": - if version < (10, 4): - return [] - formats.extend(["intel", "fat64", "fat32"]) - - elif cpu_arch == "i386": - if version < (10, 4): - return [] - formats.extend(["intel", "fat32", "fat"]) - - elif cpu_arch == "ppc64": - # TODO: Need to care about 32-bit PPC for ppc64 through 10.2? - if version > (10, 5) or version < (10, 4): - return [] - formats.append("fat64") - - elif cpu_arch == "ppc": - if version > (10, 6): - return [] - formats.extend(["fat32", "fat"]) - - if cpu_arch in {"arm64", "x86_64"}: - formats.append("universal2") - - if cpu_arch in {"x86_64", "i386", "ppc64", "ppc", "intel"}: - formats.append("universal") - - return formats - - -def mac_platforms( - version: Optional[MacVersion] = None, arch: Optional[str] = None -) -> Iterator[str]: - """ - Yields the platform tags for a macOS system. - - The `version` parameter is a two-item tuple specifying the macOS version to - generate platform tags for. The `arch` parameter is the CPU architecture to - generate platform tags for. Both parameters default to the appropriate value - for the current system. - """ - version_str, _, cpu_arch = platform.mac_ver() - if version is None: - version = cast("MacVersion", tuple(map(int, version_str.split(".")[:2]))) - else: - version = version - if arch is None: - arch = _mac_arch(cpu_arch) - else: - arch = arch - - if (10, 0) <= version and version < (11, 0): - # Prior to Mac OS 11, each yearly release of Mac OS bumped the - # "minor" version number. The major version was always 10. - for minor_version in range(version[1], -1, -1): - compat_version = 10, minor_version - binary_formats = _mac_binary_formats(compat_version, arch) - for binary_format in binary_formats: - yield "macosx_{major}_{minor}_{binary_format}".format( - major=10, minor=minor_version, binary_format=binary_format - ) - - if version >= (11, 0): - # Starting with Mac OS 11, each yearly release bumps the major version - # number. The minor versions are now the midyear updates. - for major_version in range(version[0], 10, -1): - compat_version = major_version, 0 - binary_formats = _mac_binary_formats(compat_version, arch) - for binary_format in binary_formats: - yield "macosx_{major}_{minor}_{binary_format}".format( - major=major_version, minor=0, binary_format=binary_format - ) - - if version >= (11, 0): - # Mac OS 11 on x86_64 is compatible with binaries from previous releases. - # Arm64 support was introduced in 11.0, so no Arm binaries from previous - # releases exist. - # - # However, the "universal2" binary format can have a - # macOS version earlier than 11.0 when the x86_64 part of the binary supports - # that version of macOS. - if arch == "x86_64": - for minor_version in range(16, 3, -1): - compat_version = 10, minor_version - binary_formats = _mac_binary_formats(compat_version, arch) - for binary_format in binary_formats: - yield "macosx_{major}_{minor}_{binary_format}".format( - major=compat_version[0], - minor=compat_version[1], - binary_format=binary_format, - ) - else: - for minor_version in range(16, 3, -1): - compat_version = 10, minor_version - binary_format = "universal2" - yield "macosx_{major}_{minor}_{binary_format}".format( - major=compat_version[0], - minor=compat_version[1], - binary_format=binary_format, - ) - - -def _linux_platforms(is_32bit: bool = _32_BIT_INTERPRETER) -> Iterator[str]: - linux = _normalize_string(sysconfig.get_platform()) - if is_32bit: - if linux == "linux_x86_64": - linux = "linux_i686" - elif linux == "linux_aarch64": - linux = "linux_armv7l" - _, arch = linux.split("_", 1) - yield from _manylinux.platform_tags(linux, arch) - yield from _musllinux.platform_tags(arch) - yield linux - - -def _generic_platforms() -> Iterator[str]: - yield _normalize_string(sysconfig.get_platform()) - - -def platform_tags() -> Iterator[str]: - """ - Provides the platform tags for this installation. - """ - if platform.system() == "Darwin": - return mac_platforms() - elif platform.system() == "Linux": - return _linux_platforms() - else: - return _generic_platforms() - - -def interpreter_name() -> str: - """ - Returns the name of the running interpreter. - """ - name = sys.implementation.name - return INTERPRETER_SHORT_NAMES.get(name) or name - - -def interpreter_version(*, warn: bool = False) -> str: - """ - Returns the version of the running interpreter. - """ - version = _get_config_var("py_version_nodot", warn=warn) - if version: - version = str(version) - else: - version = _version_nodot(sys.version_info[:2]) - return version - - -def _version_nodot(version: PythonVersion) -> str: - return "".join(map(str, version)) - - -def sys_tags(*, warn: bool = False) -> Iterator[Tag]: - """ - Returns the sequence of tag triples for the running interpreter. - - The order of the sequence corresponds to priority order for the - interpreter, from most to least important. - """ - - interp_name = interpreter_name() - if interp_name == "cp": - yield from cpython_tags(warn=warn) - else: - yield from generic_tags() - - if interp_name == "pp": - yield from compatible_tags(interpreter="pp3") - else: - yield from compatible_tags() diff --git a/backend/pig/Lib/python3.12/site-packages/pip/_vendor/packaging/utils.py b/backend/pig/Lib/python3.12/site-packages/pip/_vendor/packaging/utils.py deleted file mode 100644 index bab11b8..0000000 --- a/backend/pig/Lib/python3.12/site-packages/pip/_vendor/packaging/utils.py +++ /dev/null @@ -1,136 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -import re -from typing import FrozenSet, NewType, Tuple, Union, cast - -from .tags import Tag, parse_tag -from .version import InvalidVersion, Version - -BuildTag = Union[Tuple[()], Tuple[int, str]] -NormalizedName = NewType("NormalizedName", str) - - -class InvalidWheelFilename(ValueError): - """ - An invalid wheel filename was found, users should refer to PEP 427. - """ - - -class InvalidSdistFilename(ValueError): - """ - An invalid sdist filename was found, users should refer to the packaging user guide. - """ - - -_canonicalize_regex = re.compile(r"[-_.]+") -# PEP 427: The build number must start with a digit. -_build_tag_regex = re.compile(r"(\d+)(.*)") - - -def canonicalize_name(name: str) -> NormalizedName: - # This is taken from PEP 503. - value = _canonicalize_regex.sub("-", name).lower() - return cast(NormalizedName, value) - - -def canonicalize_version(version: Union[Version, str]) -> str: - """ - This is very similar to Version.__str__, but has one subtle difference - with the way it handles the release segment. - """ - if isinstance(version, str): - try: - parsed = Version(version) - except InvalidVersion: - # Legacy versions cannot be normalized - return version - else: - parsed = version - - parts = [] - - # Epoch - if parsed.epoch != 0: - parts.append(f"{parsed.epoch}!") - - # Release segment - # NB: This strips trailing '.0's to normalize - parts.append(re.sub(r"(\.0)+$", "", ".".join(str(x) for x in parsed.release))) - - # Pre-release - if parsed.pre is not None: - parts.append("".join(str(x) for x in parsed.pre)) - - # Post-release - if parsed.post is not None: - parts.append(f".post{parsed.post}") - - # Development release - if parsed.dev is not None: - parts.append(f".dev{parsed.dev}") - - # Local version segment - if parsed.local is not None: - parts.append(f"+{parsed.local}") - - return "".join(parts) - - -def parse_wheel_filename( - filename: str, -) -> Tuple[NormalizedName, Version, BuildTag, FrozenSet[Tag]]: - if not filename.endswith(".whl"): - raise InvalidWheelFilename( - f"Invalid wheel filename (extension must be '.whl'): {filename}" - ) - - filename = filename[:-4] - dashes = filename.count("-") - if dashes not in (4, 5): - raise InvalidWheelFilename( - f"Invalid wheel filename (wrong number of parts): {filename}" - ) - - parts = filename.split("-", dashes - 2) - name_part = parts[0] - # See PEP 427 for the rules on escaping the project name - if "__" in name_part or re.match(r"^[\w\d._]*$", name_part, re.UNICODE) is None: - raise InvalidWheelFilename(f"Invalid project name: {filename}") - name = canonicalize_name(name_part) - version = Version(parts[1]) - if dashes == 5: - build_part = parts[2] - build_match = _build_tag_regex.match(build_part) - if build_match is None: - raise InvalidWheelFilename( - f"Invalid build number: {build_part} in '{filename}'" - ) - build = cast(BuildTag, (int(build_match.group(1)), build_match.group(2))) - else: - build = () - tags = parse_tag(parts[-1]) - return (name, version, build, tags) - - -def parse_sdist_filename(filename: str) -> Tuple[NormalizedName, Version]: - if filename.endswith(".tar.gz"): - file_stem = filename[: -len(".tar.gz")] - elif filename.endswith(".zip"): - file_stem = filename[: -len(".zip")] - else: - raise InvalidSdistFilename( - f"Invalid sdist filename (extension must be '.tar.gz' or '.zip'):" - f" {filename}" - ) - - # We are requiring a PEP 440 version, which cannot contain dashes, - # so we split on the last dash. - name_part, sep, version_part = file_stem.rpartition("-") - if not sep: - raise InvalidSdistFilename(f"Invalid sdist filename: {filename}") - - name = canonicalize_name(name_part) - version = Version(version_part) - return (name, version) diff --git a/backend/pig/Lib/python3.12/site-packages/pip/_vendor/packaging/version.py b/backend/pig/Lib/python3.12/site-packages/pip/_vendor/packaging/version.py deleted file mode 100644 index de9a09a..0000000 --- a/backend/pig/Lib/python3.12/site-packages/pip/_vendor/packaging/version.py +++ /dev/null @@ -1,504 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -import collections -import itertools -import re -import warnings -from typing import Callable, Iterator, List, Optional, SupportsInt, Tuple, Union - -from ._structures import Infinity, InfinityType, NegativeInfinity, NegativeInfinityType - -__all__ = ["parse", "Version", "LegacyVersion", "InvalidVersion", "VERSION_PATTERN"] - -InfiniteTypes = Union[InfinityType, NegativeInfinityType] -PrePostDevType = Union[InfiniteTypes, Tuple[str, int]] -SubLocalType = Union[InfiniteTypes, int, str] -LocalType = Union[ - NegativeInfinityType, - Tuple[ - Union[ - SubLocalType, - Tuple[SubLocalType, str], - Tuple[NegativeInfinityType, SubLocalType], - ], - ..., - ], -] -CmpKey = Tuple[ - int, Tuple[int, ...], PrePostDevType, PrePostDevType, PrePostDevType, LocalType -] -LegacyCmpKey = Tuple[int, Tuple[str, ...]] -VersionComparisonMethod = Callable[ - [Union[CmpKey, LegacyCmpKey], Union[CmpKey, LegacyCmpKey]], bool -] - -_Version = collections.namedtuple( - "_Version", ["epoch", "release", "dev", "pre", "post", "local"] -) - - -def parse(version: str) -> Union["LegacyVersion", "Version"]: - """ - Parse the given version string and return either a :class:`Version` object - or a :class:`LegacyVersion` object depending on if the given version is - a valid PEP 440 version or a legacy version. - """ - try: - return Version(version) - except InvalidVersion: - return LegacyVersion(version) - - -class InvalidVersion(ValueError): - """ - An invalid version was found, users should refer to PEP 440. - """ - - -class _BaseVersion: - _key: Union[CmpKey, LegacyCmpKey] - - def __hash__(self) -> int: - return hash(self._key) - - # Please keep the duplicated `isinstance` check - # in the six comparisons hereunder - # unless you find a way to avoid adding overhead function calls. - def __lt__(self, other: "_BaseVersion") -> bool: - if not isinstance(other, _BaseVersion): - return NotImplemented - - return self._key < other._key - - def __le__(self, other: "_BaseVersion") -> bool: - if not isinstance(other, _BaseVersion): - return NotImplemented - - return self._key <= other._key - - def __eq__(self, other: object) -> bool: - if not isinstance(other, _BaseVersion): - return NotImplemented - - return self._key == other._key - - def __ge__(self, other: "_BaseVersion") -> bool: - if not isinstance(other, _BaseVersion): - return NotImplemented - - return self._key >= other._key - - def __gt__(self, other: "_BaseVersion") -> bool: - if not isinstance(other, _BaseVersion): - return NotImplemented - - return self._key > other._key - - def __ne__(self, other: object) -> bool: - if not isinstance(other, _BaseVersion): - return NotImplemented - - return self._key != other._key - - -class LegacyVersion(_BaseVersion): - def __init__(self, version: str) -> None: - self._version = str(version) - self._key = _legacy_cmpkey(self._version) - - warnings.warn( - "Creating a LegacyVersion has been deprecated and will be " - "removed in the next major release", - DeprecationWarning, - ) - - def __str__(self) -> str: - return self._version - - def __repr__(self) -> str: - return f" " - - @property - def public(self) -> str: - return self._version - - @property - def base_version(self) -> str: - return self._version - - @property - def epoch(self) -> int: - return -1 - - @property - def release(self) -> None: - return None - - @property - def pre(self) -> None: - return None - - @property - def post(self) -> None: - return None - - @property - def dev(self) -> None: - return None - - @property - def local(self) -> None: - return None - - @property - def is_prerelease(self) -> bool: - return False - - @property - def is_postrelease(self) -> bool: - return False - - @property - def is_devrelease(self) -> bool: - return False - - -_legacy_version_component_re = re.compile(r"(\d+ | [a-z]+ | \.| -)", re.VERBOSE) - -_legacy_version_replacement_map = { - "pre": "c", - "preview": "c", - "-": "final-", - "rc": "c", - "dev": "@", -} - - -def _parse_version_parts(s: str) -> Iterator[str]: - for part in _legacy_version_component_re.split(s): - part = _legacy_version_replacement_map.get(part, part) - - if not part or part == ".": - continue - - if part[:1] in "0123456789": - # pad for numeric comparison - yield part.zfill(8) - else: - yield "*" + part - - # ensure that alpha/beta/candidate are before final - yield "*final" - - -def _legacy_cmpkey(version: str) -> LegacyCmpKey: - - # We hardcode an epoch of -1 here. A PEP 440 version can only have a epoch - # greater than or equal to 0. This will effectively put the LegacyVersion, - # which uses the defacto standard originally implemented by setuptools, - # as before all PEP 440 versions. - epoch = -1 - - # This scheme is taken from pkg_resources.parse_version setuptools prior to - # it's adoption of the packaging library. - parts: List[str] = [] - for part in _parse_version_parts(version.lower()): - if part.startswith("*"): - # remove "-" before a prerelease tag - if part < "*final": - while parts and parts[-1] == "*final-": - parts.pop() - - # remove trailing zeros from each series of numeric parts - while parts and parts[-1] == "00000000": - parts.pop() - - parts.append(part) - - return epoch, tuple(parts) - - -# Deliberately not anchored to the start and end of the string, to make it -# easier for 3rd party code to reuse -VERSION_PATTERN = r""" - v? - (?: - (?:(?P [0-9]+)!)? # epoch - (?P [0-9]+(?:\.[0-9]+)*) # release segment - (?P # pre-release - [-_\.]? - (?P(a|b|c|rc|alpha|beta|pre|preview)) - [-_\.]? - (?P [0-9]+)? - )? - (?P # post release - (?:-(?P [0-9]+)) - | - (?: - [-_\.]? - (?P post|rev|r) - [-_\.]? - (?P [0-9]+)? - ) - )? - (?P # dev release - [-_\.]? - (?P dev) - [-_\.]? - (?P [0-9]+)? - )? - ) - (?:\+(?P [a-z0-9]+(?:[-_\.][a-z0-9]+)*))? # local version -""" - - -class Version(_BaseVersion): - - _regex = re.compile(r"^\s*" + VERSION_PATTERN + r"\s*$", re.VERBOSE | re.IGNORECASE) - - def __init__(self, version: str) -> None: - - # Validate the version and parse it into pieces - match = self._regex.search(version) - if not match: - raise InvalidVersion(f"Invalid version: '{version}'") - - # Store the parsed out pieces of the version - self._version = _Version( - epoch=int(match.group("epoch")) if match.group("epoch") else 0, - release=tuple(int(i) for i in match.group("release").split(".")), - pre=_parse_letter_version(match.group("pre_l"), match.group("pre_n")), - post=_parse_letter_version( - match.group("post_l"), match.group("post_n1") or match.group("post_n2") - ), - dev=_parse_letter_version(match.group("dev_l"), match.group("dev_n")), - local=_parse_local_version(match.group("local")), - ) - - # Generate a key which will be used for sorting - self._key = _cmpkey( - self._version.epoch, - self._version.release, - self._version.pre, - self._version.post, - self._version.dev, - self._version.local, - ) - - def __repr__(self) -> str: - return f" " - - def __str__(self) -> str: - parts = [] - - # Epoch - if self.epoch != 0: - parts.append(f"{self.epoch}!") - - # Release segment - parts.append(".".join(str(x) for x in self.release)) - - # Pre-release - if self.pre is not None: - parts.append("".join(str(x) for x in self.pre)) - - # Post-release - if self.post is not None: - parts.append(f".post{self.post}") - - # Development release - if self.dev is not None: - parts.append(f".dev{self.dev}") - - # Local version segment - if self.local is not None: - parts.append(f"+{self.local}") - - return "".join(parts) - - @property - def epoch(self) -> int: - _epoch: int = self._version.epoch - return _epoch - - @property - def release(self) -> Tuple[int, ...]: - _release: Tuple[int, ...] = self._version.release - return _release - - @property - def pre(self) -> Optional[Tuple[str, int]]: - _pre: Optional[Tuple[str, int]] = self._version.pre - return _pre - - @property - def post(self) -> Optional[int]: - return self._version.post[1] if self._version.post else None - - @property - def dev(self) -> Optional[int]: - return self._version.dev[1] if self._version.dev else None - - @property - def local(self) -> Optional[str]: - if self._version.local: - return ".".join(str(x) for x in self._version.local) - else: - return None - - @property - def public(self) -> str: - return str(self).split("+", 1)[0] - - @property - def base_version(self) -> str: - parts = [] - - # Epoch - if self.epoch != 0: - parts.append(f"{self.epoch}!") - - # Release segment - parts.append(".".join(str(x) for x in self.release)) - - return "".join(parts) - - @property - def is_prerelease(self) -> bool: - return self.dev is not None or self.pre is not None - - @property - def is_postrelease(self) -> bool: - return self.post is not None - - @property - def is_devrelease(self) -> bool: - return self.dev is not None - - @property - def major(self) -> int: - return self.release[0] if len(self.release) >= 1 else 0 - - @property - def minor(self) -> int: - return self.release[1] if len(self.release) >= 2 else 0 - - @property - def micro(self) -> int: - return self.release[2] if len(self.release) >= 3 else 0 - - -def _parse_letter_version( - letter: str, number: Union[str, bytes, SupportsInt] -) -> Optional[Tuple[str, int]]: - - if letter: - # We consider there to be an implicit 0 in a pre-release if there is - # not a numeral associated with it. - if number is None: - number = 0 - - # We normalize any letters to their lower case form - letter = letter.lower() - - # We consider some words to be alternate spellings of other words and - # in those cases we want to normalize the spellings to our preferred - # spelling. - if letter == "alpha": - letter = "a" - elif letter == "beta": - letter = "b" - elif letter in ["c", "pre", "preview"]: - letter = "rc" - elif letter in ["rev", "r"]: - letter = "post" - - return letter, int(number) - if not letter and number: - # We assume if we are given a number, but we are not given a letter - # then this is using the implicit post release syntax (e.g. 1.0-1) - letter = "post" - - return letter, int(number) - - return None - - -_local_version_separators = re.compile(r"[\._-]") - - -def _parse_local_version(local: str) -> Optional[LocalType]: - """ - Takes a string like abc.1.twelve and turns it into ("abc", 1, "twelve"). - """ - if local is not None: - return tuple( - part.lower() if not part.isdigit() else int(part) - for part in _local_version_separators.split(local) - ) - return None - - -def _cmpkey( - epoch: int, - release: Tuple[int, ...], - pre: Optional[Tuple[str, int]], - post: Optional[Tuple[str, int]], - dev: Optional[Tuple[str, int]], - local: Optional[Tuple[SubLocalType]], -) -> CmpKey: - - # When we compare a release version, we want to compare it with all of the - # trailing zeros removed. So we'll use a reverse the list, drop all the now - # leading zeros until we come to something non zero, then take the rest - # re-reverse it back into the correct order and make it a tuple and use - # that for our sorting key. - _release = tuple( - reversed(list(itertools.dropwhile(lambda x: x == 0, reversed(release)))) - ) - - # We need to "trick" the sorting algorithm to put 1.0.dev0 before 1.0a0. - # We'll do this by abusing the pre segment, but we _only_ want to do this - # if there is not a pre or a post segment. If we have one of those then - # the normal sorting rules will handle this case correctly. - if pre is None and post is None and dev is not None: - _pre: PrePostDevType = NegativeInfinity - # Versions without a pre-release (except as noted above) should sort after - # those with one. - elif pre is None: - _pre = Infinity - else: - _pre = pre - - # Versions without a post segment should sort before those with one. - if post is None: - _post: PrePostDevType = NegativeInfinity - - else: - _post = post - - # Versions without a development segment should sort after those with one. - if dev is None: - _dev: PrePostDevType = Infinity - - else: - _dev = dev - - if local is None: - # Versions without a local segment should sort before those with one. - _local: LocalType = NegativeInfinity - else: - # Versions with a local segment need that segment parsed to implement - # the sorting rules in PEP440. - # - Alpha numeric segments sort before numeric segments - # - Alpha numeric segments sort lexicographically - # - Numeric segments sort numerically - # - Shorter versions sort before longer versions when the prefixes - # match exactly - _local = tuple( - (i, "") if isinstance(i, int) else (NegativeInfinity, i) for i in local - ) - - return epoch, _release, _pre, _post, _dev, _local diff --git a/backend/pig/Lib/python3.12/site-packages/pip/_vendor/pkg_resources/__init__.py b/backend/pig/Lib/python3.12/site-packages/pip/_vendor/pkg_resources/__init__.py deleted file mode 100644 index ad27940..0000000 --- a/backend/pig/Lib/python3.12/site-packages/pip/_vendor/pkg_resources/__init__.py +++ /dev/null @@ -1,3361 +0,0 @@ -""" -Package resource API --------------------- - -A resource is a logical file contained within a package, or a logical -subdirectory thereof. The package resource API expects resource names -to have their path parts separated with ``/``, *not* whatever the local -path separator is. Do not use os.path operations to manipulate resource -names being passed into the API. - -The package resource API is designed to work with normal filesystem packages, -.egg files, and unpacked .egg files. It can also work in a limited way with -.zip files and with custom PEP 302 loaders that support the ``get_data()`` -method. - -This module is deprecated. Users are directed to :mod:`importlib.resources`, -:mod:`importlib.metadata` and :pypi:`packaging` instead. -""" - -import sys -import os -import io -import time -import re -import types -import zipfile -import zipimport -import warnings -import stat -import functools -import pkgutil -import operator -import platform -import collections -import plistlib -import email.parser -import errno -import tempfile -import textwrap -import inspect -import ntpath -import posixpath -import importlib -from pkgutil import get_importer - -try: - import _imp -except ImportError: - # Python 3.2 compatibility - import imp as _imp - -try: - FileExistsError -except NameError: - FileExistsError = OSError - -# capture these to bypass sandboxing -from os import utime - -try: - from os import mkdir, rename, unlink - - WRITE_SUPPORT = True -except ImportError: - # no write support, probably under GAE - WRITE_SUPPORT = False - -from os import open as os_open -from os.path import isdir, split - -try: - import importlib.machinery as importlib_machinery - - # access attribute to force import under delayed import mechanisms. - importlib_machinery.__name__ -except ImportError: - importlib_machinery = None - -from pip._internal.utils._jaraco_text import ( - yield_lines, - drop_comment, - join_continuation, -) - -from pip._vendor import platformdirs -from pip._vendor import packaging - -__import__('pip._vendor.packaging.version') -__import__('pip._vendor.packaging.specifiers') -__import__('pip._vendor.packaging.requirements') -__import__('pip._vendor.packaging.markers') -__import__('pip._vendor.packaging.utils') - -if sys.version_info < (3, 5): - raise RuntimeError("Python 3.5 or later is required") - -# declare some globals that will be defined later to -# satisfy the linters. -require = None -working_set = None -add_activation_listener = None -resources_stream = None -cleanup_resources = None -resource_dir = None -resource_stream = None -set_extraction_path = None -resource_isdir = None -resource_string = None -iter_entry_points = None -resource_listdir = None -resource_filename = None -resource_exists = None -_distribution_finders = None -_namespace_handlers = None -_namespace_packages = None - - -warnings.warn( - "pkg_resources is deprecated as an API. " - "See https://setuptools.pypa.io/en/latest/pkg_resources.html", - DeprecationWarning, - stacklevel=2 -) - - -_PEP440_FALLBACK = re.compile(r"^v?(?P (?:[0-9]+!)?[0-9]+(?:\.[0-9]+)*)", re.I) - - -class PEP440Warning(RuntimeWarning): - """ - Used when there is an issue with a version or specifier not complying with - PEP 440. - """ - - -parse_version = packaging.version.Version - - -_state_vars = {} - - -def _declare_state(vartype, **kw): - globals().update(kw) - _state_vars.update(dict.fromkeys(kw, vartype)) - - -def __getstate__(): - state = {} - g = globals() - for k, v in _state_vars.items(): - state[k] = g['_sget_' + v](g[k]) - return state - - -def __setstate__(state): - g = globals() - for k, v in state.items(): - g['_sset_' + _state_vars[k]](k, g[k], v) - return state - - -def _sget_dict(val): - return val.copy() - - -def _sset_dict(key, ob, state): - ob.clear() - ob.update(state) - - -def _sget_object(val): - return val.__getstate__() - - -def _sset_object(key, ob, state): - ob.__setstate__(state) - - -_sget_none = _sset_none = lambda *args: None - - -def get_supported_platform(): - """Return this platform's maximum compatible version. - - distutils.util.get_platform() normally reports the minimum version - of macOS that would be required to *use* extensions produced by - distutils. But what we want when checking compatibility is to know the - version of macOS that we are *running*. To allow usage of packages that - explicitly require a newer version of macOS, we must also know the - current version of the OS. - - If this condition occurs for any other platform with a version in its - platform strings, this function should be extended accordingly. - """ - plat = get_build_platform() - m = macosVersionString.match(plat) - if m is not None and sys.platform == "darwin": - try: - plat = 'macosx-%s-%s' % ('.'.join(_macos_vers()[:2]), m.group(3)) - except ValueError: - # not macOS - pass - return plat - - -__all__ = [ - # Basic resource access and distribution/entry point discovery - 'require', - 'run_script', - 'get_provider', - 'get_distribution', - 'load_entry_point', - 'get_entry_map', - 'get_entry_info', - 'iter_entry_points', - 'resource_string', - 'resource_stream', - 'resource_filename', - 'resource_listdir', - 'resource_exists', - 'resource_isdir', - # Environmental control - 'declare_namespace', - 'working_set', - 'add_activation_listener', - 'find_distributions', - 'set_extraction_path', - 'cleanup_resources', - 'get_default_cache', - # Primary implementation classes - 'Environment', - 'WorkingSet', - 'ResourceManager', - 'Distribution', - 'Requirement', - 'EntryPoint', - # Exceptions - 'ResolutionError', - 'VersionConflict', - 'DistributionNotFound', - 'UnknownExtra', - 'ExtractionError', - # Warnings - 'PEP440Warning', - # Parsing functions and string utilities - 'parse_requirements', - 'parse_version', - 'safe_name', - 'safe_version', - 'get_platform', - 'compatible_platforms', - 'yield_lines', - 'split_sections', - 'safe_extra', - 'to_filename', - 'invalid_marker', - 'evaluate_marker', - # filesystem utilities - 'ensure_directory', - 'normalize_path', - # Distribution "precedence" constants - 'EGG_DIST', - 'BINARY_DIST', - 'SOURCE_DIST', - 'CHECKOUT_DIST', - 'DEVELOP_DIST', - # "Provider" interfaces, implementations, and registration/lookup APIs - 'IMetadataProvider', - 'IResourceProvider', - 'FileMetadata', - 'PathMetadata', - 'EggMetadata', - 'EmptyProvider', - 'empty_provider', - 'NullProvider', - 'EggProvider', - 'DefaultProvider', - 'ZipProvider', - 'register_finder', - 'register_namespace_handler', - 'register_loader_type', - 'fixup_namespace_packages', - 'get_importer', - # Warnings - 'PkgResourcesDeprecationWarning', - # Deprecated/backward compatibility only - 'run_main', - 'AvailableDistributions', -] - - -class ResolutionError(Exception): - """Abstract base for dependency resolution errors""" - - def __repr__(self): - return self.__class__.__name__ + repr(self.args) - - -class VersionConflict(ResolutionError): - """ - An already-installed version conflicts with the requested version. - - Should be initialized with the installed Distribution and the requested - Requirement. - """ - - _template = "{self.dist} is installed but {self.req} is required" - - @property - def dist(self): - return self.args[0] - - @property - def req(self): - return self.args[1] - - def report(self): - return self._template.format(**locals()) - - def with_context(self, required_by): - """ - If required_by is non-empty, return a version of self that is a - ContextualVersionConflict. - """ - if not required_by: - return self - args = self.args + (required_by,) - return ContextualVersionConflict(*args) - - -class ContextualVersionConflict(VersionConflict): - """ - A VersionConflict that accepts a third parameter, the set of the - requirements that required the installed Distribution. - """ - - _template = VersionConflict._template + ' by {self.required_by}' - - @property - def required_by(self): - return self.args[2] - - -class DistributionNotFound(ResolutionError): - """A requested distribution was not found""" - - _template = ( - "The '{self.req}' distribution was not found " - "and is required by {self.requirers_str}" - ) - - @property - def req(self): - return self.args[0] - - @property - def requirers(self): - return self.args[1] - - @property - def requirers_str(self): - if not self.requirers: - return 'the application' - return ', '.join(self.requirers) - - def report(self): - return self._template.format(**locals()) - - def __str__(self): - return self.report() - - -class UnknownExtra(ResolutionError): - """Distribution doesn't have an "extra feature" of the given name""" - - -_provider_factories = {} - -PY_MAJOR = '{}.{}'.format(*sys.version_info) -EGG_DIST = 3 -BINARY_DIST = 2 -SOURCE_DIST = 1 -CHECKOUT_DIST = 0 -DEVELOP_DIST = -1 - - -def register_loader_type(loader_type, provider_factory): - """Register `provider_factory` to make providers for `loader_type` - - `loader_type` is the type or class of a PEP 302 ``module.__loader__``, - and `provider_factory` is a function that, passed a *module* object, - returns an ``IResourceProvider`` for that module. - """ - _provider_factories[loader_type] = provider_factory - - -def get_provider(moduleOrReq): - """Return an IResourceProvider for the named module or requirement""" - if isinstance(moduleOrReq, Requirement): - return working_set.find(moduleOrReq) or require(str(moduleOrReq))[0] - try: - module = sys.modules[moduleOrReq] - except KeyError: - __import__(moduleOrReq) - module = sys.modules[moduleOrReq] - loader = getattr(module, '__loader__', None) - return _find_adapter(_provider_factories, loader)(module) - - -def _macos_vers(_cache=[]): - if not _cache: - version = platform.mac_ver()[0] - # fallback for MacPorts - if version == '': - plist = '/System/Library/CoreServices/SystemVersion.plist' - if os.path.exists(plist): - if hasattr(plistlib, 'readPlist'): - plist_content = plistlib.readPlist(plist) - if 'ProductVersion' in plist_content: - version = plist_content['ProductVersion'] - - _cache.append(version.split('.')) - return _cache[0] - - -def _macos_arch(machine): - return {'PowerPC': 'ppc', 'Power_Macintosh': 'ppc'}.get(machine, machine) - - -def get_build_platform(): - """Return this platform's string for platform-specific distributions - - XXX Currently this is the same as ``distutils.util.get_platform()``, but it - needs some hacks for Linux and macOS. - """ - from sysconfig import get_platform - - plat = get_platform() - if sys.platform == "darwin" and not plat.startswith('macosx-'): - try: - version = _macos_vers() - machine = os.uname()[4].replace(" ", "_") - return "macosx-%d.%d-%s" % ( - int(version[0]), - int(version[1]), - _macos_arch(machine), - ) - except ValueError: - # if someone is running a non-Mac darwin system, this will fall - # through to the default implementation - pass - return plat - - -macosVersionString = re.compile(r"macosx-(\d+)\.(\d+)-(.*)") -darwinVersionString = re.compile(r"darwin-(\d+)\.(\d+)\.(\d+)-(.*)") -# XXX backward compat -get_platform = get_build_platform - - -def compatible_platforms(provided, required): - """Can code for the `provided` platform run on the `required` platform? - - Returns true if either platform is ``None``, or the platforms are equal. - - XXX Needs compatibility checks for Linux and other unixy OSes. - """ - if provided is None or required is None or provided == required: - # easy case - return True - - # macOS special cases - reqMac = macosVersionString.match(required) - if reqMac: - provMac = macosVersionString.match(provided) - - # is this a Mac package? - if not provMac: - # this is backwards compatibility for packages built before - # setuptools 0.6. All packages built after this point will - # use the new macOS designation. - provDarwin = darwinVersionString.match(provided) - if provDarwin: - dversion = int(provDarwin.group(1)) - macosversion = "%s.%s" % (reqMac.group(1), reqMac.group(2)) - if ( - dversion == 7 - and macosversion >= "10.3" - or dversion == 8 - and macosversion >= "10.4" - ): - return True - # egg isn't macOS or legacy darwin - return False - - # are they the same major version and machine type? - if provMac.group(1) != reqMac.group(1) or provMac.group(3) != reqMac.group(3): - return False - - # is the required OS major update >= the provided one? - if int(provMac.group(2)) > int(reqMac.group(2)): - return False - - return True - - # XXX Linux and other platforms' special cases should go here - return False - - -def run_script(dist_spec, script_name): - """Locate distribution `dist_spec` and run its `script_name` script""" - ns = sys._getframe(1).f_globals - name = ns['__name__'] - ns.clear() - ns['__name__'] = name - require(dist_spec)[0].run_script(script_name, ns) - - -# backward compatibility -run_main = run_script - - -def get_distribution(dist): - """Return a current distribution object for a Requirement or string""" - if isinstance(dist, str): - dist = Requirement.parse(dist) - if isinstance(dist, Requirement): - dist = get_provider(dist) - if not isinstance(dist, Distribution): - raise TypeError("Expected string, Requirement, or Distribution", dist) - return dist - - -def load_entry_point(dist, group, name): - """Return `name` entry point of `group` for `dist` or raise ImportError""" - return get_distribution(dist).load_entry_point(group, name) - - -def get_entry_map(dist, group=None): - """Return the entry point map for `group`, or the full entry map""" - return get_distribution(dist).get_entry_map(group) - - -def get_entry_info(dist, group, name): - """Return the EntryPoint object for `group`+`name`, or ``None``""" - return get_distribution(dist).get_entry_info(group, name) - - -class IMetadataProvider: - def has_metadata(name): - """Does the package's distribution contain the named metadata?""" - - def get_metadata(name): - """The named metadata resource as a string""" - - def get_metadata_lines(name): - """Yield named metadata resource as list of non-blank non-comment lines - - Leading and trailing whitespace is stripped from each line, and lines - with ``#`` as the first non-blank character are omitted.""" - - def metadata_isdir(name): - """Is the named metadata a directory? (like ``os.path.isdir()``)""" - - def metadata_listdir(name): - """List of metadata names in the directory (like ``os.listdir()``)""" - - def run_script(script_name, namespace): - """Execute the named script in the supplied namespace dictionary""" - - -class IResourceProvider(IMetadataProvider): - """An object that provides access to package resources""" - - def get_resource_filename(manager, resource_name): - """Return a true filesystem path for `resource_name` - - `manager` must be an ``IResourceManager``""" - - def get_resource_stream(manager, resource_name): - """Return a readable file-like object for `resource_name` - - `manager` must be an ``IResourceManager``""" - - def get_resource_string(manager, resource_name): - """Return a string containing the contents of `resource_name` - - `manager` must be an ``IResourceManager``""" - - def has_resource(resource_name): - """Does the package contain the named resource?""" - - def resource_isdir(resource_name): - """Is the named resource a directory? (like ``os.path.isdir()``)""" - - def resource_listdir(resource_name): - """List of resource names in the directory (like ``os.listdir()``)""" - - -class WorkingSet: - """A collection of active distributions on sys.path (or a similar list)""" - - def __init__(self, entries=None): - """Create working set from list of path entries (default=sys.path)""" - self.entries = [] - self.entry_keys = {} - self.by_key = {} - self.normalized_to_canonical_keys = {} - self.callbacks = [] - - if entries is None: - entries = sys.path - - for entry in entries: - self.add_entry(entry) - - @classmethod - def _build_master(cls): - """ - Prepare the master working set. - """ - ws = cls() - try: - from __main__ import __requires__ - except ImportError: - # The main program does not list any requirements - return ws - - # ensure the requirements are met - try: - ws.require(__requires__) - except VersionConflict: - return cls._build_from_requirements(__requires__) - - return ws - - @classmethod - def _build_from_requirements(cls, req_spec): - """ - Build a working set from a requirement spec. Rewrites sys.path. - """ - # try it without defaults already on sys.path - # by starting with an empty path - ws = cls([]) - reqs = parse_requirements(req_spec) - dists = ws.resolve(reqs, Environment()) - for dist in dists: - ws.add(dist) - - # add any missing entries from sys.path - for entry in sys.path: - if entry not in ws.entries: - ws.add_entry(entry) - - # then copy back to sys.path - sys.path[:] = ws.entries - return ws - - def add_entry(self, entry): - """Add a path item to ``.entries``, finding any distributions on it - - ``find_distributions(entry, True)`` is used to find distributions - corresponding to the path entry, and they are added. `entry` is - always appended to ``.entries``, even if it is already present. - (This is because ``sys.path`` can contain the same value more than - once, and the ``.entries`` of the ``sys.path`` WorkingSet should always - equal ``sys.path``.) - """ - self.entry_keys.setdefault(entry, []) - self.entries.append(entry) - for dist in find_distributions(entry, True): - self.add(dist, entry, False) - - def __contains__(self, dist): - """True if `dist` is the active distribution for its project""" - return self.by_key.get(dist.key) == dist - - def find(self, req): - """Find a distribution matching requirement `req` - - If there is an active distribution for the requested project, this - returns it as long as it meets the version requirement specified by - `req`. But, if there is an active distribution for the project and it - does *not* meet the `req` requirement, ``VersionConflict`` is raised. - If there is no active distribution for the requested project, ``None`` - is returned. - """ - dist = self.by_key.get(req.key) - - if dist is None: - canonical_key = self.normalized_to_canonical_keys.get(req.key) - - if canonical_key is not None: - req.key = canonical_key - dist = self.by_key.get(canonical_key) - - if dist is not None and dist not in req: - # XXX add more info - raise VersionConflict(dist, req) - return dist - - def iter_entry_points(self, group, name=None): - """Yield entry point objects from `group` matching `name` - - If `name` is None, yields all entry points in `group` from all - distributions in the working set, otherwise only ones matching - both `group` and `name` are yielded (in distribution order). - """ - return ( - entry - for dist in self - for entry in dist.get_entry_map(group).values() - if name is None or name == entry.name - ) - - def run_script(self, requires, script_name): - """Locate distribution for `requires` and run `script_name` script""" - ns = sys._getframe(1).f_globals - name = ns['__name__'] - ns.clear() - ns['__name__'] = name - self.require(requires)[0].run_script(script_name, ns) - - def __iter__(self): - """Yield distributions for non-duplicate projects in the working set - - The yield order is the order in which the items' path entries were - added to the working set. - """ - seen = {} - for item in self.entries: - if item not in self.entry_keys: - # workaround a cache issue - continue - - for key in self.entry_keys[item]: - if key not in seen: - seen[key] = 1 - yield self.by_key[key] - - def add(self, dist, entry=None, insert=True, replace=False): - """Add `dist` to working set, associated with `entry` - - If `entry` is unspecified, it defaults to the ``.location`` of `dist`. - On exit from this routine, `entry` is added to the end of the working - set's ``.entries`` (if it wasn't already present). - - `dist` is only added to the working set if it's for a project that - doesn't already have a distribution in the set, unless `replace=True`. - If it's added, any callbacks registered with the ``subscribe()`` method - will be called. - """ - if insert: - dist.insert_on(self.entries, entry, replace=replace) - - if entry is None: - entry = dist.location - keys = self.entry_keys.setdefault(entry, []) - keys2 = self.entry_keys.setdefault(dist.location, []) - if not replace and dist.key in self.by_key: - # ignore hidden distros - return - - self.by_key[dist.key] = dist - normalized_name = packaging.utils.canonicalize_name(dist.key) - self.normalized_to_canonical_keys[normalized_name] = dist.key - if dist.key not in keys: - keys.append(dist.key) - if dist.key not in keys2: - keys2.append(dist.key) - self._added_new(dist) - - def resolve( - self, - requirements, - env=None, - installer=None, - replace_conflicting=False, - extras=None, - ): - """List all distributions needed to (recursively) meet `requirements` - - `requirements` must be a sequence of ``Requirement`` objects. `env`, - if supplied, should be an ``Environment`` instance. If - not supplied, it defaults to all distributions available within any - entry or distribution in the working set. `installer`, if supplied, - will be invoked with each requirement that cannot be met by an - already-installed distribution; it should return a ``Distribution`` or - ``None``. - - Unless `replace_conflicting=True`, raises a VersionConflict exception - if - any requirements are found on the path that have the correct name but - the wrong version. Otherwise, if an `installer` is supplied it will be - invoked to obtain the correct version of the requirement and activate - it. - - `extras` is a list of the extras to be used with these requirements. - This is important because extra requirements may look like `my_req; - extra = "my_extra"`, which would otherwise be interpreted as a purely - optional requirement. Instead, we want to be able to assert that these - requirements are truly required. - """ - - # set up the stack - requirements = list(requirements)[::-1] - # set of processed requirements - processed = {} - # key -> dist - best = {} - to_activate = [] - - req_extras = _ReqExtras() - - # Mapping of requirement to set of distributions that required it; - # useful for reporting info about conflicts. - required_by = collections.defaultdict(set) - - while requirements: - # process dependencies breadth-first - req = requirements.pop(0) - if req in processed: - # Ignore cyclic or redundant dependencies - continue - - if not req_extras.markers_pass(req, extras): - continue - - dist = self._resolve_dist( - req, best, replace_conflicting, env, installer, required_by, to_activate - ) - - # push the new requirements onto the stack - new_requirements = dist.requires(req.extras)[::-1] - requirements.extend(new_requirements) - - # Register the new requirements needed by req - for new_requirement in new_requirements: - required_by[new_requirement].add(req.project_name) - req_extras[new_requirement] = req.extras - - processed[req] = True - - # return list of distros to activate - return to_activate - - def _resolve_dist( - self, req, best, replace_conflicting, env, installer, required_by, to_activate - ): - dist = best.get(req.key) - if dist is None: - # Find the best distribution and add it to the map - dist = self.by_key.get(req.key) - if dist is None or (dist not in req and replace_conflicting): - ws = self - if env is None: - if dist is None: - env = Environment(self.entries) - else: - # Use an empty environment and workingset to avoid - # any further conflicts with the conflicting - # distribution - env = Environment([]) - ws = WorkingSet([]) - dist = best[req.key] = env.best_match( - req, ws, installer, replace_conflicting=replace_conflicting - ) - if dist is None: - requirers = required_by.get(req, None) - raise DistributionNotFound(req, requirers) - to_activate.append(dist) - if dist not in req: - # Oops, the "best" so far conflicts with a dependency - dependent_req = required_by[req] - raise VersionConflict(dist, req).with_context(dependent_req) - return dist - - def find_plugins(self, plugin_env, full_env=None, installer=None, fallback=True): - """Find all activatable distributions in `plugin_env` - - Example usage:: - - distributions, errors = working_set.find_plugins( - Environment(plugin_dirlist) - ) - # add plugins+libs to sys.path - map(working_set.add, distributions) - # display errors - print('Could not load', errors) - - The `plugin_env` should be an ``Environment`` instance that contains - only distributions that are in the project's "plugin directory" or - directories. The `full_env`, if supplied, should be an ``Environment`` - contains all currently-available distributions. If `full_env` is not - supplied, one is created automatically from the ``WorkingSet`` this - method is called on, which will typically mean that every directory on - ``sys.path`` will be scanned for distributions. - - `installer` is a standard installer callback as used by the - ``resolve()`` method. The `fallback` flag indicates whether we should - attempt to resolve older versions of a plugin if the newest version - cannot be resolved. - - This method returns a 2-tuple: (`distributions`, `error_info`), where - `distributions` is a list of the distributions found in `plugin_env` - that were loadable, along with any other distributions that are needed - to resolve their dependencies. `error_info` is a dictionary mapping - unloadable plugin distributions to an exception instance describing the - error that occurred. Usually this will be a ``DistributionNotFound`` or - ``VersionConflict`` instance. - """ - - plugin_projects = list(plugin_env) - # scan project names in alphabetic order - plugin_projects.sort() - - error_info = {} - distributions = {} - - if full_env is None: - env = Environment(self.entries) - env += plugin_env - else: - env = full_env + plugin_env - - shadow_set = self.__class__([]) - # put all our entries in shadow_set - list(map(shadow_set.add, self)) - - for project_name in plugin_projects: - for dist in plugin_env[project_name]: - req = [dist.as_requirement()] - - try: - resolvees = shadow_set.resolve(req, env, installer) - - except ResolutionError as v: - # save error info - error_info[dist] = v - if fallback: - # try the next older version of project - continue - else: - # give up on this project, keep going - break - - else: - list(map(shadow_set.add, resolvees)) - distributions.update(dict.fromkeys(resolvees)) - - # success, no need to try any more versions of this project - break - - distributions = list(distributions) - distributions.sort() - - return distributions, error_info - - def require(self, *requirements): - """Ensure that distributions matching `requirements` are activated - - `requirements` must be a string or a (possibly-nested) sequence - thereof, specifying the distributions and versions required. The - return value is a sequence of the distributions that needed to be - activated to fulfill the requirements; all relevant distributions are - included, even if they were already activated in this working set. - """ - needed = self.resolve(parse_requirements(requirements)) - - for dist in needed: - self.add(dist) - - return needed - - def subscribe(self, callback, existing=True): - """Invoke `callback` for all distributions - - If `existing=True` (default), - call on all existing ones, as well. - """ - if callback in self.callbacks: - return - self.callbacks.append(callback) - if not existing: - return - for dist in self: - callback(dist) - - def _added_new(self, dist): - for callback in self.callbacks: - callback(dist) - - def __getstate__(self): - return ( - self.entries[:], - self.entry_keys.copy(), - self.by_key.copy(), - self.normalized_to_canonical_keys.copy(), - self.callbacks[:], - ) - - def __setstate__(self, e_k_b_n_c): - entries, keys, by_key, normalized_to_canonical_keys, callbacks = e_k_b_n_c - self.entries = entries[:] - self.entry_keys = keys.copy() - self.by_key = by_key.copy() - self.normalized_to_canonical_keys = normalized_to_canonical_keys.copy() - self.callbacks = callbacks[:] - - -class _ReqExtras(dict): - """ - Map each requirement to the extras that demanded it. - """ - - def markers_pass(self, req, extras=None): - """ - Evaluate markers for req against each extra that - demanded it. - - Return False if the req has a marker and fails - evaluation. Otherwise, return True. - """ - extra_evals = ( - req.marker.evaluate({'extra': extra}) - for extra in self.get(req, ()) + (extras or (None,)) - ) - return not req.marker or any(extra_evals) - - -class Environment: - """Searchable snapshot of distributions on a search path""" - - def __init__( - self, search_path=None, platform=get_supported_platform(), python=PY_MAJOR - ): - """Snapshot distributions available on a search path - - Any distributions found on `search_path` are added to the environment. - `search_path` should be a sequence of ``sys.path`` items. If not - supplied, ``sys.path`` is used. - - `platform` is an optional string specifying the name of the platform - that platform-specific distributions must be compatible with. If - unspecified, it defaults to the current platform. `python` is an - optional string naming the desired version of Python (e.g. ``'3.6'``); - it defaults to the current version. - - You may explicitly set `platform` (and/or `python`) to ``None`` if you - wish to map *all* distributions, not just those compatible with the - running platform or Python version. - """ - self._distmap = {} - self.platform = platform - self.python = python - self.scan(search_path) - - def can_add(self, dist): - """Is distribution `dist` acceptable for this environment? - - The distribution must match the platform and python version - requirements specified when this environment was created, or False - is returned. - """ - py_compat = ( - self.python is None - or dist.py_version is None - or dist.py_version == self.python - ) - return py_compat and compatible_platforms(dist.platform, self.platform) - - def remove(self, dist): - """Remove `dist` from the environment""" - self._distmap[dist.key].remove(dist) - - def scan(self, search_path=None): - """Scan `search_path` for distributions usable in this environment - - Any distributions found are added to the environment. - `search_path` should be a sequence of ``sys.path`` items. If not - supplied, ``sys.path`` is used. Only distributions conforming to - the platform/python version defined at initialization are added. - """ - if search_path is None: - search_path = sys.path - - for item in search_path: - for dist in find_distributions(item): - self.add(dist) - - def __getitem__(self, project_name): - """Return a newest-to-oldest list of distributions for `project_name` - - Uses case-insensitive `project_name` comparison, assuming all the - project's distributions use their project's name converted to all - lowercase as their key. - - """ - distribution_key = project_name.lower() - return self._distmap.get(distribution_key, []) - - def add(self, dist): - """Add `dist` if we ``can_add()`` it and it has not already been added""" - if self.can_add(dist) and dist.has_version(): - dists = self._distmap.setdefault(dist.key, []) - if dist not in dists: - dists.append(dist) - dists.sort(key=operator.attrgetter('hashcmp'), reverse=True) - - def best_match(self, req, working_set, installer=None, replace_conflicting=False): - """Find distribution best matching `req` and usable on `working_set` - - This calls the ``find(req)`` method of the `working_set` to see if a - suitable distribution is already active. (This may raise - ``VersionConflict`` if an unsuitable version of the project is already - active in the specified `working_set`.) If a suitable distribution - isn't active, this method returns the newest distribution in the - environment that meets the ``Requirement`` in `req`. If no suitable - distribution is found, and `installer` is supplied, then the result of - calling the environment's ``obtain(req, installer)`` method will be - returned. - """ - try: - dist = working_set.find(req) - except VersionConflict: - if not replace_conflicting: - raise - dist = None - if dist is not None: - return dist - for dist in self[req.key]: - if dist in req: - return dist - # try to download/install - return self.obtain(req, installer) - - def obtain(self, requirement, installer=None): - """Obtain a distribution matching `requirement` (e.g. via download) - - Obtain a distro that matches requirement (e.g. via download). In the - base ``Environment`` class, this routine just returns - ``installer(requirement)``, unless `installer` is None, in which case - None is returned instead. This method is a hook that allows subclasses - to attempt other ways of obtaining a distribution before falling back - to the `installer` argument.""" - if installer is not None: - return installer(requirement) - - def __iter__(self): - """Yield the unique project names of the available distributions""" - for key in self._distmap.keys(): - if self[key]: - yield key - - def __iadd__(self, other): - """In-place addition of a distribution or environment""" - if isinstance(other, Distribution): - self.add(other) - elif isinstance(other, Environment): - for project in other: - for dist in other[project]: - self.add(dist) - else: - raise TypeError("Can't add %r to environment" % (other,)) - return self - - def __add__(self, other): - """Add an environment or distribution to an environment""" - new = self.__class__([], platform=None, python=None) - for env in self, other: - new += env - return new - - -# XXX backward compatibility -AvailableDistributions = Environment - - -class ExtractionError(RuntimeError): - """An error occurred extracting a resource - - The following attributes are available from instances of this exception: - - manager - The resource manager that raised this exception - - cache_path - The base directory for resource extraction - - original_error - The exception instance that caused extraction to fail - """ - - -class ResourceManager: - """Manage resource extraction and packages""" - - extraction_path = None - - def __init__(self): - self.cached_files = {} - - def resource_exists(self, package_or_requirement, resource_name): - """Does the named resource exist?""" - return get_provider(package_or_requirement).has_resource(resource_name) - - def resource_isdir(self, package_or_requirement, resource_name): - """Is the named resource an existing directory?""" - return get_provider(package_or_requirement).resource_isdir(resource_name) - - def resource_filename(self, package_or_requirement, resource_name): - """Return a true filesystem path for specified resource""" - return get_provider(package_or_requirement).get_resource_filename( - self, resource_name - ) - - def resource_stream(self, package_or_requirement, resource_name): - """Return a readable file-like object for specified resource""" - return get_provider(package_or_requirement).get_resource_stream( - self, resource_name - ) - - def resource_string(self, package_or_requirement, resource_name): - """Return specified resource as a string""" - return get_provider(package_or_requirement).get_resource_string( - self, resource_name - ) - - def resource_listdir(self, package_or_requirement, resource_name): - """List the contents of the named resource directory""" - return get_provider(package_or_requirement).resource_listdir(resource_name) - - def extraction_error(self): - """Give an error message for problems extracting file(s)""" - - old_exc = sys.exc_info()[1] - cache_path = self.extraction_path or get_default_cache() - - tmpl = textwrap.dedent( - """ - Can't extract file(s) to egg cache - - The following error occurred while trying to extract file(s) - to the Python egg cache: - - {old_exc} - - The Python egg cache directory is currently set to: - - {cache_path} - - Perhaps your account does not have write access to this directory? - You can change the cache directory by setting the PYTHON_EGG_CACHE - environment variable to point to an accessible directory. - """ - ).lstrip() - err = ExtractionError(tmpl.format(**locals())) - err.manager = self - err.cache_path = cache_path - err.original_error = old_exc - raise err - - def get_cache_path(self, archive_name, names=()): - """Return absolute location in cache for `archive_name` and `names` - - The parent directory of the resulting path will be created if it does - not already exist. `archive_name` should be the base filename of the - enclosing egg (which may not be the name of the enclosing zipfile!), - including its ".egg" extension. `names`, if provided, should be a - sequence of path name parts "under" the egg's extraction location. - - This method should only be called by resource providers that need to - obtain an extraction location, and only for names they intend to - extract, as it tracks the generated names for possible cleanup later. - """ - extract_path = self.extraction_path or get_default_cache() - target_path = os.path.join(extract_path, archive_name + '-tmp', *names) - try: - _bypass_ensure_directory(target_path) - except Exception: - self.extraction_error() - - self._warn_unsafe_extraction_path(extract_path) - - self.cached_files[target_path] = 1 - return target_path - - @staticmethod - def _warn_unsafe_extraction_path(path): - """ - If the default extraction path is overridden and set to an insecure - location, such as /tmp, it opens up an opportunity for an attacker to - replace an extracted file with an unauthorized payload. Warn the user - if a known insecure location is used. - - See Distribute #375 for more details. - """ - if os.name == 'nt' and not path.startswith(os.environ['windir']): - # On Windows, permissions are generally restrictive by default - # and temp directories are not writable by other users, so - # bypass the warning. - return - mode = os.stat(path).st_mode - if mode & stat.S_IWOTH or mode & stat.S_IWGRP: - msg = ( - "Extraction path is writable by group/others " - "and vulnerable to attack when " - "used with get_resource_filename ({path}). " - "Consider a more secure " - "location (set with .set_extraction_path or the " - "PYTHON_EGG_CACHE environment variable)." - ).format(**locals()) - warnings.warn(msg, UserWarning) - - def postprocess(self, tempname, filename): - """Perform any platform-specific postprocessing of `tempname` - - This is where Mac header rewrites should be done; other platforms don't - have anything special they should do. - - Resource providers should call this method ONLY after successfully - extracting a compressed resource. They must NOT call it on resources - that are already in the filesystem. - - `tempname` is the current (temporary) name of the file, and `filename` - is the name it will be renamed to by the caller after this routine - returns. - """ - - if os.name == 'posix': - # Make the resource executable - mode = ((os.stat(tempname).st_mode) | 0o555) & 0o7777 - os.chmod(tempname, mode) - - def set_extraction_path(self, path): - """Set the base path where resources will be extracted to, if needed. - - If you do not call this routine before any extractions take place, the - path defaults to the return value of ``get_default_cache()``. (Which - is based on the ``PYTHON_EGG_CACHE`` environment variable, with various - platform-specific fallbacks. See that routine's documentation for more - details.) - - Resources are extracted to subdirectories of this path based upon - information given by the ``IResourceProvider``. You may set this to a - temporary directory, but then you must call ``cleanup_resources()`` to - delete the extracted files when done. There is no guarantee that - ``cleanup_resources()`` will be able to remove all extracted files. - - (Note: you may not change the extraction path for a given resource - manager once resources have been extracted, unless you first call - ``cleanup_resources()``.) - """ - if self.cached_files: - raise ValueError("Can't change extraction path, files already extracted") - - self.extraction_path = path - - def cleanup_resources(self, force=False): - """ - Delete all extracted resource files and directories, returning a list - of the file and directory names that could not be successfully removed. - This function does not have any concurrency protection, so it should - generally only be called when the extraction path is a temporary - directory exclusive to a single process. This method is not - automatically called; you must call it explicitly or register it as an - ``atexit`` function if you wish to ensure cleanup of a temporary - directory used for extractions. - """ - # XXX - - -def get_default_cache(): - """ - Return the ``PYTHON_EGG_CACHE`` environment variable - or a platform-relevant user cache dir for an app - named "Python-Eggs". - """ - return os.environ.get('PYTHON_EGG_CACHE') or platformdirs.user_cache_dir( - appname='Python-Eggs' - ) - - -def safe_name(name): - """Convert an arbitrary string to a standard distribution name - - Any runs of non-alphanumeric/. characters are replaced with a single '-'. - """ - return re.sub('[^A-Za-z0-9.]+', '-', name) - - -def safe_version(version): - """ - Convert an arbitrary string to a standard version string - """ - try: - # normalize the version - return str(packaging.version.Version(version)) - except packaging.version.InvalidVersion: - version = version.replace(' ', '.') - return re.sub('[^A-Za-z0-9.]+', '-', version) - - -def _forgiving_version(version): - """Fallback when ``safe_version`` is not safe enough - >>> parse_version(_forgiving_version('0.23ubuntu1')) - - >>> parse_version(_forgiving_version('0.23-')) - - >>> parse_version(_forgiving_version('0.-_')) - - >>> parse_version(_forgiving_version('42.+?1')) - - >>> parse_version(_forgiving_version('hello world')) - - """ - version = version.replace(' ', '.') - match = _PEP440_FALLBACK.search(version) - if match: - safe = match["safe"] - rest = version[len(safe):] - else: - safe = "0" - rest = version - local = f"sanitized.{_safe_segment(rest)}".strip(".") - return f"{safe}.dev0+{local}" - - -def _safe_segment(segment): - """Convert an arbitrary string into a safe segment""" - segment = re.sub('[^A-Za-z0-9.]+', '-', segment) - segment = re.sub('-[^A-Za-z0-9]+', '-', segment) - return re.sub(r'\.[^A-Za-z0-9]+', '.', segment).strip(".-") - - -def safe_extra(extra): - """Convert an arbitrary string to a standard 'extra' name - - Any runs of non-alphanumeric characters are replaced with a single '_', - and the result is always lowercased. - """ - return re.sub('[^A-Za-z0-9.-]+', '_', extra).lower() - - -def to_filename(name): - """Convert a project or version name to its filename-escaped form - - Any '-' characters are currently replaced with '_'. - """ - return name.replace('-', '_') - - -def invalid_marker(text): - """ - Validate text as a PEP 508 environment marker; return an exception - if invalid or False otherwise. - """ - try: - evaluate_marker(text) - except SyntaxError as e: - e.filename = None - e.lineno = None - return e - return False - - -def evaluate_marker(text, extra=None): - """ - Evaluate a PEP 508 environment marker. - Return a boolean indicating the marker result in this environment. - Raise SyntaxError if marker is invalid. - - This implementation uses the 'pyparsing' module. - """ - try: - marker = packaging.markers.Marker(text) - return marker.evaluate() - except packaging.markers.InvalidMarker as e: - raise SyntaxError(e) from e - - -class NullProvider: - """Try to implement resources and metadata for arbitrary PEP 302 loaders""" - - egg_name = None - egg_info = None - loader = None - - def __init__(self, module): - self.loader = getattr(module, '__loader__', None) - self.module_path = os.path.dirname(getattr(module, '__file__', '')) - - def get_resource_filename(self, manager, resource_name): - return self._fn(self.module_path, resource_name) - - def get_resource_stream(self, manager, resource_name): - return io.BytesIO(self.get_resource_string(manager, resource_name)) - - def get_resource_string(self, manager, resource_name): - return self._get(self._fn(self.module_path, resource_name)) - - def has_resource(self, resource_name): - return self._has(self._fn(self.module_path, resource_name)) - - def _get_metadata_path(self, name): - return self._fn(self.egg_info, name) - - def has_metadata(self, name): - if not self.egg_info: - return self.egg_info - - path = self._get_metadata_path(name) - return self._has(path) - - def get_metadata(self, name): - if not self.egg_info: - return "" - path = self._get_metadata_path(name) - value = self._get(path) - try: - return value.decode('utf-8') - except UnicodeDecodeError as exc: - # Include the path in the error message to simplify - # troubleshooting, and without changing the exception type. - exc.reason += ' in {} file at path: {}'.format(name, path) - raise - - def get_metadata_lines(self, name): - return yield_lines(self.get_metadata(name)) - - def resource_isdir(self, resource_name): - return self._isdir(self._fn(self.module_path, resource_name)) - - def metadata_isdir(self, name): - return self.egg_info and self._isdir(self._fn(self.egg_info, name)) - - def resource_listdir(self, resource_name): - return self._listdir(self._fn(self.module_path, resource_name)) - - def metadata_listdir(self, name): - if self.egg_info: - return self._listdir(self._fn(self.egg_info, name)) - return [] - - def run_script(self, script_name, namespace): - script = 'scripts/' + script_name - if not self.has_metadata(script): - raise ResolutionError( - "Script {script!r} not found in metadata at {self.egg_info!r}".format( - **locals() - ), - ) - script_text = self.get_metadata(script).replace('\r\n', '\n') - script_text = script_text.replace('\r', '\n') - script_filename = self._fn(self.egg_info, script) - namespace['__file__'] = script_filename - if os.path.exists(script_filename): - with open(script_filename) as fid: - source = fid.read() - code = compile(source, script_filename, 'exec') - exec(code, namespace, namespace) - else: - from linecache import cache - - cache[script_filename] = ( - len(script_text), - 0, - script_text.split('\n'), - script_filename, - ) - script_code = compile(script_text, script_filename, 'exec') - exec(script_code, namespace, namespace) - - def _has(self, path): - raise NotImplementedError( - "Can't perform this operation for unregistered loader type" - ) - - def _isdir(self, path): - raise NotImplementedError( - "Can't perform this operation for unregistered loader type" - ) - - def _listdir(self, path): - raise NotImplementedError( - "Can't perform this operation for unregistered loader type" - ) - - def _fn(self, base, resource_name): - self._validate_resource_path(resource_name) - if resource_name: - return os.path.join(base, *resource_name.split('/')) - return base - - @staticmethod - def _validate_resource_path(path): - """ - Validate the resource paths according to the docs. - https://setuptools.pypa.io/en/latest/pkg_resources.html#basic-resource-access - - >>> warned = getfixture('recwarn') - >>> warnings.simplefilter('always') - >>> vrp = NullProvider._validate_resource_path - >>> vrp('foo/bar.txt') - >>> bool(warned) - False - >>> vrp('../foo/bar.txt') - >>> bool(warned) - True - >>> warned.clear() - >>> vrp('/foo/bar.txt') - >>> bool(warned) - True - >>> vrp('foo/../../bar.txt') - >>> bool(warned) - True - >>> warned.clear() - >>> vrp('foo/f../bar.txt') - >>> bool(warned) - False - - Windows path separators are straight-up disallowed. - >>> vrp(r'\\foo/bar.txt') - Traceback (most recent call last): - ... - ValueError: Use of .. or absolute path in a resource path \ -is not allowed. - - >>> vrp(r'C:\\foo/bar.txt') - Traceback (most recent call last): - ... - ValueError: Use of .. or absolute path in a resource path \ -is not allowed. - - Blank values are allowed - - >>> vrp('') - >>> bool(warned) - False - - Non-string values are not. - - >>> vrp(None) - Traceback (most recent call last): - ... - AttributeError: ... - """ - invalid = ( - os.path.pardir in path.split(posixpath.sep) - or posixpath.isabs(path) - or ntpath.isabs(path) - ) - if not invalid: - return - - msg = "Use of .. or absolute path in a resource path is not allowed." - - # Aggressively disallow Windows absolute paths - if ntpath.isabs(path) and not posixpath.isabs(path): - raise ValueError(msg) - - # for compatibility, warn; in future - # raise ValueError(msg) - issue_warning( - msg[:-1] + " and will raise exceptions in a future release.", - DeprecationWarning, - ) - - def _get(self, path): - if hasattr(self.loader, 'get_data'): - return self.loader.get_data(path) - raise NotImplementedError( - "Can't perform this operation for loaders without 'get_data()'" - ) - - -register_loader_type(object, NullProvider) - - -def _parents(path): - """ - yield all parents of path including path - """ - last = None - while path != last: - yield path - last = path - path, _ = os.path.split(path) - - -class EggProvider(NullProvider): - """Provider based on a virtual filesystem""" - - def __init__(self, module): - super().__init__(module) - self._setup_prefix() - - def _setup_prefix(self): - # Assume that metadata may be nested inside a "basket" - # of multiple eggs and use module_path instead of .archive. - eggs = filter(_is_egg_path, _parents(self.module_path)) - egg = next(eggs, None) - egg and self._set_egg(egg) - - def _set_egg(self, path): - self.egg_name = os.path.basename(path) - self.egg_info = os.path.join(path, 'EGG-INFO') - self.egg_root = path - - -class DefaultProvider(EggProvider): - """Provides access to package resources in the filesystem""" - - def _has(self, path): - return os.path.exists(path) - - def _isdir(self, path): - return os.path.isdir(path) - - def _listdir(self, path): - return os.listdir(path) - - def get_resource_stream(self, manager, resource_name): - return open(self._fn(self.module_path, resource_name), 'rb') - - def _get(self, path): - with open(path, 'rb') as stream: - return stream.read() - - @classmethod - def _register(cls): - loader_names = ( - 'SourceFileLoader', - 'SourcelessFileLoader', - ) - for name in loader_names: - loader_cls = getattr(importlib_machinery, name, type(None)) - register_loader_type(loader_cls, cls) - - -DefaultProvider._register() - - -class EmptyProvider(NullProvider): - """Provider that returns nothing for all requests""" - - module_path = None - - _isdir = _has = lambda self, path: False - - def _get(self, path): - return '' - - def _listdir(self, path): - return [] - - def __init__(self): - pass - - -empty_provider = EmptyProvider() - - -class ZipManifests(dict): - """ - zip manifest builder - """ - - @classmethod - def build(cls, path): - """ - Build a dictionary similar to the zipimport directory - caches, except instead of tuples, store ZipInfo objects. - - Use a platform-specific path separator (os.sep) for the path keys - for compatibility with pypy on Windows. - """ - with zipfile.ZipFile(path) as zfile: - items = ( - ( - name.replace('/', os.sep), - zfile.getinfo(name), - ) - for name in zfile.namelist() - ) - return dict(items) - - load = build - - -class MemoizedZipManifests(ZipManifests): - """ - Memoized zipfile manifests. - """ - - manifest_mod = collections.namedtuple('manifest_mod', 'manifest mtime') - - def load(self, path): - """ - Load a manifest at path or return a suitable manifest already loaded. - """ - path = os.path.normpath(path) - mtime = os.stat(path).st_mtime - - if path not in self or self[path].mtime != mtime: - manifest = self.build(path) - self[path] = self.manifest_mod(manifest, mtime) - - return self[path].manifest - - -class ZipProvider(EggProvider): - """Resource support for zips and eggs""" - - eagers = None - _zip_manifests = MemoizedZipManifests() - - def __init__(self, module): - super().__init__(module) - self.zip_pre = self.loader.archive + os.sep - - def _zipinfo_name(self, fspath): - # Convert a virtual filename (full path to file) into a zipfile subpath - # usable with the zipimport directory cache for our target archive - fspath = fspath.rstrip(os.sep) - if fspath == self.loader.archive: - return '' - if fspath.startswith(self.zip_pre): - return fspath[len(self.zip_pre) :] - raise AssertionError("%s is not a subpath of %s" % (fspath, self.zip_pre)) - - def _parts(self, zip_path): - # Convert a zipfile subpath into an egg-relative path part list. - # pseudo-fs path - fspath = self.zip_pre + zip_path - if fspath.startswith(self.egg_root + os.sep): - return fspath[len(self.egg_root) + 1 :].split(os.sep) - raise AssertionError("%s is not a subpath of %s" % (fspath, self.egg_root)) - - @property - def zipinfo(self): - return self._zip_manifests.load(self.loader.archive) - - def get_resource_filename(self, manager, resource_name): - if not self.egg_name: - raise NotImplementedError( - "resource_filename() only supported for .egg, not .zip" - ) - # no need to lock for extraction, since we use temp names - zip_path = self._resource_to_zip(resource_name) - eagers = self._get_eager_resources() - if '/'.join(self._parts(zip_path)) in eagers: - for name in eagers: - self._extract_resource(manager, self._eager_to_zip(name)) - return self._extract_resource(manager, zip_path) - - @staticmethod - def _get_date_and_size(zip_stat): - size = zip_stat.file_size - # ymdhms+wday, yday, dst - date_time = zip_stat.date_time + (0, 0, -1) - # 1980 offset already done - timestamp = time.mktime(date_time) - return timestamp, size - - # FIXME: 'ZipProvider._extract_resource' is too complex (12) - def _extract_resource(self, manager, zip_path): # noqa: C901 - if zip_path in self._index(): - for name in self._index()[zip_path]: - last = self._extract_resource(manager, os.path.join(zip_path, name)) - # return the extracted directory name - return os.path.dirname(last) - - timestamp, size = self._get_date_and_size(self.zipinfo[zip_path]) - - if not WRITE_SUPPORT: - raise IOError( - '"os.rename" and "os.unlink" are not supported ' 'on this platform' - ) - try: - real_path = manager.get_cache_path(self.egg_name, self._parts(zip_path)) - - if self._is_current(real_path, zip_path): - return real_path - - outf, tmpnam = _mkstemp( - ".$extract", - dir=os.path.dirname(real_path), - ) - os.write(outf, self.loader.get_data(zip_path)) - os.close(outf) - utime(tmpnam, (timestamp, timestamp)) - manager.postprocess(tmpnam, real_path) - - try: - rename(tmpnam, real_path) - - except os.error: - if os.path.isfile(real_path): - if self._is_current(real_path, zip_path): - # the file became current since it was checked above, - # so proceed. - return real_path - # Windows, del old file and retry - elif os.name == 'nt': - unlink(real_path) - rename(tmpnam, real_path) - return real_path - raise - - except os.error: - # report a user-friendly error - manager.extraction_error() - - return real_path - - def _is_current(self, file_path, zip_path): - """ - Return True if the file_path is current for this zip_path - """ - timestamp, size = self._get_date_and_size(self.zipinfo[zip_path]) - if not os.path.isfile(file_path): - return False - stat = os.stat(file_path) - if stat.st_size != size or stat.st_mtime != timestamp: - return False - # check that the contents match - zip_contents = self.loader.get_data(zip_path) - with open(file_path, 'rb') as f: - file_contents = f.read() - return zip_contents == file_contents - - def _get_eager_resources(self): - if self.eagers is None: - eagers = [] - for name in ('native_libs.txt', 'eager_resources.txt'): - if self.has_metadata(name): - eagers.extend(self.get_metadata_lines(name)) - self.eagers = eagers - return self.eagers - - def _index(self): - try: - return self._dirindex - except AttributeError: - ind = {} - for path in self.zipinfo: - parts = path.split(os.sep) - while parts: - parent = os.sep.join(parts[:-1]) - if parent in ind: - ind[parent].append(parts[-1]) - break - else: - ind[parent] = [parts.pop()] - self._dirindex = ind - return ind - - def _has(self, fspath): - zip_path = self._zipinfo_name(fspath) - return zip_path in self.zipinfo or zip_path in self._index() - - def _isdir(self, fspath): - return self._zipinfo_name(fspath) in self._index() - - def _listdir(self, fspath): - return list(self._index().get(self._zipinfo_name(fspath), ())) - - def _eager_to_zip(self, resource_name): - return self._zipinfo_name(self._fn(self.egg_root, resource_name)) - - def _resource_to_zip(self, resource_name): - return self._zipinfo_name(self._fn(self.module_path, resource_name)) - - -register_loader_type(zipimport.zipimporter, ZipProvider) - - -class FileMetadata(EmptyProvider): - """Metadata handler for standalone PKG-INFO files - - Usage:: - - metadata = FileMetadata("/path/to/PKG-INFO") - - This provider rejects all data and metadata requests except for PKG-INFO, - which is treated as existing, and will be the contents of the file at - the provided location. - """ - - def __init__(self, path): - self.path = path - - def _get_metadata_path(self, name): - return self.path - - def has_metadata(self, name): - return name == 'PKG-INFO' and os.path.isfile(self.path) - - def get_metadata(self, name): - if name != 'PKG-INFO': - raise KeyError("No metadata except PKG-INFO is available") - - with io.open(self.path, encoding='utf-8', errors="replace") as f: - metadata = f.read() - self._warn_on_replacement(metadata) - return metadata - - def _warn_on_replacement(self, metadata): - replacement_char = '�' - if replacement_char in metadata: - tmpl = "{self.path} could not be properly decoded in UTF-8" - msg = tmpl.format(**locals()) - warnings.warn(msg) - - def get_metadata_lines(self, name): - return yield_lines(self.get_metadata(name)) - - -class PathMetadata(DefaultProvider): - """Metadata provider for egg directories - - Usage:: - - # Development eggs: - - egg_info = "/path/to/PackageName.egg-info" - base_dir = os.path.dirname(egg_info) - metadata = PathMetadata(base_dir, egg_info) - dist_name = os.path.splitext(os.path.basename(egg_info))[0] - dist = Distribution(basedir, project_name=dist_name, metadata=metadata) - - # Unpacked egg directories: - - egg_path = "/path/to/PackageName-ver-pyver-etc.egg" - metadata = PathMetadata(egg_path, os.path.join(egg_path,'EGG-INFO')) - dist = Distribution.from_filename(egg_path, metadata=metadata) - """ - - def __init__(self, path, egg_info): - self.module_path = path - self.egg_info = egg_info - - -class EggMetadata(ZipProvider): - """Metadata provider for .egg files""" - - def __init__(self, importer): - """Create a metadata provider from a zipimporter""" - - self.zip_pre = importer.archive + os.sep - self.loader = importer - if importer.prefix: - self.module_path = os.path.join(importer.archive, importer.prefix) - else: - self.module_path = importer.archive - self._setup_prefix() - - -_declare_state('dict', _distribution_finders={}) - - -def register_finder(importer_type, distribution_finder): - """Register `distribution_finder` to find distributions in sys.path items - - `importer_type` is the type or class of a PEP 302 "Importer" (sys.path item - handler), and `distribution_finder` is a callable that, passed a path - item and the importer instance, yields ``Distribution`` instances found on - that path item. See ``pkg_resources.find_on_path`` for an example.""" - _distribution_finders[importer_type] = distribution_finder - - -def find_distributions(path_item, only=False): - """Yield distributions accessible via `path_item`""" - importer = get_importer(path_item) - finder = _find_adapter(_distribution_finders, importer) - return finder(importer, path_item, only) - - -def find_eggs_in_zip(importer, path_item, only=False): - """ - Find eggs in zip files; possibly multiple nested eggs. - """ - if importer.archive.endswith('.whl'): - # wheels are not supported with this finder - # they don't have PKG-INFO metadata, and won't ever contain eggs - return - metadata = EggMetadata(importer) - if metadata.has_metadata('PKG-INFO'): - yield Distribution.from_filename(path_item, metadata=metadata) - if only: - # don't yield nested distros - return - for subitem in metadata.resource_listdir(''): - if _is_egg_path(subitem): - subpath = os.path.join(path_item, subitem) - dists = find_eggs_in_zip(zipimport.zipimporter(subpath), subpath) - for dist in dists: - yield dist - elif subitem.lower().endswith(('.dist-info', '.egg-info')): - subpath = os.path.join(path_item, subitem) - submeta = EggMetadata(zipimport.zipimporter(subpath)) - submeta.egg_info = subpath - yield Distribution.from_location(path_item, subitem, submeta) - - -register_finder(zipimport.zipimporter, find_eggs_in_zip) - - -def find_nothing(importer, path_item, only=False): - return () - - -register_finder(object, find_nothing) - - -def find_on_path(importer, path_item, only=False): - """Yield distributions accessible on a sys.path directory""" - path_item = _normalize_cached(path_item) - - if _is_unpacked_egg(path_item): - yield Distribution.from_filename( - path_item, - metadata=PathMetadata(path_item, os.path.join(path_item, 'EGG-INFO')), - ) - return - - entries = (os.path.join(path_item, child) for child in safe_listdir(path_item)) - - # scan for .egg and .egg-info in directory - for entry in sorted(entries): - fullpath = os.path.join(path_item, entry) - factory = dist_factory(path_item, entry, only) - for dist in factory(fullpath): - yield dist - - -def dist_factory(path_item, entry, only): - """Return a dist_factory for the given entry.""" - lower = entry.lower() - is_egg_info = lower.endswith('.egg-info') - is_dist_info = lower.endswith('.dist-info') and os.path.isdir( - os.path.join(path_item, entry) - ) - is_meta = is_egg_info or is_dist_info - return ( - distributions_from_metadata - if is_meta - else find_distributions - if not only and _is_egg_path(entry) - else resolve_egg_link - if not only and lower.endswith('.egg-link') - else NoDists() - ) - - -class NoDists: - """ - >>> bool(NoDists()) - False - - >>> list(NoDists()('anything')) - [] - """ - - def __bool__(self): - return False - - def __call__(self, fullpath): - return iter(()) - - -def safe_listdir(path): - """ - Attempt to list contents of path, but suppress some exceptions. - """ - try: - return os.listdir(path) - except (PermissionError, NotADirectoryError): - pass - except OSError as e: - # Ignore the directory if does not exist, not a directory or - # permission denied - if e.errno not in (errno.ENOTDIR, errno.EACCES, errno.ENOENT): - raise - return () - - -def distributions_from_metadata(path): - root = os.path.dirname(path) - if os.path.isdir(path): - if len(os.listdir(path)) == 0: - # empty metadata dir; skip - return - metadata = PathMetadata(root, path) - else: - metadata = FileMetadata(path) - entry = os.path.basename(path) - yield Distribution.from_location( - root, - entry, - metadata, - precedence=DEVELOP_DIST, - ) - - -def non_empty_lines(path): - """ - Yield non-empty lines from file at path - """ - with open(path) as f: - for line in f: - line = line.strip() - if line: - yield line - - -def resolve_egg_link(path): - """ - Given a path to an .egg-link, resolve distributions - present in the referenced path. - """ - referenced_paths = non_empty_lines(path) - resolved_paths = ( - os.path.join(os.path.dirname(path), ref) for ref in referenced_paths - ) - dist_groups = map(find_distributions, resolved_paths) - return next(dist_groups, ()) - - -if hasattr(pkgutil, 'ImpImporter'): - register_finder(pkgutil.ImpImporter, find_on_path) - -register_finder(importlib_machinery.FileFinder, find_on_path) - -_declare_state('dict', _namespace_handlers={}) -_declare_state('dict', _namespace_packages={}) - - -def register_namespace_handler(importer_type, namespace_handler): - """Register `namespace_handler` to declare namespace packages - - `importer_type` is the type or class of a PEP 302 "Importer" (sys.path item - handler), and `namespace_handler` is a callable like this:: - - def namespace_handler(importer, path_entry, moduleName, module): - # return a path_entry to use for child packages - - Namespace handlers are only called if the importer object has already - agreed that it can handle the relevant path item, and they should only - return a subpath if the module __path__ does not already contain an - equivalent subpath. For an example namespace handler, see - ``pkg_resources.file_ns_handler``. - """ - _namespace_handlers[importer_type] = namespace_handler - - -def _handle_ns(packageName, path_item): - """Ensure that named package includes a subpath of path_item (if needed)""" - - importer = get_importer(path_item) - if importer is None: - return None - - # use find_spec (PEP 451) and fall-back to find_module (PEP 302) - try: - spec = importer.find_spec(packageName) - except AttributeError: - # capture warnings due to #1111 - with warnings.catch_warnings(): - warnings.simplefilter("ignore") - loader = importer.find_module(packageName) - else: - loader = spec.loader if spec else None - - if loader is None: - return None - module = sys.modules.get(packageName) - if module is None: - module = sys.modules[packageName] = types.ModuleType(packageName) - module.__path__ = [] - _set_parent_ns(packageName) - elif not hasattr(module, '__path__'): - raise TypeError("Not a package:", packageName) - handler = _find_adapter(_namespace_handlers, importer) - subpath = handler(importer, path_item, packageName, module) - if subpath is not None: - path = module.__path__ - path.append(subpath) - importlib.import_module(packageName) - _rebuild_mod_path(path, packageName, module) - return subpath - - -def _rebuild_mod_path(orig_path, package_name, module): - """ - Rebuild module.__path__ ensuring that all entries are ordered - corresponding to their sys.path order - """ - sys_path = [_normalize_cached(p) for p in sys.path] - - def safe_sys_path_index(entry): - """ - Workaround for #520 and #513. - """ - try: - return sys_path.index(entry) - except ValueError: - return float('inf') - - def position_in_sys_path(path): - """ - Return the ordinal of the path based on its position in sys.path - """ - path_parts = path.split(os.sep) - module_parts = package_name.count('.') + 1 - parts = path_parts[:-module_parts] - return safe_sys_path_index(_normalize_cached(os.sep.join(parts))) - - new_path = sorted(orig_path, key=position_in_sys_path) - new_path = [_normalize_cached(p) for p in new_path] - - if isinstance(module.__path__, list): - module.__path__[:] = new_path - else: - module.__path__ = new_path - - -def declare_namespace(packageName): - """Declare that package 'packageName' is a namespace package""" - - msg = ( - f"Deprecated call to `pkg_resources.declare_namespace({packageName!r})`.\n" - "Implementing implicit namespace packages (as specified in PEP 420) " - "is preferred to `pkg_resources.declare_namespace`. " - "See https://setuptools.pypa.io/en/latest/references/" - "keywords.html#keyword-namespace-packages" - ) - warnings.warn(msg, DeprecationWarning, stacklevel=2) - - _imp.acquire_lock() - try: - if packageName in _namespace_packages: - return - - path = sys.path - parent, _, _ = packageName.rpartition('.') - - if parent: - declare_namespace(parent) - if parent not in _namespace_packages: - __import__(parent) - try: - path = sys.modules[parent].__path__ - except AttributeError as e: - raise TypeError("Not a package:", parent) from e - - # Track what packages are namespaces, so when new path items are added, - # they can be updated - _namespace_packages.setdefault(parent or None, []).append(packageName) - _namespace_packages.setdefault(packageName, []) - - for path_item in path: - # Ensure all the parent's path items are reflected in the child, - # if they apply - _handle_ns(packageName, path_item) - - finally: - _imp.release_lock() - - -def fixup_namespace_packages(path_item, parent=None): - """Ensure that previously-declared namespace packages include path_item""" - _imp.acquire_lock() - try: - for package in _namespace_packages.get(parent, ()): - subpath = _handle_ns(package, path_item) - if subpath: - fixup_namespace_packages(subpath, package) - finally: - _imp.release_lock() - - -def file_ns_handler(importer, path_item, packageName, module): - """Compute an ns-package subpath for a filesystem or zipfile importer""" - - subpath = os.path.join(path_item, packageName.split('.')[-1]) - normalized = _normalize_cached(subpath) - for item in module.__path__: - if _normalize_cached(item) == normalized: - break - else: - # Only return the path if it's not already there - return subpath - - -if hasattr(pkgutil, 'ImpImporter'): - register_namespace_handler(pkgutil.ImpImporter, file_ns_handler) - -register_namespace_handler(zipimport.zipimporter, file_ns_handler) -register_namespace_handler(importlib_machinery.FileFinder, file_ns_handler) - - -def null_ns_handler(importer, path_item, packageName, module): - return None - - -register_namespace_handler(object, null_ns_handler) - - -def normalize_path(filename): - """Normalize a file/dir name for comparison purposes""" - return os.path.normcase(os.path.realpath(os.path.normpath(_cygwin_patch(filename)))) - - -def _cygwin_patch(filename): # pragma: nocover - """ - Contrary to POSIX 2008, on Cygwin, getcwd (3) contains - symlink components. Using - os.path.abspath() works around this limitation. A fix in os.getcwd() - would probably better, in Cygwin even more so, except - that this seems to be by design... - """ - return os.path.abspath(filename) if sys.platform == 'cygwin' else filename - - -def _normalize_cached(filename, _cache={}): - try: - return _cache[filename] - except KeyError: - _cache[filename] = result = normalize_path(filename) - return result - - -def _is_egg_path(path): - """ - Determine if given path appears to be an egg. - """ - return _is_zip_egg(path) or _is_unpacked_egg(path) - - -def _is_zip_egg(path): - return ( - path.lower().endswith('.egg') - and os.path.isfile(path) - and zipfile.is_zipfile(path) - ) - - -def _is_unpacked_egg(path): - """ - Determine if given path appears to be an unpacked egg. - """ - return path.lower().endswith('.egg') and os.path.isfile( - os.path.join(path, 'EGG-INFO', 'PKG-INFO') - ) - - -def _set_parent_ns(packageName): - parts = packageName.split('.') - name = parts.pop() - if parts: - parent = '.'.join(parts) - setattr(sys.modules[parent], name, sys.modules[packageName]) - - -MODULE = re.compile(r"\w+(\.\w+)*$").match -EGG_NAME = re.compile( - r""" - (?P [^-]+) ( - -(?P [^-]+) ( - -py(?P [^-]+) ( - -(?P