Metadata-Version: 1.1
Name: hotfn
Version: 0.0.6.dev47
Summary: Library to provide HTTP over STDIN/STDOUT
Home-page: https://github.com/denismakogon/hotfn-py
Author: Denis Makogon
Author-email: lildee1991@gmail.com
License: UNKNOWN
Description: [![Build Status](https://travis-ci.org/denismakogon/hotfn-py.svg?branch=master)](https://travis-ci.org/denismakogon/hotfn-py)
        
        HTTP over STDIN/STDOUT lib parser
        =================================
        
        Purpose of this library to provide simple interface to parse HTTP 1.1 requests represented as string
        
        Raw HTTP request
        ----------------
        
        Parses raw HTTP request that contains:
         - method
         - route + query
         - headers
         - protocol version
         Optionally:
         - data
        
        Raw HTTP request may have next look:
        
            GET /v1/apps?something=something&etc=etc HTTP/1.1
            Host: localhost:8080
            Content-Length: 5
            Content-Type: application/x-www-form-urlencoded
            User-Agent: curl/7.51.0
        
            hello
        
        Each new line define by set of special characters:
        
            \n
            \r
        
        and combination is:
        
            \r\n
        
        This type of class stands for HTTP request parsing to a sane structure of:
        
         - HTTP request method
         - HTTP request URL
         - HTTP request query string represented as map
         - HTTP request headers represented as map
         - HTTP protocol version represented as tuple of major and minor versions
         - HTTP request body
        
        ```python
        import os
        import sys
        
        from hotfn.http import request
        
        with os.fdopen(sys.stdin.fileno(), 'rb') as stdin:
            req = request.RawRequest(stdin)
            method, url, query_parameters, headers, (major, minor), body = req.parse_raw_request()
        ```
        
        Raw HTTP response
        -----------------
        
        This type of class stands for transforming HTTP request object into valid string representation
        
        ```python
        import sys
        import os
        
        from hotfn.http import request
        from hotfn.http import response
        
        with os.fdopen(sys.stdin.fileno(), 'rb') as stdin:
            req = request.RawRequest(stdin)
            method, url, query_parameters, headers, (major, minor), body = req.parse_raw_request()
            resp = response.RawResponse((major, minor), 200, "OK", response_data=body)
            with os.fdopen(sys.stdout.fileno(), 'wb') as stdout:
                resp.dump(stdout)
        ```
        
        Example
        -------
        
        Assume we have HTTP 1.1 request:
        ```bash
        GET /v1/apps?something=something&etc=etc HTTP/1.1
        Host: localhost:8080
        Content-Length: 11
        Content-Type: application/x-www-form-urlencoded
        User-Agent: curl/7.51.0
        
        hello:hello
        
        ```
        This request can be transformed into data structure described above.
        Using code snippet mentioned above request data can be used to assemble a response object of the following view:
        ```bash
        HTTP/1.1 200 OK
        Content-Length: 11
        Content-Type: text/plain; charset=utf-8
        
        hello:hello
        
        ```
        This is totally valid HTTP response object.
        
        Notes
        -----
        
        Please be aware that response object by default sets content type as `text/plain; charset=utf-8`. If you need to change it use following code:
        ```python
        import os
        import sys
        
        from hotfn.http import request
        from hotfn.http import response
        
        with os.fdopen(sys.stdin.fileno(), 'rb') as stdin:
            req = request.RawRequest(stdin)
            method, url, query_parameters, headers, (major, minor), body = req.parse_raw_request()
            resp = response.RawResponse((major, minor), 200, "OK", response_data=body)
            resp.headers["Content-Type"] = "application/json"
            with os.fdopen(sys.stdout.fileno(), 'wb') as stdout:
                resp.dump(stdout)
        
        ```
        
        Handling Hot Functions
        ----------------------
        
        A main loop is supplied that can repeatedly call a user function with a series of HTTP requests.
        (TODO: should this use the WSGI API?)
        
        In order to utilise this, you can write your `app.py` as follows:
        
        ```python
        from hotfn.http import worker
        from hotfn.http import response
        
        
        def app(context, **kwargs):
            body = kwargs.get('data')
            return response.RawResponse(context.version, 200, "OK", body.readall())
        
        
        if __name__ == "__main__":
            worker.run(app)
        
        ```
        
        Automatic input coercions
        -------------------------
        
        Decorators are provided that will attempt to coerce input values to Python types.
        Some attempt is made to coerce return values from these functions also:
        
        ```python
        from hotfn.http import worker
        
        
        @worker.coerce_input_to_content_type
        def app(context, **kwargs):
            """
            body is a request body, it's type depends on content type
            """
            return kwargs.get('data')
        
        
        if __name__ == "__main__":
            worker.run(app)
        
        ```
        
        Working with async automatic input coercions
        --------------------------------------------
        
        Latest version (from 0.0.6) supports async coroutines as a request body processors:
        ```python
        
        import asyncio
        
        from hotfn.http import worker
        from hotfn.http import response
        
        
        @worker.coerce_input_to_content_type
        async def app(context, **kwargs):
            headers = {
                "Content-Type": "plain/text",
            }
            return response.RawResponse(
                context.version, 200, "OK",
                http_headers=headers,
                response_data="OK")
        
        
        if __name__ == "__main__":
            loop = asyncio.get_event_loop()
            worker.run(app, loop=loop)
        
        ```
        As you can see `app` function is no longer callable, because its type: coroutine, so we need to bypass event loop inside
        
        
Platform: UNKNOWN
Classifier: Intended Audience :: Information Technology
Classifier: Intended Audience :: System Administrators
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.5
Classifier: Programming Language :: Python :: 3.6
