{"id":27127822,"url":"https://github.com/ananto30/zero","last_synced_at":"2025-05-16T09:04:47.365Z","repository":{"id":39411986,"uuid":"257673445","full_name":"Ananto30/zero","owner":"Ananto30","description":"Zero: A simple and fast Python RPC framework","archived":false,"fork":false,"pushed_at":"2024-07-27T11:28:43.000Z","size":294,"stargazers_count":592,"open_issues_count":6,"forks_count":36,"subscribers_count":10,"default_branch":"main","last_synced_at":"2025-05-08T16:44:15.110Z","etag":null,"topics":["asyncio","framework","python","rpc","rpc-framework","zeromq"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Ananto30.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"github":null,"patreon":null,"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"otechie":null,"custom":["https://www.buymeacoffee.com/ananto30"]}},"created_at":"2020-04-21T17:56:51.000Z","updated_at":"2025-05-08T04:05:27.000Z","dependencies_parsed_at":"2024-05-28T07:25:45.964Z","dependency_job_id":"c4b27eb0-9a08-4316-bc1b-58ea6d00d6e6","html_url":"https://github.com/Ananto30/zero","commit_stats":{"total_commits":125,"total_committers":6,"mean_commits":"20.833333333333332","dds":"0.040000000000000036","last_synced_commit":"8178ec8360437e02b1745241dbee29a8f8262015"},"previous_names":[],"tags_count":20,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Ananto30%2Fzero","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Ananto30%2Fzero/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Ananto30%2Fzero/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Ananto30%2Fzero/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Ananto30","download_url":"https://codeload.github.com/Ananto30/zero/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254501557,"owners_count":22081528,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["asyncio","framework","python","rpc","rpc-framework","zeromq"],"created_at":"2025-04-07T17:58:01.251Z","updated_at":"2025-05-16T09:04:42.354Z","avatar_url":"https://github.com/Ananto30.png","language":"Python","readme":"\u003cp align=\"center\"\u003e\n    \u003cimg height=\"300px\" src=\"https://ananto30.github.io/i/1200xCL_TP.png\" /\u003e\n\u003c/p\u003e\n\u003cp align=\"center\"\u003e\n    \u003cem\u003eZero is a simple Python framework (RPC like) to build fast and high performance microservices or distributed servers\u003c/em\u003e\n\u003c/p\u003e\n\u003cp align=\"center\"\u003e\n    \u003ca href=\"https://codecov.io/gh/Ananto30/zero\" target=\"_blank\"\u003e\n        \u003cimg src=\"https://codecov.io/gh/Ananto30/zero/branch/main/graph/badge.svg?token=k0aA0G6NLs\" /\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://pypi.org/project/zeroapi/\" target=\"_blank\"\u003e\n        \u003cimg src=\"https://img.shields.io/pypi/v/zeroapi\" /\u003e\n    \u003c/a\u003e\n    \u003cbr\u003e\n    \u003ca href=\"https://app.codacy.com/gh/Ananto30/zero/dashboard?utm_source=gh\u0026utm_medium=referral\u0026utm_content=\u0026utm_campaign=Badge_grade\"\u003e\n        \u003cimg src=\"https://app.codacy.com/project/badge/Grade/f6d4db49974b470f95999565f7901595\"/\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://codeclimate.com/github/Ananto30/zero/maintainability\" target=\"_blank\"\u003e\n        \u003cimg src=\"https://api.codeclimate.com/v1/badges/4f2fd83bee97326699bc/maintainability\" /\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://pepy.tech/project/zeroapi\" target=\"_blank\"\u003e\n        \u003cimg src=\"https://static.pepy.tech/badge/zeroapi\" /\u003e\n    \u003c/a\u003e\n\u003c/p\u003e\n\n\u003chr\u003e\n\n**Features**:\n\n*   Zero provides **faster communication** (see [benchmarks](https://github.com/Ananto30/zero#benchmarks-)) between the microservices using [zeromq](https://zeromq.org/) under the hood.\n*   Zero uses messages for communication and traditional **client-server** or **request-reply** pattern is supported.\n*   Support for both **async** and **sync**.\n*   The base server (ZeroServer) **utilizes all cpu cores**.\n*   **Code generation**! See [example](https://github.com/Ananto30/zero#code-generation-) 👇\n\n**Philosophy** behind Zero:\n\n*   **Zero learning curve**: The learning curve is tends to zero. Just add functions and spin up a server, literally that's it! The framework hides the complexity of messaging pattern that enables faster communication.\n*   **ZeroMQ**: An awesome messaging library enables the power of Zero.\n\nLet's get started!\n\n# Getting started 🚀\n\n*Ensure Python 3.8+*\n\n    pip install zeroapi\n\n**For Windows**, [tornado](https://pypi.org/project/tornado/) needs to be installed separately (for async operations). It's not included with `zeroapi` because for linux and mac-os, tornado is not needed as they have their own event loops.\n\n*   Create a `server.py`\n\n    ```python\n    from zero import ZeroServer\n\n    app = ZeroServer(port=5559)\n\n    @app.register_rpc\n    def echo(msg: str) -\u003e str:\n        return msg\n\n    @app.register_rpc\n    async def hello_world() -\u003e str:\n        return \"hello world\"\n\n\n    if __name__ == \"__main__\":\n        app.run()\n    ```\n\n*   The **RPC functions only support one argument** (`msg`) for now.\n\n*   Also note that server **RPC functions are type hinted**. Type hint is **must** in Zero server. Supported types can be found [here](/zero/utils/type_util.py#L11).\n\n*   Run the server\n\n    ```shell\n    python -m server\n    ```\n\n*   Call the rpc methods\n\n    ```python\n    from zero import ZeroClient\n\n    zero_client = ZeroClient(\"localhost\", 5559)\n\n    def echo():\n        resp = zero_client.call(\"echo\", \"Hi there!\")\n        print(resp)\n\n    def hello():\n        resp = zero_client.call(\"hello_world\", None)\n        print(resp)\n\n\n    if __name__ == \"__main__\":\n        echo()\n        hello()\n    ```\n\n*   Or using async client -\n\n    ```python\n    import asyncio\n\n    from zero import AsyncZeroClient\n\n    zero_client = AsyncZeroClient(\"localhost\", 5559)\n\n    async def echo():\n        resp = await zero_client.call(\"echo\", \"Hi there!\")\n        print(resp)\n\n    async def hello():\n        resp = await zero_client.call(\"hello_world\", None)\n        print(resp)\n\n\n    if __name__ == \"__main__\":\n        loop = asyncio.get_event_loop()\n        loop.run_until_complete(echo())\n        loop.run_until_complete(hello())\n    ```\n\n# Serialization 📦\n\n## Default serializer\n\n[Msgspec](https://jcristharif.com/msgspec/) is the default serializer. So `msgspec.Struct` (for high performance) or `dataclass` or any [supported types](https://jcristharif.com/msgspec/supported-types.html) can be used easily to pass complex arguments, i.e.\n\n```python\nfrom dataclasses import dataclass\nfrom msgspec import Struct\nfrom zero import ZeroServer\n\napp = ZeroServer()\n\nclass Person(Struct):\n    name: str\n    age: int\n    dob: datetime\n\n@dataclass\nclass Order:\n    id: int\n    amount: float\n    created_at: datetime\n\n@app.register_rpc\ndef save_person(person: Person) -\u003e bool:\n    # save person to db\n    ...\n\n@app.register_rpc\ndef save_order(order: Order) -\u003e bool:\n    # save order to db\n    ...\n```\n\n## Return type on client\n\nThe return type of the RPC function can be any of the [supported types](https://jcristharif.com/msgspec/supported-types.html). If `return_type` is set in the client `call` method, then the return type will be converted to that type.\n\n```python\n@dataclass\nclass Order:\n    id: int\n    amount: float\n    created_at: datetime\n\ndef get_order(id: str) -\u003e Order:\n    return zero_client.call(\"get_order\", id, return_type=Order)\n```\n\n# Code Generation 🤖\n\nEasy to use code generation tool is also provided with schema support!\n\n*   After running the server, like above, it calls the server to get the client code. \n    \n    This makes it easy to get the latest schemas on live servers and not to maintain other file sharing approach to manage schemas.\n\n    Using `zero.generate_client` generate client code for even remote servers using the `--host` and `--port` options.\n\n    ```shell\n    python -m zero.generate_client --host localhost --port 5559 --overwrite-dir ./my_client\n    ```\n\n*   It will generate client like this -\n\n    ```python\n    from dataclasses import dataclass\n    from msgspec import Struct\n    from datetime import datetime\n\n    from zero import ZeroClient\n\n\n    zero_client = ZeroClient(\"localhost\", 5559)\n\n    class Person(Struct):\n        name: str\n        age: int\n        dob: datetime\n\n\n    @dataclass\n    class Order:\n        id: int\n        amount: float\n        created_at: datetime\n\n\n    class RpcClient:\n        def __init__(self, zero_client: ZeroClient):\n            self._zero_client = zero_client\n\n        def save_person(self, person: Person) -\u003e bool:\n            return self._zero_client.call(\"save_person\", person)\n\n        def save_order(self, order: Order) -\u003e bool:\n            return self._zero_client.call(\"save_order\", order)\n    ```\n\n    Check the schemas are copied!\n\n*   Use the client -\n\n    ```python\n    from my_client import RpcClient, zero_client\n\n    client = RpcClient(zero_client)\n\n    if __name__ == \"__main__\":\n        client.save_person(Person(name=\"John\", age=25, dob=datetime.now()))\n        client.save_order(Order(id=1, amount=100.0, created_at=datetime.now()))\n    ```\n\n*If you want a async client just replace `ZeroClient` with `AsyncZeroClient` in the generated code, and update the methods to be async. (Next version will have async client generation, hopefully 😅)*\n\n# Important notes! 📝\n\n## For multiprocessing\n\n*   `ZeroServer` should always be run under `if __name__ == \"__main__\":`, as it uses multiprocessing.\n*   `ZeroServer` creates the workers in different processes, so anything global in your code will be instantiated N times where N is the number of workers. So if you want to initiate them once, put them under `if __name__ == \"__main__\":`. But recommended to not use global vars. And Databases, Redis, other clients, creating them N times in different processes is fine and preferred.\n\n# Let's do some benchmarking! 🏎\n\nZero is all about inter service communication. In most real life scenarios, we need to call another microservice.\n\nSo we will be testing a gateway calling another server for some data. Check the [benchmark/dockerize](https://github.com/Ananto30/zero/tree/main/benchmarks/dockerize) folder for details.\n\nThere are two endpoints in every tests,\n\n*   `/hello`: Just call for a hello world response 😅\n*   `/order`: Save a Order object in redis\n\nCompare the results! 👇\n\n# Benchmarks 🏆\n\n11th Gen Intel® Core™ i7-11800H @ 2.30GHz, 8 cores, 16 threads, 16GB RAM (Docker in Ubuntu 22.04.2 LTS)\n\n*(Sorted alphabetically)*\n\n| Framework   | \"hello world\" (req/s) | 99% latency (ms) | redis save (req/s) | 99% latency (ms) |\n| ----------- | --------------------- | ---------------- | ------------------ | ---------------- |\n| aiohttp     | 14949.57              | 8.91             | 9753.87            | 13.75            |\n| aiozmq      | 13844.67              | 9.55             | 5239.14            | 30.92            |\n| blacksheep  | 32967.27              | 3.03             | 18010.67           | 6.79             |\n| fastApi     | 13154.96              | 9.07             | 8369.87            | 15.91            |\n| sanic       | 18793.08              | 5.88             | 12739.37           | 8.78             |\n| zero(sync)  | 28471.47              | 4.12             | 18114.84           | 6.69             |\n| zero(async) | 29012.03              | 3.43             | 20956.48           | 5.80             |\n\nSeems like blacksheep is faster on hello world, but in more complex operations like saving to redis, zero is the winner! 🏆\n\n# Contribution\n\nContributors are welcomed 🙏\n\n**Please leave a star ⭐ if you like Zero!**\n\n[![\"Buy Me A Coffee\"](https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png)](https://www.buymeacoffee.com/ananto30)\n","funding_links":["https://www.buymeacoffee.com/ananto30"],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fananto30%2Fzero","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fananto30%2Fzero","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fananto30%2Fzero/lists"}