hui-tools


Namehui-tools JSON
Version 0.5.8 PyPI version JSON
download
home_pagehttps://github.com/HuiDBK/py-tools
SummaryNone
upload_time2024-12-07 15:28:52
maintainerNone
docs_urlNone
authorhui
requires_python>=3.8
licenseApache
keywords
VCS
bugtrack_url
requirements openpyxl pandas requests aiohttp python-dateutil loguru cacheout redis python-memcached pytest pydantic sqlalchemy aiomysql minio asgiref nest_asyncio tqdm aiofiles python-jose
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # Py-Tools

> Py-Tools 是一个实用的 Python 工具集和可复用组件库,旨在简化常见任务,提高 Python 项目的开发效率。
> 
> 设计细节请移步到掘金查看:https://juejin.cn/column/7131286129713610766

## 安装
- 环境要求:python version >= 3.8
- 历史版本记录:https://pypi.org/project/hui-tools/#history


### 默认安装
```python
pip install hui-tools
```
默认安装如下功能可以使用
- 时间工具类
- http客户端
- 同步异步互转装饰器
- 常用枚举
- pydantic
- loguru的日志器
- jwt工具类
- 等...

### 全部安装
```python
pip install hui-tools[all]
```

### 可选安装
```python
pip install hui-tools[db-orm, db-redis, excel-tools]
```

可选参数参考:
```python
extras_require = {
    "db-orm": ["sqlalchemy[asyncio]==2.0.20", "aiomysql==0.2.0"],
    "db-redis": ["redis>=4.5.4"],
    "cache-proxy": ["redis>=4.5.4", "python-memcached==1.62", "cacheout==0.14.1"],
    "minio": ["minio==7.1.17"],
    "excel-tools": ["pandas==2.2.2", "openpyxl==3.0.10"],
    "test": ["pytest==7.3.1", "pytest-mock==3.14.0", "pytest-asyncio==0.23.8"],
}
```

### 简单使用
> 所有功能都是从 py_tools 包中导入使用
> 详细使用请查看项目的DEMO: https://github.com/HuiDBK/py-tools/tree/master/demo

生成python web项目结构模板
```python
py_tools make_project WebDemo
```

快速配置项目日志
```python
from py_tools.constants import BASE_DIR
from py_tools.logging import logger, setup_logging


def main():
    setup_logging(log_dir=BASE_DIR / "logs")
    logger.info("use log dir")
    logger.error("test error")


if __name__ == '__main__':
    main()
```

异步http客户端
```python
import asyncio
from py_tools.connections.http import AsyncHttpClient


async def main():
    url = "https://juejin.cn/"
    resp = await AsyncHttpClient().get(url).execute()
    text_data = await AsyncHttpClient().get(url, params={"test": "hui"}).text()
    json_data = await AsyncHttpClient().post(url, data={"test": "hui"}).json()
    byte_data = await AsyncHttpClient().get(url).bytes()
    
    async with AsyncHttpClient() as client:
        upload_file_ret = await client.upload_file(url, file="test.txt").json()
    
    async for chunk in AsyncHttpClient().get(url).stream(chunk_size=512):
        # 流式调用
        print(chunk)
    
    await AsyncHttpClient.close()


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

mysql数据库操作demo
```python
import asyncio
import uuid
from typing import List

from connections.sqlalchemy_demo.manager import UserFileManager
from connections.sqlalchemy_demo.table import UserFileTable
from sqlalchemy import func

from py_tools.connections.db.mysql import BaseOrmTable, DBManager, SQLAlchemyManager

db_client = SQLAlchemyManager(
    host="127.0.0.1",
    port=3306,
    user="root",
    password="123456",
    db_name="hui-demo",
)


async def create_and_transaction_demo():
    async with UserFileManager.transaction() as session:
        await UserFileManager(session).bulk_add(table_objs=[{"filename": "aaa", "oss_key": uuid.uuid4().hex}])
        user_file_obj = UserFileTable(filename="eee", oss_key=uuid.uuid4().hex)
        file_id = await UserFileManager(session).add(table_obj=user_file_obj)
        print("file_id", file_id)

        ret: UserFileTable = await UserFileManager(session).query_by_id(2)
        print("query_by_id", ret)

        # a = 1 / 0

        ret = await UserFileManager(session).query_one(
            cols=[UserFileTable.filename, UserFileTable.oss_key], conds=[UserFileTable.filename == "ccc"],
        )
        print("ret", ret)


async def query_demo():
    ret = await UserFileManager().query_one(conds=[UserFileTable.filename == "ccc"])
    print("ret", ret)

    file_count = await UserFileManager().query_one(cols=[func.count()], flat=True)
    print("str col one ret", file_count)

    filename = await UserFileManager().query_one(cols=[UserFileTable.filename], conds=[UserFileTable.id == 2], flat=True)
    print("filename", filename)

    ret = await UserFileManager().query_all(cols=[UserFileTable.filename, UserFileTable.oss_key])
    print("ret", ret)

    ret = await UserFileManager().query_all(cols=["filename", "oss_key"])
    print("str col ret", ret)

    ret: List[UserFileTable] = await UserFileManager().query_all()
    print("ret", ret)

    ret = await UserFileManager().query_all(cols=[UserFileTable.id], flat=True)
    print("ret", ret)


async def list_page_demo():
    """分页查询demo"""
    total_count, data_list = await UserFileManager().list_page(
        cols=["filename", "oss_key", "file_size"], curr_page=2, page_size=10
    )
    print("total_count", total_count, f"data_list[{len(data_list)}]", data_list)


async def run_raw_sql_demo():
    """运行原生sql demo"""
    count_sql = "select count(*) as total_count from user_file"
    count_ret = await UserFileManager().run_sql(count_sql, query_one=True)
    print("count_ret", count_ret)

    data_sql = "select * from user_file where id > :id_val and file_size >= :file_size_val"
    params = {"id_val": 20, "file_size_val": 0}
    data_ret = await UserFileManager().run_sql(data_sql, params=params)
    print("dict data_ret", data_ret)

    # 连表查询
    data_sql = """
    select
        user.id as user_id,
        username,
        user_file.id as file_id,
        filename,
        oss_key
    from 
        user_file
        join user on user.id = user_file.creator
    where 
        user_file.creator = :user_id
    """
    data_ret = await UserFileManager().run_sql(data_sql, params={"user_id": 1})
    print("join sql data_ret", data_ret)


async def curd_demo():
    await create_and_transaction_demo()
    await query_demo()
    await list_page_demo()
    await run_raw_sql_demo()


async def create_tables():
    # 根据映射创建库表
    async with DBManager.connection() as conn:
        await conn.run_sync(BaseOrmTable.metadata.create_all)


async def main():
    db_client.init_mysql_engine()
    DBManager.init_db_client(db_client)
    await create_tables()
    await curd_demo()


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

```

## Todo List

### 连接客户端
1. [x] http 同步异步客户端
2. [x] MySQL 客户端 - SQLAlchemy-ORM 封装
3. [x] Redis 客户端
4. [x] Minio 客户端 
5. 消息队列客户端,rabbitmq、kafka 
6. websocket 客户端

### 工具类
- [x] 同异步函数转化工具类
- [x] excel 工具类
- [x] 文件 工具类
- [x] 实用函数工具模块
- [x] 数据掩码工具类
- [x] 常用正则工具类
- [x] 时间工具类
- [x] 树结构转换工具类
- [x] pydantic model 、dataclass 与 SQLALChemy table 序列化与反序列工具类
- 认证相关工具类
  - [x] JWT 工具类
- 图片操作工具类,例如校验图片分辨率
- 邮件服务工具类
- 配置解析工具类
- 编码工具类,统一 base64、md5等编码入口
- 加密工具类

### 装饰器
1. [x] 超时装饰器
2. [x] 重试装饰器
3. [x] 缓存装饰器
4. [x] 异步执行装饰器

### 枚举
1. [x] 通用枚举类封装
2. [x] 错误码枚举封装
3. [x] 常用枚举

### 异常
1. [x] 业务异常类封装

### 日志
1. [x] logger 日志器(loguru)
2. [x] 快速配置项目日志函数

## 工程目录结构

```
py-tools/
    ├── py_tools/
    │   ├── chatbot/
    │   ├── connections/
    │   ├── constants/
    │   ├── data_schemas/
    │   ├── decorators/
    │   ├── enums/
    │   ├── exceptions/
    │   ├── meta_cls/
    │   └── utils/
    ├── docs/
    ├── demo/
    ├── tests/
    ├── .gitignore
    ├── LICENSE
    ├── README.md
    └── requirements.txt
```



### 项目模块

- **chatbot**: 用于构建和管理聊天机器人互动的工具集。
- **connections**: 用于连接各种服务和 API 的连接管理工具。
- **constants**: Python 项目中常用的常量。
- **data_schemas**: 用于处理结构化数据的数据模型及相关工具。
- **decorators**: 一系列有用的装饰器,用以增强函数和方法。
- **enums**: 定义常用枚举类型,方便在项目中使用。
- **exceptions**: 自定义异常类,用于项目中的错误处理。
- **meta_cls**: 元类和元编程相关的工具和技术。
- **utils**: 包含各种实用函数和工具,用于简化日常编程任务。



### 项目文档

在 `docs` 目录下存放一些项目相关文档。



### 示例

在 `demo` 目录下,您可以找到一些使用 Py-Tools 的示例代码,这些代码展示了如何使用这些工具集实现实际项目中的任务。

demo:https://github.com/HuiDBK/py-tools/tree/master/demo

### 测试

在 `tests` 目录下,包含了针对 Py-Tools 的各个组件的单元测试。通过运行这些测试,您可以确保工具集在您的环境中正常工作。



## 一起贡献
> 欢迎您对本项目进行贡献。请在提交 Pull Request 之前阅读项目的贡献指南,并确保您的代码符合项目的代码风格。

1. Fork后克隆本项目到本地:
```bash
git clone https://github.com/<github_name>/py-tools.git
```

2. 安装依赖:
```python
pip install -r requirements.txt
```

3. 配置python代码风格检查到 git hook 中

安装 pre-commit
```python
pip install pre-commit
```

再项目目录下执行
```python
pre-commit install
```
安装成功后 git commit 后会提前进行代码检查

4. 提PR

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/HuiDBK/py-tools",
    "name": "hui-tools",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.8",
    "maintainer_email": null,
    "keywords": null,
    "author": "hui",
    "author_email": "huidbk@163.com",
    "download_url": "https://files.pythonhosted.org/packages/1c/4f/b415c9f0f6ce905d4b888170e458f013238e0c726a0b0876f243806a8aa0/hui-tools-0.5.8.tar.gz",
    "platform": null,
    "description": "# Py-Tools\n\n> Py-Tools \u662f\u4e00\u4e2a\u5b9e\u7528\u7684 Python \u5de5\u5177\u96c6\u548c\u53ef\u590d\u7528\u7ec4\u4ef6\u5e93\uff0c\u65e8\u5728\u7b80\u5316\u5e38\u89c1\u4efb\u52a1\uff0c\u63d0\u9ad8 Python \u9879\u76ee\u7684\u5f00\u53d1\u6548\u7387\u3002\n> \n> \u8bbe\u8ba1\u7ec6\u8282\u8bf7\u79fb\u6b65\u5230\u6398\u91d1\u67e5\u770b\uff1ahttps://juejin.cn/column/7131286129713610766\n\n## \u5b89\u88c5\n- \u73af\u5883\u8981\u6c42\uff1apython version >= 3.8\n- \u5386\u53f2\u7248\u672c\u8bb0\u5f55\uff1ahttps://pypi.org/project/hui-tools/#history\n\n\n### \u9ed8\u8ba4\u5b89\u88c5\n```python\npip install hui-tools\n```\n\u9ed8\u8ba4\u5b89\u88c5\u5982\u4e0b\u529f\u80fd\u53ef\u4ee5\u4f7f\u7528\n- \u65f6\u95f4\u5de5\u5177\u7c7b\n- http\u5ba2\u6237\u7aef\n- \u540c\u6b65\u5f02\u6b65\u4e92\u8f6c\u88c5\u9970\u5668\n- \u5e38\u7528\u679a\u4e3e\n- pydantic\n- loguru\u7684\u65e5\u5fd7\u5668\n- jwt\u5de5\u5177\u7c7b\n- \u7b49...\n\n### \u5168\u90e8\u5b89\u88c5\n```python\npip install hui-tools[all]\n```\n\n### \u53ef\u9009\u5b89\u88c5\n```python\npip install hui-tools[db-orm, db-redis, excel-tools]\n```\n\n\u53ef\u9009\u53c2\u6570\u53c2\u8003\uff1a\n```python\nextras_require = {\n    \"db-orm\": [\"sqlalchemy[asyncio]==2.0.20\", \"aiomysql==0.2.0\"],\n    \"db-redis\": [\"redis>=4.5.4\"],\n    \"cache-proxy\": [\"redis>=4.5.4\", \"python-memcached==1.62\", \"cacheout==0.14.1\"],\n    \"minio\": [\"minio==7.1.17\"],\n    \"excel-tools\": [\"pandas==2.2.2\", \"openpyxl==3.0.10\"],\n    \"test\": [\"pytest==7.3.1\", \"pytest-mock==3.14.0\", \"pytest-asyncio==0.23.8\"],\n}\n```\n\n### \u7b80\u5355\u4f7f\u7528\n> \u6240\u6709\u529f\u80fd\u90fd\u662f\u4ece py_tools \u5305\u4e2d\u5bfc\u5165\u4f7f\u7528\n> \u8be6\u7ec6\u4f7f\u7528\u8bf7\u67e5\u770b\u9879\u76ee\u7684DEMO\uff1a https://github.com/HuiDBK/py-tools/tree/master/demo\n\n\u751f\u6210python web\u9879\u76ee\u7ed3\u6784\u6a21\u677f\n```python\npy_tools make_project WebDemo\n```\n\n\u5feb\u901f\u914d\u7f6e\u9879\u76ee\u65e5\u5fd7\n```python\nfrom py_tools.constants import BASE_DIR\nfrom py_tools.logging import logger, setup_logging\n\n\ndef main():\n    setup_logging(log_dir=BASE_DIR / \"logs\")\n    logger.info(\"use log dir\")\n    logger.error(\"test error\")\n\n\nif __name__ == '__main__':\n    main()\n```\n\n\u5f02\u6b65http\u5ba2\u6237\u7aef\n```python\nimport asyncio\nfrom py_tools.connections.http import AsyncHttpClient\n\n\nasync def main():\n    url = \"https://juejin.cn/\"\n    resp = await AsyncHttpClient().get(url).execute()\n    text_data = await AsyncHttpClient().get(url, params={\"test\": \"hui\"}).text()\n    json_data = await AsyncHttpClient().post(url, data={\"test\": \"hui\"}).json()\n    byte_data = await AsyncHttpClient().get(url).bytes()\n    \n    async with AsyncHttpClient() as client:\n        upload_file_ret = await client.upload_file(url, file=\"test.txt\").json()\n    \n    async for chunk in AsyncHttpClient().get(url).stream(chunk_size=512):\n        # \u6d41\u5f0f\u8c03\u7528\n        print(chunk)\n    \n    await AsyncHttpClient.close()\n\n\nif __name__ == \"__main__\":\n    asyncio.run(main())\n```\n\nmysql\u6570\u636e\u5e93\u64cd\u4f5cdemo\n```python\nimport asyncio\nimport uuid\nfrom typing import List\n\nfrom connections.sqlalchemy_demo.manager import UserFileManager\nfrom connections.sqlalchemy_demo.table import UserFileTable\nfrom sqlalchemy import func\n\nfrom py_tools.connections.db.mysql import BaseOrmTable, DBManager, SQLAlchemyManager\n\ndb_client = SQLAlchemyManager(\n    host=\"127.0.0.1\",\n    port=3306,\n    user=\"root\",\n    password=\"123456\",\n    db_name=\"hui-demo\",\n)\n\n\nasync def create_and_transaction_demo():\n    async with UserFileManager.transaction() as session:\n        await UserFileManager(session).bulk_add(table_objs=[{\"filename\": \"aaa\", \"oss_key\": uuid.uuid4().hex}])\n        user_file_obj = UserFileTable(filename=\"eee\", oss_key=uuid.uuid4().hex)\n        file_id = await UserFileManager(session).add(table_obj=user_file_obj)\n        print(\"file_id\", file_id)\n\n        ret: UserFileTable = await UserFileManager(session).query_by_id(2)\n        print(\"query_by_id\", ret)\n\n        # a = 1 / 0\n\n        ret = await UserFileManager(session).query_one(\n            cols=[UserFileTable.filename, UserFileTable.oss_key], conds=[UserFileTable.filename == \"ccc\"],\n        )\n        print(\"ret\", ret)\n\n\nasync def query_demo():\n    ret = await UserFileManager().query_one(conds=[UserFileTable.filename == \"ccc\"])\n    print(\"ret\", ret)\n\n    file_count = await UserFileManager().query_one(cols=[func.count()], flat=True)\n    print(\"str col one ret\", file_count)\n\n    filename = await UserFileManager().query_one(cols=[UserFileTable.filename], conds=[UserFileTable.id == 2], flat=True)\n    print(\"filename\", filename)\n\n    ret = await UserFileManager().query_all(cols=[UserFileTable.filename, UserFileTable.oss_key])\n    print(\"ret\", ret)\n\n    ret = await UserFileManager().query_all(cols=[\"filename\", \"oss_key\"])\n    print(\"str col ret\", ret)\n\n    ret: List[UserFileTable] = await UserFileManager().query_all()\n    print(\"ret\", ret)\n\n    ret = await UserFileManager().query_all(cols=[UserFileTable.id], flat=True)\n    print(\"ret\", ret)\n\n\nasync def list_page_demo():\n    \"\"\"\u5206\u9875\u67e5\u8be2demo\"\"\"\n    total_count, data_list = await UserFileManager().list_page(\n        cols=[\"filename\", \"oss_key\", \"file_size\"], curr_page=2, page_size=10\n    )\n    print(\"total_count\", total_count, f\"data_list[{len(data_list)}]\", data_list)\n\n\nasync def run_raw_sql_demo():\n    \"\"\"\u8fd0\u884c\u539f\u751fsql demo\"\"\"\n    count_sql = \"select count(*) as total_count from user_file\"\n    count_ret = await UserFileManager().run_sql(count_sql, query_one=True)\n    print(\"count_ret\", count_ret)\n\n    data_sql = \"select * from user_file where id > :id_val and file_size >= :file_size_val\"\n    params = {\"id_val\": 20, \"file_size_val\": 0}\n    data_ret = await UserFileManager().run_sql(data_sql, params=params)\n    print(\"dict data_ret\", data_ret)\n\n    # \u8fde\u8868\u67e5\u8be2\n    data_sql = \"\"\"\n    select\n        user.id as user_id,\n        username,\n        user_file.id as file_id,\n        filename,\n        oss_key\n    from \n        user_file\n        join user on user.id = user_file.creator\n    where \n        user_file.creator = :user_id\n    \"\"\"\n    data_ret = await UserFileManager().run_sql(data_sql, params={\"user_id\": 1})\n    print(\"join sql data_ret\", data_ret)\n\n\nasync def curd_demo():\n    await create_and_transaction_demo()\n    await query_demo()\n    await list_page_demo()\n    await run_raw_sql_demo()\n\n\nasync def create_tables():\n    # \u6839\u636e\u6620\u5c04\u521b\u5efa\u5e93\u8868\n    async with DBManager.connection() as conn:\n        await conn.run_sync(BaseOrmTable.metadata.create_all)\n\n\nasync def main():\n    db_client.init_mysql_engine()\n    DBManager.init_db_client(db_client)\n    await create_tables()\n    await curd_demo()\n\n\nif __name__ == \"__main__\":\n    asyncio.run(main())\n\n```\n\n## Todo List\n\n### \u8fde\u63a5\u5ba2\u6237\u7aef\n1. [x] http \u540c\u6b65\u5f02\u6b65\u5ba2\u6237\u7aef\n2. [x] MySQL \u5ba2\u6237\u7aef - SQLAlchemy-ORM \u5c01\u88c5\n3. [x] Redis \u5ba2\u6237\u7aef\n4. [x] Minio \u5ba2\u6237\u7aef \n5. \u6d88\u606f\u961f\u5217\u5ba2\u6237\u7aef\uff0crabbitmq\u3001kafka \n6. websocket \u5ba2\u6237\u7aef\n\n### \u5de5\u5177\u7c7b\n- [x] \u540c\u5f02\u6b65\u51fd\u6570\u8f6c\u5316\u5de5\u5177\u7c7b\n- [x] excel \u5de5\u5177\u7c7b\n- [x] \u6587\u4ef6 \u5de5\u5177\u7c7b\n- [x] \u5b9e\u7528\u51fd\u6570\u5de5\u5177\u6a21\u5757\n- [x] \u6570\u636e\u63a9\u7801\u5de5\u5177\u7c7b\n- [x] \u5e38\u7528\u6b63\u5219\u5de5\u5177\u7c7b\n- [x] \u65f6\u95f4\u5de5\u5177\u7c7b\n- [x] \u6811\u7ed3\u6784\u8f6c\u6362\u5de5\u5177\u7c7b\n- [x] pydantic model \u3001dataclass \u4e0e SQLALChemy table \u5e8f\u5217\u5316\u4e0e\u53cd\u5e8f\u5217\u5de5\u5177\u7c7b\n- \u8ba4\u8bc1\u76f8\u5173\u5de5\u5177\u7c7b\n  - [x] JWT \u5de5\u5177\u7c7b\n- \u56fe\u7247\u64cd\u4f5c\u5de5\u5177\u7c7b\uff0c\u4f8b\u5982\u6821\u9a8c\u56fe\u7247\u5206\u8fa8\u7387\n- \u90ae\u4ef6\u670d\u52a1\u5de5\u5177\u7c7b\n- \u914d\u7f6e\u89e3\u6790\u5de5\u5177\u7c7b\n- \u7f16\u7801\u5de5\u5177\u7c7b\uff0c\u7edf\u4e00 base64\u3001md5\u7b49\u7f16\u7801\u5165\u53e3\n- \u52a0\u5bc6\u5de5\u5177\u7c7b\n\n### \u88c5\u9970\u5668\n1. [x] \u8d85\u65f6\u88c5\u9970\u5668\n2. [x] \u91cd\u8bd5\u88c5\u9970\u5668\n3. [x] \u7f13\u5b58\u88c5\u9970\u5668\n4. [x] \u5f02\u6b65\u6267\u884c\u88c5\u9970\u5668\n\n### \u679a\u4e3e\n1. [x] \u901a\u7528\u679a\u4e3e\u7c7b\u5c01\u88c5\n2. [x] \u9519\u8bef\u7801\u679a\u4e3e\u5c01\u88c5\n3. [x] \u5e38\u7528\u679a\u4e3e\n\n### \u5f02\u5e38\n1. [x] \u4e1a\u52a1\u5f02\u5e38\u7c7b\u5c01\u88c5\n\n### \u65e5\u5fd7\n1. [x] logger \u65e5\u5fd7\u5668\uff08loguru\uff09\n2. [x] \u5feb\u901f\u914d\u7f6e\u9879\u76ee\u65e5\u5fd7\u51fd\u6570\n\n## \u5de5\u7a0b\u76ee\u5f55\u7ed3\u6784\n\n```\npy-tools/\n    \u251c\u2500\u2500 py_tools/\n    \u2502   \u251c\u2500\u2500 chatbot/\n    \u2502   \u251c\u2500\u2500 connections/\n    \u2502   \u251c\u2500\u2500 constants/\n    \u2502   \u251c\u2500\u2500 data_schemas/\n    \u2502   \u251c\u2500\u2500 decorators/\n    \u2502   \u251c\u2500\u2500 enums/\n    \u2502   \u251c\u2500\u2500 exceptions/\n    \u2502   \u251c\u2500\u2500 meta_cls/\n    \u2502   \u2514\u2500\u2500 utils/\n    \u251c\u2500\u2500 docs/\n    \u251c\u2500\u2500 demo/\n    \u251c\u2500\u2500 tests/\n    \u251c\u2500\u2500 .gitignore\n    \u251c\u2500\u2500 LICENSE\n    \u251c\u2500\u2500 README.md\n    \u2514\u2500\u2500 requirements.txt\n```\n\n\n\n### \u9879\u76ee\u6a21\u5757\n\n- **chatbot**: \u7528\u4e8e\u6784\u5efa\u548c\u7ba1\u7406\u804a\u5929\u673a\u5668\u4eba\u4e92\u52a8\u7684\u5de5\u5177\u96c6\u3002\n- **connections**: \u7528\u4e8e\u8fde\u63a5\u5404\u79cd\u670d\u52a1\u548c API \u7684\u8fde\u63a5\u7ba1\u7406\u5de5\u5177\u3002\n- **constants**: Python \u9879\u76ee\u4e2d\u5e38\u7528\u7684\u5e38\u91cf\u3002\n- **data_schemas**: \u7528\u4e8e\u5904\u7406\u7ed3\u6784\u5316\u6570\u636e\u7684\u6570\u636e\u6a21\u578b\u53ca\u76f8\u5173\u5de5\u5177\u3002\n- **decorators**: \u4e00\u7cfb\u5217\u6709\u7528\u7684\u88c5\u9970\u5668\uff0c\u7528\u4ee5\u589e\u5f3a\u51fd\u6570\u548c\u65b9\u6cd5\u3002\n- **enums**: \u5b9a\u4e49\u5e38\u7528\u679a\u4e3e\u7c7b\u578b\uff0c\u65b9\u4fbf\u5728\u9879\u76ee\u4e2d\u4f7f\u7528\u3002\n- **exceptions**: \u81ea\u5b9a\u4e49\u5f02\u5e38\u7c7b\uff0c\u7528\u4e8e\u9879\u76ee\u4e2d\u7684\u9519\u8bef\u5904\u7406\u3002\n- **meta_cls**: \u5143\u7c7b\u548c\u5143\u7f16\u7a0b\u76f8\u5173\u7684\u5de5\u5177\u548c\u6280\u672f\u3002\n- **utils**: \u5305\u542b\u5404\u79cd\u5b9e\u7528\u51fd\u6570\u548c\u5de5\u5177\uff0c\u7528\u4e8e\u7b80\u5316\u65e5\u5e38\u7f16\u7a0b\u4efb\u52a1\u3002\n\n\n\n### \u9879\u76ee\u6587\u6863\n\n\u5728 `docs` \u76ee\u5f55\u4e0b\u5b58\u653e\u4e00\u4e9b\u9879\u76ee\u76f8\u5173\u6587\u6863\u3002\n\n\n\n### \u793a\u4f8b\n\n\u5728 `demo` \u76ee\u5f55\u4e0b\uff0c\u60a8\u53ef\u4ee5\u627e\u5230\u4e00\u4e9b\u4f7f\u7528 Py-Tools \u7684\u793a\u4f8b\u4ee3\u7801\uff0c\u8fd9\u4e9b\u4ee3\u7801\u5c55\u793a\u4e86\u5982\u4f55\u4f7f\u7528\u8fd9\u4e9b\u5de5\u5177\u96c6\u5b9e\u73b0\u5b9e\u9645\u9879\u76ee\u4e2d\u7684\u4efb\u52a1\u3002\n\ndemo\uff1ahttps://github.com/HuiDBK/py-tools/tree/master/demo\n\n### \u6d4b\u8bd5\n\n\u5728 `tests` \u76ee\u5f55\u4e0b\uff0c\u5305\u542b\u4e86\u9488\u5bf9 Py-Tools \u7684\u5404\u4e2a\u7ec4\u4ef6\u7684\u5355\u5143\u6d4b\u8bd5\u3002\u901a\u8fc7\u8fd0\u884c\u8fd9\u4e9b\u6d4b\u8bd5\uff0c\u60a8\u53ef\u4ee5\u786e\u4fdd\u5de5\u5177\u96c6\u5728\u60a8\u7684\u73af\u5883\u4e2d\u6b63\u5e38\u5de5\u4f5c\u3002\n\n\n\n## \u4e00\u8d77\u8d21\u732e\n> \u6b22\u8fce\u60a8\u5bf9\u672c\u9879\u76ee\u8fdb\u884c\u8d21\u732e\u3002\u8bf7\u5728\u63d0\u4ea4 Pull Request \u4e4b\u524d\u9605\u8bfb\u9879\u76ee\u7684\u8d21\u732e\u6307\u5357\uff0c\u5e76\u786e\u4fdd\u60a8\u7684\u4ee3\u7801\u7b26\u5408\u9879\u76ee\u7684\u4ee3\u7801\u98ce\u683c\u3002\n\n1. Fork\u540e\u514b\u9686\u672c\u9879\u76ee\u5230\u672c\u5730\uff1a\n```bash\ngit clone https://github.com/<github_name>/py-tools.git\n```\n\n2. \u5b89\u88c5\u4f9d\u8d56:\n```python\npip install -r requirements.txt\n```\n\n3. \u914d\u7f6epython\u4ee3\u7801\u98ce\u683c\u68c0\u67e5\u5230 git hook \u4e2d\n\n\u5b89\u88c5 pre-commit\n```python\npip install pre-commit\n```\n\n\u518d\u9879\u76ee\u76ee\u5f55\u4e0b\u6267\u884c\n```python\npre-commit install\n```\n\u5b89\u88c5\u6210\u529f\u540e git commit \u540e\u4f1a\u63d0\u524d\u8fdb\u884c\u4ee3\u7801\u68c0\u67e5\n\n4. \u63d0PR\n",
    "bugtrack_url": null,
    "license": "Apache",
    "summary": null,
    "version": "0.5.8",
    "project_urls": {
        "Homepage": "https://github.com/HuiDBK/py-tools"
    },
    "split_keywords": [],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "b75ce77e611ebfdd682f3c87108f23c256b37514190aad0b2b4906509543a64f",
                "md5": "80967dc71123aafe1b13156be4cb201e",
                "sha256": "eb6c33916ffdfcc9e290949c8972d3b1376be477473ef89b0e989286d71d6438"
            },
            "downloads": -1,
            "filename": "hui_tools-0.5.8-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "80967dc71123aafe1b13156be4cb201e",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.8",
            "size": 74244,
            "upload_time": "2024-12-07T15:28:47",
            "upload_time_iso_8601": "2024-12-07T15:28:47.767341Z",
            "url": "https://files.pythonhosted.org/packages/b7/5c/e77e611ebfdd682f3c87108f23c256b37514190aad0b2b4906509543a64f/hui_tools-0.5.8-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "1c4fb415c9f0f6ce905d4b888170e458f013238e0c726a0b0876f243806a8aa0",
                "md5": "276de1ebf81329d4ea3e94ca537ba63e",
                "sha256": "ba4cbf8524a59f71690f14b3d287085c8dea7e09178870a2c35a0b84f7c429f6"
            },
            "downloads": -1,
            "filename": "hui-tools-0.5.8.tar.gz",
            "has_sig": false,
            "md5_digest": "276de1ebf81329d4ea3e94ca537ba63e",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.8",
            "size": 52592,
            "upload_time": "2024-12-07T15:28:52",
            "upload_time_iso_8601": "2024-12-07T15:28:52.368194Z",
            "url": "https://files.pythonhosted.org/packages/1c/4f/b415c9f0f6ce905d4b888170e458f013238e0c726a0b0876f243806a8aa0/hui-tools-0.5.8.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-12-07 15:28:52",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "HuiDBK",
    "github_project": "py-tools",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "requirements": [
        {
            "name": "openpyxl",
            "specs": [
                [
                    "==",
                    "3.0.10"
                ]
            ]
        },
        {
            "name": "pandas",
            "specs": [
                [
                    "==",
                    "2.0.3"
                ]
            ]
        },
        {
            "name": "requests",
            "specs": [
                [
                    "==",
                    "2.31.0"
                ]
            ]
        },
        {
            "name": "aiohttp",
            "specs": [
                [
                    "==",
                    "3.9.5"
                ]
            ]
        },
        {
            "name": "python-dateutil",
            "specs": [
                [
                    "==",
                    "2.8.2"
                ]
            ]
        },
        {
            "name": "loguru",
            "specs": [
                [
                    "==",
                    "0.7.2"
                ]
            ]
        },
        {
            "name": "cacheout",
            "specs": [
                [
                    "==",
                    "0.14.1"
                ]
            ]
        },
        {
            "name": "redis",
            "specs": [
                [
                    "==",
                    "5.0.1"
                ]
            ]
        },
        {
            "name": "python-memcached",
            "specs": [
                [
                    "==",
                    "1.62"
                ]
            ]
        },
        {
            "name": "pytest",
            "specs": [
                [
                    "==",
                    "7.3.1"
                ]
            ]
        },
        {
            "name": "pydantic",
            "specs": [
                [
                    "==",
                    "2.1.1"
                ]
            ]
        },
        {
            "name": "sqlalchemy",
            "specs": [
                [
                    "==",
                    "2.0.20"
                ]
            ]
        },
        {
            "name": "aiomysql",
            "specs": [
                [
                    "==",
                    "0.2.0"
                ]
            ]
        },
        {
            "name": "minio",
            "specs": [
                [
                    "==",
                    "7.1.17"
                ]
            ]
        },
        {
            "name": "asgiref",
            "specs": [
                [
                    "==",
                    "3.8.1"
                ]
            ]
        },
        {
            "name": "nest_asyncio",
            "specs": [
                [
                    "==",
                    "1.6.0"
                ]
            ]
        },
        {
            "name": "tqdm",
            "specs": [
                [
                    "==",
                    "4.66.4"
                ]
            ]
        },
        {
            "name": "aiofiles",
            "specs": [
                [
                    "==",
                    "24.1.0"
                ]
            ]
        },
        {
            "name": "python-jose",
            "specs": [
                [
                    "==",
                    "3.3.0"
                ]
            ]
        }
    ],
    "lcname": "hui-tools"
}
        
hui
Elapsed time: 3.17304s