fastapi-plugins


Namefastapi-plugins JSON
Version 0.13.0 PyPI version JSON
download
home_pagehttps://github.com/madkote/fastapi-plugins
SummaryPlugins for FastAPI framework
upload_time2024-02-16 12:22:41
maintainer
docs_urlNone
authormadkote
requires_python>=3.6.0
licenseMIT License
keywords async redis aioredis json asyncio plugin fastapi aiojobs scheduler starlette memcached aiomcache
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            <p align="center">
    <em>Plugins for FastAPI framework, high performance, easy to learn, fast to code, ready for production</em>
</p>
<p align="center">
<a href="https://travis-ci.org/madkote/fastapi-plugins" target="_blank">
    <img src="https://travis-ci.org/madkote/fastapi_plugins.svg?branch=master" alt="Build Status">
</a>
<a href="https://codecov.io/gh/madkote/fastapi-plugins" target="_blank">
    <img src="https://codecov.io/gh/madkote/fastapi_plugins/branch/master/graph/badge.svg" alt="Coverage">
</a>
<a href="https://pypi.org/project/fastapi-plugins" target="_blank">
    <img src="https://img.shields.io/pypi/v/fastapi_plugins.svg" alt="Package version">
</a>
<a href="https://gitter.im/tiangolo/fastapi?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge" target="_blank">
    <img src="https://badges.gitter.im/tiangolo/fastapi.svg" alt="Join the chat at https://gitter.im/tiangolo/fastapi">
</a>
</p>

# fastapi-plugins
FastAPI framework plugins - simple way to share `fastapi` code and utilities across applications.

The concept is `plugin` - plug a functional utility into your application without or with minimal effort.

* [Cache](./docs/cache.md)
  * [Memcached](./docs/cache.md#memcached)
  * [Redis](./docs/cache.md#redis)
* [Scheduler](./docs/scheduler.md)
* [Control](./docs/control.md)
  * [Version](./docs/control.md#version)
  * [Environment](./docs/control.md#environment)
  * [Health](./docs/control.md#health)
  * [Heartbeat](./docs/control.md#heartbeat)
* [Application settings/configuration](./docs/settings.md)
* [Logging](./docs/logger.md)
* Celery
* MQ
* and much more is already in progress...

## Changes
See [release notes](CHANGES.md)

## Installation
* by default contains
  * [Redis](./docs/cache.md#redis)
  * [Scheduler](./docs/scheduler.md)
  * [Control](./docs/control.md)
  * [Logging](./docs/logger.md)
* `memcached` adds [Memcached](#memcached)
* `all` add everything above

```sh
pip install fastapi-plugins
pip install fastapi-plugins[memcached]
pip install fastapi-plugins[all]
```

## Quick start
### Plugin
Add information about plugin system.
### Application settings
Add information about settings.
### Application configuration
Add information about configuration of an application
### Complete example
```python
import fastapi
import fastapi_plugins

from fastapi_plugins.memcached import MemcachedSettings
from fastapi_plugins.memcached import memcached_plugin, TMemcachedPlugin

import asyncio
import aiojobs
import aioredis
import contextlib
import logging

@fastapi_plugins.registered_configuration
class AppSettings(
        fastapi_plugins.ControlSettings,
        fastapi_plugins.RedisSettings,
        fastapi_plugins.SchedulerSettings,
        fastapi_plugins.LoggingSettings,
        MemcachedSettings,
):
    api_name: str = str(__name__)
    logging_level: int = logging.DEBUG
    logging_style: fastapi_plugins.LoggingStyle = fastapi_plugins.LoggingStyle.logjson


@fastapi_plugins.registered_configuration(name='sentinel')
class AppSettingsSentinel(AppSettings):
    redis_type = fastapi_plugins.RedisType.sentinel
    redis_sentinels = 'localhost:26379'


@contextlib.asynccontextmanager
async def lifespan(app: fastapi.FastAPI):
    config = fastapi_plugins.get_config()
    await fastapi_plugins.config_plugin.init_app(app, config)
    await fastapi_plugins.config_plugin.init()
    await fastapi_plugins.log_plugin.init_app(app, config, name=__name__)
    await fastapi_plugins.log_plugin.init()
    await memcached_plugin.init_app(app, config)
    await memcached_plugin.init()
    await fastapi_plugins.redis_plugin.init_app(app, config=config)
    await fastapi_plugins.redis_plugin.init()
    await fastapi_plugins.scheduler_plugin.init_app(app=app, config=config)
    await fastapi_plugins.scheduler_plugin.init()
    await fastapi_plugins.control_plugin.init_app(
        app,
        config=config,
        version=__version__,
        environ=config.model_dump()
    )
    await fastapi_plugins.control_plugin.init()
    yield
    await fastapi_plugins.control_plugin.terminate()
    await fastapi_plugins.scheduler_plugin.terminate()
    await fastapi_plugins.redis_plugin.terminate()
    await memcached_plugin.terminate()
    await fastapi_plugins.log_plugin.terminate()
    await fastapi_plugins.config_plugin.terminate()


app = fastapi_plugins.register_middleware(fastapi.FastAPI(lifespan=lifespan))


@app.get("/")
async def root_get(
        cache: fastapi_plugins.TRedisPlugin,
        conf: fastapi_plugins.TConfigPlugin,
        logger: fastapi_plugins.TLoggerPlugin
) -> typing.Dict:
    ping = await cache.ping()
    logger.debug('root_get', extra=dict(ping=ping, api_name=conf.api_name))
    return dict(ping=ping, api_name=conf.api_name)


@app.post("/jobs/schedule/<timeout>")
async def job_post(
    timeout: int=fastapi.Query(..., title='the job sleep time'),
    cache: fastapi_plugins.TRedisPlugin,
    scheduler: fastapi_plugins.TSchedulerPlugin,
    logger: fastapi_plugins.TLoggerPlugin
) -> str:
    async def coro(job_id, timeout, cache):
        await cache.set(job_id, 'processing')
        try:
            await asyncio.sleep(timeout)
            if timeout == 8:
                logger.critical('Ugly erred job %s' % job_id)
                raise Exception('ugly error')
        except asyncio.CancelledError:
            await cache.set(job_id, 'canceled')
            logger.warning('Cancel job %s' % job_id)
        except Exception:
            await cache.set(job_id, 'erred')
            logger.error('Erred job %s' % job_id)
        else:
            await cache.set(job_id, 'success')
            logger.info('Done job %s' % job_id)

    job_id = str(uuid.uuid4()).replace('-', '')
    logger = await fastapi_plugins.log_adapter(logger, extra=dict(job_id=job_id, timeout=timeout))    # noqa E501
    logger.info('New job %s' % job_id)
    await cache.set(job_id, 'pending')
    logger.debug('Pending job %s' % job_id)
    await scheduler.spawn(coro(job_id, timeout, cache))
    return job_id


@app.get("/jobs/status/<job_id>")
async def job_get(
    job_id: str=fastapi.Query(..., title='the job id'),
    cache: fastapi_plugins.TRedisPlugin,
) -> typing.Dict:
    status = await cache.get(job_id)
    if status is None:
        raise fastapi.HTTPException(
            status_code=starlette.status.HTTP_404_NOT_FOUND,
            detail='Job %s not found' % job_id
        )
    return dict(job_id=job_id, status=status)


@app.post("/memcached/demo/<key>")
async def memcached_demo_post(
    key: str=fastapi.Query(..., title='the job id'),
    cache: fastapi_plugins.TMemcachedPlugin,
) -> typing.Dict:
    await cache.set(key.encode(), str(key + '_value').encode())
    value = await cache.get(key.encode())
    return dict(ping=(await cache.ping()).decode(), key=key, value=value)
```

# Development
Issues and suggestions are welcome through [issues](https://github.com/madkote/fastapi-plugins/issues)

# License
This project is licensed under the terms of the MIT license.


# Changes
## 0.12.0 (2023-03-24)
- `[feature]` `Annotated` support
## 0.11.0 (2022-09-19)
- `[feature]` `redis-py` replaces `aioredis`
## 0.10.0 (2022-07-07)
- `[feature]` Update `aioredis` to `2.x.x`
- `[feature]` Add `fakeredis` optionally for development purpose
## 0.9.1 (2022-06-16)
- `[fix]` Fix empty router prefix for control plugin
## 0.9.0 (2021-09-27)
- `[feature]` Logging plugin
- `[feature]` Middleware interface - register middleware at application
## 0.8.2 (2021-09-23)
- `[fix]` Fix dependency for aioredis
## 0.8.1 (2021-03-31)
- `[fix]` Fix settings for Python 3.7
## 0.8.0 (2021-03-31)
- `[feature]` Settings plugin
## 0.7.0 (2021-03-29)
- `[feature]` Control plugin with Health, Heartbeat, Environment and Version
## 0.6.1 (2021-03-24)
- `[fix]` Bump `aiojobs`to get rid of not required dependencies
## 0.6.0 (2020-11-26)
- `[feature]` Memcached
## 0.5.0 (2020-11-25)
- [bug] remove `__all__` since no API as such ([#6][i6]).
- [typo] Fix typos in README ([#7][i7]).
- [feature] Add Redis TTL ([#8][i8]).
## 0.4.2 (2020-11-24)
- [bug] Fix Redis URL ([#4][i4]). 
## 0.4.1 (2020-06-16)
- Refactor requirements
## 0.4.0 (2020-04-09)
- structure and split dependencies to `extra`
## 0.3.0 (2020-04-07)
- Scheduler: tasks scheduler based on `aiojobs`
## 0.2.1 (2020-04-06)
- Redis: pre-start
## 0.2.0 (2019-12-11)
- Redis: sentinels
## 0.1.0 (2019-11-20)
- Initial release: simple redis pool client

[i4]: https://github.com/madkote/fastapi-plugins/pull/4
[i6]: https://github.com/madkote/fastapi-plugins/pull/6
[i7]: https://github.com/madkote/fastapi-plugins/pull/7
[i8]: https://github.com/madkote/fastapi-plugins/issues/8

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/madkote/fastapi-plugins",
    "name": "fastapi-plugins",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3.6.0",
    "maintainer_email": "",
    "keywords": "async,redis,aioredis,json,asyncio,plugin,fastapi,aiojobs,scheduler,starlette,memcached,aiomcache",
    "author": "madkote",
    "author_email": "madkote <madkote@bluewin.ch>",
    "download_url": "https://files.pythonhosted.org/packages/16/76/a4e7935f05f7f0563f5039052391ee0164b574d04b18723db5dce2f7b85c/fastapi-plugins-0.13.0.tar.gz",
    "platform": "any",
    "description": "<p align=\"center\">\n    <em>Plugins for FastAPI framework, high performance, easy to learn, fast to code, ready for production</em>\n</p>\n<p align=\"center\">\n<a href=\"https://travis-ci.org/madkote/fastapi-plugins\" target=\"_blank\">\n    <img src=\"https://travis-ci.org/madkote/fastapi_plugins.svg?branch=master\" alt=\"Build Status\">\n</a>\n<a href=\"https://codecov.io/gh/madkote/fastapi-plugins\" target=\"_blank\">\n    <img src=\"https://codecov.io/gh/madkote/fastapi_plugins/branch/master/graph/badge.svg\" alt=\"Coverage\">\n</a>\n<a href=\"https://pypi.org/project/fastapi-plugins\" target=\"_blank\">\n    <img src=\"https://img.shields.io/pypi/v/fastapi_plugins.svg\" alt=\"Package version\">\n</a>\n<a href=\"https://gitter.im/tiangolo/fastapi?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge\" target=\"_blank\">\n    <img src=\"https://badges.gitter.im/tiangolo/fastapi.svg\" alt=\"Join the chat at https://gitter.im/tiangolo/fastapi\">\n</a>\n</p>\n\n# fastapi-plugins\nFastAPI framework plugins - simple way to share `fastapi` code and utilities across applications.\n\nThe concept is `plugin` - plug a functional utility into your application without or with minimal effort.\n\n* [Cache](./docs/cache.md)\n  * [Memcached](./docs/cache.md#memcached)\n  * [Redis](./docs/cache.md#redis)\n* [Scheduler](./docs/scheduler.md)\n* [Control](./docs/control.md)\n  * [Version](./docs/control.md#version)\n  * [Environment](./docs/control.md#environment)\n  * [Health](./docs/control.md#health)\n  * [Heartbeat](./docs/control.md#heartbeat)\n* [Application settings/configuration](./docs/settings.md)\n* [Logging](./docs/logger.md)\n* Celery\n* MQ\n* and much more is already in progress...\n\n## Changes\nSee [release notes](CHANGES.md)\n\n## Installation\n* by default contains\n  * [Redis](./docs/cache.md#redis)\n  * [Scheduler](./docs/scheduler.md)\n  * [Control](./docs/control.md)\n  * [Logging](./docs/logger.md)\n* `memcached` adds [Memcached](#memcached)\n* `all` add everything above\n\n```sh\npip install fastapi-plugins\npip install fastapi-plugins[memcached]\npip install fastapi-plugins[all]\n```\n\n## Quick start\n### Plugin\nAdd information about plugin system.\n### Application settings\nAdd information about settings.\n### Application configuration\nAdd information about configuration of an application\n### Complete example\n```python\nimport fastapi\nimport fastapi_plugins\n\nfrom fastapi_plugins.memcached import MemcachedSettings\nfrom fastapi_plugins.memcached import memcached_plugin, TMemcachedPlugin\n\nimport asyncio\nimport aiojobs\nimport aioredis\nimport contextlib\nimport logging\n\n@fastapi_plugins.registered_configuration\nclass AppSettings(\n        fastapi_plugins.ControlSettings,\n        fastapi_plugins.RedisSettings,\n        fastapi_plugins.SchedulerSettings,\n        fastapi_plugins.LoggingSettings,\n        MemcachedSettings,\n):\n    api_name: str = str(__name__)\n    logging_level: int = logging.DEBUG\n    logging_style: fastapi_plugins.LoggingStyle = fastapi_plugins.LoggingStyle.logjson\n\n\n@fastapi_plugins.registered_configuration(name='sentinel')\nclass AppSettingsSentinel(AppSettings):\n    redis_type = fastapi_plugins.RedisType.sentinel\n    redis_sentinels = 'localhost:26379'\n\n\n@contextlib.asynccontextmanager\nasync def lifespan(app: fastapi.FastAPI):\n    config = fastapi_plugins.get_config()\n    await fastapi_plugins.config_plugin.init_app(app, config)\n    await fastapi_plugins.config_plugin.init()\n    await fastapi_plugins.log_plugin.init_app(app, config, name=__name__)\n    await fastapi_plugins.log_plugin.init()\n    await memcached_plugin.init_app(app, config)\n    await memcached_plugin.init()\n    await fastapi_plugins.redis_plugin.init_app(app, config=config)\n    await fastapi_plugins.redis_plugin.init()\n    await fastapi_plugins.scheduler_plugin.init_app(app=app, config=config)\n    await fastapi_plugins.scheduler_plugin.init()\n    await fastapi_plugins.control_plugin.init_app(\n        app,\n        config=config,\n        version=__version__,\n        environ=config.model_dump()\n    )\n    await fastapi_plugins.control_plugin.init()\n    yield\n    await fastapi_plugins.control_plugin.terminate()\n    await fastapi_plugins.scheduler_plugin.terminate()\n    await fastapi_plugins.redis_plugin.terminate()\n    await memcached_plugin.terminate()\n    await fastapi_plugins.log_plugin.terminate()\n    await fastapi_plugins.config_plugin.terminate()\n\n\napp = fastapi_plugins.register_middleware(fastapi.FastAPI(lifespan=lifespan))\n\n\n@app.get(\"/\")\nasync def root_get(\n        cache: fastapi_plugins.TRedisPlugin,\n        conf: fastapi_plugins.TConfigPlugin,\n        logger: fastapi_plugins.TLoggerPlugin\n) -> typing.Dict:\n    ping = await cache.ping()\n    logger.debug('root_get', extra=dict(ping=ping, api_name=conf.api_name))\n    return dict(ping=ping, api_name=conf.api_name)\n\n\n@app.post(\"/jobs/schedule/<timeout>\")\nasync def job_post(\n    timeout: int=fastapi.Query(..., title='the job sleep time'),\n    cache: fastapi_plugins.TRedisPlugin,\n    scheduler: fastapi_plugins.TSchedulerPlugin,\n    logger: fastapi_plugins.TLoggerPlugin\n) -> str:\n    async def coro(job_id, timeout, cache):\n        await cache.set(job_id, 'processing')\n        try:\n            await asyncio.sleep(timeout)\n            if timeout == 8:\n                logger.critical('Ugly erred job %s' % job_id)\n                raise Exception('ugly error')\n        except asyncio.CancelledError:\n            await cache.set(job_id, 'canceled')\n            logger.warning('Cancel job %s' % job_id)\n        except Exception:\n            await cache.set(job_id, 'erred')\n            logger.error('Erred job %s' % job_id)\n        else:\n            await cache.set(job_id, 'success')\n            logger.info('Done job %s' % job_id)\n\n    job_id = str(uuid.uuid4()).replace('-', '')\n    logger = await fastapi_plugins.log_adapter(logger, extra=dict(job_id=job_id, timeout=timeout))    # noqa E501\n    logger.info('New job %s' % job_id)\n    await cache.set(job_id, 'pending')\n    logger.debug('Pending job %s' % job_id)\n    await scheduler.spawn(coro(job_id, timeout, cache))\n    return job_id\n\n\n@app.get(\"/jobs/status/<job_id>\")\nasync def job_get(\n    job_id: str=fastapi.Query(..., title='the job id'),\n    cache: fastapi_plugins.TRedisPlugin,\n) -> typing.Dict:\n    status = await cache.get(job_id)\n    if status is None:\n        raise fastapi.HTTPException(\n            status_code=starlette.status.HTTP_404_NOT_FOUND,\n            detail='Job %s not found' % job_id\n        )\n    return dict(job_id=job_id, status=status)\n\n\n@app.post(\"/memcached/demo/<key>\")\nasync def memcached_demo_post(\n    key: str=fastapi.Query(..., title='the job id'),\n    cache: fastapi_plugins.TMemcachedPlugin,\n) -> typing.Dict:\n    await cache.set(key.encode(), str(key + '_value').encode())\n    value = await cache.get(key.encode())\n    return dict(ping=(await cache.ping()).decode(), key=key, value=value)\n```\n\n# Development\nIssues and suggestions are welcome through [issues](https://github.com/madkote/fastapi-plugins/issues)\n\n# License\nThis project is licensed under the terms of the MIT license.\n\n\n# Changes\n## 0.12.0 (2023-03-24)\n- `[feature]` `Annotated` support\n## 0.11.0 (2022-09-19)\n- `[feature]` `redis-py` replaces `aioredis`\n## 0.10.0 (2022-07-07)\n- `[feature]` Update `aioredis` to `2.x.x`\n- `[feature]` Add `fakeredis` optionally for development purpose\n## 0.9.1 (2022-06-16)\n- `[fix]` Fix empty router prefix for control plugin\n## 0.9.0 (2021-09-27)\n- `[feature]` Logging plugin\n- `[feature]` Middleware interface - register middleware at application\n## 0.8.2 (2021-09-23)\n- `[fix]` Fix dependency for aioredis\n## 0.8.1 (2021-03-31)\n- `[fix]` Fix settings for Python 3.7\n## 0.8.0 (2021-03-31)\n- `[feature]` Settings plugin\n## 0.7.0 (2021-03-29)\n- `[feature]` Control plugin with Health, Heartbeat, Environment and Version\n## 0.6.1 (2021-03-24)\n- `[fix]` Bump `aiojobs`to get rid of not required dependencies\n## 0.6.0 (2020-11-26)\n- `[feature]` Memcached\n## 0.5.0 (2020-11-25)\n- [bug] remove `__all__` since no API as such ([#6][i6]).\n- [typo] Fix typos in README ([#7][i7]).\n- [feature] Add Redis TTL ([#8][i8]).\n## 0.4.2 (2020-11-24)\n- [bug] Fix Redis URL ([#4][i4]). \n## 0.4.1 (2020-06-16)\n- Refactor requirements\n## 0.4.0 (2020-04-09)\n- structure and split dependencies to `extra`\n## 0.3.0 (2020-04-07)\n- Scheduler: tasks scheduler based on `aiojobs`\n## 0.2.1 (2020-04-06)\n- Redis: pre-start\n## 0.2.0 (2019-12-11)\n- Redis: sentinels\n## 0.1.0 (2019-11-20)\n- Initial release: simple redis pool client\n\n[i4]: https://github.com/madkote/fastapi-plugins/pull/4\n[i6]: https://github.com/madkote/fastapi-plugins/pull/6\n[i7]: https://github.com/madkote/fastapi-plugins/pull/7\n[i8]: https://github.com/madkote/fastapi-plugins/issues/8\n",
    "bugtrack_url": null,
    "license": "MIT License",
    "summary": "Plugins for FastAPI framework",
    "version": "0.13.0",
    "project_urls": {
        "Download": "https://github.com/madkote/fastapi-plugins/archive/0.13.0.tar.gz",
        "Homepage": "https://github.com/madkote/fastapi-plugins"
    },
    "split_keywords": [
        "async",
        "redis",
        "aioredis",
        "json",
        "asyncio",
        "plugin",
        "fastapi",
        "aiojobs",
        "scheduler",
        "starlette",
        "memcached",
        "aiomcache"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "1f85fa23c69a3c4ff323f8c777757017ecb472b68773f852acda23f8deb6ee6a",
                "md5": "130efd90151f3cf8ceac0cd3ee9d83a5",
                "sha256": "e7a6d1d3f00b90dad0b299c9433c37f586eb070f252c11984c0856cf5a6d2146"
            },
            "downloads": -1,
            "filename": "fastapi_plugins-0.13.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "130efd90151f3cf8ceac0cd3ee9d83a5",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.6.0",
            "size": 22493,
            "upload_time": "2024-02-16T12:22:39",
            "upload_time_iso_8601": "2024-02-16T12:22:39.186552Z",
            "url": "https://files.pythonhosted.org/packages/1f/85/fa23c69a3c4ff323f8c777757017ecb472b68773f852acda23f8deb6ee6a/fastapi_plugins-0.13.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "1676a4e7935f05f7f0563f5039052391ee0164b574d04b18723db5dce2f7b85c",
                "md5": "bf3069a20e173d0f296eba77bf121f06",
                "sha256": "252ef0c715c66e0374d03d86df69824af9b448564cb47a120662e103a14d1807"
            },
            "downloads": -1,
            "filename": "fastapi-plugins-0.13.0.tar.gz",
            "has_sig": false,
            "md5_digest": "bf3069a20e173d0f296eba77bf121f06",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.6.0",
            "size": 26460,
            "upload_time": "2024-02-16T12:22:41",
            "upload_time_iso_8601": "2024-02-16T12:22:41.311480Z",
            "url": "https://files.pythonhosted.org/packages/16/76/a4e7935f05f7f0563f5039052391ee0164b574d04b18723db5dce2f7b85c/fastapi-plugins-0.13.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-02-16 12:22:41",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "madkote",
    "github_project": "fastapi-plugins",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "requirements": [],
    "tox": true,
    "lcname": "fastapi-plugins"
}
        
Elapsed time: 0.24796s