zheliku-tool


Namezheliku-tool JSON
Version 0.1.4 PyPI version JSON
download
home_pageNone
SummaryLightweight timing decorator & context manager with loguru-like formatting, sync/async.
upload_time2025-11-03 17:35:57
maintainerNone
docs_urlNone
authorzheliku
requires_python>=3.12
licenseNone
keywords logging timer performance decorator asyncio
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # ⏱️ zheliku-tool

> 🔧 高精度 Python 函数计时与日志记录工具
> 基于标准库 `logging` 实现,兼容同步/异步函数、上下文管理器与滚动日志,
> 支持环境变量开关、loguru 风格格式、跨平台使用。

---

## 🌟 功能概述

`zheliku-tool` 提供了一个轻量级的计时装饰器与上下文管理器 `TimeLogger`,
让你可以一行代码轻松记录任意函数或代码块的执行耗时。

特点:

* ✅ 同步、异步函数统一支持
* ✅ 上下文管理器 (`with` / `async with`)
* ✅ 日志格式与 [loguru](https://github.com/Delgan/loguru) 兼容,带毫秒时间
* ✅ 自动创建日志目录,支持滚动文件
* ✅ 可通过环境变量一键开关
* ✅ 支持自定义文件名、日志目录与等级
* ✅ 提供片段计时器与函数式 API
* ✅ 无外部依赖,仅使用 Python 标准库

---

## 📦 安装

```bash
# 使用 uv(推荐)
uv add zheliku-tool

# 或使用 pip
pip install zheliku-tool
```

安装后导入:

```python
from zheliku_tool import TimeLogger, time_log
```

---

## 🧭 快速开始

### ✅ 1. 装饰器用法

```python
from zheliku_tool import TimeLogger


@TimeLogger(log_file="run.log")
def preprocess(data):
    # 模拟耗时计算
    import time;
    time.sleep(0.02)
    return [d ** 2 for d in data]


preprocess([1, 2, 3])
```

日志输出示例(默认格式):

```
2025-11-03 15:00:21.512 | INFO     | __main__.preprocess:7 - Ran preprocess in 20.132 ms (module=__main__, file=example.py, abs='/path/example.py', line=7, pid=3901, thread=MainThread)
```

---

### ✅ 2. 异步函数

```python
import asyncio
from zheliku_tool import TimeLogger


@TimeLogger(log_file="async.log", level=logging.DEBUG)
async def fetch_data():
    await asyncio.sleep(0.01)
    return "done"


asyncio.run(fetch_data())
```

---

### ✅ 3. 上下文管理器

```python
from zheliku_tool import TimeLogger

with TimeLogger(logger_name="load_stage", log_file="stages.log"):
    # 一段代码的耗时
    sum(i * i for i in range(10_000))
```

异步上下文同理:

```python
async with TimeLogger(logger_name="async_stage", log_file="stages.log"):
    await asyncio.sleep(0.05)
```

---

### ✅ 4. 函数式上下文 API(更简洁)

```python
from zheliku_tool import time_log

with time_log("evaluate", log_file="run.log"):
    result = sum(range(1000))
```

等价于:

```python
with TimeLogger(logger_name="evaluate", log_file="run.log"):
    result = sum(range(1000))
```

---

### ✅ 5. 手动片段计时(代码内部多段耗时)

```python
from zheliku_tool import TimeLogger


def train_step():
    seg = TimeLogger.start("train")
    # 执行部分任务
    import time;
    time.sleep(0.03)
    elapsed = seg.stop()
    print(f"train_step 耗时 {elapsed:.2f} ms")
```

---

## ⚙️ 参数说明

| 参数名            | 类型                    | 默认值                   | 说明                                            |                      |
|----------------|-----------------------|-----------------------|-----------------------------------------------|----------------------|
| `level`        | `int`                 | `logging.INFO`        | 日志等级(支持 `DEBUG/INFO/WARNING/ERROR`)           |                      |
| `enable`       | `bool`                | `True`                | 是否启用计时,`False` 时直接调用函数不记录                     |                      |
| `log_dir`      | `str \| Path`         | `None`                | 日志目录(未提供时自动取函数所在文件夹)                          |
| `log_file`     | `str \| Path` | `None`                | 日志文件路径,可相对/绝对                                 |
| `extra_msg`    | `str`                 | `None`                | 附加备注文本                                        |                      |
| `fmt`          | `str`                 | 内置默认                  | `logging` 输出格式                                |                      |
| `datefmt`      | `str`                 | `"%Y-%m-%d %H:%M:%S"` | 时间格式                                          |                      |
| `logger_name`  | `str`                 | `None`                | 自定义 logger 名(默认 `<module>.<qualname>:<line>`) |                      |
| `rotate`       | `bool`                | `False`               | 是否使用滚动日志                                      |                      |
| `max_bytes`    | `int`                 | `10*1024*1024`        | 滚动阈值(字节)                                      |                      |
| `backup_count` | `int`                 | `3`                   | 滚动保留文件数                                       |                      |

---

## 🧩 环境变量控制

> 所有环境变量均可在运行前通过 `export` 或 `.env` 文件设置。
> 优先级高于代码参数。

| 环境变量                                                    | 说明                                |
|---------------------------------------------------------|-----------------------------------|
| `TIME_LOG_ENABLE` / `TIMER_LOG_ENABLE` / `TIMER_ENABLE` | 是否启用日志(`0`、`false` 表示关闭)          |
| `TIME_LOG_LEVEL` / `TIMER_LOG_LEVEL` / `TIMER_LEVEL`    | 设置全局日志等级,如 `DEBUG`、`INFO`、`ERROR` |

### 示例:

```bash
export TIME_LOG_ENABLE=0   # 全局关闭日志
export TIMER_LOG_LEVEL=DEBUG
```

---

## 🧰 日志落地规则

1. 如果提供 `log_file`:

    * **绝对路径**:直接使用;
    * **相对路径**:基于 `log_dir`(若提供)或源文件目录。
2. 如果未提供 `log_file`:

    * 自动生成 `<源文件同名>.log`;
    * 目录为 `log_dir` 或源文件目录。
3. 会自动创建不存在的目录。
4. 同一路径复用同一个 `FileHandler`,不会重复写入。

---

## 📖 输出格式

默认格式(可自定义):

```
%(asctime)s.%(msecs)03d | %(levelname)-8s | %(name)s - %(message)s
```

对应输出示例:

```
2025-11-03 14:59:01.512 | INFO     | mymodule.train:42 - Ran train in 14.832 ms (module=mymodule, file=train.py, abs='/project/train.py', line=42, pid=1234, thread=MainThread)
```

---

## 🚀 高级用法

### 🔄 滚动日志

自动切分日志文件,防止文件过大:

```python
@TimeLogger(log_file="pipeline.log", rotate=True, max_bytes=1024 * 100, backup_count=5)
def pipeline():
    ...
```

---

### 🔍 临时禁用

```python
@TimeLogger(enable=False)
def quick_func():
    pass  # 不会产生日志
```

---

### 🔧 动态控制(环境变量)

无需改代码,运行前即可启用/禁用:

```bash
TIME_LOG_ENABLE=0 uv run python your_script.py
```

---

### 🧠 线程/进程安全性

* 日志文件写入使用标准库 `FileHandler`;
* 同一 logger 不会重复绑定;
* 可在多线程下安全使用(每条日志独立写入)。

---

## 🧪 单元测试覆盖(pytest)

完整测试文件见 `tests/test_time_tool.py`,包括:

* 同步/异步装饰器
* 同步/异步上下文
* 路径解析
* 滚动日志
* 环境变量开关
* 重复 handler 检测
* 片段计时器
* 函数式上下文管理

运行测试:

```bash
uv run pytest -v
```

---

## 📜 许可证

MIT License © 2025 [zheliku](https://github.com/zheliku)


            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "zheliku-tool",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.12",
    "maintainer_email": null,
    "keywords": "logging, timer, performance, decorator, asyncio",
    "author": "zheliku",
    "author_email": null,
    "download_url": "https://files.pythonhosted.org/packages/8d/ec/7e1e4663239160607e7ce3314ce8441e22c9f30a5a61ad32219b025c6f8e/zheliku_tool-0.1.4.tar.gz",
    "platform": null,
    "description": "# \u23f1\ufe0f zheliku-tool\n\n> \ud83d\udd27 \u9ad8\u7cbe\u5ea6 Python \u51fd\u6570\u8ba1\u65f6\u4e0e\u65e5\u5fd7\u8bb0\u5f55\u5de5\u5177\n> \u57fa\u4e8e\u6807\u51c6\u5e93 `logging` \u5b9e\u73b0\uff0c\u517c\u5bb9\u540c\u6b65/\u5f02\u6b65\u51fd\u6570\u3001\u4e0a\u4e0b\u6587\u7ba1\u7406\u5668\u4e0e\u6eda\u52a8\u65e5\u5fd7\uff0c\n> \u652f\u6301\u73af\u5883\u53d8\u91cf\u5f00\u5173\u3001loguru \u98ce\u683c\u683c\u5f0f\u3001\u8de8\u5e73\u53f0\u4f7f\u7528\u3002\n\n---\n\n## \ud83c\udf1f \u529f\u80fd\u6982\u8ff0\n\n`zheliku-tool` \u63d0\u4f9b\u4e86\u4e00\u4e2a\u8f7b\u91cf\u7ea7\u7684\u8ba1\u65f6\u88c5\u9970\u5668\u4e0e\u4e0a\u4e0b\u6587\u7ba1\u7406\u5668 `TimeLogger`\uff0c\n\u8ba9\u4f60\u53ef\u4ee5\u4e00\u884c\u4ee3\u7801\u8f7b\u677e\u8bb0\u5f55\u4efb\u610f\u51fd\u6570\u6216\u4ee3\u7801\u5757\u7684\u6267\u884c\u8017\u65f6\u3002\n\n\u7279\u70b9\uff1a\n\n* \u2705 \u540c\u6b65\u3001\u5f02\u6b65\u51fd\u6570\u7edf\u4e00\u652f\u6301\n* \u2705 \u4e0a\u4e0b\u6587\u7ba1\u7406\u5668 (`with` / `async with`)\n* \u2705 \u65e5\u5fd7\u683c\u5f0f\u4e0e [loguru](https://github.com/Delgan/loguru) \u517c\u5bb9\uff0c\u5e26\u6beb\u79d2\u65f6\u95f4\n* \u2705 \u81ea\u52a8\u521b\u5efa\u65e5\u5fd7\u76ee\u5f55\uff0c\u652f\u6301\u6eda\u52a8\u6587\u4ef6\n* \u2705 \u53ef\u901a\u8fc7\u73af\u5883\u53d8\u91cf\u4e00\u952e\u5f00\u5173\n* \u2705 \u652f\u6301\u81ea\u5b9a\u4e49\u6587\u4ef6\u540d\u3001\u65e5\u5fd7\u76ee\u5f55\u4e0e\u7b49\u7ea7\n* \u2705 \u63d0\u4f9b\u7247\u6bb5\u8ba1\u65f6\u5668\u4e0e\u51fd\u6570\u5f0f API\n* \u2705 \u65e0\u5916\u90e8\u4f9d\u8d56\uff0c\u4ec5\u4f7f\u7528 Python \u6807\u51c6\u5e93\n\n---\n\n## \ud83d\udce6 \u5b89\u88c5\n\n```bash\n# \u4f7f\u7528 uv\uff08\u63a8\u8350\uff09\nuv add zheliku-tool\n\n# \u6216\u4f7f\u7528 pip\npip install zheliku-tool\n```\n\n\u5b89\u88c5\u540e\u5bfc\u5165\uff1a\n\n```python\nfrom zheliku_tool import TimeLogger, time_log\n```\n\n---\n\n## \ud83e\udded \u5feb\u901f\u5f00\u59cb\n\n### \u2705 1. \u88c5\u9970\u5668\u7528\u6cd5\n\n```python\nfrom zheliku_tool import TimeLogger\n\n\n@TimeLogger(log_file=\"run.log\")\ndef preprocess(data):\n    # \u6a21\u62df\u8017\u65f6\u8ba1\u7b97\n    import time;\n    time.sleep(0.02)\n    return [d ** 2 for d in data]\n\n\npreprocess([1, 2, 3])\n```\n\n\u65e5\u5fd7\u8f93\u51fa\u793a\u4f8b\uff08\u9ed8\u8ba4\u683c\u5f0f\uff09\uff1a\n\n```\n2025-11-03 15:00:21.512 | INFO     | __main__.preprocess:7 - Ran preprocess in 20.132 ms (module=__main__, file=example.py, abs='/path/example.py', line=7, pid=3901, thread=MainThread)\n```\n\n---\n\n### \u2705 2. \u5f02\u6b65\u51fd\u6570\n\n```python\nimport asyncio\nfrom zheliku_tool import TimeLogger\n\n\n@TimeLogger(log_file=\"async.log\", level=logging.DEBUG)\nasync def fetch_data():\n    await asyncio.sleep(0.01)\n    return \"done\"\n\n\nasyncio.run(fetch_data())\n```\n\n---\n\n### \u2705 3. \u4e0a\u4e0b\u6587\u7ba1\u7406\u5668\n\n```python\nfrom zheliku_tool import TimeLogger\n\nwith TimeLogger(logger_name=\"load_stage\", log_file=\"stages.log\"):\n    # \u4e00\u6bb5\u4ee3\u7801\u7684\u8017\u65f6\n    sum(i * i for i in range(10_000))\n```\n\n\u5f02\u6b65\u4e0a\u4e0b\u6587\u540c\u7406\uff1a\n\n```python\nasync with TimeLogger(logger_name=\"async_stage\", log_file=\"stages.log\"):\n    await asyncio.sleep(0.05)\n```\n\n---\n\n### \u2705 4. \u51fd\u6570\u5f0f\u4e0a\u4e0b\u6587 API\uff08\u66f4\u7b80\u6d01\uff09\n\n```python\nfrom zheliku_tool import time_log\n\nwith time_log(\"evaluate\", log_file=\"run.log\"):\n    result = sum(range(1000))\n```\n\n\u7b49\u4ef7\u4e8e\uff1a\n\n```python\nwith TimeLogger(logger_name=\"evaluate\", log_file=\"run.log\"):\n    result = sum(range(1000))\n```\n\n---\n\n### \u2705 5. \u624b\u52a8\u7247\u6bb5\u8ba1\u65f6\uff08\u4ee3\u7801\u5185\u90e8\u591a\u6bb5\u8017\u65f6\uff09\n\n```python\nfrom zheliku_tool import TimeLogger\n\n\ndef train_step():\n    seg = TimeLogger.start(\"train\")\n    # \u6267\u884c\u90e8\u5206\u4efb\u52a1\n    import time;\n    time.sleep(0.03)\n    elapsed = seg.stop()\n    print(f\"train_step \u8017\u65f6 {elapsed:.2f} ms\")\n```\n\n---\n\n## \u2699\ufe0f \u53c2\u6570\u8bf4\u660e\n\n| \u53c2\u6570\u540d            | \u7c7b\u578b                    | \u9ed8\u8ba4\u503c                   | \u8bf4\u660e                                            |                      |\n|----------------|-----------------------|-----------------------|-----------------------------------------------|----------------------|\n| `level`        | `int`                 | `logging.INFO`        | \u65e5\u5fd7\u7b49\u7ea7\uff08\u652f\u6301 `DEBUG/INFO/WARNING/ERROR`\uff09           |                      |\n| `enable`       | `bool`                | `True`                | \u662f\u5426\u542f\u7528\u8ba1\u65f6\uff0c`False` \u65f6\u76f4\u63a5\u8c03\u7528\u51fd\u6570\u4e0d\u8bb0\u5f55                     |                      |\n| `log_dir`      | `str \\| Path`         | `None`                | \u65e5\u5fd7\u76ee\u5f55\uff08\u672a\u63d0\u4f9b\u65f6\u81ea\u52a8\u53d6\u51fd\u6570\u6240\u5728\u6587\u4ef6\u5939\uff09                          |\n| `log_file`     | `str \\| Path` | `None`                | \u65e5\u5fd7\u6587\u4ef6\u8def\u5f84\uff0c\u53ef\u76f8\u5bf9/\u7edd\u5bf9                                 |\n| `extra_msg`    | `str`                 | `None`                | \u9644\u52a0\u5907\u6ce8\u6587\u672c                                        |                      |\n| `fmt`          | `str`                 | \u5185\u7f6e\u9ed8\u8ba4                  | `logging` \u8f93\u51fa\u683c\u5f0f                                |                      |\n| `datefmt`      | `str`                 | `\"%Y-%m-%d %H:%M:%S\"` | \u65f6\u95f4\u683c\u5f0f                                          |                      |\n| `logger_name`  | `str`                 | `None`                | \u81ea\u5b9a\u4e49 logger \u540d\uff08\u9ed8\u8ba4 `<module>.<qualname>:<line>`\uff09 |                      |\n| `rotate`       | `bool`                | `False`               | \u662f\u5426\u4f7f\u7528\u6eda\u52a8\u65e5\u5fd7                                      |                      |\n| `max_bytes`    | `int`                 | `10*1024*1024`        | \u6eda\u52a8\u9608\u503c\uff08\u5b57\u8282\uff09                                      |                      |\n| `backup_count` | `int`                 | `3`                   | \u6eda\u52a8\u4fdd\u7559\u6587\u4ef6\u6570                                       |                      |\n\n---\n\n## \ud83e\udde9 \u73af\u5883\u53d8\u91cf\u63a7\u5236\n\n> \u6240\u6709\u73af\u5883\u53d8\u91cf\u5747\u53ef\u5728\u8fd0\u884c\u524d\u901a\u8fc7 `export` \u6216 `.env` \u6587\u4ef6\u8bbe\u7f6e\u3002\n> \u4f18\u5148\u7ea7\u9ad8\u4e8e\u4ee3\u7801\u53c2\u6570\u3002\n\n| \u73af\u5883\u53d8\u91cf                                                    | \u8bf4\u660e                                |\n|---------------------------------------------------------|-----------------------------------|\n| `TIME_LOG_ENABLE` / `TIMER_LOG_ENABLE` / `TIMER_ENABLE` | \u662f\u5426\u542f\u7528\u65e5\u5fd7\uff08`0`\u3001`false` \u8868\u793a\u5173\u95ed\uff09          |\n| `TIME_LOG_LEVEL` / `TIMER_LOG_LEVEL` / `TIMER_LEVEL`    | \u8bbe\u7f6e\u5168\u5c40\u65e5\u5fd7\u7b49\u7ea7\uff0c\u5982 `DEBUG`\u3001`INFO`\u3001`ERROR` |\n\n### \u793a\u4f8b\uff1a\n\n```bash\nexport TIME_LOG_ENABLE=0   # \u5168\u5c40\u5173\u95ed\u65e5\u5fd7\nexport TIMER_LOG_LEVEL=DEBUG\n```\n\n---\n\n## \ud83e\uddf0 \u65e5\u5fd7\u843d\u5730\u89c4\u5219\n\n1. \u5982\u679c\u63d0\u4f9b `log_file`\uff1a\n\n    * **\u7edd\u5bf9\u8def\u5f84**\uff1a\u76f4\u63a5\u4f7f\u7528\uff1b\n    * **\u76f8\u5bf9\u8def\u5f84**\uff1a\u57fa\u4e8e `log_dir`\uff08\u82e5\u63d0\u4f9b\uff09\u6216\u6e90\u6587\u4ef6\u76ee\u5f55\u3002\n2. \u5982\u679c\u672a\u63d0\u4f9b `log_file`\uff1a\n\n    * \u81ea\u52a8\u751f\u6210 `<\u6e90\u6587\u4ef6\u540c\u540d>.log`\uff1b\n    * \u76ee\u5f55\u4e3a `log_dir` \u6216\u6e90\u6587\u4ef6\u76ee\u5f55\u3002\n3. \u4f1a\u81ea\u52a8\u521b\u5efa\u4e0d\u5b58\u5728\u7684\u76ee\u5f55\u3002\n4. \u540c\u4e00\u8def\u5f84\u590d\u7528\u540c\u4e00\u4e2a `FileHandler`\uff0c\u4e0d\u4f1a\u91cd\u590d\u5199\u5165\u3002\n\n---\n\n## \ud83d\udcd6 \u8f93\u51fa\u683c\u5f0f\n\n\u9ed8\u8ba4\u683c\u5f0f\uff08\u53ef\u81ea\u5b9a\u4e49\uff09\uff1a\n\n```\n%(asctime)s.%(msecs)03d | %(levelname)-8s | %(name)s - %(message)s\n```\n\n\u5bf9\u5e94\u8f93\u51fa\u793a\u4f8b\uff1a\n\n```\n2025-11-03 14:59:01.512 | INFO     | mymodule.train:42 - Ran train in 14.832 ms (module=mymodule, file=train.py, abs='/project/train.py', line=42, pid=1234, thread=MainThread)\n```\n\n---\n\n## \ud83d\ude80 \u9ad8\u7ea7\u7528\u6cd5\n\n### \ud83d\udd04 \u6eda\u52a8\u65e5\u5fd7\n\n\u81ea\u52a8\u5207\u5206\u65e5\u5fd7\u6587\u4ef6\uff0c\u9632\u6b62\u6587\u4ef6\u8fc7\u5927\uff1a\n\n```python\n@TimeLogger(log_file=\"pipeline.log\", rotate=True, max_bytes=1024 * 100, backup_count=5)\ndef pipeline():\n    ...\n```\n\n---\n\n### \ud83d\udd0d \u4e34\u65f6\u7981\u7528\n\n```python\n@TimeLogger(enable=False)\ndef quick_func():\n    pass  # \u4e0d\u4f1a\u4ea7\u751f\u65e5\u5fd7\n```\n\n---\n\n### \ud83d\udd27 \u52a8\u6001\u63a7\u5236\uff08\u73af\u5883\u53d8\u91cf\uff09\n\n\u65e0\u9700\u6539\u4ee3\u7801\uff0c\u8fd0\u884c\u524d\u5373\u53ef\u542f\u7528/\u7981\u7528\uff1a\n\n```bash\nTIME_LOG_ENABLE=0 uv run python your_script.py\n```\n\n---\n\n### \ud83e\udde0 \u7ebf\u7a0b/\u8fdb\u7a0b\u5b89\u5168\u6027\n\n* \u65e5\u5fd7\u6587\u4ef6\u5199\u5165\u4f7f\u7528\u6807\u51c6\u5e93 `FileHandler`\uff1b\n* \u540c\u4e00 logger \u4e0d\u4f1a\u91cd\u590d\u7ed1\u5b9a\uff1b\n* \u53ef\u5728\u591a\u7ebf\u7a0b\u4e0b\u5b89\u5168\u4f7f\u7528\uff08\u6bcf\u6761\u65e5\u5fd7\u72ec\u7acb\u5199\u5165\uff09\u3002\n\n---\n\n## \ud83e\uddea \u5355\u5143\u6d4b\u8bd5\u8986\u76d6\uff08pytest\uff09\n\n\u5b8c\u6574\u6d4b\u8bd5\u6587\u4ef6\u89c1 `tests/test_time_tool.py`\uff0c\u5305\u62ec\uff1a\n\n* \u540c\u6b65/\u5f02\u6b65\u88c5\u9970\u5668\n* \u540c\u6b65/\u5f02\u6b65\u4e0a\u4e0b\u6587\n* \u8def\u5f84\u89e3\u6790\n* \u6eda\u52a8\u65e5\u5fd7\n* \u73af\u5883\u53d8\u91cf\u5f00\u5173\n* \u91cd\u590d handler \u68c0\u6d4b\n* \u7247\u6bb5\u8ba1\u65f6\u5668\n* \u51fd\u6570\u5f0f\u4e0a\u4e0b\u6587\u7ba1\u7406\n\n\u8fd0\u884c\u6d4b\u8bd5\uff1a\n\n```bash\nuv run pytest -v\n```\n\n---\n\n## \ud83d\udcdc \u8bb8\u53ef\u8bc1\n\nMIT License \u00a9 2025 [zheliku](https://github.com/zheliku)\n\n",
    "bugtrack_url": null,
    "license": null,
    "summary": "Lightweight timing decorator & context manager with loguru-like formatting, sync/async.",
    "version": "0.1.4",
    "project_urls": {
        "Changelog": "https://github.com/zheliku/zheliku-tool/master/CHANGELOG.md",
        "Homepage": "https://github.com/zheliku/zheliku-tool",
        "Issues": "https://github.com/zheliku/zheliku-tool/issues",
        "Repository": "https://github.com/zheliku/zheliku-tool.git"
    },
    "split_keywords": [
        "logging",
        " timer",
        " performance",
        " decorator",
        " asyncio"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "ddb19adca4dade8dce8bd5f43737826fc309285747749c3d6395ee17c4259acf",
                "md5": "a9b99a91d0730fd5bd5f94bb61843655",
                "sha256": "53ee39c11feba0ebe7ebe9a0ec0ed015123ed8d888076cf26167eb3add950d49"
            },
            "downloads": -1,
            "filename": "zheliku_tool-0.1.4-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "a9b99a91d0730fd5bd5f94bb61843655",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.12",
            "size": 11227,
            "upload_time": "2025-11-03T17:35:56",
            "upload_time_iso_8601": "2025-11-03T17:35:56.623263Z",
            "url": "https://files.pythonhosted.org/packages/dd/b1/9adca4dade8dce8bd5f43737826fc309285747749c3d6395ee17c4259acf/zheliku_tool-0.1.4-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "8dec7e1e4663239160607e7ce3314ce8441e22c9f30a5a61ad32219b025c6f8e",
                "md5": "72b4f90ed4da6a4093197544a1cb8772",
                "sha256": "05ea1c4288ca22363e4b4b114f77147ecbacd69a1da46581fb3f4ce560d3f79e"
            },
            "downloads": -1,
            "filename": "zheliku_tool-0.1.4.tar.gz",
            "has_sig": false,
            "md5_digest": "72b4f90ed4da6a4093197544a1cb8772",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.12",
            "size": 14671,
            "upload_time": "2025-11-03T17:35:57",
            "upload_time_iso_8601": "2025-11-03T17:35:57.600334Z",
            "url": "https://files.pythonhosted.org/packages/8d/ec/7e1e4663239160607e7ce3314ce8441e22c9f30a5a61ad32219b025c6f8e/zheliku_tool-0.1.4.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-11-03 17:35:57",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "zheliku",
    "github_project": "zheliku-tool",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "lcname": "zheliku-tool"
}
        
Elapsed time: 3.51322s