diff --git a/.gitignore b/.gitignore index 615ddc6..f6c4a2c 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ venv/ dist/ rectes.egg-info/ build/ +conf/rectes.toml diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 8a118a5..b75103d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -3,7 +3,7 @@ repos: rev: 22.3.0 hooks: - id: black - language_version: python3.10 + language_version: python3.11 - repo: https://github.com/pre-commit/pre-commit-hooks rev: v4.3.0 diff --git a/README.md b/README.md index 3b13b1c..d360349 100644 --- a/README.md +++ b/README.md @@ -10,12 +10,61 @@ on a server will be IP address of the client that made request to the server. Service is built with Python, FastAPI and is using Redis for data storage. +## Installation + +### Requirements + +- Python 3.11+ +- Redis +- Python development libraries (optional, only needed for `hiredis` module installation) + +### How to install + +#### TL/DR + +```bash +$ git clone git@git.ivnglkv.ru:ivnglkv/rectes.git +$ python3 -m venv venv +$ . ./venv/bin/activate +$ pip install . +``` + +--- + +Steps to install Rectes: + +1. Clone repository +2. (optional) Create virtual environment +3. Install package + +### Running Rectes server + +After installation is done, you can start rectes with `rectes` command. +The web server will be started with `uvicorn` ASGI web server. + +```bash +$ rectes +``` + +### Configuration + +Configuration is done through config file. By default, path is `/etc/rectes/rectes.toml`. +You can override this by setting environment variable `RECTES_CONF_FILE` value to actual file +location, i.e.: + +```bash +$ RECTES_CONF_FILE=/home/user/.conf/rectes.toml rectes +``` + +You can find all available configuration options in the example file, located +at [conf/rectes.toml.example](conf/rectes.toml.example) under Git root. + ## Contributing Codestyle is enforced with Black, and additional checks are done with the help of pre-commit-hooks, Flake8 and isort. Prior to making any commits, install `pre-commit` tool and install hooks: -``` +```bash # Alternatively, you could use 'pip install ".[development]"' $ pip install pre-commit==2.19.0 $ pre-commit install diff --git a/conf/rectes.toml.example b/conf/rectes.toml.example new file mode 100644 index 0000000..1458255 --- /dev/null +++ b/conf/rectes.toml.example @@ -0,0 +1 @@ +redis.url = 'redis://localhost' diff --git a/setup.cfg b/setup.cfg index 384c067..be2106f 100644 --- a/setup.cfg +++ b/setup.cfg @@ -7,14 +7,18 @@ package_dir = = src packages = find: install_requires = fastapi==0.78.0 - aioredis==2.0.1 -python_requires = >=3.10 + redis[hiredis]==4.4.0 + click==8.1.3 +python_requires = >=3.11 [options.extras_require] -hiredis = - hiredis==2.0.0 development = + uvicorn pre-commit==2.19.0 +[options.entry_points] +console_scripts = + rectes = rectes:cli + [options.packages.find] where = src diff --git a/src/rectes/__init__.py b/src/rectes/__init__.py index e69de29..482ed66 100644 --- a/src/rectes/__init__.py +++ b/src/rectes/__init__.py @@ -0,0 +1,5 @@ +__all__ = [ + "cli", +] + +from .cli import cli diff --git a/src/rectes/cli.py b/src/rectes/cli.py new file mode 100644 index 0000000..bb605b9 --- /dev/null +++ b/src/rectes/cli.py @@ -0,0 +1,6 @@ +import click + + +@click.command() +def cli(): + print("Hello, world") diff --git a/src/rectes/redis_db.py b/src/rectes/redis_db.py new file mode 100644 index 0000000..0cefcb3 --- /dev/null +++ b/src/rectes/redis_db.py @@ -0,0 +1,6 @@ +# noinspection PyUnresolvedReferences,PyProtectedMember +from redis import asyncio as aioredis + +from rectes.settings import settings + +redis = aioredis.from_url(settings.redis.url) diff --git a/src/rectes/settings.py b/src/rectes/settings.py new file mode 100644 index 0000000..8502888 --- /dev/null +++ b/src/rectes/settings.py @@ -0,0 +1,27 @@ +import os + +import tomllib + + +class Settings: + def __init__(self, data: dict = None): + if data: + self._data = data + else: + with open( + os.getenv("RECTES_CONF_FILE", "/etc/rectes/rectes.toml"), "rb" + ) as f: + self._data = tomllib.load(f) + + def __getattr__(self, item): + try: + value = self._data[item] + except KeyError: + raise AttributeError + if isinstance(value, dict): + return Settings(data=value) + else: + return value + + +settings = Settings()