%global _empty_manifest_terminate_build 0 Name: python-facet Version: 0.9.1 Release: 1 Summary: service manager for asyncio License: MIT URL: https://github.com/pohmelie/facet Source0: https://mirrors.nju.edu.cn/pypi/web/packages/9d/f8/e6145b20485d8ea77a10a338c35069a37a96a2d7a608abd2cd1e189dd835/facet-0.9.1.tar.gz BuildArch: noarch Requires: python3-pytest Requires: python3-pytest-asyncio Requires: python3-pytest-cov Requires: python3-flake8 %description # Facet [![Travis status for master branch](https://travis-ci.com/pohmelie/facet.svg?branch=master)](https://travis-ci.com/pohmelie/facet) [![Codecov coverage for master branch](https://codecov.io/gh/pohmelie/facet/branch/master/graph/badge.svg)](https://codecov.io/gh/pohmelie/facet) [![Pypi version](https://img.shields.io/pypi/v/facet.svg)](https://pypi.org/project/facet/) [![Pypi downloads count](https://img.shields.io/pypi/dm/facet)](https://pypi.org/project/facet/) Service manager for asyncio. # Reason [`mode`](https://github.com/ask/mode) tries to do too much job: - Messy callbacks (`on_start`, `on_started`, `on_crashed`, etc.). - Inheritance restrict naming and forces `super()` calls. - Forced logging module and logging configuration. # Features - Simple (`start`, `stop`, `dependencies` and `add_task`). - Configurable via inheritance (graceful shutdown timeout). - Mixin (no `super()` required). - Requires no runner engine (`Worker`, `Runner`, etc.) just plain `await` or `async with`. # License `facet` is offered under MIT license. # Requirements * python 3.6+ # Usage ``` python import asyncio import logging from facet import ServiceMixin class B(ServiceMixin): def __init__(self): self.value = 0 async def start(self): self.value += 1 logging.info("b started") async def stop(self): self.value -= 1 logging.info("b stopped") class A(ServiceMixin): def __init__(self): self.b = B() @property def dependencies(self): return [self.b] async def start(self): logging.info("a started") async def stop(self): logging.info("a stopped") logging.basicConfig(level=logging.DEBUG) asyncio.run(A().run()) ``` This will produce: ``` INFO:root:b started INFO:root:a started ``` Start and stop order determined by strict rule: **dependencies must be started first and stopped last**. That is why `B` starts before `A`. Since `A` may use `B` in `start` routine. Hit `ctrl-c` and you will see: ``` INFO:root:a stopped INFO:root:b stopped Traceback (most recent call last): ... KeyboardInterrupt ``` Stop order is reversed, since `A` may use `B` in `stop` routine. Any raised exception propagates to upper context. `facet` do not trying to be too smart. Service can be used as a context manager. Instead of ``` python asyncio.run(A().run()) ``` Code can look like: ``` python async def main(): async with A() as a: assert a.b.value == 1 await a.wait() asyncio.run(main()) ``` Another service feature is `add_task` method: ``` python class A(ServiceMixin): async def task(self): await asyncio.sleep(1) logging.info("task done") async def start(self): self.add_task(self.task()) logging.info("start done") logging.basicConfig(level=logging.DEBUG) asyncio.run(A().run()) ``` This will lead to background task creation and handling: ``` INFO:root:start done INFO:root:task done ``` Any non-handled exception on background task will lead the whole service stack crashed. This is also a key feature to fall down fast and loud. All background tasks will be cancelled and awaited on service stop. You can manage dependencies start/stop to start sequently, parallel or mixed. Like this: ``` python class A(ServiceMixin): def __init__(self): self.b = B() self.c = C() self.d = D() @property def dependencies(self): return [ [self.b, self.c], self.d, ] ``` This leads to first `b` and `c` starts parallel, after they successfully started `d` will try to start, and then `a` itself start will be called. And on stop routine `a` stop called first, then `d` stop, then both `b` and `c` stops parallel. The rule here is **first nesting level is sequential, second nesting level is parallel** # API Here is public methods you get on inheritance/mixin: ## `wait` ``` python async def wait(self): ``` Wait for service stop. Service must be started. This is useful when you use service as a context manager. ## `run` ``` python async def run(self): ``` Run service and wait until it stop. ## `graceful_shutdown_timeout` ``` python @property def graceful_shutdown_timeout(self): return 10 ``` How much total time in seconds wait for stop routines. This property can be overriden with subclass: ``` python class CustomServiceMixin(ServiceMixin): @property def graceful_shutdown_timeout(self): return 60 ``` ## `dependencies` ``` python @property def dependencies(self): return [] ``` Should return iterable of current service dependencies instances. ## `running` ``` python @property def running(self) -> bool: ``` Check if service is running ## `add_task` ``` python def add_task(self, coro) -> asyncio.Task: ``` Add background task. ## `start` ``` python async def start(self): pass ``` Start routine. ## `stop` ``` python async def stop(self): pass ``` Stop routine. %package -n python3-facet Summary: service manager for asyncio Provides: python-facet BuildRequires: python3-devel BuildRequires: python3-setuptools BuildRequires: python3-pip %description -n python3-facet # Facet [![Travis status for master branch](https://travis-ci.com/pohmelie/facet.svg?branch=master)](https://travis-ci.com/pohmelie/facet) [![Codecov coverage for master branch](https://codecov.io/gh/pohmelie/facet/branch/master/graph/badge.svg)](https://codecov.io/gh/pohmelie/facet) [![Pypi version](https://img.shields.io/pypi/v/facet.svg)](https://pypi.org/project/facet/) [![Pypi downloads count](https://img.shields.io/pypi/dm/facet)](https://pypi.org/project/facet/) Service manager for asyncio. # Reason [`mode`](https://github.com/ask/mode) tries to do too much job: - Messy callbacks (`on_start`, `on_started`, `on_crashed`, etc.). - Inheritance restrict naming and forces `super()` calls. - Forced logging module and logging configuration. # Features - Simple (`start`, `stop`, `dependencies` and `add_task`). - Configurable via inheritance (graceful shutdown timeout). - Mixin (no `super()` required). - Requires no runner engine (`Worker`, `Runner`, etc.) just plain `await` or `async with`. # License `facet` is offered under MIT license. # Requirements * python 3.6+ # Usage ``` python import asyncio import logging from facet import ServiceMixin class B(ServiceMixin): def __init__(self): self.value = 0 async def start(self): self.value += 1 logging.info("b started") async def stop(self): self.value -= 1 logging.info("b stopped") class A(ServiceMixin): def __init__(self): self.b = B() @property def dependencies(self): return [self.b] async def start(self): logging.info("a started") async def stop(self): logging.info("a stopped") logging.basicConfig(level=logging.DEBUG) asyncio.run(A().run()) ``` This will produce: ``` INFO:root:b started INFO:root:a started ``` Start and stop order determined by strict rule: **dependencies must be started first and stopped last**. That is why `B` starts before `A`. Since `A` may use `B` in `start` routine. Hit `ctrl-c` and you will see: ``` INFO:root:a stopped INFO:root:b stopped Traceback (most recent call last): ... KeyboardInterrupt ``` Stop order is reversed, since `A` may use `B` in `stop` routine. Any raised exception propagates to upper context. `facet` do not trying to be too smart. Service can be used as a context manager. Instead of ``` python asyncio.run(A().run()) ``` Code can look like: ``` python async def main(): async with A() as a: assert a.b.value == 1 await a.wait() asyncio.run(main()) ``` Another service feature is `add_task` method: ``` python class A(ServiceMixin): async def task(self): await asyncio.sleep(1) logging.info("task done") async def start(self): self.add_task(self.task()) logging.info("start done") logging.basicConfig(level=logging.DEBUG) asyncio.run(A().run()) ``` This will lead to background task creation and handling: ``` INFO:root:start done INFO:root:task done ``` Any non-handled exception on background task will lead the whole service stack crashed. This is also a key feature to fall down fast and loud. All background tasks will be cancelled and awaited on service stop. You can manage dependencies start/stop to start sequently, parallel or mixed. Like this: ``` python class A(ServiceMixin): def __init__(self): self.b = B() self.c = C() self.d = D() @property def dependencies(self): return [ [self.b, self.c], self.d, ] ``` This leads to first `b` and `c` starts parallel, after they successfully started `d` will try to start, and then `a` itself start will be called. And on stop routine `a` stop called first, then `d` stop, then both `b` and `c` stops parallel. The rule here is **first nesting level is sequential, second nesting level is parallel** # API Here is public methods you get on inheritance/mixin: ## `wait` ``` python async def wait(self): ``` Wait for service stop. Service must be started. This is useful when you use service as a context manager. ## `run` ``` python async def run(self): ``` Run service and wait until it stop. ## `graceful_shutdown_timeout` ``` python @property def graceful_shutdown_timeout(self): return 10 ``` How much total time in seconds wait for stop routines. This property can be overriden with subclass: ``` python class CustomServiceMixin(ServiceMixin): @property def graceful_shutdown_timeout(self): return 60 ``` ## `dependencies` ``` python @property def dependencies(self): return [] ``` Should return iterable of current service dependencies instances. ## `running` ``` python @property def running(self) -> bool: ``` Check if service is running ## `add_task` ``` python def add_task(self, coro) -> asyncio.Task: ``` Add background task. ## `start` ``` python async def start(self): pass ``` Start routine. ## `stop` ``` python async def stop(self): pass ``` Stop routine. %package help Summary: Development documents and examples for facet Provides: python3-facet-doc %description help # Facet [![Travis status for master branch](https://travis-ci.com/pohmelie/facet.svg?branch=master)](https://travis-ci.com/pohmelie/facet) [![Codecov coverage for master branch](https://codecov.io/gh/pohmelie/facet/branch/master/graph/badge.svg)](https://codecov.io/gh/pohmelie/facet) [![Pypi version](https://img.shields.io/pypi/v/facet.svg)](https://pypi.org/project/facet/) [![Pypi downloads count](https://img.shields.io/pypi/dm/facet)](https://pypi.org/project/facet/) Service manager for asyncio. # Reason [`mode`](https://github.com/ask/mode) tries to do too much job: - Messy callbacks (`on_start`, `on_started`, `on_crashed`, etc.). - Inheritance restrict naming and forces `super()` calls. - Forced logging module and logging configuration. # Features - Simple (`start`, `stop`, `dependencies` and `add_task`). - Configurable via inheritance (graceful shutdown timeout). - Mixin (no `super()` required). - Requires no runner engine (`Worker`, `Runner`, etc.) just plain `await` or `async with`. # License `facet` is offered under MIT license. # Requirements * python 3.6+ # Usage ``` python import asyncio import logging from facet import ServiceMixin class B(ServiceMixin): def __init__(self): self.value = 0 async def start(self): self.value += 1 logging.info("b started") async def stop(self): self.value -= 1 logging.info("b stopped") class A(ServiceMixin): def __init__(self): self.b = B() @property def dependencies(self): return [self.b] async def start(self): logging.info("a started") async def stop(self): logging.info("a stopped") logging.basicConfig(level=logging.DEBUG) asyncio.run(A().run()) ``` This will produce: ``` INFO:root:b started INFO:root:a started ``` Start and stop order determined by strict rule: **dependencies must be started first and stopped last**. That is why `B` starts before `A`. Since `A` may use `B` in `start` routine. Hit `ctrl-c` and you will see: ``` INFO:root:a stopped INFO:root:b stopped Traceback (most recent call last): ... KeyboardInterrupt ``` Stop order is reversed, since `A` may use `B` in `stop` routine. Any raised exception propagates to upper context. `facet` do not trying to be too smart. Service can be used as a context manager. Instead of ``` python asyncio.run(A().run()) ``` Code can look like: ``` python async def main(): async with A() as a: assert a.b.value == 1 await a.wait() asyncio.run(main()) ``` Another service feature is `add_task` method: ``` python class A(ServiceMixin): async def task(self): await asyncio.sleep(1) logging.info("task done") async def start(self): self.add_task(self.task()) logging.info("start done") logging.basicConfig(level=logging.DEBUG) asyncio.run(A().run()) ``` This will lead to background task creation and handling: ``` INFO:root:start done INFO:root:task done ``` Any non-handled exception on background task will lead the whole service stack crashed. This is also a key feature to fall down fast and loud. All background tasks will be cancelled and awaited on service stop. You can manage dependencies start/stop to start sequently, parallel or mixed. Like this: ``` python class A(ServiceMixin): def __init__(self): self.b = B() self.c = C() self.d = D() @property def dependencies(self): return [ [self.b, self.c], self.d, ] ``` This leads to first `b` and `c` starts parallel, after they successfully started `d` will try to start, and then `a` itself start will be called. And on stop routine `a` stop called first, then `d` stop, then both `b` and `c` stops parallel. The rule here is **first nesting level is sequential, second nesting level is parallel** # API Here is public methods you get on inheritance/mixin: ## `wait` ``` python async def wait(self): ``` Wait for service stop. Service must be started. This is useful when you use service as a context manager. ## `run` ``` python async def run(self): ``` Run service and wait until it stop. ## `graceful_shutdown_timeout` ``` python @property def graceful_shutdown_timeout(self): return 10 ``` How much total time in seconds wait for stop routines. This property can be overriden with subclass: ``` python class CustomServiceMixin(ServiceMixin): @property def graceful_shutdown_timeout(self): return 60 ``` ## `dependencies` ``` python @property def dependencies(self): return [] ``` Should return iterable of current service dependencies instances. ## `running` ``` python @property def running(self) -> bool: ``` Check if service is running ## `add_task` ``` python def add_task(self, coro) -> asyncio.Task: ``` Add background task. ## `start` ``` python async def start(self): pass ``` Start routine. ## `stop` ``` python async def stop(self): pass ``` Stop routine. %prep %autosetup -n facet-0.9.1 %build %py3_build %install %py3_install install -d -m755 %{buildroot}/%{_pkgdocdir} if [ -d doc ]; then cp -arf doc %{buildroot}/%{_pkgdocdir}; fi if [ -d docs ]; then cp -arf docs %{buildroot}/%{_pkgdocdir}; fi if [ -d example ]; then cp -arf example %{buildroot}/%{_pkgdocdir}; fi if [ -d examples ]; then cp -arf examples %{buildroot}/%{_pkgdocdir}; fi pushd %{buildroot} if [ -d usr/lib ]; then find usr/lib -type f -printf "/%h/%f\n" >> filelist.lst fi if [ -d usr/lib64 ]; then find usr/lib64 -type f -printf "/%h/%f\n" >> filelist.lst fi if [ -d usr/bin ]; then find usr/bin -type f -printf "/%h/%f\n" >> filelist.lst fi if [ -d usr/sbin ]; then find usr/sbin -type f -printf "/%h/%f\n" >> filelist.lst fi touch doclist.lst if [ -d usr/share/man ]; then find usr/share/man -type f -printf "/%h/%f.gz\n" >> doclist.lst fi popd mv %{buildroot}/filelist.lst . mv %{buildroot}/doclist.lst . %files -n python3-facet -f filelist.lst %dir %{python3_sitelib}/* %files help -f doclist.lst %{_docdir}/* %changelog * Tue Apr 25 2023 Python_Bot - 0.9.1-1 - Package Spec generated