├── .copier-answers.yml.tmpl ├── .dockerignore ├── .env.tmpl ├── .flake8 ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── PULL_REQUEST_TEMPLATE.md ├── dependabot.yml └── workflows │ └── codestyle.yaml ├── .gitignore ├── Dockerfile ├── LICENSE ├── Pipfile ├── Pipfile.lock ├── README.md ├── README.md.tmpl ├── app ├── __init__.py ├── api │ ├── __init__.py │ └── v1 │ │ ├── __init__.py │ │ ├── authentication.py │ │ └── users.py ├── main.py ├── models │ └── user.py └── schemas │ ├── __init__.py │ ├── authentication.py │ └── user.py ├── config.yaml.tmpl ├── copier.yaml ├── docker-compose.yaml.tmpl ├── mypy.ini ├── serve.sh └── start.sh /.copier-answers.yml.tmpl: -------------------------------------------------------------------------------- 1 | [[_copier_answers|to_nice_yaml]] -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | ### Python template 2 | # Byte-compiled / optimized / DLL files 3 | __pycache__/ 4 | *.py[cod] 5 | *$py.class 6 | 7 | # C extensions 8 | *.so 9 | 10 | # Distribution / packaging 11 | .Python 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | wheels/ 24 | share/python-wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .nox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | *.py,cover 51 | .hypothesis/ 52 | .pytest_cache/ 53 | cover/ 54 | 55 | # Translations 56 | *.mo 57 | *.pot 58 | 59 | # Django stuff: 60 | *.log 61 | local_settings.py 62 | db.sqlite3 63 | db.sqlite3-journal 64 | 65 | # Flask stuff: 66 | instance/ 67 | .webassets-cache 68 | 69 | # Scrapy stuff: 70 | .scrapy 71 | 72 | # Sphinx documentation 73 | docs/_build/ 74 | 75 | # PyBuilder 76 | .pybuilder/ 77 | target/ 78 | 79 | # Jupyter Notebook 80 | .ipynb_checkpoints 81 | 82 | # IPython 83 | profile_default/ 84 | ipython_config.py 85 | 86 | # pyenv 87 | # For a library or package, you might want to ignore these files since the code is 88 | # intended to run in multiple environments; otherwise, check them in: 89 | # .python-version 90 | 91 | # pipenv 92 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 93 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 94 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 95 | # install all needed dependencies. 96 | #Pipfile.lock 97 | 98 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 99 | __pypackages__/ 100 | 101 | # Celery stuff 102 | celerybeat-schedule 103 | celerybeat.pid 104 | 105 | # SageMath parsed files 106 | *.sage.py 107 | 108 | # Environments 109 | .env 110 | .venv 111 | env/ 112 | venv/ 113 | ENV/ 114 | env.bak/ 115 | venv.bak/ 116 | 117 | # Spyder project settings 118 | .spyderproject 119 | .spyproject 120 | 121 | # Rope project settings 122 | .ropeproject 123 | 124 | # mkdocs documentation 125 | /site 126 | 127 | # mypy 128 | .mypy_cache/ 129 | .dmypy.json 130 | dmypy.json 131 | 132 | # Pyre type checker 133 | .pyre/ 134 | 135 | # pytype static type analyzer 136 | .pytype/ 137 | 138 | # Cython debug symbols 139 | cython_debug/ 140 | 141 | ### JetBrains template 142 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider 143 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 144 | 145 | # User-specific stuff 146 | .idea/**/workspace.xml 147 | .idea/**/tasks.xml 148 | .idea/**/usage.statistics.xml 149 | .idea/**/dictionaries 150 | .idea/**/shelf 151 | 152 | # Generated files 153 | .idea/**/contentModel.xml 154 | 155 | # Sensitive or high-churn files 156 | .idea/**/dataSources/ 157 | .idea/**/dataSources.ids 158 | .idea/**/dataSources.local.xml 159 | .idea/**/sqlDataSources.xml 160 | .idea/**/dynamic.xml 161 | .idea/**/uiDesigner.xml 162 | .idea/**/dbnavigator.xml 163 | 164 | # Gradle 165 | .idea/**/gradle.xml 166 | .idea/**/libraries 167 | 168 | # Gradle and Maven with auto-import 169 | # When using Gradle or Maven with auto-import, you should exclude module files, 170 | # since they will be recreated, and may cause churn. Uncomment if using 171 | # auto-import. 172 | # .idea/artifacts 173 | # .idea/compiler.xml 174 | # .idea/jarRepositories.xml 175 | # .idea/modules.xml 176 | # .idea/*.iml 177 | # .idea/modules 178 | # *.iml 179 | # *.ipr 180 | 181 | # CMake 182 | cmake-build-*/ 183 | 184 | # Mongo Explorer plugin 185 | .idea/**/mongoSettings.xml 186 | 187 | # File-based project format 188 | *.iws 189 | 190 | # IntelliJ 191 | out/ 192 | 193 | # mpeltonen/sbt-idea plugin 194 | .idea_modules/ 195 | 196 | # JIRA plugin 197 | atlassian-ide-plugin.xml 198 | 199 | # Cursive Clojure plugin 200 | .idea/replstate.xml 201 | 202 | # Crashlytics plugin (for Android Studio and IntelliJ) 203 | com_crashlytics_export_strings.xml 204 | crashlytics.properties 205 | crashlytics-build.properties 206 | fabric.properties 207 | 208 | # Editor-based Rest Client 209 | .idea/httpRequests 210 | 211 | # Android studio 3.1+ serialized cache file 212 | .idea/caches/build_file_checksums.ser 213 | 214 | -------------------------------------------------------------------------------- /.env.tmpl: -------------------------------------------------------------------------------- 1 | JWT_SECRET_KEY="[[ jwt_secret_key ]]" 2 | DB_DRIVER="postgresql+asyncpg" 3 | DB_HOST="[[ db_host ]]" 4 | DB_PORT="[[ db_port ]]" 5 | DB_DATABASE="[[ db_database ]]" 6 | DB_USERNAME="[[ db_username ]]" 7 | DB_PASSWORD="[[ db_password ]]" 8 | DB_SQLITE=False 9 | REDIS_HOST="[[ redis_host ]]" -------------------------------------------------------------------------------- /.flake8: -------------------------------------------------------------------------------- 1 | [flake8] 2 | max-line-length = 120 3 | ignore = F401,E402 -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | **Description** 2 | Provide a description of what your changes do. 3 | 4 | **Issue** 5 | Closes #XX 6 | 7 | **Additional Notes** 8 | Add any other context about the pull request here. -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "pip" # See documentation for possible values 9 | directory: "/" # Location of package manifests 10 | schedule: 11 | interval: "daily" 12 | -------------------------------------------------------------------------------- /.github/workflows/codestyle.yaml: -------------------------------------------------------------------------------- 1 | name: Codestyle 2 | 3 | on: 4 | - push 5 | - pull_request 6 | 7 | jobs: 8 | codestyle: 9 | runs-on: ubuntu-latest 10 | 11 | steps: 12 | - name: Checkout 13 | uses: actions/checkout@v2.3.4 14 | 15 | - name: Set up Python 3.9 16 | uses: actions/setup-python@v2.2.2 17 | with: 18 | python-version: 3.9 19 | 20 | - name: Install Dependencies 21 | run: | 22 | pip install --upgrade pip 23 | pip install black mypy flake8 24 | - name: Check code formatting with black 25 | run: black -l 120 . --diff --check 26 | - name: Check code with flake8 27 | run: flake8 app/ 28 | - name: Check with MyPy 29 | run: mypy app/ 30 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ### Python template 2 | # Byte-compiled / optimized / DLL files 3 | __pycache__/ 4 | *.py[cod] 5 | *$py.class 6 | 7 | # C extensions 8 | *.so 9 | 10 | # Distribution / packaging 11 | .Python 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | wheels/ 24 | share/python-wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .nox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | *.py,cover 51 | .hypothesis/ 52 | .pytest_cache/ 53 | cover/ 54 | 55 | # Translations 56 | *.mo 57 | *.pot 58 | 59 | # Django stuff: 60 | *.log 61 | local_settings.py 62 | db.sqlite3 63 | db.sqlite3-journal 64 | 65 | # Flask stuff: 66 | instance/ 67 | .webassets-cache 68 | 69 | # Scrapy stuff: 70 | .scrapy 71 | 72 | # Sphinx documentation 73 | docs/_build/ 74 | 75 | # PyBuilder 76 | .pybuilder/ 77 | target/ 78 | 79 | # Jupyter Notebook 80 | .ipynb_checkpoints 81 | 82 | # IPython 83 | profile_default/ 84 | ipython_config.py 85 | 86 | # pyenv 87 | # For a library or package, you might want to ignore these files since the code is 88 | # intended to run in multiple environments; otherwise, check them in: 89 | # .python-version 90 | 91 | # pipenv 92 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 93 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 94 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 95 | # install all needed dependencies. 96 | #Pipfile.lock 97 | 98 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 99 | __pypackages__/ 100 | 101 | # Celery stuff 102 | celerybeat-schedule 103 | celerybeat.pid 104 | 105 | # SageMath parsed files 106 | *.sage.py 107 | 108 | # Environments 109 | .env 110 | .venv 111 | env/ 112 | venv/ 113 | ENV/ 114 | env.bak/ 115 | venv.bak/ 116 | 117 | # Spyder project settings 118 | .spyderproject 119 | .spyproject 120 | 121 | # Rope project settings 122 | .ropeproject 123 | 124 | # mkdocs documentation 125 | /site 126 | 127 | # mypy 128 | .mypy_cache/ 129 | .dmypy.json 130 | dmypy.json 131 | 132 | # Pyre type checker 133 | .pyre/ 134 | 135 | # pytype static type analyzer 136 | .pytype/ 137 | 138 | # Cython debug symbols 139 | cython_debug/ 140 | 141 | ### JetBrains template 142 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider 143 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 144 | 145 | # User-specific stuff 146 | .idea/**/workspace.xml 147 | .idea/**/tasks.xml 148 | .idea/**/usage.statistics.xml 149 | .idea/**/dictionaries 150 | .idea/**/shelf 151 | 152 | # Generated files 153 | .idea/**/contentModel.xml 154 | 155 | # Sensitive or high-churn files 156 | .idea/**/dataSources/ 157 | .idea/**/dataSources.ids 158 | .idea/**/dataSources.local.xml 159 | .idea/**/sqlDataSources.xml 160 | .idea/**/dynamic.xml 161 | .idea/**/uiDesigner.xml 162 | .idea/**/dbnavigator.xml 163 | 164 | # Gradle 165 | .idea/**/gradle.xml 166 | .idea/**/libraries 167 | 168 | # Gradle and Maven with auto-import 169 | # When using Gradle or Maven with auto-import, you should exclude module files, 170 | # since they will be recreated, and may cause churn. Uncomment if using 171 | # auto-import. 172 | # .idea/artifacts 173 | # .idea/compiler.xml 174 | # .idea/jarRepositories.xml 175 | # .idea/modules.xml 176 | # .idea/*.iml 177 | # .idea/modules 178 | # *.iml 179 | # *.ipr 180 | 181 | # CMake 182 | cmake-build-*/ 183 | 184 | # Mongo Explorer plugin 185 | .idea/**/mongoSettings.xml 186 | 187 | # File-based project format 188 | *.iws 189 | 190 | # IntelliJ 191 | out/ 192 | 193 | # mpeltonen/sbt-idea plugin 194 | .idea_modules/ 195 | 196 | # JIRA plugin 197 | atlassian-ide-plugin.xml 198 | 199 | # Cursive Clojure plugin 200 | .idea/replstate.xml 201 | 202 | # Crashlytics plugin (for Android Studio and IntelliJ) 203 | com_crashlytics_export_strings.xml 204 | crashlytics.properties 205 | crashlytics-build.properties 206 | fabric.properties 207 | 208 | # Editor-based Rest Client 209 | .idea/httpRequests 210 | 211 | # Android studio 3.1+ serialized cache file 212 | .idea/caches/build_file_checksums.ser 213 | 214 | ### VirtualEnv template 215 | # Virtualenv 216 | # http://iamzed.com/2009/05/07/a-primer-on-virtualenv/ 217 | .Python 218 | [Bb]in 219 | [Ii]nclude 220 | [Ll]ib 221 | [Ll]ib64 222 | [Ll]ocal 223 | [Ss]cripts 224 | pyvenv.cfg 225 | .venv 226 | pip-selfcheck.json 227 | 228 | .env.test 229 | 230 | .idea/ 231 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.9-alpine 2 | 3 | RUN apk add --no-cache build-base musl-dev gcc yaml-dev 4 | 5 | RUN pip install pipenv 6 | 7 | WORKDIR /app 8 | 9 | COPY Pipfile . 10 | 11 | COPY Pipfile.lock . 12 | 13 | RUN python -m pipenv install --system --deploy 14 | 15 | COPY start.sh . 16 | 17 | COPY app/ ./app 18 | 19 | COPY config.yaml . 20 | 21 | CMD chmod +x start.sh && ./start.sh -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Tert0 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /Pipfile: -------------------------------------------------------------------------------- 1 | [[source]] 2 | url = "https://pypi.org/simple" 3 | verify_ssl = true 4 | name = "pypi" 5 | 6 | [packages] 7 | fastapi = "0.92.0" 8 | fastapi-framework = "1.5.3.3" 9 | uvicorn = "0.34.3" 10 | python-dotenv = "1.0.0" 11 | sqlalchemy = "2.0.4" 12 | asyncpg = "0.30.0" 13 | pydantic = "1.10.5" 14 | 15 | 16 | [dev-packages] 17 | flake8 = "*" 18 | mypy = "*" 19 | 20 | [requires] 21 | python_version = "3.9" 22 | -------------------------------------------------------------------------------- /Pipfile.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "hash": { 4 | "sha256": "8811fb8ec170b6704918e26174e4ad82f591b3bf7aa273e68e5aa260a017b770" 5 | }, 6 | "pipfile-spec": 6, 7 | "requires": { 8 | "python_version": "3.9" 9 | }, 10 | "sources": [ 11 | { 12 | "name": "pypi", 13 | "url": "https://pypi.org/simple", 14 | "verify_ssl": true 15 | } 16 | ] 17 | }, 18 | "default": { 19 | "aioredis": { 20 | "hashes": [ 21 | "sha256:15f8af30b044c771aee6787e5ec24694c048184c7b9e54c3b60c750a4b93273a", 22 | "sha256:b61808d7e97b7cd5a92ed574937a079c9387fdadd22bfbfa7ad2fd319ecc26e3" 23 | ], 24 | "version": "==1.3.1" 25 | }, 26 | "anyio": { 27 | "hashes": [ 28 | "sha256:cfdb2b588b9fc25ede96d8db56ed50848b0b649dca3dd1df0b11f683bb9e0b5f", 29 | "sha256:f7ed51751b2c2add651e5747c891b47e26d2a21be5d32d9311dfe9692f3e5d7a" 30 | ], 31 | "markers": "python_version >= '3.8'", 32 | "version": "==4.0.0" 33 | }, 34 | "async-timeout": { 35 | "hashes": [ 36 | "sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f", 37 | "sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028" 38 | ], 39 | "markers": "python_full_version < '3.11.0'", 40 | "version": "==4.0.3" 41 | }, 42 | "asyncpg": { 43 | "hashes": [ 44 | "sha256:04ff0785ae7eed6cc138e73fc67b8e51d54ee7a3ce9b63666ce55a0bf095f7ba", 45 | "sha256:05b185ebb8083c8568ea8a40e896d5f7af4b8554b64d7719c0eaa1eb5a5c3a70", 46 | "sha256:0b448f0150e1c3b96cb0438a0d0aa4871f1472e58de14a3ec320dbb2798fb0d4", 47 | "sha256:0f5712350388d0cd0615caec629ad53c81e506b1abaaf8d14c93f54b35e3595a", 48 | "sha256:1292b84ee06ac8a2ad8e51c7475aa309245874b61333d97411aab835c4a2f737", 49 | "sha256:1b11a555a198b08f5c4baa8f8231c74a366d190755aa4f99aacec5970afe929a", 50 | "sha256:1b982daf2441a0ed314bd10817f1606f1c28b1136abd9e4f11335358c2c631cb", 51 | "sha256:1c06a3a50d014b303e5f6fc1e5f95eb28d2cee89cf58384b700da621e5d5e547", 52 | "sha256:1c198a00cce9506fcd0bf219a799f38ac7a237745e1d27f0e1f66d3707c84a5a", 53 | "sha256:26683d3b9a62836fad771a18ecf4659a30f348a561279d6227dab96182f46144", 54 | "sha256:29ff1fc8b5bf724273782ff8b4f57b0f8220a1b2324184846b39d1ab4122031d", 55 | "sha256:3152fef2e265c9c24eec4ee3d22b4f4d2703d30614b0b6753e9ed4115c8a146f", 56 | "sha256:3326e6d7381799e9735ca2ec9fd7be4d5fef5dcbc3cb555d8a463d8460607956", 57 | "sha256:3356637f0bd830407b5597317b3cb3571387ae52ddc3bca6233682be88bbbc1f", 58 | "sha256:393af4e3214c8fa4c7b86da6364384c0d1b3298d45803375572f415b6f673f38", 59 | "sha256:46973045b567972128a27d40001124fbc821c87a6cade040cfcd4fa8a30bcdc4", 60 | "sha256:51da377487e249e35bd0859661f6ee2b81db11ad1f4fc036194bc9cb2ead5056", 61 | "sha256:574156480df14f64c2d76450a3f3aaaf26105869cad3865041156b38459e935d", 62 | "sha256:578445f09f45d1ad7abddbff2a3c7f7c291738fdae0abffbeb737d3fc3ab8b75", 63 | "sha256:5b290f4726a887f75dcd1b3006f484252db37602313f806e9ffc4e5996cfe5cb", 64 | "sha256:5df69d55add4efcd25ea2a3b02025b669a285b767bfbf06e356d68dbce4234ff", 65 | "sha256:5e0511ad3dec5f6b4f7a9e063591d407eee66b88c14e2ea636f187da1dcfff6a", 66 | "sha256:64e899bce0600871b55368b8483e5e3e7f1860c9482e7f12e0a771e747988168", 67 | "sha256:68d71a1be3d83d0570049cd1654a9bdfe506e794ecc98ad0873304a9f35e411e", 68 | "sha256:6c2a2ef565400234a633da0eafdce27e843836256d40705d83ab7ec42074efb3", 69 | "sha256:6f4e83f067b35ab5e6371f8a4c93296e0439857b4569850b178a01385e82e9ad", 70 | "sha256:8b684a3c858a83cd876f05958823b68e8d14ec01bb0c0d14a6704c5bf9711773", 71 | "sha256:9110df111cabc2ed81aad2f35394a00cadf4f2e0635603db6ebbd0fc896f46a4", 72 | "sha256:915aeb9f79316b43c3207363af12d0e6fd10776641a7de8a01212afd95bdf0ed", 73 | "sha256:9a0292c6af5c500523949155ec17b7fe01a00ace33b68a476d6b5059f9630305", 74 | "sha256:9b6fde867a74e8c76c71e2f64f80c64c0f3163e687f1763cfaf21633ec24ec33", 75 | "sha256:a3479a0d9a852c7c84e822c073622baca862d1217b10a02dd57ee4a7a081f708", 76 | "sha256:aa403147d3e07a267ada2ae34dfc9324e67ccc4cdca35261c8c22792ba2b10cf", 77 | "sha256:aca1548e43bbb9f0f627a04666fedaca23db0a31a84136ad1f868cb15deb6e3a", 78 | "sha256:ae374585f51c2b444510cdf3595b97ece4f233fde739aa14b50e0d64e8a7a590", 79 | "sha256:bc6d84136f9c4d24d358f3b02be4b6ba358abd09f80737d1ac7c444f36108454", 80 | "sha256:bfb4dd5ae0699bad2b233672c8fc5ccbd9ad24b89afded02341786887e37927e", 81 | "sha256:c42f6bb65a277ce4d93f3fba46b91a265631c8df7250592dd4f11f8b0152150f", 82 | "sha256:c47806b1a8cbb0a0db896f4cd34d89942effe353a5035c62734ab13b9f938da3", 83 | "sha256:c551e9928ab6707602f44811817f82ba3c446e018bfe1d3abecc8ba5f3eac851", 84 | "sha256:c7255812ac85099a0e1ffb81b10dc477b9973345793776b128a23e60148dd1af", 85 | "sha256:c902a60b52e506d38d7e80e0dd5399f657220f24635fee368117b8b5fce1142e", 86 | "sha256:db9891e2d76e6f425746c5d2da01921e9a16b5a71a1c905b13f30e12a257c4af", 87 | "sha256:dc1f62c792752a49f88b7e6f774c26077091b44caceb1983509edc18a2222ec0", 88 | "sha256:f23b836dd90bea21104f69547923a02b167d999ce053f3d502081acea2fba15b", 89 | "sha256:f59b430b8e27557c3fb9869222559f7417ced18688375825f8f12302c34e915e", 90 | "sha256:f86b0e2cd3f1249d6fe6fd6cfe0cd4538ba994e2d8249c0491925629b9104d0f", 91 | "sha256:fb622c94db4e13137c4c7f98834185049cc50ee01d8f657ef898b6407c7b9c50", 92 | "sha256:fd4406d09208d5b4a14db9a9dbb311b6d7aeeab57bded7ed2f8ea41aeef39b34" 93 | ], 94 | "index": "pypi", 95 | "markers": "python_full_version >= '3.8.0'", 96 | "version": "==0.30.0" 97 | }, 98 | "click": { 99 | "hashes": [ 100 | "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2", 101 | "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a" 102 | ], 103 | "markers": "python_version >= '3.7'", 104 | "version": "==8.1.8" 105 | }, 106 | "exceptiongroup": { 107 | "hashes": [ 108 | "sha256:097acd85d473d75af5bb98e41b61ff7fe35efe6675e4f9370ec6ec5126d160e9", 109 | "sha256:343280667a4585d195ca1cf9cef84a4e178c4b6cf2274caef9859782b567d5e3" 110 | ], 111 | "markers": "python_version < '3.11'", 112 | "version": "==1.1.3" 113 | }, 114 | "fastapi": { 115 | "hashes": [ 116 | "sha256:023a0f5bd2c8b2609014d3bba1e14a1d7df96c6abea0a73070621c9862b9a4de", 117 | "sha256:ae7b97c778e2f2ec3fb3cb4fb14162129411d99907fb71920f6d69a524340ebf" 118 | ], 119 | "index": "pypi", 120 | "markers": "python_version >= '3.7'", 121 | "version": "==0.92.0" 122 | }, 123 | "fastapi-framework": { 124 | "hashes": [ 125 | "sha256:85aa673aa267d9dabbdb8a207628a2f2a72449696f6b5e3fc37de967ef2c621d", 126 | "sha256:af09afdb4f8f00342ae2870a52648a27549246a96dff3f1d3a10b57c15b948b3" 127 | ], 128 | "index": "pypi", 129 | "version": "==1.5.3.3" 130 | }, 131 | "greenlet": { 132 | "hashes": [ 133 | "sha256:02a807b2a58d5cdebb07050efe3d7deaf915468d112dfcf5e426d0564aa3aa4a", 134 | "sha256:0b72b802496cccbd9b31acea72b6f87e7771ccfd7f7927437d592e5c92ed703c", 135 | "sha256:0d3f83ffb18dc57243e0151331e3c383b05e5b6c5029ac29f754745c800f8ed9", 136 | "sha256:10b5582744abd9858947d163843d323d0b67be9432db50f8bf83031032bc218d", 137 | "sha256:123910c58234a8d40eaab595bc56a5ae49bdd90122dde5bdc012c20595a94c14", 138 | "sha256:1482fba7fbed96ea7842b5a7fc11d61727e8be75a077e603e8ab49d24e234383", 139 | "sha256:19834e3f91f485442adc1ee440171ec5d9a4840a1f7bd5ed97833544719ce10b", 140 | "sha256:1d363666acc21d2c204dd8705c0e0457d7b2ee7a76cb16ffc099d6799744ac99", 141 | "sha256:211ef8d174601b80e01436f4e6905aca341b15a566f35a10dd8d1e93f5dbb3b7", 142 | "sha256:269d06fa0f9624455ce08ae0179430eea61085e3cf6457f05982b37fd2cefe17", 143 | "sha256:2e7dcdfad252f2ca83c685b0fa9fba00e4d8f243b73839229d56ee3d9d219314", 144 | "sha256:334ef6ed8337bd0b58bb0ae4f7f2dcc84c9f116e474bb4ec250a8bb9bd797a66", 145 | "sha256:343675e0da2f3c69d3fb1e894ba0a1acf58f481f3b9372ce1eb465ef93cf6fed", 146 | "sha256:37f60b3a42d8b5499be910d1267b24355c495064f271cfe74bf28b17b099133c", 147 | "sha256:38ad562a104cd41e9d4644f46ea37167b93190c6d5e4048fcc4b80d34ecb278f", 148 | "sha256:3c0d36f5adc6e6100aedbc976d7428a9f7194ea79911aa4bf471f44ee13a9464", 149 | "sha256:3fd2b18432e7298fcbec3d39e1a0aa91ae9ea1c93356ec089421fabc3651572b", 150 | "sha256:4a1a6244ff96343e9994e37e5b4839f09a0207d35ef6134dce5c20d260d0302c", 151 | "sha256:4cd83fb8d8e17633ad534d9ac93719ef8937568d730ef07ac3a98cb520fd93e4", 152 | "sha256:527cd90ba3d8d7ae7dceb06fda619895768a46a1b4e423bdb24c1969823b8362", 153 | "sha256:56867a3b3cf26dc8a0beecdb4459c59f4c47cdd5424618c08515f682e1d46692", 154 | "sha256:621fcb346141ae08cb95424ebfc5b014361621b8132c48e538e34c3c93ac7365", 155 | "sha256:63acdc34c9cde42a6534518e32ce55c30f932b473c62c235a466469a710bfbf9", 156 | "sha256:6512592cc49b2c6d9b19fbaa0312124cd4c4c8a90d28473f86f92685cc5fef8e", 157 | "sha256:6672fdde0fd1a60b44fb1751a7779c6db487e42b0cc65e7caa6aa686874e79fb", 158 | "sha256:6a5b2d4cdaf1c71057ff823a19d850ed5c6c2d3686cb71f73ae4d6382aaa7a06", 159 | "sha256:6a68d670c8f89ff65c82b936275369e532772eebc027c3be68c6b87ad05ca695", 160 | "sha256:6bb36985f606a7c49916eff74ab99399cdfd09241c375d5a820bb855dfb4af9f", 161 | "sha256:73b2f1922a39d5d59cc0e597987300df3396b148a9bd10b76a058a2f2772fc04", 162 | "sha256:7709fd7bb02b31908dc8fd35bfd0a29fc24681d5cc9ac1d64ad07f8d2b7db62f", 163 | "sha256:8060b32d8586e912a7b7dac2d15b28dbbd63a174ab32f5bc6d107a1c4143f40b", 164 | "sha256:80dcd3c938cbcac986c5c92779db8e8ce51a89a849c135172c88ecbdc8c056b7", 165 | "sha256:813720bd57e193391dfe26f4871186cf460848b83df7e23e6bef698a7624b4c9", 166 | "sha256:831d6f35037cf18ca5e80a737a27d822d87cd922521d18ed3dbc8a6967be50ce", 167 | "sha256:871b0a8835f9e9d461b7fdaa1b57e3492dd45398e87324c047469ce2fc9f516c", 168 | "sha256:952256c2bc5b4ee8df8dfc54fc4de330970bf5d79253c863fb5e6761f00dda35", 169 | "sha256:96d9ea57292f636ec851a9bb961a5cc0f9976900e16e5d5647f19aa36ba6366b", 170 | "sha256:9a812224a5fb17a538207e8cf8e86f517df2080c8ee0f8c1ed2bdaccd18f38f4", 171 | "sha256:9adbd8ecf097e34ada8efde9b6fec4dd2a903b1e98037adf72d12993a1c80b51", 172 | "sha256:9de687479faec7db5b198cc365bc34addd256b0028956501f4d4d5e9ca2e240a", 173 | "sha256:a048293392d4e058298710a54dfaefcefdf49d287cd33fb1f7d63d55426e4355", 174 | "sha256:aa15a2ec737cb609ed48902b45c5e4ff6044feb5dcdfcf6fa8482379190330d7", 175 | "sha256:abe1ef3d780de56defd0c77c5ba95e152f4e4c4e12d7e11dd8447d338b85a625", 176 | "sha256:ad6fb737e46b8bd63156b8f59ba6cdef46fe2b7db0c5804388a2d0519b8ddb99", 177 | "sha256:b1660a15a446206c8545edc292ab5c48b91ff732f91b3d3b30d9a915d5ec4779", 178 | "sha256:b505fcfc26f4148551826a96f7317e02c400665fa0883fe505d4fcaab1dabfdd", 179 | "sha256:b822fab253ac0f330ee807e7485769e3ac85d5eef827ca224feaaefa462dc0d0", 180 | "sha256:bdd696947cd695924aecb3870660b7545a19851f93b9d327ef8236bfc49be705", 181 | "sha256:bdfaeecf8cc705d35d8e6de324bf58427d7eafb55f67050d8f28053a3d57118c", 182 | "sha256:be557119bf467d37a8099d91fbf11b2de5eb1fd5fc5b91598407574848dc910f", 183 | "sha256:c6b5ce7f40f0e2f8b88c28e6691ca6806814157ff05e794cdd161be928550f4c", 184 | "sha256:c94e4e924d09b5a3e37b853fe5924a95eac058cb6f6fb437ebb588b7eda79870", 185 | "sha256:cc3e2679ea13b4de79bdc44b25a0c4fcd5e94e21b8f290791744ac42d34a0353", 186 | "sha256:d1e22c22f7826096ad503e9bb681b05b8c1f5a8138469b255eb91f26a76634f2", 187 | "sha256:d5539f6da3418c3dc002739cb2bb8d169056aa66e0c83f6bacae0cd3ac26b423", 188 | "sha256:d55db1db455c59b46f794346efce896e754b8942817f46a1bada2d29446e305a", 189 | "sha256:e09dea87cc91aea5500262993cbd484b41edf8af74f976719dd83fe724644cd6", 190 | "sha256:e52a712c38e5fb4fd68e00dc3caf00b60cb65634d50e32281a9d6431b33b4af1", 191 | "sha256:e693e759e172fa1c2c90d35dea4acbdd1d609b6936115d3739148d5e4cd11947", 192 | "sha256:ecf94aa539e97a8411b5ea52fc6ccd8371be9550c4041011a091eb8b3ca1d810", 193 | "sha256:f351479a6914fd81a55c8e68963609f792d9b067fb8a60a042c585a621e0de4f", 194 | "sha256:f47932c434a3c8d3c86d865443fadc1fbf574e9b11d6650b656e602b1797908a" 195 | ], 196 | "markers": "platform_machine == 'aarch64' or (platform_machine == 'ppc64le' or (platform_machine == 'x86_64' or (platform_machine == 'amd64' or (platform_machine == 'AMD64' or (platform_machine == 'win32' or platform_machine == 'WIN32')))))", 197 | "version": "==3.0.0" 198 | }, 199 | "h11": { 200 | "hashes": [ 201 | "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", 202 | "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86" 203 | ], 204 | "markers": "python_version >= '3.8'", 205 | "version": "==0.16.0" 206 | }, 207 | "hiredis": { 208 | "hashes": [ 209 | "sha256:071c5814b850574036506a8118034f97c3cbf2fe9947ff45a27b07a48da56240", 210 | "sha256:08415ea74c1c29b9d6a4ca3dd0e810dc1af343c1d1d442e15ba133b11ab5be6a", 211 | "sha256:126623b03c31cb6ac3e0d138feb6fcc36dd43dd34fc7da7b7a0c38b5d75bc896", 212 | "sha256:14824e457e4f5cda685c3345d125da13949bcf3bb1c88eb5d248c8d2c3dee08f", 213 | "sha256:15c2a551f3b8a26f7940d6ee10b837810201754b8d7e6f6b1391655370882c5a", 214 | "sha256:17e938d9d3ee92e1adbff361706f1c36cc60eeb3e3eeca7a3a353eae344f4c91", 215 | "sha256:1cadb0ac7ba3babfd804e425946bec9717b320564a1390f163a54af9365a720a", 216 | "sha256:1d274d5c511dfc03f83f997d3238eaa9b6ee3f982640979f509373cced891e98", 217 | "sha256:20f509e3a1a20d6e5f5794fc37ceb21f70f409101fcfe7a8bde783894d51b369", 218 | "sha256:227c5b4bcb60f89008c275d596e4a7b6625a6b3c827b8a66ae582eace7051f71", 219 | "sha256:232d0a70519865741ba56e1dfefd160a580ae78c30a1517bad47b3cf95a3bc7d", 220 | "sha256:2443659c76b226267e2a04dbbb21bc2a3f91aa53bdc0c22964632753ae43a247", 221 | "sha256:2d7e459fe7313925f395148d36d9b7f4f8dac65be06e45d7af356b187cef65fc", 222 | "sha256:2fb9300959a0048138791f3d68359d61a788574ec9556bddf1fec07f2dbc5320", 223 | "sha256:334f2738700b20faa04a0d813366fb16ed17287430a6b50584161d5ad31ca6d7", 224 | "sha256:33a94d264e6e12a79d9bb8af333b01dc286b9f39c99072ab5fef94ce1f018e17", 225 | "sha256:33bc4721632ef9708fa44e5df0066053fccc8e65410a2c48573192517a533b48", 226 | "sha256:33ee3ea5cad3a8cb339352cd230b411eb437a2e75d7736c4899acab32056ccdb", 227 | "sha256:3753df5f873d473f055e1f8837bfad0bd3b277c86f3c9bf058c58f14204cd901", 228 | "sha256:3759f4789ae1913b7df278dfc9e8749205b7a106f888cd2903d19461e24a7697", 229 | "sha256:3b7fe075e91b9d9cff40eba4fb6a8eff74964d3979a39be9a9ef58b1b4cb3604", 230 | "sha256:3bf4b5bae472630c229518e4a814b1b68f10a3d9b00aeaec45f1a330f03a0251", 231 | "sha256:3f006c28c885deb99b670a5a66f367a175ab8955b0374029bad7111f5357dcd4", 232 | "sha256:3f5446068197b35a11ccc697720c41879c8657e2e761aaa8311783aac84cef20", 233 | "sha256:3fa6811a618653164f918b891a0fa07052bd71a799defa5c44d167cac5557b26", 234 | "sha256:46525fbd84523cac75af5bf524bc74aaac848beaf31b142d2df8a787d9b4bbc4", 235 | "sha256:477c34c4489666dc73cb5e89dafe2617c3e13da1298917f73d55aac4696bd793", 236 | "sha256:4b3e974ad15eb32b1f537730dea70b93a4c3db7b026de3ad2b59da49c6f7454d", 237 | "sha256:4c3b8be557e08b234774925622e196f0ee36fe4eab66cd19df934d3efd8f3743", 238 | "sha256:4e3e3e31423f888d396b1fc1f936936e52af868ac1ec17dd15e3eeba9dd4de24", 239 | "sha256:4e43e2b5acaad09cf48c032f7e4926392bb3a3f01854416cf6d82ebff94d5467", 240 | "sha256:4ed68a3b1ccb4313d2a42546fd7e7439ad4745918a48b6c9bcaa61e1e3e42634", 241 | "sha256:4f674e309cd055ee7a48304ceb8cf43265d859faf4d7d01d270ce45e976ae9d3", 242 | "sha256:50171f985e17970f87d5a29e16603d1e5b03bdbf5c2691a37e6c912942a6b657", 243 | "sha256:51341e70b467004dcbec3a6ce8c478d2d6241e0f6b01e4c56764afd5022e1e9d", 244 | "sha256:5a4bcef114fc071d5f52c386c47f35aae0a5b43673197b9288a15b584da8fa3a", 245 | "sha256:5a5c8019ff94988d56eb49b15de76fe83f6b42536d76edeb6565dbf7fe14b973", 246 | "sha256:5cda592405bbd29d53942e0389dc3fa77b49c362640210d7e94a10c14a677d4d", 247 | "sha256:5e6674a017629284ef373b50496d9fb1a89b85a20a7fa100ecd109484ec748e5", 248 | "sha256:5e7bb4dd524f50b71c20ef5a12bd61da9b463f8894b18a06130942fe31509881", 249 | "sha256:60c4e3c258eafaab21b174b17270a0cc093718d61cdbde8c03f85ec4bf835343", 250 | "sha256:61995eb826009d99ed8590747bc0da683a5f4fbb4faa8788166bf3810845cd5c", 251 | "sha256:61a72e4a523cdfc521762137559c08dfa360a3caef63620be58c699d1717dac1", 252 | "sha256:69536b821dd1bc78058a6e7541743f8d82bf2d981b91280b14c4daa6cdc7faba", 253 | "sha256:6ccdcb635dae85b006592f78e32d97f4bc7541cb27829d505f9c7fefcef48298", 254 | "sha256:6f88cafe46612b6fa68e6dea49e25bebf160598bba00101caa51cc8c1f18d597", 255 | "sha256:6f969edc851efe23010e0f53a64269f2629a9364135e9ec81c842e8b2277d0c1", 256 | "sha256:77924b0d32fd1f493d3df15d9609ddf9d94c31a364022a6bf6b525ce9da75bea", 257 | "sha256:7df645b6b7800e8b748c217fbd6a4ca8361bcb9a1ae6206cc02377833ec8a1aa", 258 | "sha256:7e17d04ea58ab8cf3f2dc52e875db16077c6357846006780086fff3189fb199d", 259 | "sha256:7f2b34a6444b8f9c1e9f84bd2c639388e5d14f128afd14a869dfb3d9af893aa2", 260 | "sha256:818dfd310aa1020a13cd08ee48e116dd8c3bb2e23b8161f8ac4df587dd5093d7", 261 | "sha256:89a258424158eb8b3ed9f65548d68998da334ef155d09488c5637723eb1cd697", 262 | "sha256:8eceffca3941775b646cd585cd19b275d382de43cc3327d22f7c75d7b003d481", 263 | "sha256:8f280ab4e043b089777b43b4227bdc2035f88da5072ab36588e0ccf77d45d058", 264 | "sha256:8f9dbe12f011a9b784f58faecc171d22465bb532c310bd588d769ba79a59ef5a", 265 | "sha256:9076ce8429785c85f824650735791738de7143f61f43ae9ed83e163c0ca0fa44", 266 | "sha256:95d2305fd2a7b179cacb48b10f618872fc565c175f9f62b854e8d1acac3e8a9e", 267 | "sha256:96d9ea6c8d4cbdeee2e0d43379ce2881e4af0454b00570677c59f33f2531cd38", 268 | "sha256:9944a2cac25ffe049a7e89f306e11b900640837d1ef38d9be0eaa4a4e2b73a52", 269 | "sha256:9a1a80a8fa767f2fdc3870316a54b84fe9fc09fa6ab6a2686783de6a228a4604", 270 | "sha256:9cd32326dfa6ce87edf754153b0105aca64486bebe93b9600ccff74fa0b224df", 271 | "sha256:9f4a65276f6ecdebe75f2a53f578fbc40e8d2860658420d5e0611c56bbf5054c", 272 | "sha256:a286ded34eb16501002e3713b3130c987366eee2ba0d58c33c72f27778e31676", 273 | "sha256:a2df98f5e071320c7d84e8bd07c0542acdd0a7519307fc31774d60e4b842ec4f", 274 | "sha256:a7205497d7276a81fe92951a29616ef96562ed2f91a02066f72b6f93cb34b40e", 275 | "sha256:aa17a3b22b3726d54d7af20394f65d4a1735a842a4e0f557dc67a90f6965c4bc", 276 | "sha256:af33f370be90b48bbaf0dab32decbdcc522b1fa95d109020a963282086518a8e", 277 | "sha256:b17baf702c6e5b4bb66e1281a3efbb1d749c9d06cdb92b665ad81e03118f78fc", 278 | "sha256:b4f3d06dc16671b88a13ae85d8ca92534c0b637d59e49f0558d040a691246422", 279 | "sha256:b9953d87418ac228f508d93898ab572775e4d3b0eeb886a1a7734553bcdaf291", 280 | "sha256:b9a7c987e161e3c58f992c63b7e26fea7fe0777f3b975799d23d65bbb8cb5899", 281 | "sha256:c6cb613148422c523945cdb8b6bed617856f2602fd8750e33773ede2616e55d5", 282 | "sha256:c9b9e5bde7030cae83aa900b5bd660decc65afd2db8c400f3c568c815a47ca2a", 283 | "sha256:cc36a9dded458d4e37492fe3e619c6c83caae794d26ad925adbce61d592f8428", 284 | "sha256:cd2614f17e261f72efc2f19f5e5ff2ee19e2296570c0dcf33409e22be30710de", 285 | "sha256:d115790f18daa99b5c11a506e48923b630ef712e9e4b40482af942c3d40638b8", 286 | "sha256:d194decd9608f11c777946f596f31d5aacad13972a0a87829ae1e6f2d26c1885", 287 | "sha256:d1a4ce40ba11da9382c14da31f4f9e88c18f7d294f523decd0fadfb81f51ad18", 288 | "sha256:d1be9e30e675f5bc1cb534633324578f6f0944a1bcffe53242cf632f554f83b6", 289 | "sha256:d20891e3f33803b26d54c77fd5745878497091e33f4bbbdd454cf6e71aee8890", 290 | "sha256:d27e560eefb57914d742a837f1da98d3b29cb22eff013c8023b7cf52ae6e051d", 291 | "sha256:dcb0569dd5bfe6004658cd0f229efa699a3169dcb4f77bd72e188adda302063d", 292 | "sha256:e62ec131816c6120eff40dffe43424e140264a15fa4ab88c301bd6a595913af3", 293 | "sha256:e75163773a309e56a9b58165cf5a50e0f84b755f6ff863b2c01a38918fe92daa", 294 | "sha256:ec58fb7c2062f835595c12f0f02dcda76d0eb0831423cc191d1e18c9276648de", 295 | "sha256:f1eadbcd3de55ac42310ff82550d3302cb4efcd4e17d76646a17b6e7004bb42b", 296 | "sha256:f2dcb8389fa3d453927b1299f46bdb38473c293c8269d5c777d33ea0e526b610", 297 | "sha256:ffaf841546905d90ff189de7397aa56413b1ce5e54547f17a98f0ebf3a3b0a3b" 298 | ], 299 | "markers": "python_version >= '3.7'", 300 | "version": "==2.2.3" 301 | }, 302 | "idna": { 303 | "hashes": [ 304 | "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc", 305 | "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0" 306 | ], 307 | "index": "pypi", 308 | "markers": "python_version >= '3.5'", 309 | "version": "==3.7" 310 | }, 311 | "passlib": { 312 | "hashes": [ 313 | "sha256:aa6bca462b8d8bda89c70b382f0c298a20b5560af6cbfa2dce410c0a2fb669f1", 314 | "sha256:defd50f72b65c5402ab2c573830a6978e5f202ad0d984793c8dde2c4152ebe04" 315 | ], 316 | "version": "==1.7.4" 317 | }, 318 | "pydantic": { 319 | "hashes": [ 320 | "sha256:1fd326aff5d6c36f05735c7c9b3d5b0e933b4ca52ad0b6e4b38038d82703d35b", 321 | "sha256:2185a3b3d98ab4506a3f6707569802d2d92c3a7ba3a9a35683a7709ea6c2aaa2", 322 | "sha256:261f357f0aecda005934e413dfd7aa4077004a174dafe414a8325e6098a8e419", 323 | "sha256:305d0376c516b0dfa1dbefeae8c21042b57b496892d721905a6ec6b79494a66d", 324 | "sha256:3257bd714de9db2102b742570a56bf7978e90441193acac109b1f500290f5718", 325 | "sha256:3353072625ea2a9a6c81ad01b91e5c07fa70deb06368c71307529abf70d23325", 326 | "sha256:36e44a4de37b8aecffa81c081dbfe42c4d2bf9f6dff34d03dce157ec65eb0f15", 327 | "sha256:3bb99cf9655b377db1a9e47fa4479e3330ea96f4123c6c8200e482704bf1eda2", 328 | "sha256:3f9d9b2be177c3cb6027cd67fbf323586417868c06c3c85d0d101703136e6b31", 329 | "sha256:45edea10b75d3da43cfda12f3792833a3fa70b6eee4db1ed6aed528cef17c74e", 330 | "sha256:51782fd81f09edcf265823c3bf43ff36d00db246eca39ee765ef58dc8421a642", 331 | "sha256:532e97c35719f137ee5405bd3eeddc5c06eb91a032bc755a44e34a712420daf3", 332 | "sha256:58e41dd1e977531ac6073b11baac8c013f3cd8706a01d3dc74e86955be8b2c0c", 333 | "sha256:5920824fe1e21cbb3e38cf0f3dd24857c8959801d1031ce1fac1d50857a03bfb", 334 | "sha256:5f3bc8f103b56a8c88021d481410874b1f13edf6e838da607dcb57ecff9b4594", 335 | "sha256:63200cd8af1af2c07964546b7bc8f217e8bda9d0a2ef0ee0c797b36353914984", 336 | "sha256:663d2dd78596c5fa3eb996bc3f34b8c2a592648ad10008f98d1348be7ae212fb", 337 | "sha256:6a4b0aab29061262065bbdede617ef99cc5914d1bf0ddc8bcd8e3d7928d85bd6", 338 | "sha256:6bb0452d7b8516178c969d305d9630a3c9b8cf16fcf4713261c9ebd465af0d73", 339 | "sha256:72ef3783be8cbdef6bca034606a5de3862be6b72415dc5cb1fb8ddbac110049a", 340 | "sha256:76c930ad0746c70f0368c4596020b736ab65b473c1f9b3872310a835d852eb19", 341 | "sha256:7c5b94d598c90f2f46b3a983ffb46ab806a67099d118ae0da7ef21a2a4033b28", 342 | "sha256:7ce1612e98c6326f10888df951a26ec1a577d8df49ddcaea87773bfbe23ba5cc", 343 | "sha256:8481dca324e1c7b715ce091a698b181054d22072e848b6fc7895cd86f79b4449", 344 | "sha256:87f831e81ea0589cd18257f84386bf30154c5f4bed373b7b75e5cb0b5d53ea87", 345 | "sha256:9a9d9155e2a9f38b2eb9374c88f02fd4d6851ae17b65ee786a87d032f87008f8", 346 | "sha256:9e337ac83686645a46db0e825acceea8e02fca4062483f40e9ae178e8bd1103a", 347 | "sha256:b429f7c457aebb7fbe7cd69c418d1cd7c6fdc4d3c8697f45af78b8d5a7955760", 348 | "sha256:b473d00ccd5c2061fd896ac127b7755baad233f8d996ea288af14ae09f8e0d1e", 349 | "sha256:bd46a0e6296346c477e59a954da57beaf9c538da37b9df482e50f836e4a7d4bb", 350 | "sha256:c428c0f64a86661fb4873495c4fac430ec7a7cef2b8c1c28f3d1a7277f9ea5ab", 351 | "sha256:c9e5b778b6842f135902e2d82624008c6a79710207e28e86966cd136c621bfee", 352 | "sha256:ca9075ab3de9e48b75fa8ccb897c34ccc1519177ad8841d99f7fd74cf43be5bf", 353 | "sha256:f582cac9d11c227c652d3ce8ee223d94eb06f4228b52a8adaafa9fa62e73d5c9", 354 | "sha256:f5bee6c523d13944a1fdc6f0525bc86dbbd94372f17b83fa6331aabacc8fd08e", 355 | "sha256:f836444b4c5ece128b23ec36a446c9ab7f9b0f7981d0d27e13a7c366ee163f8a" 356 | ], 357 | "index": "pypi", 358 | "markers": "python_version >= '3.7'", 359 | "version": "==1.10.5" 360 | }, 361 | "pyjwt": { 362 | "hashes": [ 363 | "sha256:69285c7e31fc44f68a1feb309e948e0df53259d579295e6cfe2b1792329f05fd", 364 | "sha256:d83c3d892a77bbb74d3e1a2cfa90afaadb60945205d1095d9221f04466f64c14" 365 | ], 366 | "markers": "python_version >= '3.7'", 367 | "version": "==2.6.0" 368 | }, 369 | "python-dotenv": { 370 | "hashes": [ 371 | "sha256:a8df96034aae6d2d50a4ebe8216326c61c3eb64836776504fcca410e5937a3ba", 372 | "sha256:f5971a9226b701070a4bf2c38c89e5a3f0d64de8debda981d1db98583009122a" 373 | ], 374 | "index": "pypi", 375 | "markers": "python_version >= '3.8'", 376 | "version": "==1.0.0" 377 | }, 378 | "pyyaml": { 379 | "hashes": [ 380 | "sha256:01b45c0191e6d66c470b6cf1b9531a771a83c1c4208272ead47a3ae4f2f603bf", 381 | "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293", 382 | "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b", 383 | "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57", 384 | "sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b", 385 | "sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4", 386 | "sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07", 387 | "sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba", 388 | "sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9", 389 | "sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287", 390 | "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513", 391 | "sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0", 392 | "sha256:432557aa2c09802be39460360ddffd48156e30721f5e8d917f01d31694216782", 393 | "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0", 394 | "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92", 395 | "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f", 396 | "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2", 397 | "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc", 398 | "sha256:81957921f441d50af23654aa6c5e5eaf9b06aba7f0a19c18a538dc7ef291c5a1", 399 | "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c", 400 | "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86", 401 | "sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4", 402 | "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c", 403 | "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34", 404 | "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b", 405 | "sha256:afa17f5bc4d1b10afd4466fd3a44dc0e245382deca5b3c353d8b757f9e3ecb8d", 406 | "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c", 407 | "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb", 408 | "sha256:bfaef573a63ba8923503d27530362590ff4f576c626d86a9fed95822a8255fd7", 409 | "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737", 410 | "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3", 411 | "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d", 412 | "sha256:d4b0ba9512519522b118090257be113b9468d804b19d63c71dbcf4a48fa32358", 413 | "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53", 414 | "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78", 415 | "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803", 416 | "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a", 417 | "sha256:dbad0e9d368bb989f4515da330b88a057617d16b6a8245084f1b05400f24609f", 418 | "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174", 419 | "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5" 420 | ], 421 | "markers": "python_version >= '3.6'", 422 | "version": "==6.0" 423 | }, 424 | "sniffio": { 425 | "hashes": [ 426 | "sha256:e60305c5e5d314f5389259b7f22aaa33d8f7dee49763119234af3755c55b9101", 427 | "sha256:eecefdce1e5bbfb7ad2eeaabf7c1eeb404d7757c379bd1f7e5cce9d8bf425384" 428 | ], 429 | "markers": "python_version >= '3.7'", 430 | "version": "==1.3.0" 431 | }, 432 | "sqlalchemy": { 433 | "hashes": [ 434 | "sha256:011ef3c33f30bae5637c575f30647e0add98686642d237f0c3a1e3d9b35747fa", 435 | "sha256:0adca8a3ca77234a142c5afed29322fb501921f13d1d5e9fa4253450d786c160", 436 | "sha256:1644c603558590f465b3fa16e4557d87d3962bc2c81fd7ea85b582ecf4676b31", 437 | "sha256:2267c004e78e291bba0dc766a9711c389649cf3e662cd46eec2bc2c238c637bd", 438 | "sha256:25e4e54575f9d2af1eab82d3a470fca27062191c48ee57b6386fe09a3c0a6a33", 439 | "sha256:2a2f9120eb32190bdba31d1022181ef08f257aed4f984f3368aa4e838de72bc0", 440 | "sha256:2c82395e2925639e6d320592943608070678e7157bd1db2672a63be9c7889434", 441 | "sha256:3f927340b37fe65ec42e19af7ce15260a73e11c6b456febb59009bfdfec29a35", 442 | "sha256:54aa9f40d88728dd058e951eeb5ecc55241831ba4011e60c641738c1da0146b7", 443 | "sha256:57dcd9eed52413f7270b22797aa83c71b698db153d1541c1e83d45ecdf8e95e7", 444 | "sha256:582053571125895d008d4b8d9687d12d4bd209c076cdbab3504da307e2a0a2bd", 445 | "sha256:59cf0cdb29baec4e074c7520d7226646a8a8f856b87d8300f3e4494901d55235", 446 | "sha256:6363697c938b9a13e07f1bc2cd433502a7aa07efd55b946b31d25b9449890621", 447 | "sha256:662a79e80f3e9fe33b7861c19fedf3d8389fab2413c04bba787e3f1139c22188", 448 | "sha256:67901b91bf5821482fcbe9da988cb16897809624ddf0fde339cd62365cc50032", 449 | "sha256:679b9bd10bb32b8d3befed4aad4356799b6ec1bdddc0f930a79e41ba5b084124", 450 | "sha256:738c80705e11c1268827dbe22c01162a9cdc98fc6f7901b429a1459db2593060", 451 | "sha256:77a380bf8721b416782c763e0ff66f80f3b05aee83db33ddfc0eac20bcb6791f", 452 | "sha256:77d05773d5c79f2d3371d81697d54ee1b2c32085ad434ce9de4482e457ecb018", 453 | "sha256:817aab80f7e8fe581696dae7aaeb2ceb0b7ea70ad03c95483c9115970d2a9b00", 454 | "sha256:81f1ea264278fcbe113b9a5840f13a356cb0186e55b52168334124f1cd1bc495", 455 | "sha256:8a88b32ce5b69d18507ffc9f10401833934ebc353c7b30d1e056023c64f0a736", 456 | "sha256:8ff0a7c669ec7cdb899eae7e622211c2dd8725b82655db2b41740d39e3cda466", 457 | "sha256:918c2b553e3c78268b187f70983c9bc6f91e451a4f934827e9c919e03d258bd7", 458 | "sha256:954f1ad73b78ea5ba5a35c89c4a5dfd0f3a06c17926503de19510eb9b3857bde", 459 | "sha256:95a18e1a6af2114dbd9ee4f168ad33070d6317e11bafa28d983cc7b585fe900b", 460 | "sha256:9946ee503962859f1a9e1ad17dff0859269b0cb453686747fe87f00b0e030b34", 461 | "sha256:9a7ecaf90fe9ec8e45c86828f4f183564b33c9514e08667ca59e526fea63893a", 462 | "sha256:a42e6831e82dfa6d16b45f0c98c69e7b0defc64d76213173456355034450c414", 463 | "sha256:b01dce097cf6f145da131a53d4cce7f42e0bfa9ae161dd171a423f7970d296d0", 464 | "sha256:b5deafb4901618b3f98e8df7099cd11edd0d1e6856912647e28968b803de0dae", 465 | "sha256:b67d6e626caa571fb53accaac2fba003ef4f7317cb3481e9ab99dad6e89a70d6", 466 | "sha256:c1e8edc49b32483cd5d2d015f343e16be7dfab89f4aaf66b0fa6827ab356880d", 467 | "sha256:c621f05859caed5c0aab032888a3d3bde2cae3988ca151113cbecf262adad976", 468 | "sha256:ce54965a94673a0ebda25e7c3a05bf1aa74fd78cc452a1a710b704bf73fb8402", 469 | "sha256:d8efdda920988bcade542f53a2890751ff680474d548f32df919a35a21404e3f", 470 | "sha256:dc7b9f55c2f72c13b2328b8a870ff585c993ba1b5c155ece5c9d3216fa4b18f6", 471 | "sha256:dd801375f19a6e1f021dabd8b1714f2fdb91cbc835cd13b5dd0bd7e9860392d7", 472 | "sha256:f342057422d6bcfdd4996e34cd5c7f78f7e500112f64b113f334cdfc6a0c593d", 473 | "sha256:f696828784ab2c07b127bfd2f2d513f47ec58924c29cff5b19806ac37acee31c", 474 | "sha256:fdb2686eb01f670cdc6c43f092e333ff08c1cf0b646da5256c1237dc4ceef4ae" 475 | ], 476 | "index": "pypi", 477 | "markers": "python_version >= '3.7'", 478 | "version": "==2.0.4" 479 | }, 480 | "starlette": { 481 | "hashes": [ 482 | "sha256:774f1df1983fd594b9b6fb3ded39c2aa1979d10ac45caac0f4255cbe2acb8628", 483 | "sha256:854c71e73736c429c2bdb07801f2c76c9cba497e7c3cf4988fde5e95fe4cdb3c" 484 | ], 485 | "markers": "python_version >= '3.7'", 486 | "version": "==0.25.0" 487 | }, 488 | "toml": { 489 | "hashes": [ 490 | "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b", 491 | "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f" 492 | ], 493 | "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'", 494 | "version": "==0.10.2" 495 | }, 496 | "typing-extensions": { 497 | "hashes": [ 498 | "sha256:a439e7c04b49fec3e5d3e2beaa21755cadbbdc391694e28ccdd36ca4a1408f8c", 499 | "sha256:e6c81219bd689f51865d9e372991c540bda33a0379d5573cddb9a3a23f7caaef" 500 | ], 501 | "markers": "python_version >= '3.8'", 502 | "version": "==4.13.2" 503 | }, 504 | "uvicorn": { 505 | "hashes": [ 506 | "sha256:16246631db62bdfbf069b0645177d6e8a77ba950cfedbfd093acef9444e4d885", 507 | "sha256:35919a9a979d7a59334b6b10e05d77c1d0d574c50e0fc98b8b1a0f165708b55a" 508 | ], 509 | "index": "pypi", 510 | "markers": "python_version >= '3.9'", 511 | "version": "==0.34.3" 512 | } 513 | }, 514 | "develop": { 515 | "flake8": { 516 | "hashes": [ 517 | "sha256:93b92ba5bdb60754a6da14fa3b93a9361fd00a59632ada61fd7b130436c40343", 518 | "sha256:fa558ae3f6f7dbf2b4f22663e5343b6b6023620461f8d4ff2019ef4b5ee70426" 519 | ], 520 | "index": "pypi", 521 | "markers": "python_version >= '3.9'", 522 | "version": "==7.2.0" 523 | }, 524 | "mccabe": { 525 | "hashes": [ 526 | "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325", 527 | "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e" 528 | ], 529 | "markers": "python_version >= '3.6'", 530 | "version": "==0.7.0" 531 | }, 532 | "mypy": { 533 | "hashes": [ 534 | "sha256:021a68568082c5b36e977d54e8f1de978baf401a33884ffcea09bd8e88a98f4c", 535 | "sha256:089bedc02307c2548eb51f426e085546db1fa7dd87fbb7c9fa561575cf6eb1ff", 536 | "sha256:09a8da6a0ee9a9770b8ff61b39c0bb07971cda90e7297f4213741b48a0cc8d93", 537 | "sha256:0b07e107affb9ee6ce1f342c07f51552d126c32cd62955f59a7db94a51ad12c0", 538 | "sha256:15486beea80be24ff067d7d0ede673b001d0d684d0095803b3e6e17a886a2a92", 539 | "sha256:29e1499864a3888bca5c1542f2d7232c6e586295183320caa95758fc84034031", 540 | "sha256:2e7e0ad35275e02797323a5aa1be0b14a4d03ffdb2e5f2b0489fa07b89c67b21", 541 | "sha256:4086883a73166631307fdd330c4a9080ce24913d4f4c5ec596c601b3a4bdd777", 542 | "sha256:54066fed302d83bf5128632d05b4ec68412e1f03ef2c300434057d66866cea4b", 543 | "sha256:55f9076c6ce55dd3f8cd0c6fff26a008ca8e5131b89d5ba6d86bd3f47e736eeb", 544 | "sha256:6a2322896003ba66bbd1318c10d3afdfe24e78ef12ea10e2acd985e9d684a666", 545 | "sha256:7909541fef256527e5ee9c0a7e2aeed78b6cda72ba44298d1334fe7881b05c5c", 546 | "sha256:82d056e6faa508501af333a6af192c700b33e15865bda49611e3d7d8358ebea2", 547 | "sha256:84b94283f817e2aa6350a14b4a8fb2a35a53c286f97c9d30f53b63620e7af8ab", 548 | "sha256:936ccfdd749af4766be824268bfe22d1db9eb2f34a3ea1d00ffbe5b5265f5491", 549 | "sha256:9f826aaa7ff8443bac6a494cf743f591488ea940dd360e7dd330e30dd772a5ab", 550 | "sha256:a5fcfdb7318c6a8dd127b14b1052743b83e97a970f0edb6c913211507a255e20", 551 | "sha256:a7e32297a437cc915599e0578fa6bc68ae6a8dc059c9e009c628e1c47f91495d", 552 | "sha256:a9e056237c89f1587a3be1a3a70a06a698d25e2479b9a2f57325ddaaffc3567b", 553 | "sha256:afe420c9380ccec31e744e8baff0d406c846683681025db3531b32db56962d52", 554 | "sha256:b4968f14f44c62e2ec4a038c8797a87315be8df7740dc3ee8d3bfe1c6bf5dba8", 555 | "sha256:bd4e1ebe126152a7bbaa4daedd781c90c8f9643c79b9748caa270ad542f12bec", 556 | "sha256:c5436d11e89a3ad16ce8afe752f0f373ae9620841c50883dc96f8b8805620b13", 557 | "sha256:c6fb60cbd85dc65d4d63d37cb5c86f4e3a301ec605f606ae3a9173e5cf34997b", 558 | "sha256:d045d33c284e10a038f5e29faca055b90eee87da3fc63b8889085744ebabb5a1", 559 | "sha256:e71d6f0090c2256c713ed3d52711d01859c82608b5d68d4fa01a3fe30df95571", 560 | "sha256:eb14a4a871bb8efb1e4a50360d4e3c8d6c601e7a31028a2c79f9bb659b63d730", 561 | "sha256:eb5fbc8063cb4fde7787e4c0406aa63094a34a2daf4673f359a1fb64050e9cb2", 562 | "sha256:f2622af30bf01d8fc36466231bdd203d120d7a599a6d88fb22bdcb9dbff84090", 563 | "sha256:f2ed0e0847a80655afa2c121835b848ed101cc7b8d8d6ecc5205aedc732b1436", 564 | "sha256:f56236114c425620875c7cf71700e3d60004858da856c6fc78998ffe767b73d3", 565 | "sha256:feec38097f71797da0231997e0de3a58108c51845399669ebc532c815f93866b" 566 | ], 567 | "index": "pypi", 568 | "markers": "python_version >= '3.9'", 569 | "version": "==1.16.0" 570 | }, 571 | "mypy-extensions": { 572 | "hashes": [ 573 | "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505", 574 | "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558" 575 | ], 576 | "markers": "python_version >= '3.8'", 577 | "version": "==1.1.0" 578 | }, 579 | "pathspec": { 580 | "hashes": [ 581 | "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08", 582 | "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712" 583 | ], 584 | "markers": "python_version >= '3.8'", 585 | "version": "==0.12.1" 586 | }, 587 | "pycodestyle": { 588 | "hashes": [ 589 | "sha256:35863c5974a271c7a726ed228a14a4f6daf49df369d8c50cd9a6f58a5e143ba9", 590 | "sha256:c8415bf09abe81d9c7f872502a6eee881fbe85d8763dd5b9924bb0a01d67efae" 591 | ], 592 | "markers": "python_version >= '3.9'", 593 | "version": "==2.13.0" 594 | }, 595 | "pyflakes": { 596 | "hashes": [ 597 | "sha256:8752eee11d4ef3a4be642d774863047864b47406cba906fabf8dd892cf98d5b3", 598 | "sha256:af4d63344d478524956e9950a9ae11da51414622479b8c148647fe9722e96837" 599 | ], 600 | "markers": "python_version >= '3.9'", 601 | "version": "==3.3.1" 602 | }, 603 | "tomli": { 604 | "hashes": [ 605 | "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6", 606 | "sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd", 607 | "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c", 608 | "sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b", 609 | "sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8", 610 | "sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6", 611 | "sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77", 612 | "sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff", 613 | "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea", 614 | "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192", 615 | "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249", 616 | "sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee", 617 | "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4", 618 | "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98", 619 | "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8", 620 | "sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4", 621 | "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281", 622 | "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744", 623 | "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69", 624 | "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13", 625 | "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140", 626 | "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e", 627 | "sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e", 628 | "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc", 629 | "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff", 630 | "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec", 631 | "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2", 632 | "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222", 633 | "sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106", 634 | "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272", 635 | "sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a", 636 | "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7" 637 | ], 638 | "markers": "python_version >= '3.8'", 639 | "version": "==2.2.1" 640 | }, 641 | "typing-extensions": { 642 | "hashes": [ 643 | "sha256:a439e7c04b49fec3e5d3e2beaa21755cadbbdc391694e28ccdd36ca4a1408f8c", 644 | "sha256:e6c81219bd689f51865d9e372991c540bda33a0379d5573cddb9a3a23f7caaef" 645 | ], 646 | "markers": "python_version >= '3.8'", 647 | "version": "==4.13.2" 648 | } 649 | } 650 | } 651 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Fastapi-Framework-Template -------------------------------------------------------------------------------- /README.md.tmpl: -------------------------------------------------------------------------------- 1 | ## [[project_name]] -------------------------------------------------------------------------------- /app/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Tert0/fastapi-framework-template/c4adc56838a9062db41d81fce8fba6dde4823462/app/__init__.py -------------------------------------------------------------------------------- /app/api/__init__.py: -------------------------------------------------------------------------------- 1 | from fastapi import APIRouter 2 | from .v1 import users, authentication 3 | 4 | api_v1_router = APIRouter() 5 | 6 | api_v1_router.include_router(authentication.router) 7 | api_v1_router.include_router(users.router) 8 | -------------------------------------------------------------------------------- /app/api/v1/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Tert0/fastapi-framework-template/c4adc56838a9062db41d81fce8fba6dde4823462/app/api/v1/__init__.py -------------------------------------------------------------------------------- /app/api/v1/authentication.py: -------------------------------------------------------------------------------- 1 | from typing import Dict 2 | 3 | from fastapi import APIRouter, Depends, HTTPException 4 | from fastapi_framework import ( 5 | redis_dependency, 6 | database_dependency, 7 | pwd_context, 8 | generate_tokens, 9 | check_refresh_token, 10 | invalidate_refresh_token, 11 | get_data, 12 | Redis, 13 | ) 14 | from app.schemas.authentication import Tokens 15 | from fastapi_framework.database import select, DB 16 | import re 17 | from app.models.user import User 18 | from app.schemas.user import UserSchema 19 | 20 | router = APIRouter(prefix="/authentication", tags=["auth"]) 21 | 22 | RE_USERNAME = re.compile(r"^[A-Za-z0-9\_\-\.äöüÄÖÜ]{3,50}$") 23 | 24 | 25 | @router.on_event("startup") 26 | async def on_startup(): 27 | await redis_dependency.init() 28 | await database_dependency.init() 29 | 30 | 31 | @router.post("/token", response_model=Tokens) 32 | async def token_route( 33 | username: str, password: str, redis: Redis = Depends(redis_dependency), db: DB = Depends(database_dependency) 34 | ): 35 | user: User 36 | if not (user := await db.first(select(User).filter_by(username=username))): 37 | raise HTTPException(401, detail="Username or Password is wrong") 38 | if not pwd_context.verify(password, user.password): 39 | raise HTTPException(401, detail="Username or Password is wrong") 40 | return await generate_tokens({"user": {"id": user.id, "username": user.username}}, int(user.id), redis) 41 | 42 | 43 | @router.post("/register", response_model=UserSchema) 44 | async def register_route(username: str, password: str, db: DB = Depends(database_dependency)): 45 | if await db.exists(select(User).filter_by(username=username)): 46 | raise HTTPException(409, "Username already exists") 47 | if not RE_USERNAME.match(username): 48 | raise HTTPException(400, "Username doesn't match Regex") 49 | user: User = await User.create(username, pwd_context.hash(password), db) 50 | await db.commit() 51 | return UserSchema(**{"id": user.id, "username": user.username}) 52 | 53 | 54 | @router.post("/refresh", response_model=Tokens) 55 | async def refresh_route( 56 | refresh_token: str, redis: Redis = Depends(redis_dependency), db: DB = Depends(database_dependency) 57 | ): 58 | data: Dict = {} 59 | if not await check_refresh_token(refresh_token, redis): 60 | raise HTTPException(401, "Refresh Token Invalid") 61 | try: 62 | data = await get_data(refresh_token) 63 | except HTTPException as e: 64 | if e.detail == "Token is expired": 65 | await invalidate_refresh_token(refresh_token, redis) 66 | raise e 67 | user: User = await db.first(select(User).filter_by(id=int(data["user_id"]))) 68 | if not user: 69 | raise HTTPException(500, "Unexpected Error") 70 | await invalidate_refresh_token(refresh_token, redis) 71 | return await generate_tokens({"user": {"id": user.id, "username": user.username}}, int(user.id), redis) 72 | 73 | 74 | @router.post("/logout") 75 | async def logout_route(refresh_token: str, redis: Redis = Depends(redis_dependency)): 76 | await invalidate_refresh_token(refresh_token, redis) 77 | return "Logged out" 78 | -------------------------------------------------------------------------------- /app/api/v1/users.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | from fastapi import APIRouter, Depends, HTTPException 4 | from fastapi_framework import get_data, database_dependency, pwd_context 5 | from fastapi_framework.database import DB, select 6 | from app.schemas.user import UserSchema, UpdateUser 7 | 8 | from app.models.user import User 9 | 10 | router = APIRouter(prefix="/user", tags=["user"]) 11 | 12 | RE_USERNAME = re.compile(r"^[A-Za-z0-9\_\-\.äöüÄÖÜ]{3,50}$") 13 | 14 | 15 | @router.get("/", response_model=UserSchema) 16 | async def get_user(data=Depends(get_data), db: DB = Depends(database_dependency)): 17 | user: User = await db.first(select(User).filter_by(id=data["user"]["id"])) 18 | return UserSchema(**{"id": user.id, "username": user.username}) 19 | 20 | 21 | @router.put("/", response_model=UserSchema) 22 | async def update_user(updated_user: UpdateUser, data=Depends(get_data), db: DB = Depends(database_dependency)): 23 | user: User = await db.first(select(User).filter_by(id=data["user"]["id"])) 24 | if user.username == updated_user.username: 25 | updated_user.username = None 26 | elif updated_user.username: 27 | if not RE_USERNAME.match(updated_user.username): 28 | raise HTTPException(400, "Username doesn't match Regex") 29 | if await db.exists(select(User).filter_by(username=updated_user.username)): 30 | raise HTTPException(409, "Username already used") 31 | if not updated_user.username and not updated_user.password: 32 | raise HTTPException(400, "Nothing Changed") 33 | if not user: 34 | raise HTTPException(500, "Unexpected Error") 35 | if updated_user.username: 36 | user.username = updated_user.username 37 | if updated_user.password: 38 | user.password = pwd_context.hash(updated_user.password) 39 | await db.commit() 40 | return UserSchema(**{"id": user.id, "username": user.username}) 41 | -------------------------------------------------------------------------------- /app/main.py: -------------------------------------------------------------------------------- 1 | from fastapi import FastAPI 2 | from fastapi.middleware.cors import CORSMiddleware 3 | from app.api import api_v1_router 4 | from fastapi_framework import Config, ConfigField 5 | 6 | 7 | class FastAPIConfig(Config): 8 | CONFIG_PATH = "config.yaml" 9 | CONFIG_TYPE = "yaml" 10 | 11 | name: str = ConfigField("FastAPI Project") 12 | version: str = ConfigField("0.1.0") 13 | 14 | 15 | app = FastAPI(title=FastAPIConfig.name, version=FastAPIConfig.version) 16 | 17 | app.add_middleware( 18 | CORSMiddleware, 19 | allow_origins=["*"], 20 | allow_credentials=True, 21 | allow_methods=["*"], 22 | allow_headers=["*"], 23 | ) 24 | 25 | app.include_router(api_v1_router, prefix="/v1") 26 | -------------------------------------------------------------------------------- /app/models/user.py: -------------------------------------------------------------------------------- 1 | from typing import Union 2 | 3 | from fastapi_framework.database import database_dependency, DB 4 | from sqlalchemy import Column, Integer, String 5 | 6 | 7 | class User(database_dependency.db.Base): 8 | __tablename__ = "users" 9 | id: Union[int, Column] = Column(Integer, primary_key=True) 10 | username: Union[str, Column] = Column(String(50), unique=True) 11 | password: Union[str, Column] = Column(String(255)) 12 | 13 | @staticmethod 14 | async def create(username: str, password: str, db: DB) -> "User": 15 | row: User = User(username=username, password=password) 16 | await db.add(row) 17 | return row 18 | -------------------------------------------------------------------------------- /app/schemas/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Tert0/fastapi-framework-template/c4adc56838a9062db41d81fce8fba6dde4823462/app/schemas/__init__.py -------------------------------------------------------------------------------- /app/schemas/authentication.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | 3 | 4 | class Tokens(BaseModel): 5 | access_token: str 6 | refresh_token: str 7 | token_type: str = "bearer" 8 | -------------------------------------------------------------------------------- /app/schemas/user.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | from pydantic import BaseModel 4 | 5 | 6 | class UserSchema(BaseModel): 7 | id: int 8 | username: str 9 | 10 | 11 | class CreateUser(BaseModel): 12 | username: str 13 | password: str 14 | 15 | 16 | class UpdateUser(BaseModel): 17 | username: Optional[str] 18 | password: Optional[str] 19 | -------------------------------------------------------------------------------- /config.yaml.tmpl: -------------------------------------------------------------------------------- 1 | name: [[ project_name ]] 2 | version: 0.1.0 3 | -------------------------------------------------------------------------------- /copier.yaml: -------------------------------------------------------------------------------- 1 | project_name: 2 | type: str 3 | jwt_secret_key: 4 | type: str 5 | secret: true 6 | db_host: 7 | type: str 8 | default: db 9 | db_port: 10 | type: int 11 | default: 5432 12 | db_database: 13 | type: str 14 | db_username: 15 | type: str 16 | default: postgres 17 | db_password: 18 | type: str 19 | secret: true 20 | redis_host: 21 | type: str 22 | default: redis 23 | _answers_file: .copier-answers.yml -------------------------------------------------------------------------------- /docker-compose.yaml.tmpl: -------------------------------------------------------------------------------- 1 | version: '3.9' 2 | 3 | services: 4 | redis: 5 | image: redis:alpine 6 | 7 | db: 8 | image: postgres:alpine 9 | environment: 10 | - POSTGRES_USER=[[ db_username ]] 11 | - POSTGRES_DB=[[ db_database ]] 12 | - POSTGRES_PASSWORD=[[ db_password ]] 13 | healthcheck: 14 | test: [ "CMD-SHELL", "pg_isready -U [[ db_username ]]" ] 15 | interval: 5s 16 | timeout: 5s 17 | retries: 5 18 | 19 | app: 20 | build: 21 | context: . 22 | dockerfile: Dockerfile 23 | ports: 24 | - 8899:80 25 | env_file: .env 26 | depends_on: 27 | db: 28 | condition: service_healthy 29 | redis: 30 | condition: service_started -------------------------------------------------------------------------------- /mypy.ini: -------------------------------------------------------------------------------- 1 | [mypy] 2 | ignore_missing_imports = True -------------------------------------------------------------------------------- /serve.sh: -------------------------------------------------------------------------------- 1 | python3 -m uvicorn app.main:app --port 8899 --host 0.0.0.0 --reload -------------------------------------------------------------------------------- /start.sh: -------------------------------------------------------------------------------- 1 | python3 -m uvicorn app.main:app --port 80 --host 0.0.0.0 --------------------------------------------------------------------------------