summaryrefslogtreecommitdiff
path: root/python-facet.spec
diff options
context:
space:
mode:
Diffstat (limited to 'python-facet.spec')
-rw-r--r--python-facet.spec697
1 files changed, 697 insertions, 0 deletions
diff --git a/python-facet.spec b/python-facet.spec
new file mode 100644
index 0000000..3e5238c
--- /dev/null
+++ b/python-facet.spec
@@ -0,0 +1,697 @@
+%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 11 2023 Python_Bot <Python_Bot@openeuler.org> - 0.9.1-1
+- Package Spec generated