ASGI specification and utilities

Related tags

WSGI Servers asgiref
Overview

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.

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.

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:

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

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.

Cruicially, 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 [email protected]. 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.

Comments
  • On ASGI's double-callable interface.

    On ASGI's double-callable interface.

    This isn't intended as an actionable point right now, rather just a point of conversation. I think it's worth bringing up given that ASGI is pre-PEP at this point. (And that we might still just about be at a point where we could adapt things if we felt it worthwhile enough.)

    I'm starting to wonder (again) if the double-callable structure if neccessarily a better trade-off than a single-callable. eg. the difference between:

    ASGI as it stands:

    class App:
        def __init__(self, scope):
            self.scope = scope
    
        async def __call__(self, receive, send):
            await send({
                'type': 'http.response.start',
                'status': 200,
                'headers': [
                    [b'content-type', b'text/plain'],
                ]
            })
            await send({
                'type': 'http.response.body',
                'body': b'Hello, world!',
            })
    

    An alternative interface:

    async def app(scope, receive, send):
        await send({
            'type': 'http.response.start',
            'status': 200,
            'headers': [
                [b'content-type', b'text/plain'],
            ]
        })
        await send({
            'type': 'http.response.body',
            'body': b'Hello, world!',
        })
    

    The double-callable does allow classes to directly implement the ASGI interface, and for class based endpoint implementations it ends up being simpler.

    However it's more complex for function based endpoint implementations, for middleware implementation patterns, and for instantiate-to-configure application implementations.

    In each of those cases you end up either with a closure around an inner function, or partially-bound functools.partial. Both of those cases make for less easy-to-understand concepts and more awkward flows.

    E.g. A typical middleware pattern with ASGI...

    class Middleware:
        def __init__(self, app, **middleware_config):
            self.app = app
            ...
    
        def __call__(self, scope):
            return functools.partial(self.asgi, scope=scope)
    
        async def asgi(self, receive, send, scope):
            ...
    

    An alternative:

    class Middleware:
        def __init__(self, app, **middleware_config):
            self.app = app
            ...
    
        async def __call__(self, scope, receive, send):
            ...
    

    Similarly with instantiate-to-configure ASGI applications, you currently end up having to return a partially bound method:

    StaticFiles as ASGI...

    class StaticFiles:
        def __init__(self, directory):
            self.directory = directory
            ...
    
        def __call__(self, scope):
            return functools.partial(self.asgi, scope=scope)
    
        async def asgi(self, receive, send, scope):
            ...
    

    Alternative:

    class StaticFiles:
        def __init__(self, directory):
            self.directory = directory
            ...
    
        async def __call__(self, scope, receive, send):
            ...
    

    The flip side with a single-callable is that you can't point directly at a class as an ASGI interface. For endpoint implementations, you end up needing to do something like this pattern instead...

    class App:
        def __init__(self, scope, receive, send):
            self.scope = scope
            self.receive = receive
            self.send = send
    
        async def dispatch(self):
            await self.send({'type': 'http.response.start', ...})
            await self.send({'type': 'http.response.body', ...})
    
        @classmethod
        async def asgi(cls, scope, receive, send):
            instance = cls(scope, receive, send)
            await instance.dispatch()
    
    # app = App.asgi
    

    This all starts matters a little in Starlette, where ASGI is the interface all the way through - you end up with a more complex flow, and less easy-to-understand primitives. It also ends up with more indirect tracebacks.

    (I noticed this in particular when considering how to improve the stack traces for 500 responses. I was hoping to delimit each frame as "Inside the middleware stack", "Inside the router", "Inside the endpoint" - that's easy to do if the traceback frames match up directly to the ASGI functions themselves, but it's not do-able if the frames are from a function that's been returned from another function.)

    Anyways, not asking for any action on this neccessarily, but it's something I've been thinking over that I wanted to make visible while ASGI is still pre-PEP.

    opened by tomchristie 38
  • REMOTE_USER support

    REMOTE_USER support

    The CGI RFC provides for a REMOTE_USER variable, which holds the username of the user who has been authenticated by the front-end Web server. For a WSGI application, this can be obtained as environ["REMOTE_USER"], since a WSGI application gets access to all CGI variables. It would be nice if an ASGI application could get access to the same thing.

    opened by Hawk777 27
  • Excessive use of asgiref.local and sync_to_async breaks other context local implementations

    Excessive use of asgiref.local and sync_to_async breaks other context local implementations

    I am writing on behalf of my employer, sentry.io.

    I am not sure whether this issue should be filed against Django or asgiref. Starting with Django 3.1, signal handlers for got_request_exception are executed with the wrong contextvars context when running as part of an ASGI request. This can be easily demonstrated by wrapping the Django ASGI app in a middleware that stores something on the context, and trying to retreive that same value from that signal handler.

    This is how I became aware of Django's custom context local implementation that is shipped as part of asgiref. I understand why you do the things you do, but consider that this will break a lot of tracing tooling for Python that may only be orthogonal to Django or ASGI. The situation around context locals is already awful enough, it would be terrible if Sentry and tools like it had to implement a codepath specifically for Django 3 applications, or anything that uses asgiref.local.

    I can see the following options:

    1. avoid releasing Django 3.1 with whatever changes just happened that made errorhandlers execute in the wrong contextvars context. Considering that Django 3.1 is already in alpha I would at least consider this as a stopgap measure.
    2. modify asgiref.sync_to_async and its inverse to "drive" contextvars if they are available such that contextvars always behave identically to asgiref.local
    3. drop asgiref.local entirely and swap it out for the aiocontextvars package on PyPI, as the primary purpose of implementing asgiref.local from scratch seemed to have been to support Python 3.6. One would still have to implement 2) for this to work, but the advantage here is that aiocontextvars seems to be significantly more popular across frameworks than asgiref.local.

    Those options are not mutually exclusive.

    Thanks for considering.

    opened by untitaker 25
  • [RFC] add lifespan.shutdown.notice event

    [RFC] add lifespan.shutdown.notice event

    Hi 👋 and thanks for the excellent specification! I would like to propose a change to allow looping endpoints to cleanly exit when an ASGI application shuts down.

    Use Case

    An ASGI application exposes an indefinitely looping endpoint using Server-Sent Events to push unidirectional data to browser clients without client polling or WebSockets.

    Example

    A counter event-stream sends incrementing numbers to a connected client until they disconnect, or the server shuts down.

    import asyncio
    
    state = {"should_exit": False, "counter": 0}
    
    
    async def is_disconnected(receive) -> bool:
        """Check for a "http.disconnect" message"""
        receive_task = asyncio.create_task(receive())
        try:
            await asyncio.wait_for(receive_task, 1)
            message = receive_task.result()
            if message["type"] == "http.disconnect":
                print("disconnect received")
                return True
        except asyncio.TimeoutError:
            receive_task.cancel()
        return False
    
    
    async def lifespan(scope, receive, send):
        """Handle lifespan events"""
        while True:
            message = await receive()
            if message["type"] == "lifespan.startup":
                print("startup received")
                await send({"type": "lifespan.startup.complete"})
            elif message["type"] == "lifespan.shutdown.notice":
                state["should_exit"] = True
                print("shutdown notice received")
            elif message["type"] == "lifespan.shutdown":
                print("shutdown received")
                await send({"type": "lifespan.shutdown.complete"})
                return
    
    
    async def http(scope, receive, send):
        message = await receive()
        assert message["type"] == "http.request"
    
        while message.get("more_body"):
            message = await receive()
    
        await send(
            {
                "type": "http.response.start",
                "status": 200,
                "headers": [
                    (b"cache-control", b"no-cache"),
                    (b"content-type", b"text/event-stream"),
                    (b"connection", b"keep-alive"),
                ],
            }
        )
    
        while True:
            await send(
                {
                    "type": "http.response.body",
                    "body": f"data: {state['counter']}\n\n".encode("utf-8"),
                    "more_body": True,
                }
            )
            state["counter"] += 1
            # Check to see if the client disconnected
            if await is_disconnected(receive):
                break
            else:
                print(f"counter = {state['counter']}")
    
            # The lifespan.shutdown.notice event fired
            if state["should_exit"]:
                print("shutdown notice received, exiting loop")
                await send(
                    {
                        "type": "http.response.body",
                        "more_body": False,
                    }
                )
                break
    
            await asyncio.sleep(3)
    
    
    async def app(scope, receive, send):
        if scope["type"] == "lifespan":
            await lifespan(scope, receive, send)
        elif scope["type"] == "http":
            await http(scope, receive, send)
    
    

    Problem

    With version 2.0 of the lifespan extension, this app can't terminate gracefully without going outside the spec, because the lifespan.shutdown event fires "when the server has stopped accepting connections and closed all active connections."

    In most cases, firing a shutdown event after all connections have been closed is fine because requests complete and return. However, when you have looping applications that need to break on shutdown, they can't add shutdown handlers to trigger the breakout because they won't fire until the connection has exited.

    Proposal

    I explored the minimal changes to support this use-case. Creating a new event looks like the lowest impact way of adding support for signaling connections to gracefully exit. It limits the breakage in existing ASGI frameworks by leaving the "and closed all active connections" requirement for firing shutdown while allowing for looping endpoints to exit during application shutdown.

    opened by justindujardin 18
  • Provide raw path / URI

    Provide raw path / URI

    The path currently gets unquoted / percent-decoded, which results in unrecoverable loss of information: a request to /foo/bar is the same as /foo%2Fbar.

    With WSGI there seems to exist workarounds via RAW_URI / REQUEST_URI (e.g. in gunicorn, https://github.com/etianen/aiohttp-wsgi/pull/17).

    I think it would be nice to have raw_path officially in the spec. I am not sure if it should be a unicode string, or bytes (to avoid another field later on).

    (I do not think that raw_uri (path + query info) is necessary, since query_string is already given as bytes)

    Current spec: https://asgi.readthedocs.io/en/latest/specs/www.html#id1 (Via https://github.com/encode/uvicorn/pull/354)

    blocked/user-response 
    opened by blueyed 18
  • Proposal:

    Proposal: "http.response.template" extension.

    In situations where an application server is happens to be returning template-rendered data, it's hugely valuable for the template and context information to be sent in the ASGI messaging, alongside the actual rendered content.

    Right now we use this in Starlette, so that an ASGI-based test client is able to provide response.template and response.context information back to the user.

    Formalising this, would allow us to support this kind of usage:

    # This client calls directly into an ASGI app, rather than making network requests.
    client = httpx.AsyncClient(app=app)
    
    # Make the request.
    response = await client.get("http://testserver/")
    assert response.status_code == 200
    
    # This information is made available through the "http.response.template" extension.
    # Ensure that we're on the homepage, and that no messages are displayed.
    assert response.template == "homepage.html"
    assert response.context["user_messages"] == []
    

    It's not totally obvious if an extension such as this should strictly focus on template/context info, or if there's a more general purpose "extra info" extension that ought to be considered here, but I figure it's worth opening this for discussion.

    Informally, here's ~how the existing Starlette implementation looks...

    # If the ASGI `http.response.template` extension is supported,
    # then we can send this style of message...
    {
        "type": "http.response.template",
        "template": "homepage.html",
        "context": {"user_messages": []}
    }
    
    opened by tomchristie 17
  • Provide the un-%-decoded path

    Provide the un-%-decoded path

    As far as I can tell, ASGI follows the precedent set by WSGI in providing only a %-decoded string representation of the path. I believe this is a mistake. In particular, %2F is not a path separator by the URI RFC, but an application can't tell it apart from /.

    I suggest either providing a raw_path byte string, or deserializing the path properly and passing it as a list.

    opened by edk0 17
  • [possible bug] 'code' is not labeled as optional

    [possible bug] 'code' is not labeled as optional

    In https://asgi.readthedocs.io/en/latest/specs/www.html#disconnect-receive-event-ws it does not say code is optional, yet it says "as per websocket spec", where code is optional ("may contain"). Later on in Close - send event it explicitly mentions that the code there is optional. In the first link should code be optional or required?

    If code is optional I would be happy to submit a PR to this repo to update the docs.

    This is not just a theoretical question, as we are facing a bug that may be related to this. In https://github.com/django/channels/blob/38324816c115567e198a573bc294d8345df5e8a9/channels/generic/websocket.py#L105 channels assumes that the code key exists, but in our case it doesn't exist and a KeyError is raised.

    opened by caleb15 16
  • v3.4.x get_running_loop break django-channels runworker

    v3.4.x get_running_loop break django-channels runworker

    get_running_loop raise RuntimeError with any django-channels runworker command because there is no running event loop...

    patch?

    diff --git a/asgiref/server.py b/asgiref/server.py
    index fb1c394..d1d27f4 100644
    --- a/asgiref/server.py
    +++ b/asgiref/server.py
    @@ -56,8 +56,8 @@ class StatelessServer:
             """
             Runs the asyncio event loop with our handler loop.
             """
    -        event_loop = get_running_loop()
    -        asyncio.ensure_future(self.application_checker())
    +        event_loop = asyncio.get_event_loop()
    +        asyncio.ensure_future(self.application_checker(), loop=event_loop)
             try:
                 event_loop.run_until_complete(self.handle())
             except KeyboardInterrupt:
    
    opened by lsaavedr 15
  • version 3.3.0 hang problem

    version 3.3.0 hang problem

    When I upgrade from version 3.2.10 to 3.3.0(daphne:2.5.0, python:3.8.2, django:2.2.16), the server looks like hang there randomly, no error info found in access.log and asgi.log.

    the supervisord.conf as follow:

    [fcgi-program:om]
    directory=./
    socket=tcp://0.0.0.0:8000
    command=daphne -u ./daphne%(process_num)d.sock --fd 0 --access-log ./logs/access.log --proxy-headers MyProject.asgi:application
    numprocs=4
    process_name=asgi%(process_num)d
    stdout_logfile=./logs/asgi.log
    redirect_stderr=true
    

    Now, I downgrade to 3.2.10, everything is OK.

    Maybe modification about thread has some bugs or something I should do to adapt it.

    opened by belongwqz 14
  • WWW Spec changes

    WWW Spec changes

    WWW Spec: Allow for a HTTP response before Websocket handshake acceptance

    This allows HTTP responses such as 401, authentication required to be sent to the client by a framework that requires authenticated websocket connections. It would also allow for redirect responses or other more exotic framework responses.

    WWW Spec: Add a server push message

    This specifies how a client should indicate that a HTTP/2 server push should be initiated.

    opened by pgjones 14
  • Nested sync_to_async(thread_sensitive=True) calls do not run in the same thread.

    Nested sync_to_async(thread_sensitive=True) calls do not run in the same thread.

    While testing, I noticed that nesting calls to async_to_sync and sync_to_async causes two calls to sync_to_async(thread_sensitive=True) to run in different threads if you call sync_to_async(thread_sensitive=False) in between those two calls. It seems that once sync_to_async is called with thread_sensitive=False, all subsequent (nested) calls with thread_sensitive=True will run on the new parent thread rather than the main thread.

    Example Code

    import threading
    from asgiref.sync import async_to_sync, sync_to_async
    
    
    def method5():
        print(f"Third call to sync_to_sync: {threading.get_ident()}")
    
    
    async def method4():
        print(f"Third call to async_to_sync: {threading.get_ident()}")
        await sync_to_async(method5)()
    
    
    def method3():
        print(f"Second call to sync_to_async: {threading.get_ident()}")
        async_to_sync(method4)()
    
    
    async def method2():
        print(f"Second call to async_to_sync: {threading.get_ident()}")
        await sync_to_async(method3, thread_sensitive=False)()
    
    
    def method1():
        print(f"First call to sync_to_async: {threading.get_ident()}")
        async_to_sync(method2)()
    
    
    async def start():
        print(f"First call to async_to_sync: {threading.get_ident()}")
        await sync_to_async(method1)()
    
    print(f"Main thread: {threading.get_ident()}")
    async_to_sync(start)()
    

    Output

    Main thread: 4593313280
    First call to async_to_sync: 123145368514560
    First call to sync_to_async: 4593313280
    Second call to async_to_sync: 123145368514560
    Second call to sync_to_async: 123145373769728
    Third call to async_to_sync: 123145368514560
    Third call to sync_to_sync: 123145373769728
    

    As you can see, the main thread is 4593313280. The first call to sync_to_async(thread_sensitive=True) runs on the main thread, as expected. The second call to sync_to_async(thread_sensitive=False) creates a new thread (123145373769728), as expected. However, the third and fourth calls to sync_to_async(thread_sensitive=True) run on thread 123145373769728 rather than the main thread.

    This seems to contradict the behavior described in the README:

    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)

    Is this a bug? Or is this expected behavior, and merely a gap in the documentation?

    Thanks! Charlie

    opened by charliesteele 1
  • sync_to_async calls hang / deadlock when called in a task

    sync_to_async calls hang / deadlock when called in a task

    I ran into a weird deadlock when writing a django async view and trying to use asyncio.wait_for() in conjunction with sync_to_async to call a sync function but timeout if it takes longer than a few seconds. Internally, wait_for() creates a couple of async tasks using create_task(). So calling create_task() on the return of sync_to_async hangs forever.

    Here's a simple asgi application that reproduces the problem. I'm on asgiref 3.5.2, and I've tested this with both daphne and uvicorn. The swing between the async context and the sync context is meant to replicate the control flow used in django if you have a sync middleware in your middleware stack.

    import asyncio
    
    from asgiref.sync import sync_to_async, async_to_sync, ThreadSensitiveContext
    
    
    def some_sync_function():
        print("Some_sync_function")
    
    
    async def django_async_view():
        print("django_async_view")
        # Works:
        #await sync_to_async(some_sync_function)()
    
        # Doesn't work, times out:
        await asyncio.wait_for(sync_to_async(some_sync_function, thread_sensitive=True)(), timeout=5)
    
        # Also doesn't work, hangs forever:
        #await asyncio.create_task(sync_to_async(some_sync_function, thread_sensitive=True)())
    
    
    def django_sync_middleware():
        print("django_sync_middleware")
        async_to_sync(django_async_view)()
    
    
    async def application(scope, receive, send):
    
        # Gets a "Single thread executor already being used, would deadlock" error
        #await sync_to_async(django_sync_middleware, thread_sensitive=True)()
    
        # Gets an asyncio.TimeoutError:
        async with ThreadSensitiveContext():
            await sync_to_async(django_sync_middleware, thread_sensitive=True)()
    
        await send(
            {
                "type": "http.response.start",
                "status": 200,
                "headers": [
                    (b"content-type", b"text/plain"),
                ],
            }
        )
        await send(
            {
                "type": "http.response.body",
                "body": b"Hello, world!",
            }
        )
    

    Am I doing something wrong? Or is this a bug?

    opened by brownan 4
  • Example apps in docs

    Example apps in docs

    The spec currently defines a lot of details without any example apps (except in the lifespan section). It would be good to include basic examples, perhaps function and class versions for both full apps and middleware.

    opened by adamchainz 4
  • Should frameworks change scope values?

    Should frameworks change scope values?

    See https://github.com/pgjones/hypercorn/issues/75 where Starlette changes the scope["path"], should ASGI frameworks do this or consider the existing values immutable? (I don't think the specification says - I may work around by passing a copy to the framework)

    opened by pgjones 4
  • RE: Add HTTP Trailers

    RE: Add HTTP Trailers

    There is already a PR open regarding this. I wanted to open this to add options to the discussion. I did the uvicorn implementation.

    As stated in the other proposal PR this works a bit differently. This adds a new message type http.response.trailers and a new trailers bool property to http.response.start. IMO this simplifies the implementation.

    My original POC did not account for chunked trailers but this would be easy to add with a more_trailers property similar to the more_body property.

    Personally I like the more_body being set to false when the body is done and trailers being sent after. It makes more sense to me, but at the end of the day if any trailers get added I will be happy.

    opened by sam-kleiner 1
AWS Lambda & API Gateway support for ASGI

Mangum Mangum is an adapter for using ASGI applications with AWS Lambda & API Gateway. It is intended to provide an easy-to-use, configurable wrapper

Jordan Eremieff 1.2k Jan 6, 2023
Hypothesis is a powerful, flexible, and easy to use library for property-based testing.

Hypothesis Hypothesis is a family of testing libraries which let you write tests parametrized by a source of examples. A Hypothesis implementation the

Hypothesis 6.4k Jan 1, 2023
Generic automation framework for acceptance testing and RPA

Robot Framework Introduction Installation Example Usage Documentation Support and contact Contributing License Introduction Robot Framework is a gener

Robot Framework 7.7k Dec 31, 2022
A modern API testing tool for web applications built with Open API and GraphQL specifications.

Schemathesis Schemathesis is a modern API testing tool for web applications built with Open API and GraphQL specifications. It reads the application s

Schemathesis.io 1.6k Jan 4, 2023
Automatically mock your HTTP interactions to simplify and speed up testing

VCR.py ?? This is a Python version of Ruby's VCR library. Source code https://github.com/kevin1024/vcrpy Documentation https://vcrpy.readthedocs.io/ R

Kevin McCarthy 2.3k Jan 1, 2023
Mixer -- Is a fixtures replacement. Supported Django, Flask, SqlAlchemy and custom python objects.

The Mixer is a helper to generate instances of Django or SQLAlchemy models. It's useful for testing and fixture replacement. Fast and convenient test-

Kirill Klenov 871 Dec 25, 2022
gunicorn 'Green Unicorn' is a WSGI HTTP Server for UNIX, fast clients and sleepy applications.

Gunicorn Gunicorn 'Green Unicorn' is a Python WSGI HTTP Server for UNIX. It's a pre-fork worker model ported from Ruby's Unicorn project. The Gunicorn

Benoit Chesneau 8.7k Jan 1, 2023
Waitress - A WSGI server for Python 2 and 3

Waitress Waitress is a production-quality pure-Python WSGI server with very acceptable performance. It has no dependencies except ones which live in t

Pylons Project 1.2k Dec 30, 2022
An HTTP server to easily download and upload files.

httpsweet An HTTP server to easily download and upload files. It was created with flexibility in mind, allowing be used in many different situations,

Eloy 17 Dec 23, 2022
A Plover python dictionary allowing for consistent symbol input with specification of attachment and capitalisation in one stroke.

Emily's Symbol Dictionary Design This dictionary was created with the following goals in mind: Have a consistent method to type (pretty much) every sy

Emily 68 Jan 7, 2023
A Python module and command line utility for working with web archive data using the WACZ format specification

py-wacz The py-wacz repository contains a Python module and command line utility for working with web archive data using the WACZ format specification

Webrecorder 14 Oct 24, 2022
Python interface to Oracle Database conforming to the Python DB API 2.0 specification.

cx_Oracle version 8.2 (Development) cx_Oracle is a Python extension module that enables access to Oracle Database. It conforms to the Python database

Oracle 841 Dec 21, 2022
Lumen provides a framework for visual analytics, which allows users to build data-driven dashboards from a simple yaml specification

Lumen project provides a framework for visual analytics, which allows users to build data-driven dashboards from a simple yaml specification

HoloViz 120 Jan 4, 2023
Data derived from the OpenType specification

This package currently provides the opentypespec.tags module, which exports FEATURE_TAGS, SCRIPT_TAGS, LANGUAGE_TAGS and BASELINE_TAGS dictionaries, representing data from the Layout Tag Registry

Simon Cozens 4 Dec 1, 2022
Histogram specification using openCV in python .

histogram specification using openCV in python . Have to input miu and sigma to draw gausssian distribution which will be used to map the input image . Example input can be miu = 128 sigma = 30

Tamzid hasan 6 Nov 17, 2021
Specification for storing geospatial vector data (point, line, polygon) in Parquet

GeoParquet About This repository defines how to store geospatial vector data (point, lines, polygons) in Apache Parquet, a popular columnar storage fo

Open Geospatial Consortium 449 Dec 27, 2022
ASGI middleware to record and emit timing metrics (to something like statsd)

timing-asgi This is a timing middleware for ASGI, useful for automatic instrumentation of ASGI endpoints. This was developed at GRID for use with our

Steinn Eldjárn Sigurðarson 99 Nov 21, 2022
Drop-in MessagePack support for ASGI applications and frameworks

msgpack-asgi msgpack-asgi allows you to add automatic MessagePack content negotiation to ASGI applications (Starlette, FastAPI, Quart, etc.), with a s

Florimond Manca 128 Jan 2, 2023
ASGI middleware for authentication, rate limiting, and building CRUD endpoints.

Piccolo API Utilities for easily exposing Piccolo models as REST endpoints in ASGI apps, such as Starlette and FastAPI. Includes a bunch of useful ASG

null 81 Dec 9, 2022
Inject an ID into every log message from a Django request. ASGI compatible, integrates with Sentry, and works with Celery

Django GUID Now with ASGI support! Django GUID attaches a unique correlation ID/request ID to all your log outputs for every request. In other words,

snok 300 Dec 29, 2022