Skip to main content

The easiest way to use sockets in Python

Project description

EasyNetwork

The easiest way to use sockets in Python!

PyPI PyPI - License PyPI - Python Version

Test Documentation Status Codecov CodeFactor Grade

pre-commit pre-commit.ci status

Checked with mypy Code style: black Imports: isort security: bandit

Hatch project pdm-managed

Installation

From PyPI repository

pip install --user easynetwork

From source

git clone https://github.com/francis-clairicia/EasyNetwork.git
cd EasyNetwork
pip install --user .

Overview

EasyNetwork completely encapsulates the socket handling, providing you with a higher level interface that allows an application/software to completely handle the logic part with Python objects, without worrying about how to process, send or receive data over the network.

The communication protocol can be whatever you want, be it JSON, Pickle, ASCII, structure, base64 encoded, compressed, encrypted, or any other format that is not part of the standard library. You choose the data format and the library takes care of the rest.

Works with TCP and UDP.

Documentation

Coming soon.

Usage

TCP Echo server with JSON data

import logging
from collections.abc import AsyncGenerator
from typing import Any, TypeAlias

from easynetwork.api_async.server import AsyncStreamClient, AsyncStreamRequestHandler
from easynetwork.api_sync.server import StandaloneTCPNetworkServer
from easynetwork.exceptions import StreamProtocolParseError
from easynetwork.protocol import StreamProtocol
from easynetwork.serializers import JSONSerializer

# These TypeAliases are there to help you understand
# where requests and responses are used in the code
RequestType: TypeAlias = Any
ResponseType: TypeAlias = Any


class JSONProtocol(StreamProtocol[ResponseType, RequestType]):
    def __init__(self) -> None:
        super().__init__(JSONSerializer())


class EchoRequestHandler(AsyncStreamRequestHandler[RequestType, ResponseType]):
    def __init__(self) -> None:
        self.logger: logging.Logger = logging.getLogger(self.__class__.__name__)

    async def handle(
        self,
        client: AsyncStreamClient[ResponseType],
    ) -> AsyncGenerator[None, RequestType]:
        try:
            request: RequestType = yield  # A JSON request has been sent by this client
        except StreamProtocolParseError:
            # Invalid JSON data sent
            # This is an example of how you can answer to an invalid request
            await client.send_packet({"error": "Invalid JSON", "code": "parse_error"})
            return

        self.logger.info(f"{client!r} sent {request!r}")

        # As a good echo handler, the request is sent back to the client
        response: ResponseType = request
        await client.send_packet(response)

        # Leaving the generator will NOT close the connection,
        # a new generator will be created afterwards.
        # You may manually close the connection if you want to:
        # await client.aclose()


def main() -> None:
    host = None  # Bind on all interfaces
    port = 9000

    logging.basicConfig(level=logging.INFO, format="[ %(levelname)s ] [ %(name)s ] %(message)s")
    with StandaloneTCPNetworkServer(host, port, JSONProtocol(), EchoRequestHandler()) as server:
        try:
            server.serve_forever()
        except KeyboardInterrupt:
            pass


if __name__ == "__main__":
    main()

TCP Echo client with JSON data

from typing import Any

from easynetwork.api_sync.client import TCPNetworkClient
from easynetwork.protocol import StreamProtocol
from easynetwork.serializers import JSONSerializer


class JSONProtocol(StreamProtocol[Any, Any]):
    def __init__(self) -> None:
        super().__init__(JSONSerializer())


def main() -> None:
    with TCPNetworkClient(("localhost", 9000), JSONProtocol()) as client:
        client.send_packet({"data": {"my_body": ["as json"]}})
        response = client.recv_packet()  # response should be the sent dictionary
        print(response)  # prints {'data': {'my_body': ['as json']}}


if __name__ == "__main__":
    main()
Asynchronous version ( with async def )
import asyncio
from typing import Any

from easynetwork.api_async.client import AsyncTCPNetworkClient
from easynetwork.protocol import StreamProtocol
from easynetwork.serializers import JSONSerializer


class JSONProtocol(StreamProtocol[Any, Any]):
    def __init__(self) -> None:
        super().__init__(JSONSerializer())


async def main() -> None:
    async with AsyncTCPNetworkClient(("localhost", 9000), JSONProtocol()) as client:
        await client.send_packet({"data": {"my_body": ["as json"]}})
        response = await client.recv_packet()  # response should be the sent dictionary
        print(response)  # prints {'data': {'my_body': ['as json']}}


if __name__ == "__main__":
    asyncio.run(main())

License

This project is licensed under the terms of the Apache Software License 2.0.

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

easynetwork-1.0.0rc5.tar.gz (285.3 kB view hashes)

Uploaded Source

Built Distribution

easynetwork-1.0.0rc5-py3-none-any.whl (182.9 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