<!-- markdownlint-disable MD033 MD036 MD041 -->
<p align="center">
<a href="https://v2.nonebot.dev/"><img src="https://v2.nonebot.dev/logo.png" width="200" height="200" alt="nonebot"></a>
</p>
<div align="center">
# NoneBot Plugin DataStore
_✨ NoneBot 数据存储插件 ✨_
</div>
<p align="center">
<a href="https://raw.githubusercontent.com/he0119/nonebot-plugin-datastore/main/LICENSE">
<img src="https://img.shields.io/github/license/he0119/nonebot-plugin-datastore.svg" alt="license">
</a>
<a href="https://pypi.python.org/pypi/nonebot-plugin-datastore">
<img src="https://img.shields.io/pypi/v/nonebot-plugin-datastore.svg" alt="pypi">
</a>
<img src="https://img.shields.io/badge/python-3.8+-blue.svg" alt="python">
<a href="https://codecov.io/gh/he0119/nonebot-plugin-datastore">
<img src="https://codecov.io/gh/he0119/nonebot-plugin-datastore/branch/main/graph/badge.svg?token=jd5ufc1alv"/>
</a>
<a href="https://jq.qq.com/?_wv=1027&k=7zQUpiGp">
<img src="https://img.shields.io/badge/QQ%E7%BE%A4-730374631-orange?style=flat-square" alt="QQ Chat Group">
</a>
</p>
## 安装
- 使用 nb-cli
```sh
nb plugin install nonebot-plugin-datastore
```
- 使用 pip
```sh
pip install nonebot-plugin-datastore
```
## 使用方式
先在插件代码最前面声明依赖
```python
from nonebot import require
require("nonebot_plugin_datastore")
```
### 插件数据相关功能
```python
from nonebot_plugin_datastore import get_plugin_data
plugin_data = get_plugin_data()
# 获取插件缓存目录
plugin_data.cache_dir
# 获取插件配置目录
plugin_data.config_dir
# 获取插件数据目录
plugin_data.data_dir
# 读取配置
await plugin_data.config.get(key)
# 存储配置
await plugin_data.config.set(key, value)
```
### 数据库相关功能,详细用法见 [SQLAlchemy](https://docs.sqlalchemy.org/orm/quickstart.html)
```python
from nonebot import on_command
from nonebot.params import Depends
from sqlalchemy.ext.asyncio.session import AsyncSession
from sqlalchemy.orm import Mapped, mapped_column
from nonebot_plugin_datastore import get_plugin_data, get_session
# 定义模型
Model = get_plugin_data().Model
class Example(Model):
"""示例模型"""
id: Mapped[int] = mapped_column(primary_key=True)
message: Mapped[str]
matcher = on_command("test")
# 数据库相关操作
@matcher.handle()
async def handle(session: AsyncSession = Depends(get_session)):
example = Example(message="matcher")
session.add(example)
await session.commit()
# 因为 driver.on_startup 无法保证函数运行顺序
# 如需在 NoneBot 启动时且数据库初始化后运行的函数
# 请使用 post_db_init 而不是 Nonebot 的 on_startup
from nonebot_plugin_datastore.db import post_db_init
@post_db_init
async def do_something():
pass
```
### 命令行支持(需安装 [nb-cli 1.0+](https://github.com/nonebot/nb-cli))
如果使用 pipx 安装的 nb-cli,则需要运行 `pip install nonebot-plugin-datastore[cli]` 安装命令行所需依赖。
#### 数据存储路径
```shell
# 获取当前数据存储路径
nb datastore dir
# 获取指定插件的数据存储路径
nb datastore dir --name plugin_name
```
#### 数据库管理,详细用法见 [Alembic](https://alembic.sqlalchemy.org/en/latest/)
生成迁移文件
```shell
# 生成项目内所有启用数据库插件的迁移文件(不包括 site-packages 中的插件)
nb datastore migrate
# 生成指定插件的迁移文件
nb datastore migrate --name plugin_name -m example
```
升级插件数据库
```shell
# 升级所有启用数据库插件的数据库
nb datastore upgrade
# 升级指定插件的数据库
nb datastore upgrade --name plugin_name
# 升级至指定版本
nb datastore upgrade --name plugin_name revision
```
降级插件数据库
```shell
# 降级所有启用数据库插件的数据库
nb datastore downgrade
# 降级指定插件的数据库
nb datastore downgrade --name plugin_name
# 降级至指定版本
nb datastore downgrade --name plugin_name revision
```
## 注意
### 数据库迁移
推荐启动机器人前运行 `nb datastore upgrade` 升级数据库至最新版本。因为当前插件自动迁移依赖 `NoneBot` 的 `on_startup` 钩子,很容易受到其他插件影响。
这里推荐 [tiangolo/uvicorn-gunicorn](https://github.com/tiangolo/uvicorn-gunicorn-docker) 镜像,通过配置 `prestart.sh` 可确保启动机器人前运行迁移脚本。具体的例子可参考 [CoolQBot](https://github.com/he0119/CoolQBot/)。
### MySQL 数据库连接丢失
当使用 `MySQL` 时,你可能会遇到 `2013: lost connection to mysql server during query` 的报错。
如果遇到这种错误,可以尝试设置 `pool_recycle` 为一个小于数据库超时的值。或者设置 `pool_pre_ping` 为 `True`。
```env
DATASTORE_ENGINE_OPTIONS={"pool_recycle": 3600}
DATASTORE_ENGINE_OPTIONS={"pool_pre_ping": true}
```
详细介绍可查看 `SQLAlchemy` 文档的 [dealing-with-disconnects](https://docs.sqlalchemy.org/en/20/core/pooling.html#dealing-with-disconnects) 章节。
### SQLite 数据库已锁定
使用 `SQLite` 数据库时,如果在写入时遇到 `(sqlite3.OperationalError) database is locked` 错误。可尝试将 `poolclass` 设置为 `StaticPool`,保持有且仅有一个连接。不过这样设置之后,在程序运行期间,你的数据库文件都将被占用。
## 配置项
配置方式:直接在 `NoneBot` 全局配置文件中添加以下配置项即可。
### datastore_cache_dir
- 类型: `Path`
- 默认:
- macOS: ~/Library/Caches/nonebot2
- Unix: ~/.cache/nonebot2 (XDG default)
- Windows: C:\Users\<username>\AppData\Local\nonebot2\Cache
- 说明: 缓存目录
### datastore_config_dir
- 类型: `Path`
- 默认:
- macOS: same as user_data_dir
- Unix: ~/.config/nonebot2
- Win XP (roaming): C:\Documents and Settings\<username>\Local Settings\Application Data\nonebot2
- Win 7 (roaming): C:\Users\<username>\AppData\Roaming\nonebot2
- 说明: 配置目录
### datastore_data_dir
- 类型: `Path`
- 默认:
- macOS: ~/Library/Application Support/nonebot2
- Unix: ~/.local/share/nonebot2 or in $XDG_DATA_HOME, if defined
- Win XP (not roaming): C:\Documents and Settings\<username>\Application Data\nonebot2
- Win 7 (not roaming): C:\Users\<username>\AppData\Local\nonebot2
- 说明: 数据目录
### datastore_enable_database
- 类型: `bool`
- 默认: `True`
- 说明: 是否启动数据库
### datastore_database_url
- 类型: `str`
- 默认: `sqlite+aiosqlite:///data_dir/data.db`
- 说明: 数据库连接字符串,默认使用 SQLite 数据库
### datastore_database_echo
- 类型: `bool`
- 默认: `False`
- 说明: `echo` 和 `echo_pool` 的默认值,是否显示数据库执行的语句与其参数列表,还有连接池的相关信息
### datastore_engine_options
- 类型: `dict[str, Any]`
- 默认: `{}`
- 说明: 向 `sqlalchemy.ext.asyncio.create_async_engine()` 传递的参数
### datastore_config_provider
- 类型: `str`
- 默认: `~json`
- 说明: 选择存放配置的类型,当前支持 json, yaml, toml, database 四种类型,也可设置为实现 `ConfigProvider` 的自定义类型。
## 鸣谢
- [`NoneBot Plugin LocalStore`](https://github.com/nonebot/plugin-localstore): 提供了默认的文件存储位置
- [`Flask-SQLAlchemy`](https://github.com/pallets-eco/flask-sqlalchemy/): 借鉴了数据库的实现思路
- [`Flask-Alembic`](https://github.com/davidism/flask-alembic): 借鉴了命令行的实现思路
Raw data
{
"_id": null,
"home_page": "https://github.com/he0119/nonebot-plugin-datastore",
"name": "nonebot-plugin-datastore",
"maintainer": "",
"docs_url": null,
"requires_python": ">=3.8,<4.0",
"maintainer_email": "",
"keywords": "",
"author": "hemengyang",
"author_email": "hmy0119@gmail.com",
"download_url": "https://files.pythonhosted.org/packages/b2/45/302450e1b22d2e3a65710e4fc48797e721850265804aa0c0b7ac174bf171/nonebot_plugin_datastore-0.6.0.tar.gz",
"platform": null,
"description": "<!-- markdownlint-disable MD033 MD036 MD041 -->\n\n<p align=\"center\">\n <a href=\"https://v2.nonebot.dev/\"><img src=\"https://v2.nonebot.dev/logo.png\" width=\"200\" height=\"200\" alt=\"nonebot\"></a>\n</p>\n\n<div align=\"center\">\n\n# NoneBot Plugin DataStore\n\n_\u2728 NoneBot \u6570\u636e\u5b58\u50a8\u63d2\u4ef6 \u2728_\n\n</div>\n\n<p align=\"center\">\n <a href=\"https://raw.githubusercontent.com/he0119/nonebot-plugin-datastore/main/LICENSE\">\n <img src=\"https://img.shields.io/github/license/he0119/nonebot-plugin-datastore.svg\" alt=\"license\">\n </a>\n <a href=\"https://pypi.python.org/pypi/nonebot-plugin-datastore\">\n <img src=\"https://img.shields.io/pypi/v/nonebot-plugin-datastore.svg\" alt=\"pypi\">\n </a>\n <img src=\"https://img.shields.io/badge/python-3.8+-blue.svg\" alt=\"python\">\n <a href=\"https://codecov.io/gh/he0119/nonebot-plugin-datastore\">\n <img src=\"https://codecov.io/gh/he0119/nonebot-plugin-datastore/branch/main/graph/badge.svg?token=jd5ufc1alv\"/>\n </a>\n <a href=\"https://jq.qq.com/?_wv=1027&k=7zQUpiGp\">\n <img src=\"https://img.shields.io/badge/QQ%E7%BE%A4-730374631-orange?style=flat-square\" alt=\"QQ Chat Group\">\n </a>\n</p>\n\n## \u5b89\u88c5\n\n- \u4f7f\u7528 nb-cli\n\n```sh\nnb plugin install nonebot-plugin-datastore\n```\n\n- \u4f7f\u7528 pip\n\n```sh\npip install nonebot-plugin-datastore\n```\n\n## \u4f7f\u7528\u65b9\u5f0f\n\n\u5148\u5728\u63d2\u4ef6\u4ee3\u7801\u6700\u524d\u9762\u58f0\u660e\u4f9d\u8d56\n\n```python\nfrom nonebot import require\nrequire(\"nonebot_plugin_datastore\")\n```\n\n### \u63d2\u4ef6\u6570\u636e\u76f8\u5173\u529f\u80fd\n\n```python\nfrom nonebot_plugin_datastore import get_plugin_data\n\nplugin_data = get_plugin_data()\n\n# \u83b7\u53d6\u63d2\u4ef6\u7f13\u5b58\u76ee\u5f55\nplugin_data.cache_dir\n# \u83b7\u53d6\u63d2\u4ef6\u914d\u7f6e\u76ee\u5f55\nplugin_data.config_dir\n# \u83b7\u53d6\u63d2\u4ef6\u6570\u636e\u76ee\u5f55\nplugin_data.data_dir\n\n# \u8bfb\u53d6\u914d\u7f6e\nawait plugin_data.config.get(key)\n# \u5b58\u50a8\u914d\u7f6e\nawait plugin_data.config.set(key, value)\n```\n\n### \u6570\u636e\u5e93\u76f8\u5173\u529f\u80fd\uff0c\u8be6\u7ec6\u7528\u6cd5\u89c1 [SQLAlchemy](https://docs.sqlalchemy.org/orm/quickstart.html)\n\n```python\nfrom nonebot import on_command\nfrom nonebot.params import Depends\nfrom sqlalchemy.ext.asyncio.session import AsyncSession\nfrom sqlalchemy.orm import Mapped, mapped_column\n\nfrom nonebot_plugin_datastore import get_plugin_data, get_session\n\n# \u5b9a\u4e49\u6a21\u578b\nModel = get_plugin_data().Model\n\nclass Example(Model):\n \"\"\"\u793a\u4f8b\u6a21\u578b\"\"\"\n\n id: Mapped[int] = mapped_column(primary_key=True)\n message: Mapped[str]\n\nmatcher = on_command(\"test\")\n\n# \u6570\u636e\u5e93\u76f8\u5173\u64cd\u4f5c\n@matcher.handle()\nasync def handle(session: AsyncSession = Depends(get_session)):\n example = Example(message=\"matcher\")\n session.add(example)\n await session.commit()\n\n# \u56e0\u4e3a driver.on_startup \u65e0\u6cd5\u4fdd\u8bc1\u51fd\u6570\u8fd0\u884c\u987a\u5e8f\n# \u5982\u9700\u5728 NoneBot \u542f\u52a8\u65f6\u4e14\u6570\u636e\u5e93\u521d\u59cb\u5316\u540e\u8fd0\u884c\u7684\u51fd\u6570\n# \u8bf7\u4f7f\u7528 post_db_init \u800c\u4e0d\u662f Nonebot \u7684 on_startup\nfrom nonebot_plugin_datastore.db import post_db_init\n\n\n@post_db_init\nasync def do_something():\n pass\n```\n\n### \u547d\u4ee4\u884c\u652f\u6301\uff08\u9700\u5b89\u88c5 [nb-cli 1.0+](https://github.com/nonebot/nb-cli)\uff09\n\n\u5982\u679c\u4f7f\u7528 pipx \u5b89\u88c5\u7684 nb-cli\uff0c\u5219\u9700\u8981\u8fd0\u884c `pip install nonebot-plugin-datastore[cli]` \u5b89\u88c5\u547d\u4ee4\u884c\u6240\u9700\u4f9d\u8d56\u3002\n\n#### \u6570\u636e\u5b58\u50a8\u8def\u5f84\n\n```shell\n# \u83b7\u53d6\u5f53\u524d\u6570\u636e\u5b58\u50a8\u8def\u5f84\nnb datastore dir\n# \u83b7\u53d6\u6307\u5b9a\u63d2\u4ef6\u7684\u6570\u636e\u5b58\u50a8\u8def\u5f84\nnb datastore dir --name plugin_name\n```\n\n#### \u6570\u636e\u5e93\u7ba1\u7406\uff0c\u8be6\u7ec6\u7528\u6cd5\u89c1 [Alembic](https://alembic.sqlalchemy.org/en/latest/)\n\n\u751f\u6210\u8fc1\u79fb\u6587\u4ef6\n\n```shell\n# \u751f\u6210\u9879\u76ee\u5185\u6240\u6709\u542f\u7528\u6570\u636e\u5e93\u63d2\u4ef6\u7684\u8fc1\u79fb\u6587\u4ef6\uff08\u4e0d\u5305\u62ec site-packages \u4e2d\u7684\u63d2\u4ef6\uff09\nnb datastore migrate\n# \u751f\u6210\u6307\u5b9a\u63d2\u4ef6\u7684\u8fc1\u79fb\u6587\u4ef6\nnb datastore migrate --name plugin_name -m example\n```\n\n\u5347\u7ea7\u63d2\u4ef6\u6570\u636e\u5e93\n\n```shell\n# \u5347\u7ea7\u6240\u6709\u542f\u7528\u6570\u636e\u5e93\u63d2\u4ef6\u7684\u6570\u636e\u5e93\nnb datastore upgrade\n# \u5347\u7ea7\u6307\u5b9a\u63d2\u4ef6\u7684\u6570\u636e\u5e93\nnb datastore upgrade --name plugin_name\n# \u5347\u7ea7\u81f3\u6307\u5b9a\u7248\u672c\nnb datastore upgrade --name plugin_name revision\n```\n\n\u964d\u7ea7\u63d2\u4ef6\u6570\u636e\u5e93\n\n```shell\n# \u964d\u7ea7\u6240\u6709\u542f\u7528\u6570\u636e\u5e93\u63d2\u4ef6\u7684\u6570\u636e\u5e93\nnb datastore downgrade\n# \u964d\u7ea7\u6307\u5b9a\u63d2\u4ef6\u7684\u6570\u636e\u5e93\nnb datastore downgrade --name plugin_name\n# \u964d\u7ea7\u81f3\u6307\u5b9a\u7248\u672c\nnb datastore downgrade --name plugin_name revision\n```\n\n## \u6ce8\u610f\n\n### \u6570\u636e\u5e93\u8fc1\u79fb\n\n\u63a8\u8350\u542f\u52a8\u673a\u5668\u4eba\u524d\u8fd0\u884c `nb datastore upgrade` \u5347\u7ea7\u6570\u636e\u5e93\u81f3\u6700\u65b0\u7248\u672c\u3002\u56e0\u4e3a\u5f53\u524d\u63d2\u4ef6\u81ea\u52a8\u8fc1\u79fb\u4f9d\u8d56 `NoneBot` \u7684 `on_startup` \u94a9\u5b50\uff0c\u5f88\u5bb9\u6613\u53d7\u5230\u5176\u4ed6\u63d2\u4ef6\u5f71\u54cd\u3002\n\n\u8fd9\u91cc\u63a8\u8350 [tiangolo/uvicorn-gunicorn](https://github.com/tiangolo/uvicorn-gunicorn-docker) \u955c\u50cf\uff0c\u901a\u8fc7\u914d\u7f6e `prestart.sh` \u53ef\u786e\u4fdd\u542f\u52a8\u673a\u5668\u4eba\u524d\u8fd0\u884c\u8fc1\u79fb\u811a\u672c\u3002\u5177\u4f53\u7684\u4f8b\u5b50\u53ef\u53c2\u8003 [CoolQBot](https://github.com/he0119/CoolQBot/)\u3002\n\n### MySQL \u6570\u636e\u5e93\u8fde\u63a5\u4e22\u5931\n\n\u5f53\u4f7f\u7528 `MySQL` \u65f6\uff0c\u4f60\u53ef\u80fd\u4f1a\u9047\u5230 `2013: lost connection to mysql server during query` \u7684\u62a5\u9519\u3002\n\n\u5982\u679c\u9047\u5230\u8fd9\u79cd\u9519\u8bef\uff0c\u53ef\u4ee5\u5c1d\u8bd5\u8bbe\u7f6e `pool_recycle` \u4e3a\u4e00\u4e2a\u5c0f\u4e8e\u6570\u636e\u5e93\u8d85\u65f6\u7684\u503c\u3002\u6216\u8005\u8bbe\u7f6e `pool_pre_ping` \u4e3a `True`\u3002\n\n```env\nDATASTORE_ENGINE_OPTIONS={\"pool_recycle\": 3600}\nDATASTORE_ENGINE_OPTIONS={\"pool_pre_ping\": true}\n```\n\n\u8be6\u7ec6\u4ecb\u7ecd\u53ef\u67e5\u770b `SQLAlchemy` \u6587\u6863\u7684 [dealing-with-disconnects](https://docs.sqlalchemy.org/en/20/core/pooling.html#dealing-with-disconnects) \u7ae0\u8282\u3002\n\n### SQLite \u6570\u636e\u5e93\u5df2\u9501\u5b9a\n\n\u4f7f\u7528 `SQLite` \u6570\u636e\u5e93\u65f6\uff0c\u5982\u679c\u5728\u5199\u5165\u65f6\u9047\u5230 `(sqlite3.OperationalError) database is locked` \u9519\u8bef\u3002\u53ef\u5c1d\u8bd5\u5c06 `poolclass` \u8bbe\u7f6e\u4e3a `StaticPool`\uff0c\u4fdd\u6301\u6709\u4e14\u4ec5\u6709\u4e00\u4e2a\u8fde\u63a5\u3002\u4e0d\u8fc7\u8fd9\u6837\u8bbe\u7f6e\u4e4b\u540e\uff0c\u5728\u7a0b\u5e8f\u8fd0\u884c\u671f\u95f4\uff0c\u4f60\u7684\u6570\u636e\u5e93\u6587\u4ef6\u90fd\u5c06\u88ab\u5360\u7528\u3002\n\n## \u914d\u7f6e\u9879\n\n\u914d\u7f6e\u65b9\u5f0f\uff1a\u76f4\u63a5\u5728 `NoneBot` \u5168\u5c40\u914d\u7f6e\u6587\u4ef6\u4e2d\u6dfb\u52a0\u4ee5\u4e0b\u914d\u7f6e\u9879\u5373\u53ef\u3002\n\n### datastore_cache_dir\n\n- \u7c7b\u578b: `Path`\n- \u9ed8\u8ba4:\n - macOS: ~/Library/Caches/nonebot2\n - Unix: ~/.cache/nonebot2 (XDG default)\n - Windows: C:\\Users\\<username>\\AppData\\Local\\nonebot2\\Cache\n- \u8bf4\u660e: \u7f13\u5b58\u76ee\u5f55\n\n### datastore_config_dir\n\n- \u7c7b\u578b: `Path`\n- \u9ed8\u8ba4:\n - macOS: same as user_data_dir\n - Unix: ~/.config/nonebot2\n - Win XP (roaming): C:\\Documents and Settings\\<username>\\Local Settings\\Application Data\\nonebot2\n - Win 7 (roaming): C:\\Users\\<username>\\AppData\\Roaming\\nonebot2\n- \u8bf4\u660e: \u914d\u7f6e\u76ee\u5f55\n\n### datastore_data_dir\n\n- \u7c7b\u578b: `Path`\n- \u9ed8\u8ba4:\n - macOS: ~/Library/Application Support/nonebot2\n - Unix: ~/.local/share/nonebot2 or in $XDG_DATA_HOME, if defined\n - Win XP (not roaming): C:\\Documents and Settings\\<username>\\Application Data\\nonebot2\n - Win 7 (not roaming): C:\\Users\\<username>\\AppData\\Local\\nonebot2\n- \u8bf4\u660e: \u6570\u636e\u76ee\u5f55\n\n### datastore_enable_database\n\n- \u7c7b\u578b: `bool`\n- \u9ed8\u8ba4: `True`\n- \u8bf4\u660e: \u662f\u5426\u542f\u52a8\u6570\u636e\u5e93\n\n### datastore_database_url\n\n- \u7c7b\u578b: `str`\n- \u9ed8\u8ba4: `sqlite+aiosqlite:///data_dir/data.db`\n- \u8bf4\u660e: \u6570\u636e\u5e93\u8fde\u63a5\u5b57\u7b26\u4e32\uff0c\u9ed8\u8ba4\u4f7f\u7528 SQLite \u6570\u636e\u5e93\n\n### datastore_database_echo\n\n- \u7c7b\u578b: `bool`\n- \u9ed8\u8ba4: `False`\n- \u8bf4\u660e: `echo` \u548c `echo_pool` \u7684\u9ed8\u8ba4\u503c\uff0c\u662f\u5426\u663e\u793a\u6570\u636e\u5e93\u6267\u884c\u7684\u8bed\u53e5\u4e0e\u5176\u53c2\u6570\u5217\u8868\uff0c\u8fd8\u6709\u8fde\u63a5\u6c60\u7684\u76f8\u5173\u4fe1\u606f\n\n### datastore_engine_options\n\n- \u7c7b\u578b: `dict[str, Any]`\n- \u9ed8\u8ba4: `{}`\n- \u8bf4\u660e: \u5411 `sqlalchemy.ext.asyncio.create_async_engine()` \u4f20\u9012\u7684\u53c2\u6570\n\n### datastore_config_provider\n\n- \u7c7b\u578b: `str`\n- \u9ed8\u8ba4: `~json`\n- \u8bf4\u660e: \u9009\u62e9\u5b58\u653e\u914d\u7f6e\u7684\u7c7b\u578b\uff0c\u5f53\u524d\u652f\u6301 json, yaml, toml, database \u56db\u79cd\u7c7b\u578b\uff0c\u4e5f\u53ef\u8bbe\u7f6e\u4e3a\u5b9e\u73b0 `ConfigProvider` \u7684\u81ea\u5b9a\u4e49\u7c7b\u578b\u3002\n\n## \u9e23\u8c22\n\n- [`NoneBot Plugin LocalStore`](https://github.com/nonebot/plugin-localstore): \u63d0\u4f9b\u4e86\u9ed8\u8ba4\u7684\u6587\u4ef6\u5b58\u50a8\u4f4d\u7f6e\n- [`Flask-SQLAlchemy`](https://github.com/pallets-eco/flask-sqlalchemy/): \u501f\u9274\u4e86\u6570\u636e\u5e93\u7684\u5b9e\u73b0\u601d\u8def\n- [`Flask-Alembic`](https://github.com/davidism/flask-alembic): \u501f\u9274\u4e86\u547d\u4ee4\u884c\u7684\u5b9e\u73b0\u601d\u8def\n\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "\u9002\u7528\u4e8e Nonebot2 \u7684\u6570\u636e\u5b58\u50a8\u63d2\u4ef6",
"version": "0.6.0",
"split_keywords": [],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "b2b571044527628d45a818c516f64a060622939b0a557e2d770219ece12ae69d",
"md5": "d23688b7f16deafdbbbcc086be164f47",
"sha256": "e274e7afdb2b4cd03caafd82c4616a29234f3d6f94bcbe292b8ef7845dd51d09"
},
"downloads": -1,
"filename": "nonebot_plugin_datastore-0.6.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "d23688b7f16deafdbbbcc086be164f47",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.8,<4.0",
"size": 24337,
"upload_time": "2023-03-19T16:20:08",
"upload_time_iso_8601": "2023-03-19T16:20:08.487180Z",
"url": "https://files.pythonhosted.org/packages/b2/b5/71044527628d45a818c516f64a060622939b0a557e2d770219ece12ae69d/nonebot_plugin_datastore-0.6.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "b245302450e1b22d2e3a65710e4fc48797e721850265804aa0c0b7ac174bf171",
"md5": "45750c5cda92bfbc353438fdf8854534",
"sha256": "8667ed359a017aa0c376e920bb70899f2189aa781f4670c87143cfaac10a5540"
},
"downloads": -1,
"filename": "nonebot_plugin_datastore-0.6.0.tar.gz",
"has_sig": false,
"md5_digest": "45750c5cda92bfbc353438fdf8854534",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.8,<4.0",
"size": 20103,
"upload_time": "2023-03-19T16:20:10",
"upload_time_iso_8601": "2023-03-19T16:20:10.150215Z",
"url": "https://files.pythonhosted.org/packages/b2/45/302450e1b22d2e3a65710e4fc48797e721850265804aa0c0b7ac174bf171/nonebot_plugin_datastore-0.6.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2023-03-19 16:20:10",
"github": true,
"gitlab": false,
"bitbucket": false,
"github_user": "he0119",
"github_project": "nonebot-plugin-datastore",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "nonebot-plugin-datastore"
}