simplejrpc


Namesimplejrpc JSON
Version 2.2.6 PyPI version JSON
download
home_pagehttps://github.com/GMSSH/app-sdk-py
Summarysimple jsonrpc
upload_time2025-07-14 06:35:32
maintainerNone
docs_urlNone
authorZack
requires_python>=3.10
licenseMIT
keywords gm gm-sdk simplejrpc gmssh jsonrpc jsonrpcserver jsonrpcclient
VCS
bugtrack_url
requirements jsonrpcclient jsonrpcserver loguru PyYAML WTForms
Travis-CI No Travis.
coveralls test coverage No coveralls.
            [![Latest Version](https://img.shields.io/pypi/v/simplejrpc.svg)](https://pypi.python.org/pypi/simplejrpc/)
[![Supported Python versions](https://img.shields.io/pypi/pyversions/simplejrpc.svg)](https://pypi.python.org/pypi/simplejrpc/)
[![Downloads](https://img.shields.io/pypi/dm/simplejrpc.svg)](https://pypi.org/project/simplejrpc/)

simplejrpc
==========


# 1. Getting Started Quickly

### 1.1 Install SDK

Install the SDK using pip:

```bash
pip3 install simplejrpc
```

> Once installed, you can import and use the SDK functions in your project.

---

# 2. Service Registration

### 2.1 Register a Socket File

Since the SDK communicates with the backend process via a **Unix Socket file** (based on the JSON-RPC 2.0 protocol), you must explicitly specify the `socket_path` to ensure the service generates a `.sock` file and exposes communication capabilities.

```python
# main.py
from simplejrpc import ServerApplication

# Specify the Unix Socket file path
socket_path = "/xxx/app.socket"

# Create the application instance
app = ServerApplication(socket_path=socket_path)
```

> ✅ Tip: Make sure the path is writable and does not conflict with other services.

---

### 2.2 Register a Configuration File (Logging System)

To enable logging, specify the path to a logger config file during initialization. You can also call `app.setup_logger(config_path)` after the app starts to load the logger config dynamically.

* Supported format: **YAML**
* If not configured, a simple logger provided by loguru is used by default.

```python
# main.py
from simplejrpc import ServerApplication

sock_path = "/xxx/app.sock"
config_path = "/xxx/config.yaml"

# Initialize the app with logger configuration
app = ServerApplication(socket_path=sock_path, config_path=config_path)

# Alternatively, configure the logger after initialization:
# app.setup_logger(config_path)
```

---

### 2.3 Register Methods (Business Routes)

Registering methods exposes functions as interfaces accessible via JSON-RPC.

#### ✅ Default Registration (Using Function Name)

If the method name is not explicitly specified, the system will use the function name by default:

```python
from simplejrpc.response import jsonify


@app.route()  # Registered as 'hello' by default
async def hello():
    return jsonify(data="hello", msg="OK")
```

#### ✅ Explicit Registration (Specify Method Name)

You can also specify a method name using the `name` parameter. It’s recommended to keep it consistent with the function name for maintainability:

```python
from simplejrpc.response import jsonify


@app.route(name="hello")  # Explicitly set method name
async def hello():
    return jsonify(data="hello", msg="OK")
```

> ⚠️ Note: If `name` differs from the function name, it may cause confusion during maintenance or calls. Consistent naming is advised.

---

# 3. Making Requests

---

## 3.1 Request and Response Structure

### ✅ Supported Parameter Formats

The framework supports two ways of receiving request parameters:

#### 📌 Explicit Parameter Declaration (Recommended)

Use when parameters are fixed and clearly named:

```python
@app.route(name="hello")
async def hello(lang, action):
    # Directly receive request parameters lang and action
    ...
```

✅ Advantage: Clear typing, easier validation and maintenance.

---

#### 📌 Dynamic Parameter Handling (\*args, \*\*kwargs)

Use when the number of parameters is variable or needs generic processing:

```python
@app.route(name="hello")
async def hello(*args, **kwargs):
    lang = kwargs.get("lang")
    action = kwargs.get("action")
    ...
```

---

### ✅ Standard Response Format

All responses should be returned using `jsonify`, containing `code`, `data`, and `msg` fields:

```python
from simplejrpc.response import jsonify


@app.route(name="hello")
async def hello():
    return jsonify(code=400, data=True, msg="Operation failed")
```

---

### ✅ Example Response Structure

#### Success Response:

```json
{
    "jsonrpc": "2.0",
    "result": {
        "code": 200,
        "meta": {
            "endpoint": null,
            "close": 1
        },
        "data": [],
        "msg": "OK"
    },
    "id": 1
}
```

#### Error Response:

```json
{
    "jsonrpc": "2.0",
    "result": {
        "code": 400,
        "meta": {
            "endpoint": null,
            "close": 1
        },
        "data": null,
        "msg": "expected value ['start', 'stop']"
    },
    "id": 1
}
```

---

## 3.2 Start the Service

Example server code:

```python
# main.py
import asyncio
from simplejrpc import ServerApplication
from simplejrpc.response import jsonify

socket_path = "/xxx/app.socket"
app = ServerApplication(socket_path)


@app.route(name="hello")
async def hello():
    return jsonify(data="hello", msg="OK")


if __name__ == "__main__":
    asyncio.run(app.run())
```

Start the service:

```bash
$ python3 main.py
```

---

## 3.3 Call Interface (Client Test)

Use the SDK's `Request` class for testing:

```python
from simplejrpc import Request

# Must match the socket path used by the server
socket_path = "/xxx/app.sock"


def test_hello():
    method = "hello"
    params = {
        "lang": "zh-CN",
        "action": "start"
    }

    request = Request(socket_path)
    result = request.send_request(method, params)
    print("[recv] >", result)
```

---

# 4. Making Requests

---

## 4.1 Form Validation

The SDK integrates [`wtforms`](https://wtforms.readthedocs.io/en/3.1.x/) to provide a simple yet powerful validation system with support for custom validators.

### ✅ Example: Define and Use a Form Class

```python
from simplejrpc.schemas import BaseForm, StrRangeValidator, simple
from simplejrpc.response import jsonify


# Custom form class, restricts 'action' to "start" or "stop"
class TestForm(BaseForm):
    action = simple.StringField(
        validators=[StrRangeValidator(allows=["start", "stop"])]
    )


# Specify socket path and register app
socket_path = "/xxx/app.socket"
app = ServerApplication(socket_path)


# Specify 'form' to trigger validation automatically
@app.route(name="hello", form=TestForm)
async def hello(lang, action):
    return jsonify(data=[1, 2, 3], msg="OK")
```

---

### ✅ Custom Validators

You can create custom validation logic by extending `BaseValidator`.

> A custom validator class must inherit from `BaseValidator` and implement the `validator(form, field)` method. Only two parameters are accepted: the form instance and the field instance.

```python
from simplejrpc import BaseValidator


class TestValidator(BaseValidator):
    def validator(self, form, field):
        # Custom logic: value must be uppercase
        if field.data and not field.data.isupper():
            raise ValueError("Field must be uppercase")
```

Use the custom validator in your form:

```python
class TestForm(BaseForm):
    action = simple.StringField(
        validators=[
            StrRangeValidator(allows=["start", "stop"]),
            TestValidator()
        ]
    )
```

---

## 4.2 Exception Handling

The framework includes a built-in exception handling system. Just raise exceptions, and the framework will format them into standard JSON-RPC error responses.

### ✅ Example

```python
from simplejrpc.exceptions import RPCException


@app.route(name="hello", form=TestForm)
async def hello(lang, action):
    raise RPCException("Test error")  # Automatically caught and formatted
```

### ✅ Custom Exception Classes

The framework provides a base exception class that can be extended:

```python
class UnauthorizedError(RPCException):
    """Unauthorized"""

class ValidationError(RPCException):
    """Validation failed"""

class FileNotFoundError(RPCException):
    """File not found"""

class ValueError(RPCException):
    """Value error"""

class RuntimeError(RPCException):
    """Runtime error"""
```

---

## 4.3 Internationalization (i18n)

The SDK supports multilingual output using `.ini` files, driven by the `lang` parameter in each request.

### ✅ Initialize Language Configuration

Your project root should include an `i18n/` directory:

```bash
project/
├── main.py
└── i18n/
    ├── zh-CN.ini
    └── en.ini
```

Initialize with `GI18n()`:

```python
GI18n(i18n_dir="i18n", lang="zh-CN")
```

> ⚠️ Each request should include a `lang` parameter, which the framework uses to set the language.

---

### ✅ Example 1: Basic Translation

**en.ini**

```ini
TEST_I18N = "test"
```

**Python usage:**

```python
from simplejrpc import i18n

print(i18n.translate("TEST_I18N"))  # Output: test
```

---

### ✅ Example 2: Placeholder Translation (Parameterized)

**en.ini**

```ini
TEST_I18N = "test{}"
```

**Python usage:**

```python
from simplejrpc import  i18n

print(i18n.translate_ctx("TEST_I18N", "i18n"))  # Output: testi18n
```

---

### ✅ Supported Languages

| Language Code | Description         | Region/Note      |
| ------------- | ------------------- | ---------------- |
| `en`          | English             | Default          |
| `zh-CN`       | Simplified Chinese  | Mainland China   |
| `zh-TW`       | Traditional Chinese | Taiwan/Hong Kong |
| `ja`          | Japanese            | Japan            |
| `ru`          | Russian             | Russia           |

---

## 4.4 Middleware Support

The framework supports middleware for handling common logic before and after request processing, such as logging, authentication, or performance analysis.

### ✅ Example Usage

```python
from simplejrpc import ServerApplication
from simplejrpc.interfaces import RPCMiddleware


class CustomMiddleware(RPCMiddleware):
    def process_request(self, request, context):
        print("[Before] Incoming request:", request)
        return request

    def process_response(self, response, context):
        print("[After] Outgoing response:", response)
        return response


# Register middleware
app = ServerApplication("/xxx/app.sock")
app.middleware(CustomMiddleware())
```

---

Would you like this translated version exported into a PDF or Markdown file?


Feedback
--------

Open a ticket / fork the project on [Gitee](https://gitee.com/gmssh_1/simplerpc.git).

Open a ticket / fork the project on [Github](https://github.com/GMSSH/app-sdk-py.git).

Here is the fully translated version of your documentation from Chinese to English:

---

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/GMSSH/app-sdk-py",
    "name": "simplejrpc",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.10",
    "maintainer_email": null,
    "keywords": "gm, gm-sdk, simplejrpc, gmssh, jsonrpc, jsonrpcserver, jsonrpcclient",
    "author": "Zack",
    "author_email": "f1125564921@163.com",
    "download_url": "https://files.pythonhosted.org/packages/87/2f/faa78c8896eb27ec6fee5f14b0967eb2cb4def6d1eb64e9231ce780d6a52/simplejrpc-2.2.6.tar.gz",
    "platform": null,
    "description": "[![Latest Version](https://img.shields.io/pypi/v/simplejrpc.svg)](https://pypi.python.org/pypi/simplejrpc/)\n[![Supported Python versions](https://img.shields.io/pypi/pyversions/simplejrpc.svg)](https://pypi.python.org/pypi/simplejrpc/)\n[![Downloads](https://img.shields.io/pypi/dm/simplejrpc.svg)](https://pypi.org/project/simplejrpc/)\n\nsimplejrpc\n==========\n\n\n# 1. Getting Started Quickly\n\n### 1.1 Install SDK\n\nInstall the SDK using pip:\n\n```bash\npip3 install simplejrpc\n```\n\n> Once installed, you can import and use the SDK functions in your project.\n\n---\n\n# 2. Service Registration\n\n### 2.1 Register a Socket File\n\nSince the SDK communicates with the backend process via a **Unix Socket file** (based on the JSON-RPC 2.0 protocol), you must explicitly specify the `socket_path` to ensure the service generates a `.sock` file and exposes communication capabilities.\n\n```python\n# main.py\nfrom simplejrpc import ServerApplication\n\n# Specify the Unix Socket file path\nsocket_path = \"/xxx/app.socket\"\n\n# Create the application instance\napp = ServerApplication(socket_path=socket_path)\n```\n\n> \u2705 Tip: Make sure the path is writable and does not conflict with other services.\n\n---\n\n### 2.2 Register a Configuration File (Logging System)\n\nTo enable logging, specify the path to a logger config file during initialization. You can also call `app.setup_logger(config_path)` after the app starts to load the logger config dynamically.\n\n* Supported format: **YAML**\n* If not configured, a simple logger provided by loguru is used by default.\n\n```python\n# main.py\nfrom simplejrpc import ServerApplication\n\nsock_path = \"/xxx/app.sock\"\nconfig_path = \"/xxx/config.yaml\"\n\n# Initialize the app with logger configuration\napp = ServerApplication(socket_path=sock_path, config_path=config_path)\n\n# Alternatively, configure the logger after initialization:\n# app.setup_logger(config_path)\n```\n\n---\n\n### 2.3 Register Methods (Business Routes)\n\nRegistering methods exposes functions as interfaces accessible via JSON-RPC.\n\n#### \u2705 Default Registration (Using Function Name)\n\nIf the method name is not explicitly specified, the system will use the function name by default:\n\n```python\nfrom simplejrpc.response import jsonify\n\n\n@app.route()  # Registered as 'hello' by default\nasync def hello():\n    return jsonify(data=\"hello\", msg=\"OK\")\n```\n\n#### \u2705 Explicit Registration (Specify Method Name)\n\nYou can also specify a method name using the `name` parameter. It\u2019s recommended to keep it consistent with the function name for maintainability:\n\n```python\nfrom simplejrpc.response import jsonify\n\n\n@app.route(name=\"hello\")  # Explicitly set method name\nasync def hello():\n    return jsonify(data=\"hello\", msg=\"OK\")\n```\n\n> \u26a0\ufe0f Note: If `name` differs from the function name, it may cause confusion during maintenance or calls. Consistent naming is advised.\n\n---\n\n# 3. Making Requests\n\n---\n\n## 3.1 Request and Response Structure\n\n### \u2705 Supported Parameter Formats\n\nThe framework supports two ways of receiving request parameters:\n\n#### \ud83d\udccc Explicit Parameter Declaration (Recommended)\n\nUse when parameters are fixed and clearly named:\n\n```python\n@app.route(name=\"hello\")\nasync def hello(lang, action):\n    # Directly receive request parameters lang and action\n    ...\n```\n\n\u2705 Advantage: Clear typing, easier validation and maintenance.\n\n---\n\n#### \ud83d\udccc Dynamic Parameter Handling (\\*args, \\*\\*kwargs)\n\nUse when the number of parameters is variable or needs generic processing:\n\n```python\n@app.route(name=\"hello\")\nasync def hello(*args, **kwargs):\n    lang = kwargs.get(\"lang\")\n    action = kwargs.get(\"action\")\n    ...\n```\n\n---\n\n### \u2705 Standard Response Format\n\nAll responses should be returned using `jsonify`, containing `code`, `data`, and `msg` fields:\n\n```python\nfrom simplejrpc.response import jsonify\n\n\n@app.route(name=\"hello\")\nasync def hello():\n    return jsonify(code=400, data=True, msg=\"Operation failed\")\n```\n\n---\n\n### \u2705 Example Response Structure\n\n#### Success Response:\n\n```json\n{\n    \"jsonrpc\": \"2.0\",\n    \"result\": {\n        \"code\": 200,\n        \"meta\": {\n            \"endpoint\": null,\n            \"close\": 1\n        },\n        \"data\": [],\n        \"msg\": \"OK\"\n    },\n    \"id\": 1\n}\n```\n\n#### Error Response:\n\n```json\n{\n    \"jsonrpc\": \"2.0\",\n    \"result\": {\n        \"code\": 400,\n        \"meta\": {\n            \"endpoint\": null,\n            \"close\": 1\n        },\n        \"data\": null,\n        \"msg\": \"expected value ['start', 'stop']\"\n    },\n    \"id\": 1\n}\n```\n\n---\n\n## 3.2 Start the Service\n\nExample server code:\n\n```python\n# main.py\nimport asyncio\nfrom simplejrpc import ServerApplication\nfrom simplejrpc.response import jsonify\n\nsocket_path = \"/xxx/app.socket\"\napp = ServerApplication(socket_path)\n\n\n@app.route(name=\"hello\")\nasync def hello():\n    return jsonify(data=\"hello\", msg=\"OK\")\n\n\nif __name__ == \"__main__\":\n    asyncio.run(app.run())\n```\n\nStart the service:\n\n```bash\n$ python3 main.py\n```\n\n---\n\n## 3.3 Call Interface (Client Test)\n\nUse the SDK's `Request` class for testing:\n\n```python\nfrom simplejrpc import Request\n\n# Must match the socket path used by the server\nsocket_path = \"/xxx/app.sock\"\n\n\ndef test_hello():\n    method = \"hello\"\n    params = {\n        \"lang\": \"zh-CN\",\n        \"action\": \"start\"\n    }\n\n    request = Request(socket_path)\n    result = request.send_request(method, params)\n    print(\"[recv] >\", result)\n```\n\n---\n\n# 4. Making Requests\n\n---\n\n## 4.1 Form Validation\n\nThe SDK integrates [`wtforms`](https://wtforms.readthedocs.io/en/3.1.x/) to provide a simple yet powerful validation system with support for custom validators.\n\n### \u2705 Example: Define and Use a Form Class\n\n```python\nfrom simplejrpc.schemas import BaseForm, StrRangeValidator, simple\nfrom simplejrpc.response import jsonify\n\n\n# Custom form class, restricts 'action' to \"start\" or \"stop\"\nclass TestForm(BaseForm):\n    action = simple.StringField(\n        validators=[StrRangeValidator(allows=[\"start\", \"stop\"])]\n    )\n\n\n# Specify socket path and register app\nsocket_path = \"/xxx/app.socket\"\napp = ServerApplication(socket_path)\n\n\n# Specify 'form' to trigger validation automatically\n@app.route(name=\"hello\", form=TestForm)\nasync def hello(lang, action):\n    return jsonify(data=[1, 2, 3], msg=\"OK\")\n```\n\n---\n\n### \u2705 Custom Validators\n\nYou can create custom validation logic by extending `BaseValidator`.\n\n> A custom validator class must inherit from `BaseValidator` and implement the `validator(form, field)` method. Only two parameters are accepted: the form instance and the field instance.\n\n```python\nfrom simplejrpc import BaseValidator\n\n\nclass TestValidator(BaseValidator):\n    def validator(self, form, field):\n        # Custom logic: value must be uppercase\n        if field.data and not field.data.isupper():\n            raise ValueError(\"Field must be uppercase\")\n```\n\nUse the custom validator in your form:\n\n```python\nclass TestForm(BaseForm):\n    action = simple.StringField(\n        validators=[\n            StrRangeValidator(allows=[\"start\", \"stop\"]),\n            TestValidator()\n        ]\n    )\n```\n\n---\n\n## 4.2 Exception Handling\n\nThe framework includes a built-in exception handling system. Just raise exceptions, and the framework will format them into standard JSON-RPC error responses.\n\n### \u2705 Example\n\n```python\nfrom simplejrpc.exceptions import RPCException\n\n\n@app.route(name=\"hello\", form=TestForm)\nasync def hello(lang, action):\n    raise RPCException(\"Test error\")  # Automatically caught and formatted\n```\n\n### \u2705 Custom Exception Classes\n\nThe framework provides a base exception class that can be extended:\n\n```python\nclass UnauthorizedError(RPCException):\n    \"\"\"Unauthorized\"\"\"\n\nclass ValidationError(RPCException):\n    \"\"\"Validation failed\"\"\"\n\nclass FileNotFoundError(RPCException):\n    \"\"\"File not found\"\"\"\n\nclass ValueError(RPCException):\n    \"\"\"Value error\"\"\"\n\nclass RuntimeError(RPCException):\n    \"\"\"Runtime error\"\"\"\n```\n\n---\n\n## 4.3 Internationalization (i18n)\n\nThe SDK supports multilingual output using `.ini` files, driven by the `lang` parameter in each request.\n\n### \u2705 Initialize Language Configuration\n\nYour project root should include an `i18n/` directory:\n\n```bash\nproject/\n\u251c\u2500\u2500 main.py\n\u2514\u2500\u2500 i18n/\n    \u251c\u2500\u2500 zh-CN.ini\n    \u2514\u2500\u2500 en.ini\n```\n\nInitialize with `GI18n()`:\n\n```python\nGI18n(i18n_dir=\"i18n\", lang=\"zh-CN\")\n```\n\n> \u26a0\ufe0f Each request should include a `lang` parameter, which the framework uses to set the language.\n\n---\n\n### \u2705 Example 1: Basic Translation\n\n**en.ini**\n\n```ini\nTEST_I18N = \"test\"\n```\n\n**Python usage:**\n\n```python\nfrom simplejrpc import i18n\n\nprint(i18n.translate(\"TEST_I18N\"))  # Output: test\n```\n\n---\n\n### \u2705 Example 2: Placeholder Translation (Parameterized)\n\n**en.ini**\n\n```ini\nTEST_I18N = \"test{}\"\n```\n\n**Python usage:**\n\n```python\nfrom simplejrpc import  i18n\n\nprint(i18n.translate_ctx(\"TEST_I18N\", \"i18n\"))  # Output: testi18n\n```\n\n---\n\n### \u2705 Supported Languages\n\n| Language Code | Description         | Region/Note      |\n| ------------- | ------------------- | ---------------- |\n| `en`          | English             | Default          |\n| `zh-CN`       | Simplified Chinese  | Mainland China   |\n| `zh-TW`       | Traditional Chinese | Taiwan/Hong Kong |\n| `ja`          | Japanese            | Japan            |\n| `ru`          | Russian             | Russia           |\n\n---\n\n## 4.4 Middleware Support\n\nThe framework supports middleware for handling common logic before and after request processing, such as logging, authentication, or performance analysis.\n\n### \u2705 Example Usage\n\n```python\nfrom simplejrpc import ServerApplication\nfrom simplejrpc.interfaces import RPCMiddleware\n\n\nclass CustomMiddleware(RPCMiddleware):\n    def process_request(self, request, context):\n        print(\"[Before] Incoming request:\", request)\n        return request\n\n    def process_response(self, response, context):\n        print(\"[After] Outgoing response:\", response)\n        return response\n\n\n# Register middleware\napp = ServerApplication(\"/xxx/app.sock\")\napp.middleware(CustomMiddleware())\n```\n\n---\n\nWould you like this translated version exported into a PDF or Markdown file?\n\n\nFeedback\n--------\n\nOpen a ticket / fork the project on [Gitee](https://gitee.com/gmssh_1/simplerpc.git).\n\nOpen a ticket / fork the project on [Github](https://github.com/GMSSH/app-sdk-py.git).\n\nHere is the fully translated version of your documentation from Chinese to English:\n\n---\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "simple jsonrpc",
    "version": "2.2.6",
    "project_urls": {
        "Homepage": "https://github.com/GMSSH/app-sdk-py"
    },
    "split_keywords": [
        "gm",
        " gm-sdk",
        " simplejrpc",
        " gmssh",
        " jsonrpc",
        " jsonrpcserver",
        " jsonrpcclient"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "b5ca37f967c13dbc9becb76079cda0325f021133b2040253faf441ed02c0adf3",
                "md5": "b30e2c2adf1ed98d5217446ac2589007",
                "sha256": "bf370f3c822660a0504492aeefda8b87b0b1d80c2746e3a6b66c79f165bd069c"
            },
            "downloads": -1,
            "filename": "simplejrpc-2.2.6-py2.py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "b30e2c2adf1ed98d5217446ac2589007",
            "packagetype": "bdist_wheel",
            "python_version": "py2.py3",
            "requires_python": ">=3.10",
            "size": 54474,
            "upload_time": "2025-07-14T06:35:31",
            "upload_time_iso_8601": "2025-07-14T06:35:31.249604Z",
            "url": "https://files.pythonhosted.org/packages/b5/ca/37f967c13dbc9becb76079cda0325f021133b2040253faf441ed02c0adf3/simplejrpc-2.2.6-py2.py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "872ffaa78c8896eb27ec6fee5f14b0967eb2cb4def6d1eb64e9231ce780d6a52",
                "md5": "7e767adfc6136ae961ac1c1b0971e138",
                "sha256": "4a74f0f45641fe97fed19f10322f3dcba91b94bb192dbddbf97769e7cb361426"
            },
            "downloads": -1,
            "filename": "simplejrpc-2.2.6.tar.gz",
            "has_sig": false,
            "md5_digest": "7e767adfc6136ae961ac1c1b0971e138",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.10",
            "size": 53616,
            "upload_time": "2025-07-14T06:35:32",
            "upload_time_iso_8601": "2025-07-14T06:35:32.752789Z",
            "url": "https://files.pythonhosted.org/packages/87/2f/faa78c8896eb27ec6fee5f14b0967eb2cb4def6d1eb64e9231ce780d6a52/simplejrpc-2.2.6.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-07-14 06:35:32",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "GMSSH",
    "github_project": "app-sdk-py",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "requirements": [
        {
            "name": "jsonrpcclient",
            "specs": [
                [
                    "==",
                    "4.0.3"
                ]
            ]
        },
        {
            "name": "jsonrpcserver",
            "specs": [
                [
                    "==",
                    "5.0.9"
                ]
            ]
        },
        {
            "name": "loguru",
            "specs": [
                [
                    "==",
                    "0.7.3"
                ]
            ]
        },
        {
            "name": "PyYAML",
            "specs": [
                [
                    "==",
                    "6.0.2"
                ]
            ]
        },
        {
            "name": "WTForms",
            "specs": [
                [
                    "==",
                    "3.2.1"
                ]
            ]
        }
    ],
    "lcname": "simplejrpc"
}
        
Elapsed time: 0.82388s