Metadata-Version: 2.5
Name: py-lmobile-toolkit
Version: 4.0.1
Summary: Synchronous and asynchronous Lmobile (微网通联) SMS API client for Python / 微网通联短信接口同步与异步客户端
Project-URL: HomePage, https://gitee.com/guolei19850528/py_lmobile_toolkit
Project-URL: Repository, https://gitee.com/guolei19850528/py_lmobile_toolkit
Author-email: 郭磊 <174000902@qq.com>
License: MIT
License-File: LICENSE
Keywords: asynchronous,http-api,messaging,python-client,sms,synchronous,text-messaging,微网通联,短信,短信发送,短信接口
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Communications :: Chat
Classifier: Topic :: Internet :: WWW/HTTP
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Typing :: Typed
Requires-Python: >=3.9
Requires-Dist: httpx<1.0,>=0.24.0
Requires-Dist: pydantic<3.0,>=2.0.0
Provides-Extra: all
Requires-Dist: mkdocs-material>=9.0.0; extra == 'all'
Requires-Dist: mkdocs>=1.5.0; extra == 'all'
Requires-Dist: mypy>=1.10.0; extra == 'all'
Requires-Dist: pre-commit>=3.7.0; extra == 'all'
Requires-Dist: pytest-asyncio>=0.23.0; extra == 'all'
Requires-Dist: pytest-cov>=5.0.0; extra == 'all'
Requires-Dist: pytest>=8.0.0; extra == 'all'
Requires-Dist: python-dotenv>=1.0.0; extra == 'all'
Requires-Dist: respx>=0.21.0; extra == 'all'
Requires-Dist: ruff>=0.8.0; extra == 'all'
Provides-Extra: dev
Requires-Dist: mypy>=1.10.0; extra == 'dev'
Requires-Dist: pre-commit>=3.7.0; extra == 'dev'
Requires-Dist: python-dotenv>=1.0.0; extra == 'dev'
Requires-Dist: ruff>=0.8.0; extra == 'dev'
Provides-Extra: docs
Requires-Dist: mkdocs-material>=9.0.0; extra == 'docs'
Requires-Dist: mkdocs>=1.5.0; extra == 'docs'
Provides-Extra: test
Requires-Dist: pytest-asyncio>=0.23.0; extra == 'test'
Requires-Dist: pytest-cov>=5.0.0; extra == 'test'
Requires-Dist: pytest>=8.0.0; extra == 'test'
Requires-Dist: respx>=0.21.0; extra == 'test'
Description-Content-Type: text/markdown

# py-lmobile-toolkit

[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

[中文](README.md) | [English](README.en.md)

## 📄 文档

- [微网通联（Lmobile）短信接口官方文档](https://www.lmobile.cn/ApiPages/index.html)
- [httpx](https://www.python-httpx.org/)
- [Pydantic](https://docs.pydantic.dev/)

## 📖 项目介绍

`py-lmobile-toolkit` 是一个用于调用微网通联短信 HTTP 接口的 Python 工具包，为 Python 开发者提供统一的短信提交接口。项目提供同步和异步客户端，使用 `httpx` 发送 HTTP 请求，并使用 Pydantic 校验请求参数及解析接口响应。

本工具包支持 Python 3.9 及以上版本。调用短信发送接口会提交真实请求，请在使用前确认短信平台账户、已报备签名、短信内容和接收号码；短信发送可能产生费用。

## 🏗️ 软件架构

```text
py_lmobile_toolkit/
├── src/py_lmobile_toolkit/
│   ├── __init__.py
│   └── sms/
│       ├── __init__.py
│       ├── client.py       # 短信同步及异步客户端
│       ├── exception.py    # 客户端异常
│       ├── request.py      # 短信请求模型及签名构造
│       └── response.py     # 短信响应模型
├── examples/
│   └── sms/
│       ├── .env.example    # 示例环境变量模板
│       ├── send_sms_sync.py
│       └── send_sms_async.py
└── tests/
    └── sms/
        ├── conftest.py
        └── test_send_sms.py
```

### 核心模块说明

#### sms 模块 - 微网通联短信接口

| 模块 | 说明 |
|------|------|
| `sms/client.py` | 提供同步 `Client` 和异步 `AsyncClient`，均通过 `send_sms` 提交短信。 |
| `sms/request.py` | 定义 `SendSmsPayload` 请求模型，构造认证字段并校验号码、短信内容及可选参数。 |
| `sms/response.py` | 定义 `SendSmsResponse` 响应模型，使用 `ok` 属性判断 `Result` 是否为 `succ`（忽略大小写）。 |
| `sms/exception.py` | 定义 `ConfigError` 配置异常和 `NetworkError` 网络请求异常。 |

## 🛠️ 安装教程

### 方式一：使用 uv 安装（推荐）

```bash
uv add py-lmobile-toolkit
```

### 方式二：使用 pip 安装

```bash
pip install py-lmobile-toolkit
```

### 方式三：从源码安装

```bash
git clone https://gitee.com/guolei19850528/py_lmobile_toolkit.git
cd py_lmobile_toolkit
uv sync
```

## 📖 使用说明

> ⚠️ 注意：以下示例中的账户、密码、号码和签名均为占位内容。请替换为短信平台实际配置，并使用已报备的签名及审核通过的短信内容。执行示例会提交真实短信请求。

### 1. sms 模块 - 短信发送

短信模块通过平台账户、密码和产品编号初始化客户端。`send_sms` 支持单个号码、逗号分隔的号码字符串或号码序列。

#### 1.1 发送短信

**同步发送：**

```python
from py_lmobile_toolkit.sms.client import Client

with Client(
    account_id="短信平台账户",
    password="短信平台密码",
    product_id=1012,
) as client:
    response = client.send_sms(
        ["13800000001", "13800000002"],
        "【已报备签名】这是一条测试短信",
    )
    if response.ok:
        print(f"短信提交成功，消息编号：{response.MsgId}")
    else:
        print(f"短信提交失败：{response.Reason}")
```

**异步发送：**

```python
import asyncio

from py_lmobile_toolkit.sms.client import AsyncClient


async def main() -> None:
    async with AsyncClient(
        account_id="短信平台账户",
        password="短信平台密码",
        product_id=1012,
    ) as client:
        response = await client.send_sms(
            "13800000001,13800000002",
            "【已报备签名】这是一条测试短信",
        )
        if response.ok:
            print(f"短信提交成功，消息编号：{response.MsgId}")
        else:
            print(f"短信提交失败：{response.Reason}")


asyncio.run(main())
```

#### 1.2 客户端配置

同步客户端 `Client` 和异步客户端 `AsyncClient` 使用相同的构造参数：

| 参数 | 必填 | 默认值 | 说明 |
|------|------|--------|------|
| `account_id` | 是 | — | 短信平台账户。 |
| `password` | 是 | — | 短信平台密码。 |
| `product_id` | 是 | — | 短信产品编号，支持正整数或数字字符串；客户端会转换为正整数。 |
| `password_encryption_key` | 否 | `SMmsEncryptKey` | 短信接口使用的密码加密密钥。 |
| `base_url` | 否 | `https://api.51welink.com` | 短信服务接口地址。 |
| `timeout` | 否 | `30.0` | HTTP 请求超时时间，单位为秒。 |

#### 1.3 短信发送参数及响应

`send_sms(phone_nos, content, *, extend_no=None, send_time=None, out_id=None)` 支持以下参数：

| 参数 | 说明 |
|------|------|
| `phone_nos` | 一个号码、号码序列，或英文逗号分隔的号码字符串。 |
| `content` | 短信正文，长度为 1 至 1000 个字符，应包含已报备签名。 |
| `extend_no` | 可选企业扩展码，最多 12 位数字。 |
| `send_time` | 可选定时发送时间，可传字符串或 `datetime`。 |
| `out_id` | 可选用户自定义标识，最多 32 个字符。 |

接口返回 `SendSmsResponse`，其属性名与平台响应字段一致：`Result`、`Reason`、`MsgId` 和 `SplitCount`。`response.ok` 在 `Result` 等于 `succ`（忽略大小写）时为 `True`。

#### 1.4 使用环境变量运行示例

示例脚本从**运行命令时的当前目录**加载 `.env` 文件，且系统中已有的环境变量优先。复制配置模板并填写平台账户、密码、产品编号、接收号码及短信内容：

```bash
cp examples/sms/.env.example .env
```

短信正文 `SMS_CONTENT` 应包含运营商审核通过的短信签名。完成配置后运行同步或异步示例：

```bash
python examples/sms/send_sms_sync.py
```

```bash
python examples/sms/send_sms_async.py
```

`.env` 文件包含账户凭据，请勿提交到版本控制。

#### 1.5 异常处理

客户端配置无效或请求参数不符合模型校验时会产生 `ConfigError` 或 Pydantic `ValidationError`；HTTP 网络请求失败时会产生 `NetworkError`。调用方可根据需要显式处理：

```python
from py_lmobile_toolkit.sms.exception import ConfigError, NetworkError

try:
    # 在此处初始化客户端并调用 send_sms。
    ...
except (ConfigError, NetworkError) as exc:
    print(f"短信请求失败：{exc}")
```

## 🤝 贡献指南

欢迎为 `py-lmobile-toolkit` 贡献代码！如果您想贡献，请按照以下步骤：

1. Fork 本仓库
2. 创建您的特性分支：`git checkout -b feature/your-feature`
3. 提交您的更改：`git commit -m 'Add some feature'`
4. 推送到分支：`git push origin feature/your-feature`
5. 提交一个拉取请求

请确保提交的代码符合代码风格规范，并通过所有测试用例。运行单元测试时请使用：

```bash
uv sync --extra dev --extra test
uv run pytest tests/sms -m "not integration"
```

真实短信集成测试可能产生费用，请勿在未确认账户、号码和短信内容的情况下运行。

## 👨‍💻 作者信息

- **姓名**: 郭磊
- **邮箱**: [174000902@qq.com](mailto:174000902@qq.com)

## 📄 许可证

本项目基于 [MIT 许可证](https://gitee.com/guolei19850528/py_lmobile_toolkit/blob/master/LICENSE) 开源。
