mode-ng


Namemode-ng JSON
Version 0.6.1 PyPI version JSON
download
home_page
SummaryAsyncIO Service-based programming.
upload_time2022-12-08 09:49:24
maintainer
docs_urlNone
author
requires_python>=3.10
licenseBSD 3-Clause License
keywords asyncio service bootsteps graph coroutine actor
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            =====================
Mode AsyncIO Services
=====================

|license| |wheel| |pyversion| |pyimp| |black|

:Version: 0.6.1
:Web: http://mode-ng.readthedocs.org/
:Download: https://pypi.org/project/mode-ng
:Source: https://github.com/lqhuang/mode-ng
:Keywords: async, service, framework, actors, bootsteps, graph

.. |license| image:: https://img.shields.io/pypi/l/mode-ng.svg
    :alt: BSD License
    :target: https://opensource.org/licenses/BSD-3-Clause
.. |wheel| image:: https://img.shields.io/pypi/wheel/mode-ng.svg
    :alt: Mode can be installed via wheel
    :target: http://pypi.org/project/mode-ng/
.. |pyversion| image:: https://img.shields.io/pypi/pyversions/mode-ng.svg
    :alt: Supported Python versions.
    :target: http://pypi.org/project/mode-ng/
.. |pyimp| image:: https://img.shields.io/pypi/implementation/mode-ng.svg
    :alt: Supported Python implementations.
    :target: http://pypi.org/project/mode-ng/
.. |black| image:: https://img.shields.io/badge/code_style-black-000000.svg?style=flat
    :alt: Use ``black`` as code formatter
    :target: https://github.com/psf/black

Why the fork
============

Original ``mode`` homepage: https://github.com/ask/mode. Thanks to its creator Ask Solem (@ask).

First fork: ``mode-streaming``
------------------------------

Project homepage: https://github.com/faust-streaming/mode

We have decided to fork the original *Mode* project because there is a critical process of releasing new versions which causes uncertainty in the community. Everybody is welcome to contribute to this *fork*, and you can be added as a manitainer.

We want to:

- Ensure continues release
- Code quality
- Support latest Python versions
- Update the documentation

and more...

A new fork: ``mode-ng``
-----------------------

**WIP** notice. Welcome to try it in your programs and feedback!

Well, here is an another fork for ``mode``. Generally, my target is to
create an individual and separated repository to develop ``mode`` for next
stage/generation and keep rolling forward fastly.

``mode`` could be a very potential and powerful framework for various
applications. So I very care about how ``faust-streaming`` and ``mode-streaming``
goes in future. Currently the most important thing in developing ``mode-streaming``
is to fix bugs and keep back compatibility for ``faust-streaming``, it would be
uncertain or not-willing to add new features. For now, one big problem is if I
try to continue working on current ``mode-streaming`` branch, it's hard to me
to know its consequences in ``faust-streaming``. I don't want to introduce
break changes and inconsistent behaviors.

Hence, ``mode-ng`` provides a new package to make some aggressive improvements, do some experiments,
and do not consider compatible problems from ``faust-streaming``. At least,
``mode-ng`` can be quickly used by more users with more advanced features to
build their own applications. In the future, if this fork could be ported back
to ``mode-streaming`` or used as base framework of ``faust-streaming``, that
would be really great!

Here are some thoughts from practical experiences and what I want to do next step:

- Bug fixes: yeah, why not.
- Use standard library implementations: When mode was first developed,
  many features haven't exist, so there are many hacks and tricky solutions in
  ``mode`` codes. Like ``cached_property``, ``AsyncMock``, ``loop arguments``,
  even ``Object`` class (missing some inner ``__xxx__`` attrs after redefinition).
- Port some features from faust: ``web`` module in faust is really useful for
  building application. With web part, ``mode`` is able to expose, control,
  monitor and more from outside api.
- Improve or complete left part of ``signal`` module: Some modules like ``Signal``
  are unfinished. It will be useful for some observer patterns in programming.
- Add some message commuting behaviors like real actors? (for thread serices?)
- More documents and more examples

Why minimal supported Python version is ``3.10``?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

It's more like a personal flavor for now. But if we say ``py3.6`` bring us stable ``async/await`` syntax firstly to introduce wonderful coroutine concurrency, I thought ``py3.10`` would be the next major popular minimal supported version with a more matured ``asyncio`` api interfaces. From feedbacks from many real cases, ``asyncio`` interfaces have changed a lot. Happy news is it stabilized by development of std library. And Python 3.10 is faster than before, though Python is not a language which cares about speed, seldom people don't want to higher performance.

This is not absolute, it aslo depends how many people want back compatibility for older versions.

Installation
============

You can install Mode either via the Python Package Index (PyPI)
or from source.

To install using ``pip``:

.. code:: console

    $ pip install -U mode-ng

Downloading and installing from source
--------------------------------------

Download the latest version of Mode from http://pypi.org/project/mode-ng

You can install it by doing the following:

.. code:: console

    $ tar xvfz mode-ng-0.6.1.tar.gz
    $ cd mode-0.6.1
    $ python setup.py build
    $ python setup.py install

The last command must be executed as a privileged user if
you are not currently using a virtualenv.

Using the development version
-----------------------------

With pip
~~~~~~~~

You can install the latest snapshot of Mode using the following
pip command:

.. code:: console

    $ pip install https://github.com/lqhuang/mode-ng/zipball/master#egg=mode-ng

What is Mode?
=============

Mode is a very minimal Python library built-on top of AsyncIO that makes
it much easier to use.

In Mode your program is built out of services that you can start, stop,
restart and supervise.

A service is just a class:

.. code:: python

    class PageViewCache(Service):
        redis: Redis = None

        async def on_start(self) -> None:
            self.redis = connect_to_redis()

        async def update(self, url: str, n: int = 1) -> int:
            return await self.redis.incr(url, n)

        async def get(self, url: str) -> int:
            return await self.redis.get(url)


Services are started, stopped and restarted and have
callbacks for those actions.

It can start another service:

.. code:: python

    class App(Service):
        page_view_cache: PageViewCache = None

        async def on_start(self) -> None:
            await self.add_runtime_dependency(self.page_view_cache)

        @cached_property
        def page_view_cache(self) -> PageViewCache:
            return PageViewCache()

It can include background tasks:

.. code:: python

    class PageViewCache(Service):

        @Service.timer(1.0)
        async def _update_cache(self) -> None:
            self.data = await cache.get('key')

Services that depends on other services actually form a graph
that you can visualize.

Worker
------

Mode optionally provides a worker that you can use to start the program,
with support for logging, blocking detection, remote debugging and more.

To start a worker add this to your program:

.. code:: python

    if __name__ == "__main__":
        from mode import Worker
        Worker(Service(), loglevel="info").execute_from_commandline()

Then execute your program to start the worker:

.. code:: console

    $ python examples/tutorial.py
    [2018-03-27 15:47:12,159: INFO]: [^Worker]: Starting...
    [2018-03-27 15:47:12,160: INFO]: [^-AppService]: Starting...
    [2018-03-27 15:47:12,160: INFO]: [^--Websockets]: Starting...
    STARTING WEBSOCKET SERVER
    [2018-03-27 15:47:12,161: INFO]: [^--UserCache]: Starting...
    [2018-03-27 15:47:12,161: INFO]: [^--Webserver]: Starting...
    [2018-03-27 15:47:12,164: INFO]: [^--Webserver]: Serving on port 8000
    REMOVING EXPIRED USERS
    REMOVING EXPIRED USERS

To stop it hit ``Control-c``:

.. code:: console

    [2018-03-27 15:55:08,084: INFO]: [^Worker]: Stopping on signal received...
    [2018-03-27 15:55:08,084: INFO]: [^Worker]: Stopping...
    [2018-03-27 15:55:08,084: INFO]: [^-AppService]: Stopping...
    [2018-03-27 15:55:08,084: INFO]: [^--UserCache]: Stopping...
    REMOVING EXPIRED USERS
    [2018-03-27 15:55:08,085: INFO]: [^Worker]: Gathering service tasks...
    [2018-03-27 15:55:08,085: INFO]: [^--UserCache]: -Stopped!
    [2018-03-27 15:55:08,085: INFO]: [^--Webserver]: Stopping...
    [2018-03-27 15:55:08,085: INFO]: [^Worker]: Gathering all futures...
    [2018-03-27 15:55:08,085: INFO]: [^--Webserver]: Closing server
    [2018-03-27 15:55:08,086: INFO]: [^--Webserver]: Waiting for server to close handle
    [2018-03-27 15:55:08,086: INFO]: [^--Webserver]: Shutting down web application
    [2018-03-27 15:55:08,086: INFO]: [^--Webserver]: Waiting for handler to shut down
    [2018-03-27 15:55:08,086: INFO]: [^--Webserver]: Cleanup
    [2018-03-27 15:55:08,086: INFO]: [^--Webserver]: -Stopped!
    [2018-03-27 15:55:08,086: INFO]: [^--Websockets]: Stopping...
    [2018-03-27 15:55:08,086: INFO]: [^--Websockets]: -Stopped!
    [2018-03-27 15:55:08,087: INFO]: [^-AppService]: -Stopped!
    [2018-03-27 15:55:08,087: INFO]: [^Worker]: -Stopped!

Beacons
-------

The ``beacon`` object that we pass to services keeps track of the services
in a graph.

They are not stricly required, but can be used to visualize a running
system, for example we can render it as a pretty graph.

This requires you to have the ``pydot`` library and GraphViz
installed:

.. code:: console

    $ pip install pydot

Let's change the app service class to dump the graph to an image at startup:

.. code:: python

    class AppService(Service):

        async def on_start(self) -> None:
            print('APP STARTING')
            import pydot
            import io

            o = io.StringIO()
            beacon = self.app.beacon.root or self.app.beacon
            beacon.as_graph().to_dot(o)
            graph, = pydot.graph_from_dot_data(o.getvalue())

            print('WRITING GRAPH TO image.png')
            with open('image.png', 'wb') as fh:
                fh.write(graph.create_png())


Creating a Service
==================

To define a service, simply subclass and fill in the methods
to do stuff as the service is started/stopped etc.:

.. code:: python

    class MyService(Service):

        async def on_start(self) -> None:
            print('Im starting now')

        async def on_started(self) -> None:
            print('Im ready')

        async def on_stop(self) -> None:
            print('Im stopping now')

To start the service, call ``await service.start()``:

.. code:: python

    await service.start()

Or you can use ``mode.Worker`` (or a subclass of this) to start your
services-based asyncio program from the console:

.. code:: python

    if __name__ == '__main__':
        import mode
        worker = mode.Worker(
            MyService(),
            loglevel='INFO',
            logfile=None,
            daemon=False,
        )
        worker.execute_from_commandline()

It's a Graph!
=============

Services can start other services, coroutines, and background tasks.

1) Starting other services using ``add_depenency``:

.. code:: python

    class MyService(Service):

        def __post_init__(self) -> None:
           self.add_dependency(OtherService(loop=self.loop))

2) Start a list of services using ``on_init_dependencies``:

.. code:: python

    class MyService(Service):

        def on_init_dependencies(self) -> None:
            return [
                ServiceA(loop=self.loop),
                ServiceB(loop=self.loop),
                ServiceC(loop=self.loop),
            ]

3) Start a future/coroutine (that will be waited on to complete on stop):

.. code:: python

    class MyService(Service):

        async def on_start(self) -> None:
            self.add_future(self.my_coro())

        async def my_coro(self) -> None:
            print('Executing coroutine')

4) Start a background task:

.. code:: python

    class MyService(Service):

        @Service.task
        async def _my_coro(self) -> None:
            print('Executing coroutine')


5) Start a background task that keeps running:

.. code:: python

    class MyService(Service):

        @Service.task
        async def _my_coro(self) -> None:
            while not self.should_stop:
                # NOTE: self.sleep will wait for one second, or
                #       until service stopped/crashed.
                await self.sleep(1.0)
                print('Background thread waking up')

FAQ
===

Can I use Mode with Django/Flask/etc.?
--------------------------------------

Yes! Use gevent/eventlet as a bridge to integrate with asyncio.

Using ``gevent``
~~~~~~~~~~~~~~~~

This works with any blocking Python library that can work with gevent.

Using gevent requires you to install the ``aiogevent`` module,
and you can install this as a bundle with Mode:

.. code:: console

    $ pip install -U mode-ng[gevent]

Then to actually use gevent as the event loop you have to
execute the following in your entrypoint module (usually where you
start the worker), before any other third party libraries are imported:

.. code:: python

    #!/usr/bin/env python3
    import mode.loop
    mode.loop.use('gevent')
    # execute program

REMEMBER: This must be located at the very top of the module,
in such a way that it executes before you import other libraries.

Using ``eventlet``
~~~~~~~~~~~~~~~~~~

This works with any blocking Python library that can work with eventlet.

Using eventlet requires you to install the ``aioeventlet`` module,
and you can install this as a bundle with Mode:

.. code:: console

    $ pip install -U mode-ng[eventlet]

Then to actually use eventlet as the event loop you have to
execute the following in your entrypoint module (usually where you
start the worker), before any other third party libraries are imported:

.. code:: python

    #!/usr/bin/env python3
    import mode.loop
    mode.loop.use('eventlet')
    # execute program

REMEMBER: It's very important this is at the very top of the module,
and that it executes before you import libraries.

Can I use Mode with Tornado?
----------------------------

Yes! Use the ``tornado.platform.asyncio`` bridge:
http://www.tornadoweb.org/en/stable/asyncio.html

Can I use Mode with Twisted?
-----------------------------

Yes! Use the asyncio reactor implementation:
https://twistedmatrix.com/documents/17.1.0/api/twisted.internet.asyncioreactor.html

At Shutdown I get lots of warnings, what is this about?
-------------------------------------------------------

If you get warnings such as this at shutdown:

.. code:: text

    Task was destroyed but it is pending!
    task: <Task pending coro=<Service._execute_task() running at /opt/devel/mode/mode/services.py:643> wait_for=<Future pending cb=[<TaskWakeupMethWrapper object at 0x1100a7468>()]>>
    Task was destroyed but it is pending!
    task: <Task pending coro=<Service._execute_task() running at /opt/devel/mode/mode/services.py:643> wait_for=<Future pending cb=[<TaskWakeupMethWrapper object at 0x1100a72e8>()]>>
    Task was destroyed but it is pending!
    task: <Task pending coro=<Service._execute_task() running at /opt/devel/mode/mode/services.py:643> wait_for=<Future pending cb=[<TaskWakeupMethWrapper object at 0x1100a7678>()]>>
    Task was destroyed but it is pending!
    task: <Task pending coro=<Event.wait() running at /Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/asyncio/locks.py:269> cb=[_release_waiter(<Future pendi...1100a7468>()]>)() at /Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/asyncio/tasks.py:316]>
    Task was destroyed but it is pending!
        task: <Task pending coro=<Event.wait() running at /Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/asyncio/locks.py:269> cb=[_release_waiter(<Future pendi...1100a7678>()]>)() at /Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/asyncio/tasks.py:316]>

It usually means you forgot to stop a service before the process exited.


Contributing
============

For guidance on setting up a development environment and how to make a contribution
to `mode-ng`, see the `contributing guidelines`_.

.. _contributing guidelines: https://github.com/lqhuang/mode-ng/blob/master/CONTRIBUTING.md

Code of Conduct
===============

Check `code of conduct`_ for recommended or discouraged behaviors while communicating.

.. _code of conduct: https://github.com/lqhuang/mode-ng/blob/master/CODE_OF_CONDUCT.md

            

Raw data

            {
    "_id": null,
    "home_page": "",
    "name": "mode-ng",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3.10",
    "maintainer_email": "Lanqing Huang <lqhuang@outlook.com>",
    "keywords": "asyncio,service,bootsteps,graph,coroutine,actor",
    "author": "",
    "author_email": "Ask Solem <ask@celeryproject.org>",
    "download_url": "https://files.pythonhosted.org/packages/cf/1b/6bed9e6bfa136c8f987db190c3cf342cefef2b5a0929d6953f0dc8b4d108/mode-ng-0.6.1.tar.gz",
    "platform": null,
    "description": "=====================\nMode AsyncIO Services\n=====================\n\n|license| |wheel| |pyversion| |pyimp| |black|\n\n:Version: 0.6.1\n:Web: http://mode-ng.readthedocs.org/\n:Download: https://pypi.org/project/mode-ng\n:Source: https://github.com/lqhuang/mode-ng\n:Keywords: async, service, framework, actors, bootsteps, graph\n\n.. |license| image:: https://img.shields.io/pypi/l/mode-ng.svg\n    :alt: BSD License\n    :target: https://opensource.org/licenses/BSD-3-Clause\n.. |wheel| image:: https://img.shields.io/pypi/wheel/mode-ng.svg\n    :alt: Mode can be installed via wheel\n    :target: http://pypi.org/project/mode-ng/\n.. |pyversion| image:: https://img.shields.io/pypi/pyversions/mode-ng.svg\n    :alt: Supported Python versions.\n    :target: http://pypi.org/project/mode-ng/\n.. |pyimp| image:: https://img.shields.io/pypi/implementation/mode-ng.svg\n    :alt: Supported Python implementations.\n    :target: http://pypi.org/project/mode-ng/\n.. |black| image:: https://img.shields.io/badge/code_style-black-000000.svg?style=flat\n    :alt: Use ``black`` as code formatter\n    :target: https://github.com/psf/black\n\nWhy the fork\n============\n\nOriginal ``mode`` homepage: https://github.com/ask/mode. Thanks to its creator Ask Solem (@ask).\n\nFirst fork: ``mode-streaming``\n------------------------------\n\nProject homepage: https://github.com/faust-streaming/mode\n\nWe have decided to fork the original *Mode* project because there is a critical process of releasing new versions which causes uncertainty in the community. Everybody is welcome to contribute to this *fork*, and you can be added as a manitainer.\n\nWe want to:\n\n- Ensure continues release\n- Code quality\n- Support latest Python versions\n- Update the documentation\n\nand more...\n\nA new fork: ``mode-ng``\n-----------------------\n\n**WIP** notice. Welcome to try it in your programs and feedback!\n\nWell, here is an another fork for ``mode``. Generally, my target is to\ncreate an individual and separated repository to develop ``mode`` for next\nstage/generation and keep rolling forward fastly.\n\n``mode`` could be a very potential and powerful framework for various\napplications. So I very care about how ``faust-streaming`` and ``mode-streaming``\ngoes in future. Currently the most important thing in developing ``mode-streaming``\nis to fix bugs and keep back compatibility for ``faust-streaming``, it would be\nuncertain or not-willing to add new features. For now, one big problem is if I\ntry to continue working on current ``mode-streaming`` branch, it's hard to me\nto know its consequences in ``faust-streaming``. I don't want to introduce\nbreak changes and inconsistent behaviors.\n\nHence, ``mode-ng`` provides a new package to make some aggressive improvements, do some experiments,\nand do not consider compatible problems from ``faust-streaming``. At least,\n``mode-ng`` can be quickly used by more users with more advanced features to\nbuild their own applications. In the future, if this fork could be ported back\nto ``mode-streaming`` or used as base framework of ``faust-streaming``, that\nwould be really great!\n\nHere are some thoughts from practical experiences and what I want to do next step:\n\n- Bug fixes: yeah, why not.\n- Use standard library implementations: When mode was first developed,\n  many features haven't exist, so there are many hacks and tricky solutions in\n  ``mode`` codes. Like ``cached_property``, ``AsyncMock``, ``loop arguments``,\n  even ``Object`` class (missing some inner ``__xxx__`` attrs after redefinition).\n- Port some features from faust: ``web`` module in faust is really useful for\n  building application. With web part, ``mode`` is able to expose, control,\n  monitor and more from outside api.\n- Improve or complete left part of ``signal`` module: Some modules like ``Signal``\n  are unfinished. It will be useful for some observer patterns in programming.\n- Add some message commuting behaviors like real actors? (for thread serices?)\n- More documents and more examples\n\nWhy minimal supported Python version is ``3.10``?\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nIt's more like a personal flavor for now. But if we say ``py3.6`` bring us stable ``async/await`` syntax firstly to introduce wonderful coroutine concurrency, I thought ``py3.10`` would be the next major popular minimal supported version with a more matured ``asyncio`` api interfaces. From feedbacks from many real cases, ``asyncio`` interfaces have changed a lot. Happy news is it stabilized by development of std library. And Python 3.10 is faster than before, though Python is not a language which cares about speed, seldom people don't want to higher performance.\n\nThis is not absolute, it aslo depends how many people want back compatibility for older versions.\n\nInstallation\n============\n\nYou can install Mode either via the Python Package Index (PyPI)\nor from source.\n\nTo install using ``pip``:\n\n.. code:: console\n\n    $ pip install -U mode-ng\n\nDownloading and installing from source\n--------------------------------------\n\nDownload the latest version of Mode from http://pypi.org/project/mode-ng\n\nYou can install it by doing the following:\n\n.. code:: console\n\n    $ tar xvfz mode-ng-0.6.1.tar.gz\n    $ cd mode-0.6.1\n    $ python setup.py build\n    $ python setup.py install\n\nThe last command must be executed as a privileged user if\nyou are not currently using a virtualenv.\n\nUsing the development version\n-----------------------------\n\nWith pip\n~~~~~~~~\n\nYou can install the latest snapshot of Mode using the following\npip command:\n\n.. code:: console\n\n    $ pip install https://github.com/lqhuang/mode-ng/zipball/master#egg=mode-ng\n\nWhat is Mode?\n=============\n\nMode is a very minimal Python library built-on top of AsyncIO that makes\nit much easier to use.\n\nIn Mode your program is built out of services that you can start, stop,\nrestart and supervise.\n\nA service is just a class:\n\n.. code:: python\n\n    class PageViewCache(Service):\n        redis: Redis = None\n\n        async def on_start(self) -> None:\n            self.redis = connect_to_redis()\n\n        async def update(self, url: str, n: int = 1) -> int:\n            return await self.redis.incr(url, n)\n\n        async def get(self, url: str) -> int:\n            return await self.redis.get(url)\n\n\nServices are started, stopped and restarted and have\ncallbacks for those actions.\n\nIt can start another service:\n\n.. code:: python\n\n    class App(Service):\n        page_view_cache: PageViewCache = None\n\n        async def on_start(self) -> None:\n            await self.add_runtime_dependency(self.page_view_cache)\n\n        @cached_property\n        def page_view_cache(self) -> PageViewCache:\n            return PageViewCache()\n\nIt can include background tasks:\n\n.. code:: python\n\n    class PageViewCache(Service):\n\n        @Service.timer(1.0)\n        async def _update_cache(self) -> None:\n            self.data = await cache.get('key')\n\nServices that depends on other services actually form a graph\nthat you can visualize.\n\nWorker\n------\n\nMode optionally provides a worker that you can use to start the program,\nwith support for logging, blocking detection, remote debugging and more.\n\nTo start a worker add this to your program:\n\n.. code:: python\n\n    if __name__ == \"__main__\":\n        from mode import Worker\n        Worker(Service(), loglevel=\"info\").execute_from_commandline()\n\nThen execute your program to start the worker:\n\n.. code:: console\n\n    $ python examples/tutorial.py\n    [2018-03-27 15:47:12,159: INFO]: [^Worker]: Starting...\n    [2018-03-27 15:47:12,160: INFO]: [^-AppService]: Starting...\n    [2018-03-27 15:47:12,160: INFO]: [^--Websockets]: Starting...\n    STARTING WEBSOCKET SERVER\n    [2018-03-27 15:47:12,161: INFO]: [^--UserCache]: Starting...\n    [2018-03-27 15:47:12,161: INFO]: [^--Webserver]: Starting...\n    [2018-03-27 15:47:12,164: INFO]: [^--Webserver]: Serving on port 8000\n    REMOVING EXPIRED USERS\n    REMOVING EXPIRED USERS\n\nTo stop it hit ``Control-c``:\n\n.. code:: console\n\n    [2018-03-27 15:55:08,084: INFO]: [^Worker]: Stopping on signal received...\n    [2018-03-27 15:55:08,084: INFO]: [^Worker]: Stopping...\n    [2018-03-27 15:55:08,084: INFO]: [^-AppService]: Stopping...\n    [2018-03-27 15:55:08,084: INFO]: [^--UserCache]: Stopping...\n    REMOVING EXPIRED USERS\n    [2018-03-27 15:55:08,085: INFO]: [^Worker]: Gathering service tasks...\n    [2018-03-27 15:55:08,085: INFO]: [^--UserCache]: -Stopped!\n    [2018-03-27 15:55:08,085: INFO]: [^--Webserver]: Stopping...\n    [2018-03-27 15:55:08,085: INFO]: [^Worker]: Gathering all futures...\n    [2018-03-27 15:55:08,085: INFO]: [^--Webserver]: Closing server\n    [2018-03-27 15:55:08,086: INFO]: [^--Webserver]: Waiting for server to close handle\n    [2018-03-27 15:55:08,086: INFO]: [^--Webserver]: Shutting down web application\n    [2018-03-27 15:55:08,086: INFO]: [^--Webserver]: Waiting for handler to shut down\n    [2018-03-27 15:55:08,086: INFO]: [^--Webserver]: Cleanup\n    [2018-03-27 15:55:08,086: INFO]: [^--Webserver]: -Stopped!\n    [2018-03-27 15:55:08,086: INFO]: [^--Websockets]: Stopping...\n    [2018-03-27 15:55:08,086: INFO]: [^--Websockets]: -Stopped!\n    [2018-03-27 15:55:08,087: INFO]: [^-AppService]: -Stopped!\n    [2018-03-27 15:55:08,087: INFO]: [^Worker]: -Stopped!\n\nBeacons\n-------\n\nThe ``beacon`` object that we pass to services keeps track of the services\nin a graph.\n\nThey are not stricly required, but can be used to visualize a running\nsystem, for example we can render it as a pretty graph.\n\nThis requires you to have the ``pydot`` library and GraphViz\ninstalled:\n\n.. code:: console\n\n    $ pip install pydot\n\nLet's change the app service class to dump the graph to an image at startup:\n\n.. code:: python\n\n    class AppService(Service):\n\n        async def on_start(self) -> None:\n            print('APP STARTING')\n            import pydot\n            import io\n\n            o = io.StringIO()\n            beacon = self.app.beacon.root or self.app.beacon\n            beacon.as_graph().to_dot(o)\n            graph, = pydot.graph_from_dot_data(o.getvalue())\n\n            print('WRITING GRAPH TO image.png')\n            with open('image.png', 'wb') as fh:\n                fh.write(graph.create_png())\n\n\nCreating a Service\n==================\n\nTo define a service, simply subclass and fill in the methods\nto do stuff as the service is started/stopped etc.:\n\n.. code:: python\n\n    class MyService(Service):\n\n        async def on_start(self) -> None:\n            print('Im starting now')\n\n        async def on_started(self) -> None:\n            print('Im ready')\n\n        async def on_stop(self) -> None:\n            print('Im stopping now')\n\nTo start the service, call ``await service.start()``:\n\n.. code:: python\n\n    await service.start()\n\nOr you can use ``mode.Worker`` (or a subclass of this) to start your\nservices-based asyncio program from the console:\n\n.. code:: python\n\n    if __name__ == '__main__':\n        import mode\n        worker = mode.Worker(\n            MyService(),\n            loglevel='INFO',\n            logfile=None,\n            daemon=False,\n        )\n        worker.execute_from_commandline()\n\nIt's a Graph!\n=============\n\nServices can start other services, coroutines, and background tasks.\n\n1) Starting other services using ``add_depenency``:\n\n.. code:: python\n\n    class MyService(Service):\n\n        def __post_init__(self) -> None:\n           self.add_dependency(OtherService(loop=self.loop))\n\n2) Start a list of services using ``on_init_dependencies``:\n\n.. code:: python\n\n    class MyService(Service):\n\n        def on_init_dependencies(self) -> None:\n            return [\n                ServiceA(loop=self.loop),\n                ServiceB(loop=self.loop),\n                ServiceC(loop=self.loop),\n            ]\n\n3) Start a future/coroutine (that will be waited on to complete on stop):\n\n.. code:: python\n\n    class MyService(Service):\n\n        async def on_start(self) -> None:\n            self.add_future(self.my_coro())\n\n        async def my_coro(self) -> None:\n            print('Executing coroutine')\n\n4) Start a background task:\n\n.. code:: python\n\n    class MyService(Service):\n\n        @Service.task\n        async def _my_coro(self) -> None:\n            print('Executing coroutine')\n\n\n5) Start a background task that keeps running:\n\n.. code:: python\n\n    class MyService(Service):\n\n        @Service.task\n        async def _my_coro(self) -> None:\n            while not self.should_stop:\n                # NOTE: self.sleep will wait for one second, or\n                #       until service stopped/crashed.\n                await self.sleep(1.0)\n                print('Background thread waking up')\n\nFAQ\n===\n\nCan I use Mode with Django/Flask/etc.?\n--------------------------------------\n\nYes! Use gevent/eventlet as a bridge to integrate with asyncio.\n\nUsing ``gevent``\n~~~~~~~~~~~~~~~~\n\nThis works with any blocking Python library that can work with gevent.\n\nUsing gevent requires you to install the ``aiogevent`` module,\nand you can install this as a bundle with Mode:\n\n.. code:: console\n\n    $ pip install -U mode-ng[gevent]\n\nThen to actually use gevent as the event loop you have to\nexecute the following in your entrypoint module (usually where you\nstart the worker), before any other third party libraries are imported:\n\n.. code:: python\n\n    #!/usr/bin/env python3\n    import mode.loop\n    mode.loop.use('gevent')\n    # execute program\n\nREMEMBER: This must be located at the very top of the module,\nin such a way that it executes before you import other libraries.\n\nUsing ``eventlet``\n~~~~~~~~~~~~~~~~~~\n\nThis works with any blocking Python library that can work with eventlet.\n\nUsing eventlet requires you to install the ``aioeventlet`` module,\nand you can install this as a bundle with Mode:\n\n.. code:: console\n\n    $ pip install -U mode-ng[eventlet]\n\nThen to actually use eventlet as the event loop you have to\nexecute the following in your entrypoint module (usually where you\nstart the worker), before any other third party libraries are imported:\n\n.. code:: python\n\n    #!/usr/bin/env python3\n    import mode.loop\n    mode.loop.use('eventlet')\n    # execute program\n\nREMEMBER: It's very important this is at the very top of the module,\nand that it executes before you import libraries.\n\nCan I use Mode with Tornado?\n----------------------------\n\nYes! Use the ``tornado.platform.asyncio`` bridge:\nhttp://www.tornadoweb.org/en/stable/asyncio.html\n\nCan I use Mode with Twisted?\n-----------------------------\n\nYes! Use the asyncio reactor implementation:\nhttps://twistedmatrix.com/documents/17.1.0/api/twisted.internet.asyncioreactor.html\n\nAt Shutdown I get lots of warnings, what is this about?\n-------------------------------------------------------\n\nIf you get warnings such as this at shutdown:\n\n.. code:: text\n\n    Task was destroyed but it is pending!\n    task: <Task pending coro=<Service._execute_task() running at /opt/devel/mode/mode/services.py:643> wait_for=<Future pending cb=[<TaskWakeupMethWrapper object at 0x1100a7468>()]>>\n    Task was destroyed but it is pending!\n    task: <Task pending coro=<Service._execute_task() running at /opt/devel/mode/mode/services.py:643> wait_for=<Future pending cb=[<TaskWakeupMethWrapper object at 0x1100a72e8>()]>>\n    Task was destroyed but it is pending!\n    task: <Task pending coro=<Service._execute_task() running at /opt/devel/mode/mode/services.py:643> wait_for=<Future pending cb=[<TaskWakeupMethWrapper object at 0x1100a7678>()]>>\n    Task was destroyed but it is pending!\n    task: <Task pending coro=<Event.wait() running at /Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/asyncio/locks.py:269> cb=[_release_waiter(<Future pendi...1100a7468>()]>)() at /Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/asyncio/tasks.py:316]>\n    Task was destroyed but it is pending!\n        task: <Task pending coro=<Event.wait() running at /Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/asyncio/locks.py:269> cb=[_release_waiter(<Future pendi...1100a7678>()]>)() at /Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/asyncio/tasks.py:316]>\n\nIt usually means you forgot to stop a service before the process exited.\n\n\nContributing\n============\n\nFor guidance on setting up a development environment and how to make a contribution\nto `mode-ng`, see the `contributing guidelines`_.\n\n.. _contributing guidelines: https://github.com/lqhuang/mode-ng/blob/master/CONTRIBUTING.md\n\nCode of Conduct\n===============\n\nCheck `code of conduct`_ for recommended or discouraged behaviors while communicating.\n\n.. _code of conduct: https://github.com/lqhuang/mode-ng/blob/master/CODE_OF_CONDUCT.md\n",
    "bugtrack_url": null,
    "license": "BSD 3-Clause License",
    "summary": "AsyncIO Service-based programming.",
    "version": "0.6.1",
    "project_urls": {
        "homepage": "https://github.com/lqhuang/mode-ng"
    },
    "split_keywords": [
        "asyncio",
        "service",
        "bootsteps",
        "graph",
        "coroutine",
        "actor"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "95e62cd61c3e9791d4342c8069fcff65fd7b1879243b966a9ecfdd1df23adfd2",
                "md5": "41ab777e8643ea23c68c93a5952ae039",
                "sha256": "ade9aa3e3e15b2a66139ce3f6d39fb68e03b4aee51ea49137378fdd86c2f1b4e"
            },
            "downloads": -1,
            "filename": "mode_ng-0.6.1-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "41ab777e8643ea23c68c93a5952ae039",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.10",
            "size": 93342,
            "upload_time": "2022-12-08T09:49:20",
            "upload_time_iso_8601": "2022-12-08T09:49:20.294202Z",
            "url": "https://files.pythonhosted.org/packages/95/e6/2cd61c3e9791d4342c8069fcff65fd7b1879243b966a9ecfdd1df23adfd2/mode_ng-0.6.1-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "cf1b6bed9e6bfa136c8f987db190c3cf342cefef2b5a0929d6953f0dc8b4d108",
                "md5": "78827300f5b6f024db2119d66169f25d",
                "sha256": "f6d42e831660a31e155fed69e920147680749e5f625cc9e35e660fcc799960bd"
            },
            "downloads": -1,
            "filename": "mode-ng-0.6.1.tar.gz",
            "has_sig": false,
            "md5_digest": "78827300f5b6f024db2119d66169f25d",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.10",
            "size": 263459,
            "upload_time": "2022-12-08T09:49:24",
            "upload_time_iso_8601": "2022-12-08T09:49:24.417045Z",
            "url": "https://files.pythonhosted.org/packages/cf/1b/6bed9e6bfa136c8f987db190c3cf342cefef2b5a0929d6953f0dc8b4d108/mode-ng-0.6.1.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2022-12-08 09:49:24",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "lqhuang",
    "github_project": "mode-ng",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "tox": true,
    "lcname": "mode-ng"
}
        
Elapsed time: 0.23528s