123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248 |
- Metadata-Version: 2.1
- Name: asgiref
- Version: 3.4.1
- Summary: ASGI specs, helper code, and adapters
- Home-page: https://github.com/django/asgiref/
- Author: Django Software Foundation
- Author-email: foundation@djangoproject.com
- License: BSD
- Project-URL: Documentation, https://asgi.readthedocs.io/
- Project-URL: Further Documentation, https://docs.djangoproject.com/en/stable/topics/async/#async-adapter-functions
- Project-URL: Changelog, https://github.com/django/asgiref/blob/master/CHANGELOG.txt
- Platform: UNKNOWN
- Classifier: Development Status :: 5 - Production/Stable
- Classifier: Environment :: Web Environment
- Classifier: Intended Audience :: Developers
- Classifier: License :: OSI Approved :: BSD License
- Classifier: Operating System :: OS Independent
- Classifier: Programming Language :: Python
- Classifier: Programming Language :: Python :: 3
- Classifier: Programming Language :: Python :: 3 :: Only
- Classifier: Programming Language :: Python :: 3.6
- Classifier: Programming Language :: Python :: 3.7
- Classifier: Programming Language :: Python :: 3.8
- Classifier: Programming Language :: Python :: 3.9
- Classifier: Topic :: Internet :: WWW/HTTP
- Requires-Python: >=3.6
- License-File: LICENSE
- Requires-Dist: typing-extensions ; python_version < "3.8"
- Provides-Extra: tests
- Requires-Dist: pytest ; extra == 'tests'
- Requires-Dist: pytest-asyncio ; extra == 'tests'
- Requires-Dist: mypy (>=0.800) ; extra == 'tests'
- asgiref
- =======
- .. image:: https://api.travis-ci.org/django/asgiref.svg
- :target: https://travis-ci.org/django/asgiref
- .. image:: https://img.shields.io/pypi/v/asgiref.svg
- :target: https://pypi.python.org/pypi/asgiref
- ASGI is a standard for Python asynchronous web apps and servers to communicate
- with each other, and positioned as an asynchronous successor to WSGI. You can
- read more at https://asgi.readthedocs.io/en/latest/
- This package includes ASGI base libraries, such as:
- * Sync-to-async and async-to-sync function wrappers, ``asgiref.sync``
- * Server base classes, ``asgiref.server``
- * A WSGI-to-ASGI adapter, in ``asgiref.wsgi``
- Function wrappers
- -----------------
- These allow you to wrap or decorate async or sync functions to call them from
- the other style (so you can call async functions from a synchronous thread,
- or vice-versa).
- In particular:
- * AsyncToSync lets a synchronous subthread stop and wait while the async
- function is called on the main thread's event loop, and then control is
- returned to the thread when the async function is finished.
- * SyncToAsync lets async code call a synchronous function, which is run in
- a threadpool and control returned to the async coroutine when the synchronous
- function completes.
- The idea is to make it easier to call synchronous APIs from async code and
- asynchronous APIs from synchronous code so it's easier to transition code from
- one style to the other. In the case of Channels, we wrap the (synchronous)
- Django view system with SyncToAsync to allow it to run inside the (asynchronous)
- ASGI server.
- Note that exactly what threads things run in is very specific, and aimed to
- keep maximum compatibility with old synchronous code. See
- "Synchronous code & Threads" below for a full explanation. By default,
- ``sync_to_async`` will run all synchronous code in the program in the same
- thread for safety reasons; you can disable this for more performance with
- ``@sync_to_async(thread_sensitive=False)``, but make sure that your code does
- not rely on anything bound to threads (like database connections) when you do.
- Threadlocal replacement
- -----------------------
- This is a drop-in replacement for ``threading.local`` that works with both
- threads and asyncio Tasks. Even better, it will proxy values through from a
- task-local context to a thread-local context when you use ``sync_to_async``
- to run things in a threadpool, and vice-versa for ``async_to_sync``.
- If you instead want true thread- and task-safety, you can set
- ``thread_critical`` on the Local object to ensure this instead.
- Server base classes
- -------------------
- Includes a ``StatelessServer`` class which provides all the hard work of
- writing a stateless server (as in, does not handle direct incoming sockets
- but instead consumes external streams or sockets to work out what is happening).
- An example of such a server would be a chatbot server that connects out to
- a central chat server and provides a "connection scope" per user chatting to
- it. There's only one actual connection, but the server has to separate things
- into several scopes for easier writing of the code.
- You can see an example of this being used in `frequensgi <https://github.com/andrewgodwin/frequensgi>`_.
- WSGI-to-ASGI adapter
- --------------------
- Allows you to wrap a WSGI application so it appears as a valid ASGI application.
- Simply wrap it around your WSGI application like so::
- asgi_application = WsgiToAsgi(wsgi_application)
- The WSGI application will be run in a synchronous threadpool, and the wrapped
- ASGI application will be one that accepts ``http`` class messages.
- Please note that not all extended features of WSGI may be supported (such as
- file handles for incoming POST bodies).
- Dependencies
- ------------
- ``asgiref`` requires Python 3.6 or higher.
- Contributing
- ------------
- Please refer to the
- `main Channels contributing docs <https://github.com/django/channels/blob/master/CONTRIBUTING.rst>`_.
- Testing
- '''''''
- To run tests, make sure you have installed the ``tests`` extra with the package::
- cd asgiref/
- pip install -e .[tests]
- pytest
- Building the documentation
- ''''''''''''''''''''''''''
- The documentation uses `Sphinx <http://www.sphinx-doc.org>`_::
- cd asgiref/docs/
- pip install sphinx
- To build the docs, you can use the default tools::
- sphinx-build -b html . _build/html # or `make html`, if you've got make set up
- cd _build/html
- python -m http.server
- ...or you can use ``sphinx-autobuild`` to run a server and rebuild/reload
- your documentation changes automatically::
- pip install sphinx-autobuild
- sphinx-autobuild . _build/html
- Releasing
- '''''''''
- To release, first add details to CHANGELOG.txt and update the version number in ``asgiref/__init__.py``.
- Then, build and push the packages::
- python -m build
- twine upload dist/*
- rm -r build/ dist/
- Implementation Details
- ----------------------
- Synchronous code & threads
- ''''''''''''''''''''''''''
- The ``asgiref.sync`` module provides two wrappers that let you go between
- asynchronous and synchronous code at will, while taking care of the rough edges
- for you.
- Unfortunately, the rough edges are numerous, and the code has to work especially
- hard to keep things in the same thread as much as possible. Notably, the
- restrictions we are working with are:
- * All synchronous code called through ``SyncToAsync`` and marked with
- ``thread_sensitive`` should run in the same thread as each other (and if the
- outer layer of the program is synchronous, the main thread)
- * If a thread already has a running async loop, ``AsyncToSync`` can't run things
- on that loop if it's blocked on synchronous code that is above you in the
- call stack.
- The first compromise you get to might be that ``thread_sensitive`` code should
- just run in the same thread and not spawn in a sub-thread, fulfilling the first
- restriction, but that immediately runs you into the second restriction.
- The only real solution is to essentially have a variant of ThreadPoolExecutor
- that executes any ``thread_sensitive`` code on the outermost synchronous
- thread - either the main thread, or a single spawned subthread.
- This means you now have two basic states:
- * If the outermost layer of your program is synchronous, then all async code
- run through ``AsyncToSync`` will run in a per-call event loop in arbitrary
- sub-threads, while all ``thread_sensitive`` code will run in the main thread.
- * If the outermost layer of your program is asynchronous, then all async code
- runs on the main thread's event loop, and all ``thread_sensitive`` synchronous
- code will run in a single shared sub-thread.
- Crucially, this means that in both cases there is a thread which is a shared
- resource that all ``thread_sensitive`` code must run on, and there is a chance
- that this thread is currently blocked on its own ``AsyncToSync`` call. Thus,
- ``AsyncToSync`` needs to act as an executor for thread code while it's blocking.
- The ``CurrentThreadExecutor`` class provides this functionality; rather than
- simply waiting on a Future, you can call its ``run_until_future`` method and
- it will run submitted code until that Future is done. This means that code
- inside the call can then run code on your thread.
- Maintenance and Security
- ------------------------
- To report security issues, please contact security@djangoproject.com. For GPG
- signatures and more security process information, see
- https://docs.djangoproject.com/en/dev/internals/security/.
- To report bugs or request new features, please open a new GitHub issue.
- This repository is part of the Channels project. For the shepherd and maintenance team, please see the
- `main Channels readme <https://github.com/django/channels/blob/master/README.rst>`_.
|