Skip to main content

The module provides functionality to expose Python functions to be called remotely over ethernet.

Project description

Remotecall

The module provides functionality to expose Python functions to be called remotely over ethernet.

The implementation uses Python's http.server.HTTPServer to implement a server side functionality and Request for client implementation.

Getting started

Exposing a function to be called remotely.

Server

Create a server and expose a function.

    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.

    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.

  python -m remotecall generate_client http://localhost:8000

Usage

Basic example

Server side implementation to expose hello() function:

    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.

    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.

    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.

    def echo(message: str) -> str:
        return message

Client

Calling the function from the client side.

    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

    server = Server(...)
    server.use_ssl(cert_file="server.crt", key_file="server.key")

Client

    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

    server = Server(...)
    server.set_authenticator(BasicAuthenticator("user", "pass"))

Client

    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 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.

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.

    $ python -m remotecall fetch_api http://localhost:8000

For example, in case of echo example the output would be:

{
    "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.

    $ python -m remotecall fetch_api http://localhost:8000 --output api.json

Client code can be generated based on the definition:

    $ 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.

    $ 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:

python3 -m venv venv

Activate virtual environment:

source venv/bin/activate

Running from source

pip install -e .

Installing from source

pip install .
python -m remotecall

Running tests

pip install .[test]
pytest

py.test -s

Building

Creating a wheel

$ pip install wheel
$ python setup.py bdist_wheel

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

remotecall-0.3.0.tar.gz (27.3 kB view hashes)

Uploaded Source

Built Distribution

remotecall-0.3.0-py3-none-any.whl (26.4 kB view hashes)

Uploaded Python 3

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page