├── .github ├── CODEOWNERS ├── FUNDING.yml └── dependabot.yml ├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── config.py ├── main.py ├── poetry.lock ├── pyproject.toml ├── redis_python_tutorial ├── __init__.py ├── client.py ├── data │ ├── __init__.py │ ├── hash.py │ ├── list.py │ ├── set.py │ ├── string.py │ └── zset.py └── logger.py ├── renovate.json └── requirements.txt /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | @hackersandslackers/hackers-contributors 2 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | custom: ['https://www.buymeacoffee.com/hackersslackers'] 4 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: pip 4 | directory: "/" 5 | schedule: 6 | interval: daily 7 | time: "10:00" 8 | open-pull-requests-limit: 10 9 | ignore: 10 | - dependency-name: python-dotenv 11 | versions: 12 | - 0.15.0 13 | - 0.16.0 14 | - dependency-name: pytest 15 | versions: 16 | - 6.2.2 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | pip-wheel-metadata/ 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 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | target/ 76 | 77 | # Jupyter Notebook 78 | .ipynb_checkpoints 79 | 80 | # IPython 81 | profile_default/ 82 | ipython_config.py 83 | 84 | # pyenv 85 | .python-version 86 | 87 | # pipenv 88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 91 | # install all needed dependencies. 92 | #Pipfile.lock 93 | 94 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 95 | __pypackages__/ 96 | 97 | # Celery stuff 98 | celerybeat-schedule 99 | celerybeat.pid 100 | 101 | # SageMath parsed files 102 | *.sage.py 103 | 104 | # Environments 105 | .env 106 | .venv 107 | env/ 108 | venv/ 109 | ENV/ 110 | env.bak/ 111 | venv.bak/ 112 | 113 | # Spyder project settings 114 | .spyderproject 115 | .spyproject 116 | 117 | # Rope project settings 118 | .ropeproject 119 | 120 | # mkdocs documentation 121 | /site 122 | 123 | # mypy 124 | .mypy_cache/ 125 | .dmypy.json 126 | dmypy.json 127 | 128 | # Pyre type checker 129 | .pyre/ 130 | 131 | # OSX 132 | .DS_Store 133 | 134 | # Idea 135 | .idea/ 136 | 137 | # Etc 138 | ignoreme.py 139 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Hackers and Slackers 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. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | PROJECT_NAME := $(shell basename $CURDIR) 2 | VIRTUAL_ENVIRONMENT := $(CURDIR)/.venv 3 | LOCAL_PYTHON := $(VIRTUAL_ENVIRONMENT)/bin/python3 4 | 5 | define HELP 6 | Manage $(PROJECT_NAME). Usage: 7 | 8 | make run - Run $(PROJECT_NAME) locally. 9 | make install - Create local virtualenv & install dependencies. 10 | make deploy - Set up project & run locally. 11 | make update - Update dependencies via Poetry and output resulting `requirements.txt`. 12 | make format - Run Python code formatter & sort dependencies. 13 | make lint - Check code formatting with flake8. 14 | make clean - Remove extraneous compiled files, caches, logs, etc. 15 | 16 | endef 17 | export HELP 18 | 19 | 20 | .PHONY: run restart install update format test lint clean help 21 | 22 | 23 | all help: 24 | @echo "$$HELP" 25 | 26 | env: .venv/bin/activate 27 | 28 | .PHONY: run 29 | run: env 30 | $(LOCAL_PYTHON) -m main 31 | 32 | 33 | .PHONY: install 34 | install: 35 | if [ ! -d "./.venv" ]; then python3 -m venv $(VIRTUAL_ENVIRONMENT); fi 36 | $(shell . .venv/bin/activate) 37 | $(LOCAL_PYTHON) -m pip install --upgrade pip setuptools wheel 38 | $(LOCAL_PYTHON) -m pip install -r requirements.txt 39 | 40 | 41 | .PHONY: deploy 42 | deploy: 43 | make clean 44 | make install 45 | make run 46 | 47 | 48 | .PHONY: update 49 | update: 50 | if [ ! -d "./.venv" ]; then python3 -m venv $(VIRTUAL_ENVIRONMENT); fi 51 | .venv/bin/python3 -m pip install --upgrade pip setuptools wheel 52 | poetry update 53 | poetry export -f requirements.txt --output requirements.txt --without-hashes 54 | 55 | 56 | .PHONY: test 57 | test: env 58 | $(LOCAL_PYTHON) -m \ 59 | coverage run -m pytest -v \ 60 | --disable-pytest-warnings \ 61 | && coverage html --title='Coverage Report' -d .reports \ 62 | && open .reports/index.html 63 | 64 | 65 | .PHONY: format 66 | format: env 67 | isort --multi-line=3 . 68 | black . 69 | 70 | 71 | .PHONY: lint 72 | lint: 73 | $(LOCAL_PYTHON) -m flake8 . --count \ 74 | --select=E9,F63,F7,F82 \ 75 | --exclude .git,.github,__pycache__,.pytest_cache,.venv,logs,creds,.venv,docs,logs,.reports \ 76 | --show-source \ 77 | --statistics 78 | 79 | 80 | .PHONY: clean 81 | clean: 82 | find . -name '**/*.pyc' -delete 83 | find . -name '__pycache__' -delete 84 | find . -name 'poetry.lock' -delete 85 | find . -name 'Pipefile.lock' -delete 86 | find . -name '*.log' -delete 87 | find . -name '.coverage' -delete 88 | find . -wholename 'logs/*.json' -delete 89 | find . -type d -name '.pytest_cache' -exec rm -rf {} + 90 | find . -type d -name '**/.pytest_cache' -exec rm -rf {} + 91 | find . -type d -name './logs' -exec rm -rf {} + 92 | find . -type d -name './.reports' -exec rm -rf {} + 93 | 94 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Redis Python Tutorial 2 | 3 | ![Python](https://img.shields.io/badge/Python-v3.9-blue.svg?logo=python&longCache=true&logoColor=white&colorB=5e81ac&style=flat-square&colorA=4c566a) 4 | ![Redis](https://img.shields.io/badge/Redis-v4.2.2-red.svg?longCache=true&style=flat-square&logo=redis&logoColor=white&colorA=4c566a&colorB=bf616a) 5 | ![Loguru](https://img.shields.io/badge/Loguru-v0.6.0-blue.svg?longCache=true&logo=python&style=flat-square&logoColor=white&colorB=5e81ac&colorA=4c566a) 6 | ![GitHub Last Commit](https://img.shields.io/github/last-commit/google/skia.svg?style=flat-square&colorA=4c566a&colorB=a3be8c&logo=GitHub) 7 | [![GitHub Issues](https://img.shields.io/github/issues/hackersandslackers/redis-python-tutorial.svg?style=flat-square&colorA=4c566a&logo=GitHub&colorB=ebcb8b)](https://github.com/hackersandslackers/redis-python-tutorial/issues) 8 | [![GitHub Stars](https://img.shields.io/github/stars/hackersandslackers/redis-python-tutorial.svg?style=flat-square8&colorA=4c566a&logo=GitHub&colorB=ebcb8b)](https://github.com/hackersandslackers/redis-python-tutorial/stargazers) 9 | [![GitHub Forks](https://img.shields.io/github/forks/hackersandslackers/redis-python-tutorial.svg?style=flat-square&colorA=4c566a&logo=GitHub&colorB=ebcb8b)](https://github.com/hackersandslackers/redis-python-tutorial/network) 10 | 11 | ![Redis Python](https://res.cloudinary.com/hackers/image/upload/v1580673187/2020/02/redis%402x.jpg) 12 | 13 | Leverage in-memory data storage to cache data, handle user sessions, and avoid database transactions to keep your Python app snappy. 14 | 15 | * **Tutorial**: https://hackersandslackers.com/redis-py-python/ 16 | 17 | ## Getting Started 18 | 19 | ### Installation 20 | 21 | ```shell 22 | $ git clone https://github.com/hackersandslackers/redis-python-tutorial.git 23 | $ cd redis-python-tutorial 24 | $ make deploy 25 | ``` 26 | 27 | ----- 28 | 29 | **Hackers and Slackers** tutorials are free of charge. If you found this tutorial helpful, a [small donation](https://www.buymeacoffee.com/hackersslackers) would be greatly appreciated to keep us in business. All proceeds go towards coffee, and all coffee goes towards more content. 30 | -------------------------------------------------------------------------------- /config.py: -------------------------------------------------------------------------------- 1 | """Construct Redis connection URI.""" 2 | from os import getenv, path 3 | 4 | from dotenv import load_dotenv 5 | 6 | # Load environment variables 7 | BASE_DIR = path.abspath(path.dirname(__file__)) 8 | load_dotenv(path.join(BASE_DIR, ".env")) 9 | 10 | # Redis config 11 | REDIS_HOST = getenv("REDIS_HOST") 12 | REDIS_USERNAME = getenv("REDIS_USERNAME") 13 | REDIS_PASSWORD = getenv("REDIS_PASSWORD") 14 | REDIS_PORT = getenv("REDIS_PORT") 15 | REDIS_DB = getenv("REDIS_DB") 16 | REDIS_URI = f"redis://:{REDIS_HOST}@{REDIS_USERNAME}:{REDIS_PORT}/{REDIS_DB}" 17 | 18 | REDIS_EXPIRATION = 604800 19 | 20 | # Logging 21 | PERSIST_LOG_FILES = True 22 | -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | """Application entry point.""" 2 | from redis_python_tutorial import init_app 3 | 4 | if __name__ == "__main__": 5 | init_app() 6 | -------------------------------------------------------------------------------- /poetry.lock: -------------------------------------------------------------------------------- 1 | [[package]] 2 | name = "astroid" 3 | version = "2.11.3" 4 | description = "An abstract syntax tree for Python with inference support." 5 | category = "dev" 6 | optional = false 7 | python-versions = ">=3.6.2" 8 | 9 | [package.dependencies] 10 | lazy-object-proxy = ">=1.4.0" 11 | typing-extensions = {version = ">=3.10", markers = "python_version < \"3.10\""} 12 | wrapt = ">=1.11,<2" 13 | 14 | [[package]] 15 | name = "async-timeout" 16 | version = "4.0.2" 17 | description = "Timeout context manager for asyncio programs" 18 | category = "main" 19 | optional = false 20 | python-versions = ">=3.6" 21 | 22 | [[package]] 23 | name = "atomicwrites" 24 | version = "1.4.0" 25 | description = "Atomic file writes." 26 | category = "dev" 27 | optional = false 28 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 29 | 30 | [[package]] 31 | name = "attrs" 32 | version = "21.4.0" 33 | description = "Classes Without Boilerplate" 34 | category = "dev" 35 | optional = false 36 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 37 | 38 | [package.extras] 39 | dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "furo", "sphinx", "sphinx-notfound-page", "pre-commit", "cloudpickle"] 40 | docs = ["furo", "sphinx", "zope.interface", "sphinx-notfound-page"] 41 | tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "cloudpickle"] 42 | tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "cloudpickle"] 43 | 44 | [[package]] 45 | name = "black" 46 | version = "22.3.0" 47 | description = "The uncompromising code formatter." 48 | category = "dev" 49 | optional = false 50 | python-versions = ">=3.6.2" 51 | 52 | [package.dependencies] 53 | click = ">=8.0.0" 54 | mypy-extensions = ">=0.4.3" 55 | pathspec = ">=0.9.0" 56 | platformdirs = ">=2" 57 | tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} 58 | typing-extensions = {version = ">=3.10.0.0", markers = "python_version < \"3.10\""} 59 | 60 | [package.extras] 61 | colorama = ["colorama (>=0.4.3)"] 62 | d = ["aiohttp (>=3.7.4)"] 63 | jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] 64 | uvloop = ["uvloop (>=0.15.2)"] 65 | 66 | [[package]] 67 | name = "click" 68 | version = "8.1.2" 69 | description = "Composable command line interface toolkit" 70 | category = "dev" 71 | optional = false 72 | python-versions = ">=3.7" 73 | 74 | [package.dependencies] 75 | colorama = {version = "*", markers = "platform_system == \"Windows\""} 76 | 77 | [[package]] 78 | name = "colorama" 79 | version = "0.4.4" 80 | description = "Cross-platform colored terminal text." 81 | category = "main" 82 | optional = false 83 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 84 | 85 | [[package]] 86 | name = "coverage" 87 | version = "6.3.2" 88 | description = "Code coverage measurement for Python" 89 | category = "dev" 90 | optional = false 91 | python-versions = ">=3.7" 92 | 93 | [package.extras] 94 | toml = ["tomli"] 95 | 96 | [[package]] 97 | name = "deprecated" 98 | version = "1.2.13" 99 | description = "Python @deprecated decorator to deprecate old python classes, functions or methods." 100 | category = "main" 101 | optional = false 102 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 103 | 104 | [package.dependencies] 105 | wrapt = ">=1.10,<2" 106 | 107 | [package.extras] 108 | dev = ["tox", "bump2version (<1)", "sphinx (<2)", "importlib-metadata (<3)", "importlib-resources (<4)", "configparser (<5)", "sphinxcontrib-websupport (<2)", "zipp (<2)", "PyTest (<5)", "PyTest-Cov (<2.6)", "pytest", "pytest-cov"] 109 | 110 | [[package]] 111 | name = "dill" 112 | version = "0.3.4" 113 | description = "serialize all of python" 114 | category = "dev" 115 | optional = false 116 | python-versions = ">=2.7, !=3.0.*" 117 | 118 | [package.extras] 119 | graph = ["objgraph (>=1.7.2)"] 120 | 121 | [[package]] 122 | name = "flake8" 123 | version = "4.0.1" 124 | description = "the modular source code checker: pep8 pyflakes and co" 125 | category = "dev" 126 | optional = false 127 | python-versions = ">=3.6" 128 | 129 | [package.dependencies] 130 | mccabe = ">=0.6.0,<0.7.0" 131 | pycodestyle = ">=2.8.0,<2.9.0" 132 | pyflakes = ">=2.4.0,<2.5.0" 133 | 134 | [[package]] 135 | name = "iniconfig" 136 | version = "1.1.1" 137 | description = "iniconfig: brain-dead simple config-ini parsing" 138 | category = "dev" 139 | optional = false 140 | python-versions = "*" 141 | 142 | [[package]] 143 | name = "isort" 144 | version = "5.10.1" 145 | description = "A Python utility / library to sort Python imports." 146 | category = "dev" 147 | optional = false 148 | python-versions = ">=3.6.1,<4.0" 149 | 150 | [package.extras] 151 | pipfile_deprecated_finder = ["pipreqs", "requirementslib"] 152 | requirements_deprecated_finder = ["pipreqs", "pip-api"] 153 | colors = ["colorama (>=0.4.3,<0.5.0)"] 154 | plugins = ["setuptools"] 155 | 156 | [[package]] 157 | name = "lazy-object-proxy" 158 | version = "1.7.1" 159 | description = "A fast and thorough lazy object proxy." 160 | category = "dev" 161 | optional = false 162 | python-versions = ">=3.6" 163 | 164 | [[package]] 165 | name = "loguru" 166 | version = "0.6.0" 167 | description = "Python logging made (stupidly) simple" 168 | category = "main" 169 | optional = false 170 | python-versions = ">=3.5" 171 | 172 | [package.dependencies] 173 | colorama = {version = ">=0.3.4", markers = "sys_platform == \"win32\""} 174 | win32-setctime = {version = ">=1.0.0", markers = "sys_platform == \"win32\""} 175 | 176 | [package.extras] 177 | dev = ["colorama (>=0.3.4)", "docutils (==0.16)", "flake8 (>=3.7.7)", "tox (>=3.9.0)", "pytest (>=4.6.2)", "pytest-cov (>=2.7.1)", "black (>=19.10b0)", "isort (>=5.1.1)", "Sphinx (>=4.1.1)", "sphinx-autobuild (>=0.7.1)", "sphinx-rtd-theme (>=0.4.3)"] 178 | 179 | [[package]] 180 | name = "mccabe" 181 | version = "0.6.1" 182 | description = "McCabe checker, plugin for flake8" 183 | category = "dev" 184 | optional = false 185 | python-versions = "*" 186 | 187 | [[package]] 188 | name = "mock" 189 | version = "4.0.3" 190 | description = "Rolling backport of unittest.mock for all Pythons" 191 | category = "dev" 192 | optional = false 193 | python-versions = ">=3.6" 194 | 195 | [package.extras] 196 | build = ["twine", "wheel", "blurb"] 197 | docs = ["sphinx"] 198 | test = ["pytest (<5.4)", "pytest-cov"] 199 | 200 | [[package]] 201 | name = "mypy" 202 | version = "0.950" 203 | description = "Optional static typing for Python" 204 | category = "dev" 205 | optional = false 206 | python-versions = ">=3.6" 207 | 208 | [package.dependencies] 209 | mypy-extensions = ">=0.4.3" 210 | tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} 211 | typing-extensions = ">=3.10" 212 | 213 | [package.extras] 214 | dmypy = ["psutil (>=4.0)"] 215 | python2 = ["typed-ast (>=1.4.0,<2)"] 216 | reports = ["lxml"] 217 | 218 | [[package]] 219 | name = "mypy-extensions" 220 | version = "0.4.3" 221 | description = "Experimental type system extensions for programs checked with the mypy typechecker." 222 | category = "dev" 223 | optional = false 224 | python-versions = "*" 225 | 226 | [[package]] 227 | name = "packaging" 228 | version = "21.3" 229 | description = "Core utilities for Python packages" 230 | category = "main" 231 | optional = false 232 | python-versions = ">=3.6" 233 | 234 | [package.dependencies] 235 | pyparsing = ">=2.0.2,<3.0.5 || >3.0.5" 236 | 237 | [[package]] 238 | name = "pathspec" 239 | version = "0.9.0" 240 | description = "Utility library for gitignore style pattern matching of file paths." 241 | category = "dev" 242 | optional = false 243 | python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" 244 | 245 | [[package]] 246 | name = "platformdirs" 247 | version = "2.5.2" 248 | description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." 249 | category = "dev" 250 | optional = false 251 | python-versions = ">=3.7" 252 | 253 | [package.extras] 254 | docs = ["furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx-autodoc-typehints (>=1.12)", "sphinx (>=4)"] 255 | test = ["appdirs (==1.4.4)", "pytest-cov (>=2.7)", "pytest-mock (>=3.6)", "pytest (>=6)"] 256 | 257 | [[package]] 258 | name = "pluggy" 259 | version = "1.0.0" 260 | description = "plugin and hook calling mechanisms for python" 261 | category = "dev" 262 | optional = false 263 | python-versions = ">=3.6" 264 | 265 | [package.extras] 266 | dev = ["pre-commit", "tox"] 267 | testing = ["pytest", "pytest-benchmark"] 268 | 269 | [[package]] 270 | name = "py" 271 | version = "1.11.0" 272 | description = "library with cross-python path, ini-parsing, io, code, log facilities" 273 | category = "dev" 274 | optional = false 275 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 276 | 277 | [[package]] 278 | name = "pycodestyle" 279 | version = "2.8.0" 280 | description = "Python style guide checker" 281 | category = "dev" 282 | optional = false 283 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 284 | 285 | [[package]] 286 | name = "pyflakes" 287 | version = "2.4.0" 288 | description = "passive checker of Python programs" 289 | category = "dev" 290 | optional = false 291 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 292 | 293 | [[package]] 294 | name = "pylint" 295 | version = "2.13.7" 296 | description = "python code static checker" 297 | category = "dev" 298 | optional = false 299 | python-versions = ">=3.6.2" 300 | 301 | [package.dependencies] 302 | astroid = ">=2.11.3,<=2.12.0-dev0" 303 | colorama = {version = "*", markers = "sys_platform == \"win32\""} 304 | dill = ">=0.2" 305 | isort = ">=4.2.5,<6" 306 | mccabe = ">=0.6,<0.8" 307 | platformdirs = ">=2.2.0" 308 | tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} 309 | typing-extensions = {version = ">=3.10.0", markers = "python_version < \"3.10\""} 310 | 311 | [package.extras] 312 | testutil = ["gitpython (>3)"] 313 | 314 | [[package]] 315 | name = "pyparsing" 316 | version = "3.0.8" 317 | description = "pyparsing module - Classes and methods to define and execute parsing grammars" 318 | category = "main" 319 | optional = false 320 | python-versions = ">=3.6.8" 321 | 322 | [package.extras] 323 | diagrams = ["railroad-diagrams", "jinja2"] 324 | 325 | [[package]] 326 | name = "pytest" 327 | version = "7.1.2" 328 | description = "pytest: simple powerful testing with Python" 329 | category = "dev" 330 | optional = false 331 | python-versions = ">=3.7" 332 | 333 | [package.dependencies] 334 | atomicwrites = {version = ">=1.0", markers = "sys_platform == \"win32\""} 335 | attrs = ">=19.2.0" 336 | colorama = {version = "*", markers = "sys_platform == \"win32\""} 337 | iniconfig = "*" 338 | packaging = "*" 339 | pluggy = ">=0.12,<2.0" 340 | py = ">=1.8.2" 341 | tomli = ">=1.0.0" 342 | 343 | [package.extras] 344 | testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"] 345 | 346 | [[package]] 347 | name = "python-dotenv" 348 | version = "0.20.0" 349 | description = "Read key-value pairs from a .env file and set them as environment variables" 350 | category = "main" 351 | optional = false 352 | python-versions = ">=3.5" 353 | 354 | [package.extras] 355 | cli = ["click (>=5.0)"] 356 | 357 | [[package]] 358 | name = "redis" 359 | version = "4.2.2" 360 | description = "Python client for Redis database and key-value store" 361 | category = "main" 362 | optional = false 363 | python-versions = ">=3.6" 364 | 365 | [package.dependencies] 366 | async-timeout = ">=4.0.2" 367 | deprecated = ">=1.2.3" 368 | packaging = ">=20.4" 369 | 370 | [package.extras] 371 | hiredis = ["hiredis (>=1.0.0)"] 372 | ocsp = ["cryptography (>=36.0.1)", "pyopenssl (==20.0.1)", "requests (>=2.26.0)"] 373 | 374 | [[package]] 375 | name = "tomli" 376 | version = "2.0.1" 377 | description = "A lil' TOML parser" 378 | category = "dev" 379 | optional = false 380 | python-versions = ">=3.7" 381 | 382 | [[package]] 383 | name = "typing-extensions" 384 | version = "4.2.0" 385 | description = "Backported and Experimental Type Hints for Python 3.7+" 386 | category = "dev" 387 | optional = false 388 | python-versions = ">=3.7" 389 | 390 | [[package]] 391 | name = "win32-setctime" 392 | version = "1.1.0" 393 | description = "A small Python utility to set file creation time on Windows" 394 | category = "main" 395 | optional = false 396 | python-versions = ">=3.5" 397 | 398 | [package.extras] 399 | dev = ["pytest (>=4.6.2)", "black (>=19.3b0)"] 400 | 401 | [[package]] 402 | name = "wrapt" 403 | version = "1.14.0" 404 | description = "Module for decorators, wrappers and monkey patching." 405 | category = "main" 406 | optional = false 407 | python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" 408 | 409 | [metadata] 410 | lock-version = "1.1" 411 | python-versions = "3.9" 412 | content-hash = "9e956517d749d2f6c7652c0b302c806dc1c775d2eb41d7eca799859bbe356c30" 413 | 414 | [metadata.files] 415 | astroid = [ 416 | {file = "astroid-2.11.3-py3-none-any.whl", hash = "sha256:f1af57483cd17e963b2eddce8361e00fc593d1520fe19948488e94ff6476bd71"}, 417 | {file = "astroid-2.11.3.tar.gz", hash = "sha256:4e5ba10571e197785e312966ea5efb2f5783176d4c1a73fa922d474ae2be59f7"}, 418 | ] 419 | async-timeout = [ 420 | {file = "async-timeout-4.0.2.tar.gz", hash = "sha256:2163e1640ddb52b7a8c80d0a67a08587e5d245cc9c553a74a847056bc2976b15"}, 421 | {file = "async_timeout-4.0.2-py3-none-any.whl", hash = "sha256:8ca1e4fcf50d07413d66d1a5e416e42cfdf5851c981d679a09851a6853383b3c"}, 422 | ] 423 | atomicwrites = [ 424 | {file = "atomicwrites-1.4.0-py2.py3-none-any.whl", hash = "sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197"}, 425 | {file = "atomicwrites-1.4.0.tar.gz", hash = "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"}, 426 | ] 427 | attrs = [ 428 | {file = "attrs-21.4.0-py2.py3-none-any.whl", hash = "sha256:2d27e3784d7a565d36ab851fe94887c5eccd6a463168875832a1be79c82828b4"}, 429 | {file = "attrs-21.4.0.tar.gz", hash = "sha256:626ba8234211db98e869df76230a137c4c40a12d72445c45d5f5b716f076e2fd"}, 430 | ] 431 | black = [ 432 | {file = "black-22.3.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:2497f9c2386572e28921fa8bec7be3e51de6801f7459dffd6e62492531c47e09"}, 433 | {file = "black-22.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5795a0375eb87bfe902e80e0c8cfaedf8af4d49694d69161e5bd3206c18618bb"}, 434 | {file = "black-22.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e3556168e2e5c49629f7b0f377070240bd5511e45e25a4497bb0073d9dda776a"}, 435 | {file = "black-22.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:67c8301ec94e3bcc8906740fe071391bce40a862b7be0b86fb5382beefecd968"}, 436 | {file = "black-22.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:fd57160949179ec517d32ac2ac898b5f20d68ed1a9c977346efbac9c2f1e779d"}, 437 | {file = "black-22.3.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:cc1e1de68c8e5444e8f94c3670bb48a2beef0e91dddfd4fcc29595ebd90bb9ce"}, 438 | {file = "black-22.3.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d2fc92002d44746d3e7db7cf9313cf4452f43e9ea77a2c939defce3b10b5c82"}, 439 | {file = "black-22.3.0-cp36-cp36m-win_amd64.whl", hash = "sha256:a6342964b43a99dbc72f72812bf88cad8f0217ae9acb47c0d4f141a6416d2d7b"}, 440 | {file = "black-22.3.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:328efc0cc70ccb23429d6be184a15ce613f676bdfc85e5fe8ea2a9354b4e9015"}, 441 | {file = "black-22.3.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:06f9d8846f2340dfac80ceb20200ea5d1b3f181dd0556b47af4e8e0b24fa0a6b"}, 442 | {file = "black-22.3.0-cp37-cp37m-win_amd64.whl", hash = "sha256:ad4efa5fad66b903b4a5f96d91461d90b9507a812b3c5de657d544215bb7877a"}, 443 | {file = "black-22.3.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e8477ec6bbfe0312c128e74644ac8a02ca06bcdb8982d4ee06f209be28cdf163"}, 444 | {file = "black-22.3.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:637a4014c63fbf42a692d22b55d8ad6968a946b4a6ebc385c5505d9625b6a464"}, 445 | {file = "black-22.3.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:863714200ada56cbc366dc9ae5291ceb936573155f8bf8e9de92aef51f3ad0f0"}, 446 | {file = "black-22.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10dbe6e6d2988049b4655b2b739f98785a884d4d6b85bc35133a8fb9a2233176"}, 447 | {file = "black-22.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:cee3e11161dde1b2a33a904b850b0899e0424cc331b7295f2a9698e79f9a69a0"}, 448 | {file = "black-22.3.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:5891ef8abc06576985de8fa88e95ab70641de6c1fca97e2a15820a9b69e51b20"}, 449 | {file = "black-22.3.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:30d78ba6bf080eeaf0b7b875d924b15cd46fec5fd044ddfbad38c8ea9171043a"}, 450 | {file = "black-22.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ee8f1f7228cce7dffc2b464f07ce769f478968bfb3dd1254a4c2eeed84928aad"}, 451 | {file = "black-22.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6ee227b696ca60dd1c507be80a6bc849a5a6ab57ac7352aad1ffec9e8b805f21"}, 452 | {file = "black-22.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:9b542ced1ec0ceeff5b37d69838106a6348e60db7b8fdd245294dc1d26136265"}, 453 | {file = "black-22.3.0-py3-none-any.whl", hash = "sha256:bc58025940a896d7e5356952228b68f793cf5fcb342be703c3a2669a1488cb72"}, 454 | {file = "black-22.3.0.tar.gz", hash = "sha256:35020b8886c022ced9282b51b5a875b6d1ab0c387b31a065b84db7c33085ca79"}, 455 | ] 456 | click = [ 457 | {file = "click-8.1.2-py3-none-any.whl", hash = "sha256:24e1a4a9ec5bf6299411369b208c1df2188d9eb8d916302fe6bf03faed227f1e"}, 458 | {file = "click-8.1.2.tar.gz", hash = "sha256:479707fe14d9ec9a0757618b7a100a0ae4c4e236fac5b7f80ca68028141a1a72"}, 459 | ] 460 | colorama = [ 461 | {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"}, 462 | {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"}, 463 | ] 464 | coverage = [ 465 | {file = "coverage-6.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9b27d894748475fa858f9597c0ee1d4829f44683f3813633aaf94b19cb5453cf"}, 466 | {file = "coverage-6.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:37d1141ad6b2466a7b53a22e08fe76994c2d35a5b6b469590424a9953155afac"}, 467 | {file = "coverage-6.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f9987b0354b06d4df0f4d3e0ec1ae76d7ce7cbca9a2f98c25041eb79eec766f1"}, 468 | {file = "coverage-6.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:26e2deacd414fc2f97dd9f7676ee3eaecd299ca751412d89f40bc01557a6b1b4"}, 469 | {file = "coverage-6.3.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4dd8bafa458b5c7d061540f1ee9f18025a68e2d8471b3e858a9dad47c8d41903"}, 470 | {file = "coverage-6.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:46191097ebc381fbf89bdce207a6c107ac4ec0890d8d20f3360345ff5976155c"}, 471 | {file = "coverage-6.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6f89d05e028d274ce4fa1a86887b071ae1755082ef94a6740238cd7a8178804f"}, 472 | {file = "coverage-6.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:58303469e9a272b4abdb9e302a780072c0633cdcc0165db7eec0f9e32f901e05"}, 473 | {file = "coverage-6.3.2-cp310-cp310-win32.whl", hash = "sha256:2fea046bfb455510e05be95e879f0e768d45c10c11509e20e06d8fcaa31d9e39"}, 474 | {file = "coverage-6.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:a2a8b8bcc399edb4347a5ca8b9b87e7524c0967b335fbb08a83c8421489ddee1"}, 475 | {file = "coverage-6.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:f1555ea6d6da108e1999b2463ea1003fe03f29213e459145e70edbaf3e004aaa"}, 476 | {file = "coverage-6.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e5f4e1edcf57ce94e5475fe09e5afa3e3145081318e5fd1a43a6b4539a97e518"}, 477 | {file = "coverage-6.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7a15dc0a14008f1da3d1ebd44bdda3e357dbabdf5a0b5034d38fcde0b5c234b7"}, 478 | {file = "coverage-6.3.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21b7745788866028adeb1e0eca3bf1101109e2dc58456cb49d2d9b99a8c516e6"}, 479 | {file = "coverage-6.3.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:8ce257cac556cb03be4a248d92ed36904a59a4a5ff55a994e92214cde15c5bad"}, 480 | {file = "coverage-6.3.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:b0be84e5a6209858a1d3e8d1806c46214e867ce1b0fd32e4ea03f4bd8b2e3359"}, 481 | {file = "coverage-6.3.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:acf53bc2cf7282ab9b8ba346746afe703474004d9e566ad164c91a7a59f188a4"}, 482 | {file = "coverage-6.3.2-cp37-cp37m-win32.whl", hash = "sha256:8bdde1177f2311ee552f47ae6e5aa7750c0e3291ca6b75f71f7ffe1f1dab3dca"}, 483 | {file = "coverage-6.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:b31651d018b23ec463e95cf10070d0b2c548aa950a03d0b559eaa11c7e5a6fa3"}, 484 | {file = "coverage-6.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:07e6db90cd9686c767dcc593dff16c8c09f9814f5e9c51034066cad3373b914d"}, 485 | {file = "coverage-6.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2c6dbb42f3ad25760010c45191e9757e7dce981cbfb90e42feef301d71540059"}, 486 | {file = "coverage-6.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c76aeef1b95aff3905fb2ae2d96e319caca5b76fa41d3470b19d4e4a3a313512"}, 487 | {file = "coverage-6.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8cf5cfcb1521dc3255d845d9dca3ff204b3229401994ef8d1984b32746bb45ca"}, 488 | {file = "coverage-6.3.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8fbbdc8d55990eac1b0919ca69eb5a988a802b854488c34b8f37f3e2025fa90d"}, 489 | {file = "coverage-6.3.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:ec6bc7fe73a938933d4178c9b23c4e0568e43e220aef9472c4f6044bfc6dd0f0"}, 490 | {file = "coverage-6.3.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:9baff2a45ae1f17c8078452e9e5962e518eab705e50a0aa8083733ea7d45f3a6"}, 491 | {file = "coverage-6.3.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:fd9e830e9d8d89b20ab1e5af09b32d33e1a08ef4c4e14411e559556fd788e6b2"}, 492 | {file = "coverage-6.3.2-cp38-cp38-win32.whl", hash = "sha256:f7331dbf301b7289013175087636bbaf5b2405e57259dd2c42fdcc9fcc47325e"}, 493 | {file = "coverage-6.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:68353fe7cdf91f109fc7d474461b46e7f1f14e533e911a2a2cbb8b0fc8613cf1"}, 494 | {file = "coverage-6.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b78e5afb39941572209f71866aa0b206c12f0109835aa0d601e41552f9b3e620"}, 495 | {file = "coverage-6.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4e21876082ed887baed0146fe222f861b5815455ada3b33b890f4105d806128d"}, 496 | {file = "coverage-6.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:34626a7eee2a3da12af0507780bb51eb52dca0e1751fd1471d0810539cefb536"}, 497 | {file = "coverage-6.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1ebf730d2381158ecf3dfd4453fbca0613e16eaa547b4170e2450c9707665ce7"}, 498 | {file = "coverage-6.3.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd6fe30bd519694b356cbfcaca9bd5c1737cddd20778c6a581ae20dc8c04def2"}, 499 | {file = "coverage-6.3.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:96f8a1cb43ca1422f36492bebe63312d396491a9165ed3b9231e778d43a7fca4"}, 500 | {file = "coverage-6.3.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:dd035edafefee4d573140a76fdc785dc38829fe5a455c4bb12bac8c20cfc3d69"}, 501 | {file = "coverage-6.3.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5ca5aeb4344b30d0bec47481536b8ba1181d50dbe783b0e4ad03c95dc1296684"}, 502 | {file = "coverage-6.3.2-cp39-cp39-win32.whl", hash = "sha256:f5fa5803f47e095d7ad8443d28b01d48c0359484fec1b9d8606d0e3282084bc4"}, 503 | {file = "coverage-6.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:9548f10d8be799551eb3a9c74bbf2b4934ddb330e08a73320123c07f95cc2d92"}, 504 | {file = "coverage-6.3.2-pp36.pp37.pp38-none-any.whl", hash = "sha256:18d520c6860515a771708937d2f78f63cc47ab3b80cb78e86573b0a760161faf"}, 505 | {file = "coverage-6.3.2.tar.gz", hash = "sha256:03e2a7826086b91ef345ff18742ee9fc47a6839ccd517061ef8fa1976e652ce9"}, 506 | ] 507 | deprecated = [ 508 | {file = "Deprecated-1.2.13-py2.py3-none-any.whl", hash = "sha256:64756e3e14c8c5eea9795d93c524551432a0be75629f8f29e67ab8caf076c76d"}, 509 | {file = "Deprecated-1.2.13.tar.gz", hash = "sha256:43ac5335da90c31c24ba028af536a91d41d53f9e6901ddb021bcc572ce44e38d"}, 510 | ] 511 | dill = [ 512 | {file = "dill-0.3.4-py2.py3-none-any.whl", hash = "sha256:7e40e4a70304fd9ceab3535d36e58791d9c4a776b38ec7f7ec9afc8d3dca4d4f"}, 513 | {file = "dill-0.3.4.zip", hash = "sha256:9f9734205146b2b353ab3fec9af0070237b6ddae78452af83d2fca84d739e675"}, 514 | ] 515 | flake8 = [ 516 | {file = "flake8-4.0.1-py2.py3-none-any.whl", hash = "sha256:479b1304f72536a55948cb40a32dce8bb0ffe3501e26eaf292c7e60eb5e0428d"}, 517 | {file = "flake8-4.0.1.tar.gz", hash = "sha256:806e034dda44114815e23c16ef92f95c91e4c71100ff52813adf7132a6ad870d"}, 518 | ] 519 | iniconfig = [ 520 | {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"}, 521 | {file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"}, 522 | ] 523 | isort = [ 524 | {file = "isort-5.10.1-py3-none-any.whl", hash = "sha256:6f62d78e2f89b4500b080fe3a81690850cd254227f27f75c3a0c491a1f351ba7"}, 525 | {file = "isort-5.10.1.tar.gz", hash = "sha256:e8443a5e7a020e9d7f97f1d7d9cd17c88bcb3bc7e218bf9cf5095fe550be2951"}, 526 | ] 527 | lazy-object-proxy = [ 528 | {file = "lazy-object-proxy-1.7.1.tar.gz", hash = "sha256:d609c75b986def706743cdebe5e47553f4a5a1da9c5ff66d76013ef396b5a8a4"}, 529 | {file = "lazy_object_proxy-1.7.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bb8c5fd1684d60a9902c60ebe276da1f2281a318ca16c1d0a96db28f62e9166b"}, 530 | {file = "lazy_object_proxy-1.7.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a57d51ed2997e97f3b8e3500c984db50a554bb5db56c50b5dab1b41339b37e36"}, 531 | {file = "lazy_object_proxy-1.7.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd45683c3caddf83abbb1249b653a266e7069a09f486daa8863fb0e7496a9fdb"}, 532 | {file = "lazy_object_proxy-1.7.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:8561da8b3dd22d696244d6d0d5330618c993a215070f473b699e00cf1f3f6443"}, 533 | {file = "lazy_object_proxy-1.7.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fccdf7c2c5821a8cbd0a9440a456f5050492f2270bd54e94360cac663398739b"}, 534 | {file = "lazy_object_proxy-1.7.1-cp310-cp310-win32.whl", hash = "sha256:898322f8d078f2654d275124a8dd19b079080ae977033b713f677afcfc88e2b9"}, 535 | {file = "lazy_object_proxy-1.7.1-cp310-cp310-win_amd64.whl", hash = "sha256:85b232e791f2229a4f55840ed54706110c80c0a210d076eee093f2b2e33e1bfd"}, 536 | {file = "lazy_object_proxy-1.7.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:46ff647e76f106bb444b4533bb4153c7370cdf52efc62ccfc1a28bdb3cc95442"}, 537 | {file = "lazy_object_proxy-1.7.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:12f3bb77efe1367b2515f8cb4790a11cffae889148ad33adad07b9b55e0ab22c"}, 538 | {file = "lazy_object_proxy-1.7.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c19814163728941bb871240d45c4c30d33b8a2e85972c44d4e63dd7107faba44"}, 539 | {file = "lazy_object_proxy-1.7.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:e40f2013d96d30217a51eeb1db28c9ac41e9d0ee915ef9d00da639c5b63f01a1"}, 540 | {file = "lazy_object_proxy-1.7.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:2052837718516a94940867e16b1bb10edb069ab475c3ad84fd1e1a6dd2c0fcfc"}, 541 | {file = "lazy_object_proxy-1.7.1-cp36-cp36m-win32.whl", hash = "sha256:6a24357267aa976abab660b1d47a34aaf07259a0c3859a34e536f1ee6e76b5bb"}, 542 | {file = "lazy_object_proxy-1.7.1-cp36-cp36m-win_amd64.whl", hash = "sha256:6aff3fe5de0831867092e017cf67e2750c6a1c7d88d84d2481bd84a2e019ec35"}, 543 | {file = "lazy_object_proxy-1.7.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:6a6e94c7b02641d1311228a102607ecd576f70734dc3d5e22610111aeacba8a0"}, 544 | {file = "lazy_object_proxy-1.7.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c4ce15276a1a14549d7e81c243b887293904ad2d94ad767f42df91e75fd7b5b6"}, 545 | {file = "lazy_object_proxy-1.7.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e368b7f7eac182a59ff1f81d5f3802161932a41dc1b1cc45c1f757dc876b5d2c"}, 546 | {file = "lazy_object_proxy-1.7.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:6ecbb350991d6434e1388bee761ece3260e5228952b1f0c46ffc800eb313ff42"}, 547 | {file = "lazy_object_proxy-1.7.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:553b0f0d8dbf21890dd66edd771f9b1b5f51bd912fa5f26de4449bfc5af5e029"}, 548 | {file = "lazy_object_proxy-1.7.1-cp37-cp37m-win32.whl", hash = "sha256:c7a683c37a8a24f6428c28c561c80d5f4fd316ddcf0c7cab999b15ab3f5c5c69"}, 549 | {file = "lazy_object_proxy-1.7.1-cp37-cp37m-win_amd64.whl", hash = "sha256:df2631f9d67259dc9620d831384ed7732a198eb434eadf69aea95ad18c587a28"}, 550 | {file = "lazy_object_proxy-1.7.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:07fa44286cda977bd4803b656ffc1c9b7e3bc7dff7d34263446aec8f8c96f88a"}, 551 | {file = "lazy_object_proxy-1.7.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4dca6244e4121c74cc20542c2ca39e5c4a5027c81d112bfb893cf0790f96f57e"}, 552 | {file = "lazy_object_proxy-1.7.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:91ba172fc5b03978764d1df5144b4ba4ab13290d7bab7a50f12d8117f8630c38"}, 553 | {file = "lazy_object_proxy-1.7.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:043651b6cb706eee4f91854da4a089816a6606c1428fd391573ef8cb642ae4f7"}, 554 | {file = "lazy_object_proxy-1.7.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b9e89b87c707dd769c4ea91f7a31538888aad05c116a59820f28d59b3ebfe25a"}, 555 | {file = "lazy_object_proxy-1.7.1-cp38-cp38-win32.whl", hash = "sha256:9d166602b525bf54ac994cf833c385bfcc341b364e3ee71e3bf5a1336e677b55"}, 556 | {file = "lazy_object_proxy-1.7.1-cp38-cp38-win_amd64.whl", hash = "sha256:8f3953eb575b45480db6568306893f0bd9d8dfeeebd46812aa09ca9579595148"}, 557 | {file = "lazy_object_proxy-1.7.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:dd7ed7429dbb6c494aa9bc4e09d94b778a3579be699f9d67da7e6804c422d3de"}, 558 | {file = "lazy_object_proxy-1.7.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:70ed0c2b380eb6248abdef3cd425fc52f0abd92d2b07ce26359fcbc399f636ad"}, 559 | {file = "lazy_object_proxy-1.7.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7096a5e0c1115ec82641afbdd70451a144558ea5cf564a896294e346eb611be1"}, 560 | {file = "lazy_object_proxy-1.7.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:f769457a639403073968d118bc70110e7dce294688009f5c24ab78800ae56dc8"}, 561 | {file = "lazy_object_proxy-1.7.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:39b0e26725c5023757fc1ab2a89ef9d7ab23b84f9251e28f9cc114d5b59c1b09"}, 562 | {file = "lazy_object_proxy-1.7.1-cp39-cp39-win32.whl", hash = "sha256:2130db8ed69a48a3440103d4a520b89d8a9405f1b06e2cc81640509e8bf6548f"}, 563 | {file = "lazy_object_proxy-1.7.1-cp39-cp39-win_amd64.whl", hash = "sha256:677ea950bef409b47e51e733283544ac3d660b709cfce7b187f5ace137960d61"}, 564 | {file = "lazy_object_proxy-1.7.1-pp37.pp38-none-any.whl", hash = "sha256:d66906d5785da8e0be7360912e99c9188b70f52c422f9fc18223347235691a84"}, 565 | ] 566 | loguru = [ 567 | {file = "loguru-0.6.0-py3-none-any.whl", hash = "sha256:4e2414d534a2ab57573365b3e6d0234dfb1d84b68b7f3b948e6fb743860a77c3"}, 568 | {file = "loguru-0.6.0.tar.gz", hash = "sha256:066bd06758d0a513e9836fd9c6b5a75bfb3fd36841f4b996bc60b547a309d41c"}, 569 | ] 570 | mccabe = [ 571 | {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"}, 572 | {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"}, 573 | ] 574 | mock = [ 575 | {file = "mock-4.0.3-py3-none-any.whl", hash = "sha256:122fcb64ee37cfad5b3f48d7a7d51875d7031aaf3d8be7c42e2bee25044eee62"}, 576 | {file = "mock-4.0.3.tar.gz", hash = "sha256:7d3fbbde18228f4ff2f1f119a45cdffa458b4c0dee32eb4d2bb2f82554bac7bc"}, 577 | ] 578 | mypy = [ 579 | {file = "mypy-0.950-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cf9c261958a769a3bd38c3e133801ebcd284ffb734ea12d01457cb09eacf7d7b"}, 580 | {file = "mypy-0.950-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b5b5bd0ffb11b4aba2bb6d31b8643902c48f990cc92fda4e21afac658044f0c0"}, 581 | {file = "mypy-0.950-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5e7647df0f8fc947388e6251d728189cfadb3b1e558407f93254e35abc026e22"}, 582 | {file = "mypy-0.950-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:eaff8156016487c1af5ffa5304c3e3fd183edcb412f3e9c72db349faf3f6e0eb"}, 583 | {file = "mypy-0.950-cp310-cp310-win_amd64.whl", hash = "sha256:563514c7dc504698fb66bb1cf897657a173a496406f1866afae73ab5b3cdb334"}, 584 | {file = "mypy-0.950-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:dd4d670eee9610bf61c25c940e9ade2d0ed05eb44227275cce88701fee014b1f"}, 585 | {file = "mypy-0.950-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ca75ecf2783395ca3016a5e455cb322ba26b6d33b4b413fcdedfc632e67941dc"}, 586 | {file = "mypy-0.950-cp36-cp36m-win_amd64.whl", hash = "sha256:6003de687c13196e8a1243a5e4bcce617d79b88f83ee6625437e335d89dfebe2"}, 587 | {file = "mypy-0.950-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:4c653e4846f287051599ed8f4b3c044b80e540e88feec76b11044ddc5612ffed"}, 588 | {file = "mypy-0.950-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:e19736af56947addedce4674c0971e5dceef1b5ec7d667fe86bcd2b07f8f9075"}, 589 | {file = "mypy-0.950-cp37-cp37m-win_amd64.whl", hash = "sha256:ef7beb2a3582eb7a9f37beaf38a28acfd801988cde688760aea9e6cc4832b10b"}, 590 | {file = "mypy-0.950-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:0112752a6ff07230f9ec2f71b0d3d4e088a910fdce454fdb6553e83ed0eced7d"}, 591 | {file = "mypy-0.950-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ee0a36edd332ed2c5208565ae6e3a7afc0eabb53f5327e281f2ef03a6bc7687a"}, 592 | {file = "mypy-0.950-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:77423570c04aca807508a492037abbd72b12a1fb25a385847d191cd50b2c9605"}, 593 | {file = "mypy-0.950-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:5ce6a09042b6da16d773d2110e44f169683d8cc8687e79ec6d1181a72cb028d2"}, 594 | {file = "mypy-0.950-cp38-cp38-win_amd64.whl", hash = "sha256:5b231afd6a6e951381b9ef09a1223b1feabe13625388db48a8690f8daa9b71ff"}, 595 | {file = "mypy-0.950-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:0384d9f3af49837baa92f559d3fa673e6d2652a16550a9ee07fc08c736f5e6f8"}, 596 | {file = "mypy-0.950-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1fdeb0a0f64f2a874a4c1f5271f06e40e1e9779bf55f9567f149466fc7a55038"}, 597 | {file = "mypy-0.950-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:61504b9a5ae166ba5ecfed9e93357fd51aa693d3d434b582a925338a2ff57fd2"}, 598 | {file = "mypy-0.950-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a952b8bc0ae278fc6316e6384f67bb9a396eb30aced6ad034d3a76120ebcc519"}, 599 | {file = "mypy-0.950-cp39-cp39-win_amd64.whl", hash = "sha256:eaea21d150fb26d7b4856766e7addcf929119dd19fc832b22e71d942835201ef"}, 600 | {file = "mypy-0.950-py3-none-any.whl", hash = "sha256:a4d9898f46446bfb6405383b57b96737dcfd0a7f25b748e78ef3e8c576bba3cb"}, 601 | {file = "mypy-0.950.tar.gz", hash = "sha256:1b333cfbca1762ff15808a0ef4f71b5d3eed8528b23ea1c3fb50543c867d68de"}, 602 | ] 603 | mypy-extensions = [ 604 | {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, 605 | {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, 606 | ] 607 | packaging = [ 608 | {file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"}, 609 | {file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"}, 610 | ] 611 | pathspec = [ 612 | {file = "pathspec-0.9.0-py2.py3-none-any.whl", hash = "sha256:7d15c4ddb0b5c802d161efc417ec1a2558ea2653c2e8ad9c19098201dc1c993a"}, 613 | {file = "pathspec-0.9.0.tar.gz", hash = "sha256:e564499435a2673d586f6b2130bb5b95f04a3ba06f81b8f895b651a3c76aabb1"}, 614 | ] 615 | platformdirs = [ 616 | {file = "platformdirs-2.5.2-py3-none-any.whl", hash = "sha256:027d8e83a2d7de06bbac4e5ef7e023c02b863d7ea5d079477e722bb41ab25788"}, 617 | {file = "platformdirs-2.5.2.tar.gz", hash = "sha256:58c8abb07dcb441e6ee4b11d8df0ac856038f944ab98b7be6b27b2a3c7feef19"}, 618 | ] 619 | pluggy = [ 620 | {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"}, 621 | {file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"}, 622 | ] 623 | py = [ 624 | {file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"}, 625 | {file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"}, 626 | ] 627 | pycodestyle = [ 628 | {file = "pycodestyle-2.8.0-py2.py3-none-any.whl", hash = "sha256:720f8b39dde8b293825e7ff02c475f3077124006db4f440dcbc9a20b76548a20"}, 629 | {file = "pycodestyle-2.8.0.tar.gz", hash = "sha256:eddd5847ef438ea1c7870ca7eb78a9d47ce0cdb4851a5523949f2601d0cbbe7f"}, 630 | ] 631 | pyflakes = [ 632 | {file = "pyflakes-2.4.0-py2.py3-none-any.whl", hash = "sha256:3bb3a3f256f4b7968c9c788781e4ff07dce46bdf12339dcda61053375426ee2e"}, 633 | {file = "pyflakes-2.4.0.tar.gz", hash = "sha256:05a85c2872edf37a4ed30b0cce2f6093e1d0581f8c19d7393122da7e25b2b24c"}, 634 | ] 635 | pylint = [ 636 | {file = "pylint-2.13.7-py3-none-any.whl", hash = "sha256:13ddbbd8872c804574149e81197c28877eba75224ba6b76cd8652fc31df55c1c"}, 637 | {file = "pylint-2.13.7.tar.gz", hash = "sha256:911d3a97c808f7554643bcc5416028cfdc42eae34ed129b150741888c688d5d5"}, 638 | ] 639 | pyparsing = [ 640 | {file = "pyparsing-3.0.8-py3-none-any.whl", hash = "sha256:ef7b523f6356f763771559412c0d7134753f037822dad1b16945b7b846f7ad06"}, 641 | {file = "pyparsing-3.0.8.tar.gz", hash = "sha256:7bf433498c016c4314268d95df76c81b842a4cb2b276fa3312cfb1e1d85f6954"}, 642 | ] 643 | pytest = [ 644 | {file = "pytest-7.1.2-py3-none-any.whl", hash = "sha256:13d0e3ccfc2b6e26be000cb6568c832ba67ba32e719443bfe725814d3c42433c"}, 645 | {file = "pytest-7.1.2.tar.gz", hash = "sha256:a06a0425453864a270bc45e71f783330a7428defb4230fb5e6a731fde06ecd45"}, 646 | ] 647 | python-dotenv = [ 648 | {file = "python-dotenv-0.20.0.tar.gz", hash = "sha256:b7e3b04a59693c42c36f9ab1cc2acc46fa5df8c78e178fc33a8d4cd05c8d498f"}, 649 | {file = "python_dotenv-0.20.0-py3-none-any.whl", hash = "sha256:d92a187be61fe482e4fd675b6d52200e7be63a12b724abbf931a40ce4fa92938"}, 650 | ] 651 | redis = [ 652 | {file = "redis-4.2.2-py3-none-any.whl", hash = "sha256:4e95f4ec5f49e636efcf20061a5a9110c20852f607cfca6865c07aaa8a739ee2"}, 653 | {file = "redis-4.2.2.tar.gz", hash = "sha256:0107dc8e98a4f1d1d4aa00100e044287f77121a1e6d2085545c4b7fa94a7a27f"}, 654 | ] 655 | tomli = [ 656 | {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, 657 | {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, 658 | ] 659 | typing-extensions = [ 660 | {file = "typing_extensions-4.2.0-py3-none-any.whl", hash = "sha256:6657594ee297170d19f67d55c05852a874e7eb634f4f753dbd667855e07c1708"}, 661 | {file = "typing_extensions-4.2.0.tar.gz", hash = "sha256:f1c24655a0da0d1b67f07e17a5e6b2a105894e6824b92096378bb3668ef02376"}, 662 | ] 663 | win32-setctime = [ 664 | {file = "win32_setctime-1.1.0-py3-none-any.whl", hash = "sha256:231db239e959c2fe7eb1d7dc129f11172354f98361c4fa2d6d2d7e278baa8aad"}, 665 | {file = "win32_setctime-1.1.0.tar.gz", hash = "sha256:15cf5750465118d6929ae4de4eb46e8edae9a5634350c01ba582df868e932cb2"}, 666 | ] 667 | wrapt = [ 668 | {file = "wrapt-1.14.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:5a9a1889cc01ed2ed5f34574c90745fab1dd06ec2eee663e8ebeefe363e8efd7"}, 669 | {file = "wrapt-1.14.0-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:9a3ff5fb015f6feb78340143584d9f8a0b91b6293d6b5cf4295b3e95d179b88c"}, 670 | {file = "wrapt-1.14.0-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:4b847029e2d5e11fd536c9ac3136ddc3f54bc9488a75ef7d040a3900406a91eb"}, 671 | {file = "wrapt-1.14.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:9a5a544861b21e0e7575b6023adebe7a8c6321127bb1d238eb40d99803a0e8bd"}, 672 | {file = "wrapt-1.14.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:88236b90dda77f0394f878324cfbae05ae6fde8a84d548cfe73a75278d760291"}, 673 | {file = "wrapt-1.14.0-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:f0408e2dbad9e82b4c960274214af533f856a199c9274bd4aff55d4634dedc33"}, 674 | {file = "wrapt-1.14.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:9d8c68c4145041b4eeae96239802cfdfd9ef927754a5be3f50505f09f309d8c6"}, 675 | {file = "wrapt-1.14.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:22626dca56fd7f55a0733e604f1027277eb0f4f3d95ff28f15d27ac25a45f71b"}, 676 | {file = "wrapt-1.14.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:65bf3eb34721bf18b5a021a1ad7aa05947a1767d1aa272b725728014475ea7d5"}, 677 | {file = "wrapt-1.14.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:09d16ae7a13cff43660155383a2372b4aa09109c7127aa3f24c3cf99b891c330"}, 678 | {file = "wrapt-1.14.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:debaf04f813ada978d7d16c7dfa16f3c9c2ec9adf4656efdc4defdf841fc2f0c"}, 679 | {file = "wrapt-1.14.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:748df39ed634851350efa87690c2237a678ed794fe9ede3f0d79f071ee042561"}, 680 | {file = "wrapt-1.14.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1807054aa7b61ad8d8103b3b30c9764de2e9d0c0978e9d3fc337e4e74bf25faa"}, 681 | {file = "wrapt-1.14.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:763a73ab377390e2af26042f685a26787c402390f682443727b847e9496e4a2a"}, 682 | {file = "wrapt-1.14.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:8529b07b49b2d89d6917cfa157d3ea1dfb4d319d51e23030664a827fe5fd2131"}, 683 | {file = "wrapt-1.14.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:68aeefac31c1f73949662ba8affaf9950b9938b712fb9d428fa2a07e40ee57f8"}, 684 | {file = "wrapt-1.14.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:59d7d92cee84a547d91267f0fea381c363121d70fe90b12cd88241bd9b0e1763"}, 685 | {file = "wrapt-1.14.0-cp310-cp310-win32.whl", hash = "sha256:3a88254881e8a8c4784ecc9cb2249ff757fd94b911d5df9a5984961b96113fff"}, 686 | {file = "wrapt-1.14.0-cp310-cp310-win_amd64.whl", hash = "sha256:9a242871b3d8eecc56d350e5e03ea1854de47b17f040446da0e47dc3e0b9ad4d"}, 687 | {file = "wrapt-1.14.0-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:a65bffd24409454b889af33b6c49d0d9bcd1a219b972fba975ac935f17bdf627"}, 688 | {file = "wrapt-1.14.0-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:9d9fcd06c952efa4b6b95f3d788a819b7f33d11bea377be6b8980c95e7d10775"}, 689 | {file = "wrapt-1.14.0-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:db6a0ddc1282ceb9032e41853e659c9b638789be38e5b8ad7498caac00231c23"}, 690 | {file = "wrapt-1.14.0-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:14e7e2c5f5fca67e9a6d5f753d21f138398cad2b1159913ec9e9a67745f09ba3"}, 691 | {file = "wrapt-1.14.0-cp35-cp35m-win32.whl", hash = "sha256:6d9810d4f697d58fd66039ab959e6d37e63ab377008ef1d63904df25956c7db0"}, 692 | {file = "wrapt-1.14.0-cp35-cp35m-win_amd64.whl", hash = "sha256:d808a5a5411982a09fef6b49aac62986274ab050e9d3e9817ad65b2791ed1425"}, 693 | {file = "wrapt-1.14.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:b77159d9862374da213f741af0c361720200ab7ad21b9f12556e0eb95912cd48"}, 694 | {file = "wrapt-1.14.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:36a76a7527df8583112b24adc01748cd51a2d14e905b337a6fefa8b96fc708fb"}, 695 | {file = "wrapt-1.14.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a0057b5435a65b933cbf5d859cd4956624df37b8bf0917c71756e4b3d9958b9e"}, 696 | {file = "wrapt-1.14.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a0a4ca02752ced5f37498827e49c414d694ad7cf451ee850e3ff160f2bee9d3"}, 697 | {file = "wrapt-1.14.0-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:8c6be72eac3c14baa473620e04f74186c5d8f45d80f8f2b4eda6e1d18af808e8"}, 698 | {file = "wrapt-1.14.0-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:21b1106bff6ece8cb203ef45b4f5778d7226c941c83aaaa1e1f0f4f32cc148cd"}, 699 | {file = "wrapt-1.14.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:493da1f8b1bb8a623c16552fb4a1e164c0200447eb83d3f68b44315ead3f9036"}, 700 | {file = "wrapt-1.14.0-cp36-cp36m-win32.whl", hash = "sha256:89ba3d548ee1e6291a20f3c7380c92f71e358ce8b9e48161401e087e0bc740f8"}, 701 | {file = "wrapt-1.14.0-cp36-cp36m-win_amd64.whl", hash = "sha256:729d5e96566f44fccac6c4447ec2332636b4fe273f03da128fff8d5559782b06"}, 702 | {file = "wrapt-1.14.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:891c353e95bb11abb548ca95c8b98050f3620a7378332eb90d6acdef35b401d4"}, 703 | {file = "wrapt-1.14.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:23f96134a3aa24cc50614920cc087e22f87439053d886e474638c68c8d15dc80"}, 704 | {file = "wrapt-1.14.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6807bcee549a8cb2f38f73f469703a1d8d5d990815c3004f21ddb68a567385ce"}, 705 | {file = "wrapt-1.14.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6915682f9a9bc4cf2908e83caf5895a685da1fbd20b6d485dafb8e218a338279"}, 706 | {file = "wrapt-1.14.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:f2f3bc7cd9c9fcd39143f11342eb5963317bd54ecc98e3650ca22704b69d9653"}, 707 | {file = "wrapt-1.14.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:3a71dbd792cc7a3d772ef8cd08d3048593f13d6f40a11f3427c000cf0a5b36a0"}, 708 | {file = "wrapt-1.14.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:5a0898a640559dec00f3614ffb11d97a2666ee9a2a6bad1259c9facd01a1d4d9"}, 709 | {file = "wrapt-1.14.0-cp37-cp37m-win32.whl", hash = "sha256:167e4793dc987f77fd476862d32fa404d42b71f6a85d3b38cbce711dba5e6b68"}, 710 | {file = "wrapt-1.14.0-cp37-cp37m-win_amd64.whl", hash = "sha256:d066ffc5ed0be00cd0352c95800a519cf9e4b5dd34a028d301bdc7177c72daf3"}, 711 | {file = "wrapt-1.14.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d9bdfa74d369256e4218000a629978590fd7cb6cf6893251dad13d051090436d"}, 712 | {file = "wrapt-1.14.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2498762814dd7dd2a1d0248eda2afbc3dd9c11537bc8200a4b21789b6df6cd38"}, 713 | {file = "wrapt-1.14.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5f24ca7953f2643d59a9c87d6e272d8adddd4a53bb62b9208f36db408d7aafc7"}, 714 | {file = "wrapt-1.14.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5b835b86bd5a1bdbe257d610eecab07bf685b1af2a7563093e0e69180c1d4af1"}, 715 | {file = "wrapt-1.14.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b21650fa6907e523869e0396c5bd591cc326e5c1dd594dcdccac089561cacfb8"}, 716 | {file = "wrapt-1.14.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:354d9fc6b1e44750e2a67b4b108841f5f5ea08853453ecbf44c81fdc2e0d50bd"}, 717 | {file = "wrapt-1.14.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:1f83e9c21cd5275991076b2ba1cd35418af3504667affb4745b48937e214bafe"}, 718 | {file = "wrapt-1.14.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:61e1a064906ccba038aa3c4a5a82f6199749efbbb3cef0804ae5c37f550eded0"}, 719 | {file = "wrapt-1.14.0-cp38-cp38-win32.whl", hash = "sha256:28c659878f684365d53cf59dc9a1929ea2eecd7ac65da762be8b1ba193f7e84f"}, 720 | {file = "wrapt-1.14.0-cp38-cp38-win_amd64.whl", hash = "sha256:b0ed6ad6c9640671689c2dbe6244680fe8b897c08fd1fab2228429b66c518e5e"}, 721 | {file = "wrapt-1.14.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b3f7e671fb19734c872566e57ce7fc235fa953d7c181bb4ef138e17d607dc8a1"}, 722 | {file = "wrapt-1.14.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:87fa943e8bbe40c8c1ba4086971a6fefbf75e9991217c55ed1bcb2f1985bd3d4"}, 723 | {file = "wrapt-1.14.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4775a574e9d84e0212f5b18886cace049a42e13e12009bb0491562a48bb2b758"}, 724 | {file = "wrapt-1.14.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9d57677238a0c5411c76097b8b93bdebb02eb845814c90f0b01727527a179e4d"}, 725 | {file = "wrapt-1.14.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:00108411e0f34c52ce16f81f1d308a571df7784932cc7491d1e94be2ee93374b"}, 726 | {file = "wrapt-1.14.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d332eecf307fca852d02b63f35a7872de32d5ba8b4ec32da82f45df986b39ff6"}, 727 | {file = "wrapt-1.14.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:01f799def9b96a8ec1ef6b9c1bbaf2bbc859b87545efbecc4a78faea13d0e3a0"}, 728 | {file = "wrapt-1.14.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:47045ed35481e857918ae78b54891fac0c1d197f22c95778e66302668309336c"}, 729 | {file = "wrapt-1.14.0-cp39-cp39-win32.whl", hash = "sha256:2eca15d6b947cfff51ed76b2d60fd172c6ecd418ddab1c5126032d27f74bc350"}, 730 | {file = "wrapt-1.14.0-cp39-cp39-win_amd64.whl", hash = "sha256:bb36fbb48b22985d13a6b496ea5fb9bb2a076fea943831643836c9f6febbcfdc"}, 731 | {file = "wrapt-1.14.0.tar.gz", hash = "sha256:8323a43bd9c91f62bb7d4be74cc9ff10090e7ef820e27bfe8815c57e68261311"}, 732 | ] 733 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "Redis Python Tutorial" 3 | version = "0.1.0" 4 | description = "" 5 | authors = ["Todd Birchard "] 6 | maintainers = ["Todd Birchard "] 7 | license = "MIT" 8 | readme = "README.md" 9 | homepage = "https://hackersandslackers.com/redis-py-python/" 10 | repository = "https://github.com/hackersandslackers/redis-python-tutorial/" 11 | documentation = "https://hackersandslackers.com/redis-py-python/" 12 | keywords = [ 13 | "Redis", 14 | "Cache", 15 | "Queue", 16 | "Memory", 17 | "NoSQL" 18 | ] 19 | 20 | [tool.poetry.dependencies] 21 | python = "3.9" 22 | redis = "*" 23 | loguru = "*" 24 | python-dotenv = "*" 25 | 26 | [tool.poetry.dev-dependencies] 27 | pytest = "*" 28 | coverage = "*" 29 | mock = "*" 30 | mypy = "*" 31 | black = "*" 32 | isort = "*" 33 | flake8 = "*" 34 | pylint = "*" 35 | 36 | [build-system] 37 | requires = ["poetry>=1.1.12"] 38 | build-backend = "poetry.masonry.api" 39 | 40 | [tool.poetry.scripts] 41 | run = "main:init_script" 42 | 43 | [tool.poetry.urls] 44 | issues = "https://github.com/hackersandslackers/redis-python-tutorial/issues" 45 | 46 | [tool.black] 47 | line-length = 100 48 | -------------------------------------------------------------------------------- /redis_python_tutorial/__init__.py: -------------------------------------------------------------------------------- 1 | """Set and manipulate data in Redis.""" 2 | from redis_python_tutorial.client import r 3 | from redis_python_tutorial.data import init_db_with_values 4 | from redis_python_tutorial.data.hash import hash_values_demo 5 | from redis_python_tutorial.data.list import list_values_demo 6 | from redis_python_tutorial.data.set import set_values_demo 7 | from redis_python_tutorial.data.string import string_values_demo 8 | from redis_python_tutorial.data.zset import sorted_set_values_demo 9 | 10 | 11 | def init_app(): 12 | """Entry point function.""" 13 | r.flushdb() 14 | init_db_with_values(r) 15 | string_values_demo(r) 16 | hash_values_demo(r) 17 | list_values_demo(r) 18 | set_values_demo(r) 19 | sorted_set_values_demo(r) 20 | -------------------------------------------------------------------------------- /redis_python_tutorial/client.py: -------------------------------------------------------------------------------- 1 | """Create Redis client.""" 2 | import redis 3 | 4 | from config import REDIS_DB, REDIS_HOST, REDIS_PASSWORD, REDIS_PORT 5 | 6 | r = redis.StrictRedis( 7 | host=REDIS_HOST, 8 | password=REDIS_PASSWORD, 9 | port=REDIS_PORT, 10 | db=REDIS_DB, 11 | charset="utf-8", 12 | decode_responses=True, 13 | ) 14 | -------------------------------------------------------------------------------- /redis_python_tutorial/data/__init__.py: -------------------------------------------------------------------------------- 1 | """Set and manipulate data in Redis.""" 2 | from time import time 3 | 4 | from config import REDIS_EXPIRATION 5 | 6 | 7 | def init_db_with_values(r): 8 | """Set single key/value pairs.""" 9 | r.set("ip_address", "0.0.0.0.") 10 | r.set("timestamp", int(time())) 11 | r.set("user_agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_3)") 12 | r.set("current_page", "account", REDIS_EXPIRATION) 13 | return r.keys() 14 | -------------------------------------------------------------------------------- /redis_python_tutorial/data/hash.py: -------------------------------------------------------------------------------- 1 | """Working with hash values.""" 2 | from redis import Redis 3 | 4 | from redis_python_tutorial.logger import LOGGER 5 | 6 | 7 | def hash_values_demo(r: Redis): 8 | """ 9 | Create a Redis hash value. 10 | 11 | :param Redis r: Remote Redis instance. 12 | """ 13 | record = { 14 | "name": "Hackers and Slackers", 15 | "description": "Mediocre tutorials", 16 | "website": "https://hackersandslackers.com/", 17 | "github": "https://github.com/hackersandslackers", 18 | } 19 | r.hset("business", mapping=record) 20 | LOGGER.info(f"business: {r.hgetall('business')}") 21 | -------------------------------------------------------------------------------- /redis_python_tutorial/data/list.py: -------------------------------------------------------------------------------- 1 | """Working with list values.""" 2 | from redis import Redis 3 | 4 | from redis_python_tutorial.logger import LOGGER 5 | 6 | 7 | def list_values_demo(r: Redis): 8 | """ 9 | Create and modify a Redis list. 10 | 11 | :param Redis r: Remote Redis instance. 12 | """ 13 | """Push and pop items from a list.""" 14 | # Add single string to a new list. 15 | r.lpush("my_list", "A") 16 | LOGGER.info(f"my_list: {r.lrange('my_list', 0, -1)}") 17 | 18 | # Push second string to list from the right. 19 | r.rpush("my_list", "B") 20 | LOGGER.info(f"my_list: {r.lrange('my_list', 0, -1)}") 21 | 22 | # Push third string to list from the right. 23 | r.rpush("my_list", "C") 24 | LOGGER.info(f"my_list: {r.lrange('my_list', 0, -1)}") 25 | 26 | # Remove 1 instance from the list where the value equals 'C'. 27 | r.lrem("my_list", 1, "C") 28 | LOGGER.info(f"my_list: {r.lrange('my_list', 0, -1)}") 29 | 30 | # Push a string to our list from the left. 31 | r.lpush("my_list", "C") 32 | LOGGER.info(f"my_list: {r.lrange('my_list', 0, -1)}") 33 | 34 | # Pop first element of our list and move it to the back. 35 | r.rpush("my_list", r.lpop("my_list")) 36 | LOGGER.info(f"my_list: {r.lrange('my_list', 0, -1)}") 37 | -------------------------------------------------------------------------------- /redis_python_tutorial/data/set.py: -------------------------------------------------------------------------------- 1 | """Working with set values.""" 2 | from redis import Redis 3 | 4 | from redis_python_tutorial.logger import LOGGER 5 | 6 | 7 | def set_values_demo(r: Redis): 8 | """ 9 | Create Redis sets & execute unions and intersects. 10 | 11 | :param Redis r: Remote Redis instance. 12 | """ 13 | # Add item to set 1 14 | r.sadd("my_set_1", "Y") 15 | LOGGER.info(f"my_set_1: {r.smembers('my_set_1')}'") 16 | 17 | # Add item to set 1 18 | r.sadd("my_set_1", "X") 19 | LOGGER.info(f"my_set_1: {r.smembers('my_set_1')}'") 20 | 21 | # Add item to set 2 22 | r.sadd("my_set_2", "X") 23 | LOGGER.info(f"my_set_2: {r.smembers('my_set_2')}'") 24 | 25 | # Add item to set 2 26 | r.sadd("my_set_2", "Z") 27 | LOGGER.info(f"my_set2: {r.smembers('my_set_2')}'") 28 | 29 | # Union set 1 and set 2 30 | LOGGER.info(f"Union: {r.sunion('my_set_1', 'my_set_2')}") 31 | 32 | # Intersect set 1 and set 2 33 | LOGGER.info(f"Intersect: {r.sinter('my_set_1', 'my_set_2')}") 34 | -------------------------------------------------------------------------------- /redis_python_tutorial/data/string.py: -------------------------------------------------------------------------------- 1 | """Working with string values.""" 2 | from redis import Redis 3 | 4 | from redis_python_tutorial.logger import LOGGER 5 | 6 | 7 | def string_values_demo(r: Redis): 8 | """ 9 | Work with Redis strings to store simple values, or manipulate them as integers. 10 | 11 | :param Redis r: Remote Redis instance. 12 | """ 13 | # Create string value 14 | r.set("index", "1") 15 | LOGGER.info(f"index: {r.get('index')}") 16 | 17 | # Increment string by 1 18 | r.incr("index") 19 | LOGGER.info(f"index: {r.get('index')}") 20 | 21 | # Decrement string by 1 22 | r.decr("index") 23 | LOGGER.info(f"index: {r.get('index')}") 24 | 25 | # Increment string by 3 26 | r.incrby("index", 3) 27 | LOGGER.info(f"index: {r.get('index')}") 28 | -------------------------------------------------------------------------------- /redis_python_tutorial/data/zset.py: -------------------------------------------------------------------------------- 1 | """Working with sorted set values.""" 2 | from redis import Redis 3 | 4 | from redis_python_tutorial.logger import LOGGER 5 | 6 | 7 | def sorted_set_values_demo(r: Redis): 8 | """ 9 | Create Redis sorted sets and manipulate the contents. 10 | 11 | :param Redis r: Remote Redis instance. 12 | """ 13 | # Initialize sorted set with 3 values 14 | r.zadd( 15 | "top_songs_set", 16 | {"Never Change - Jay Z": 1, "Rich Girl - Hall & Oats": 2, "The Prayer - Griz": 3}, 17 | ) 18 | LOGGER.info(f"top_songs_set: {r.zrange('top_songs_set', 0, -1)}'") 19 | 20 | # Add item to set with conflicting value 21 | r.zadd("top_songs_set", {"Can't Figure it Out - Bishop Lamont": 3}) 22 | LOGGER.info(f"top_songs_set: {r.zrange('top_songs_set', 0, -1)}'") 23 | 24 | # Shift index of a value 25 | r.zincrby("top_songs_set", 3, "Never Change - Jay Z") 26 | LOGGER.info(f"top_songs_set: {r.zrange('top_songs_set', 0, -1)}'") 27 | -------------------------------------------------------------------------------- /redis_python_tutorial/logger.py: -------------------------------------------------------------------------------- 1 | """Custom logger.""" 2 | import json 3 | from os import path 4 | from sys import stdout 5 | 6 | from loguru import logger 7 | 8 | from config import BASE_DIR, PERSIST_LOG_FILES 9 | 10 | 11 | def json_formatter(record: dict) -> str: 12 | """ 13 | Pass raw log to be serialized. 14 | 15 | :param dict record: Dictionary containing logged message with metadata. 16 | 17 | :returns: str 18 | """ 19 | 20 | def serialize(log: dict) -> str: 21 | """ 22 | Parse log message into Datadog JSON format. 23 | 24 | :param dict log: Dictionary containing logged message with metadata. 25 | 26 | :returns: str 27 | """ 28 | subset = { 29 | "time": log["time"].strftime("%m/%d/%Y, %H:%M:%S"), 30 | "message": log["message"], 31 | "level": log["level"].name, 32 | "function": log.get("function"), 33 | "module": log.get("name"), 34 | } 35 | if log.get("exception", None): 36 | subset.update({"exception": log["exception"]}) 37 | return json.dumps(subset) 38 | 39 | record["extra"]["serialized"] = serialize(record) 40 | return "{extra[serialized]},\n" 41 | 42 | 43 | def log_formatter(record: dict) -> str: 44 | """ 45 | Formatter for .log records 46 | 47 | :param dict record: Key/value object containing a single log's message & metadata. 48 | 49 | :returns: str 50 | """ 51 | if record["level"].name == "TRACE": 52 | return "{time:MM-DD-YYYY HH:mm:ss} | {level}: {message}\n" 53 | elif record["level"].name == "INFO": 54 | return "{time:MM-DD-YYYY HH:mm:ss} | {level}: {message}\n" 55 | elif record["level"].name == "WARNING": 56 | return "{time:MM-DD-YYYY HH:mm:ss} | {level}: {message}\n" 57 | elif record["level"].name == "SUCCESS": 58 | return "{time:MM-DD-YYYY HH:mm:ss} | {level}: {message}\n" 59 | elif record["level"].name == "ERROR": 60 | return "{time:MM-DD-YYYY HH:mm:ss} | {level}: {message}\n" 61 | return "{time:MM-DD-YYYY HH:mm:ss} | {level}: {message}\n" 62 | 63 | 64 | def create_logger() -> logger: 65 | """ 66 | Configure custom logger. 67 | 68 | :returns: logger 69 | """ 70 | logger.remove() 71 | logger.add( 72 | stdout, 73 | colorize=True, 74 | catch=True, 75 | format=log_formatter, 76 | ) 77 | if PERSIST_LOG_FILES == "production" and path.isdir(f"{BASE_DIR}/log/"): 78 | logger.add( 79 | f"{BASE_DIR}/log/info.log", 80 | colorize=True, 81 | catch=True, 82 | format=log_formatter, 83 | rotation="300 MB", 84 | compression="zip", 85 | ) 86 | logger.add( 87 | f"{BASE_DIR}/logs/error.log", 88 | colorize=True, 89 | catch=True, 90 | format=log_formatter, 91 | rotation="300 MB", 92 | compression="zip", 93 | level="ERROR", 94 | ) 95 | return logger 96 | 97 | 98 | # Custom logger 99 | LOGGER = create_logger() 100 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "config:base" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | async-timeout==4.0.3; python_version >= "3.6" 2 | colorama==0.4.6; python_version >= "3.5" and python_full_version < "3.0.0" and sys_platform == "win32" or sys_platform == "win32" and python_version >= "3.5" and python_full_version >= "3.5.0" 3 | deprecated==1.2.14; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6" 4 | loguru==0.7.2; python_version >= "3.5" 5 | packaging==21.3; python_version >= "3.6" 6 | pyparsing==3.1.1; python_full_version >= "3.6.8" and python_version >= "3.6" 7 | python-dotenv==0.21.1; python_version >= "3.5" 8 | redis==4.4.4; python_version >= "3.6" 9 | win32-setctime==1.1.0; sys_platform == "win32" and python_version >= "3.5" 10 | wrapt==1.15.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.6" 11 | --------------------------------------------------------------------------------