Metadata-Version: 2.1
Name: remotecall
Version: 0.4.0
Summary: The module provides functionality to expose Python functions to be called remotely over ethernet.
Home-page: https://gitlab.com/slaine/remotecall.git/
Author: Sami Laine
Author-email: sami.jy.laine@gmail.com
License: BSD-3-Clause
Description: # Remotecall
        
        The module provides functionality to expose Python functions to be called remotely over ethernet.
        
        The implementation uses Python's 
        [http.server.HTTPServer](https://docs.python.org/3/library/http.server.html) to implement a server
        side functionality and [Request](https://pypi.org/project/requests/) for client implementation.
        
        ## Getting started
        
        Exposing a function to be called remotely.
        
        ### Server
        
        Create a server and expose a function.
        
        ```python
            from remotecall import Server
        
            def hello() -> str:
                return "Hello World"
        
            with Server(("localhost", 8000)) as server:
                server.expose(hello)
                server.serve_forever()
        ```
        
        ### Client
        
        Subclass a client from BaseClient to call exposed functions.
        
        ```python
            from remotecall import Server
        
            class Client(BaseClient):
                def hello(self) -> str:
                    return self.call("hello")
            
            client = Client(("localhost", 8000))
            client.hello()
        ```
        
        ### Code generation
        
        Use the module to generate client code instead of writing the client code. 
        
        ```sh
          python -m remotecall generate_client http://localhost:8000
        ```
        
        
        # Usage
        
        ## Basic example
        
        Server side implementation to expose hello() function:
        
        ```python
            from remotecall import Server
        
            def hello() -> str:
                return "Hello World"
        
            with Server(server_address=("localhost", 8000)) as server:
                server.register(hello)
                server.serve_forever()
        ```
        
        Client side implementation is based on BaseClient class which is a thin wrapper around Requests 
        module.  
        
        ```python
            from remotecall import BaseClient
        
            client = BaseClient(server_address=("localhost", 8000))
            client.call("hello")
        ```
        
        Subclassing BaseClient makes accessing the available functions more convenient - for example, by 
        enabling IDE autocompletion and providing the type information.
        
        ```python
            from remotecall import BaseClient
        
            class Client(BaseClient):
                def hello(self) -> str:
                    return self.call("hello")
        
            client = Client(server_address=("localhost", 8000))
            client.hello()
        ```
        
        Usage of `python -m remotecall generate_client` automates the client code generation.
        
        For more example, see examples directory.
        
        
        ## Passing arguments
        
        Module uses Python type annotations to determine type of parameter and return 
        values. 
        
        The type information is used to generate API definition. The API definition is provided in JSON 
        format and can be used to generate client code. 
        
        The type information is also used to encode and decode data - like parameter and return values - 
        send between client and server. 
        
        The implementation support basic Python data types including `bytes`, `int`, `float`, `bool`, `str`,
        `list`, `tuple` and `dict`. It is possible to add support for addition types. See examples 
        directory for an implementation for _PIL Images_ and _NumPy_ arrays. 
        
        #### Server
        
        Exposing a function with parameters and return value.
        
        ```python
            def echo(message: str) -> str:
                return message
        ```
        
        #### Client
        
        Calling the function from the client side.
        
        ```python
            class Client(BaseClient):
                def echo(self, message: str) -> str:
                    return self.call("echo", message=message)
        ```
        
        
        ## HTTPS and SSL
        
        By default, the server uses HTTP for the communication. HTTPS communication can be enabled by 
        providing SSL certificate. The certificate is used to create a SSLContext to wrap 
        the underlying socket instance.
        
        See _examples_ folder for an example and instructions to generate a self-signed certificate.
        
        #### Server
        
        ```python
            server = Server(...)
            server.use_ssl(cert_file="server.crt", key_file="server.key")
        ```
        
        #### Client
        
        ```python
            client = BaseClient(...)
            client.use_ssl(cert_file="server.pem")
        ```
        
        
        ## Authentication
        
        By default, the server does not require authentication. 
        
        Server provides an implementation for HTTP basic authenticator that can be set in use as 
        demonstrated below. However, it's also possible to subclass
        `remotecall.authentication.Authenticator` and implement other type of authenticators.
        
        Client implementation wraps _Requests_ library and makes it possible to use the 
        authentication methods available for that library. More documentation can be found from the 
        library documentation https://requests.readthedocs.io/en/latest/user/authentication/.
        
        #### Server
        
        ```python
            server = Server(...)
            server.set_authenticator(BasicAuthenticator("user", "pass"))
        ```
        
        #### Client
        
        ```python
            from requests.auth import HTTPBasicAuth
            
            client = BaseClient(...)
            client.set_authentication(HTTPBasicAuth("user", "pass"))
        ```
        
        ### Implementing authenticator
        
        Implementing a custom authenticator begins with subclassing `remotecall.authentication.
        Authenticator`.
        
        Authenticator is expected to implement `authenticate` method to carry out the authentication. It 
        is called right after the HTTP server's `do_*` method gets called. 
        
        `authenticate` method receives an instance of 
        [`BaseHTTPRequestHandler`](https://docs.python.org/3/library/http.server.html#http.server.BaseHTTPRequestHandler)
        that represents the HTTP request received by the HTTP server and to handle it.
        
        `Authenticator` is expected to handle the actions required to carry out the authentication. 
        
        It may raise `AuthenticationError` if the server should not continue processing the request. 
        Server expects the authenticator to resolves the request by sending the corresponding headers and 
        related data.
        
        ```python
        class Authenticator(ABC):
            @abstractmethod
            def authenticate(self, request: BaseHTTPRequestHandler):
                """Do the authentication."""
        ```
        
        
        ## Code generation
        
        The module provides an easy way to generate a Python client for a service provided by a server.
        
        The API definition can be fetched from the server with the following command line command. The 
        command returns an API definition in JSON format.
        
        ```sh
            $ python -m remotecall fetch_api http://localhost:8000
        ```
        
        For example, in case of _echo_ example the output would be:
        
        ```json
        {
            "endpoints": [
                {
                    "name": "echo",
                    "documentation": "",
                    "parameters": [
                        {
                            "name": "message",
                            "type": "str"
                        }
                    ],
                    "return_type": "str"
                }
            ],
            "ssl_enabled": false,
            "address": {
                "hostname": "localhost",
                "port": 8000
            }
        }
        ```
        
        The API definition can be written in a file with `output` option.
        
        ```sh
            $ python -m remotecall fetch_api http://localhost:8000 --output api.json
        ```
        
        Client code can be generated based on the definition:
        
        ```sh
            $ python -m remotecall generate_client api.json --output client.py
        ```
        
        Where, `output` defines the output file. 
        
        By default, the client class is named as `Client`. This can be changed by using `name` 
        option. For example, `--name EchoClient`.
        
        The above steps can be combined if the intermediate results are not needed.
        
        ```sh
            $ python -m remotecall generate_client http://localhost:8000 --output client.py
        ```
        
        
        ## Extending supported data type
        
        See _examples/image_ and _examples/numpy_ for image and numpy codec examples.
        
        
        # Development
        
        ## Set up virtual environment
        
        Create virtual environment:
        
        ```sh
        python3 -m venv venv
        ```
        
        Activate virtual environment:
        
        ```sh
        source venv/bin/activate
        ```
        
        ## Running from source
        
        ```sh
        pip install -e .
        ```
        ### Installing from source
        
        ```sh
        pip install .
        python -m remotecall
        ```
        
        # Running tests
        
        ```sh
        pip install .[test]
        pytest
        
        py.test -s
        ```
        
        # Building
        
        ## Creating a wheel
        
        ```sh
        $ pip install wheel
        $ python setup.py bdist_wheel
        ```
        
Platform: UNKNOWN
Description-Content-Type: text/markdown
Provides-Extra: test
Provides-Extra: full
Provides-Extra: numpycodec
Provides-Extra: imagecodec
