# Midscene Python
Midscene Python 是一个基于 AI 的自动化框架,支持 Web 和 Android 平台的 UI 自动化操作。
## 概述
Midscene Python 提供全面的 UI 自动化能力,具有以下核心特性:
- **自然语言驱动**:使用自然语言描述自动化任务
- **多平台支持**:支持 Web(Selenium/Playwright)和 Android(ADB)
- **AI 模型集成**:支持 GPT-4V、Qwen2.5-VL、Gemini 等多种视觉语言模型
- **可视化调试**:提供详细的执行报告和调试信息
- **缓存机制**:智能缓存提升执行效率
## 项目架构
```
midscene-python/
├── midscene/ # 核心框架
│ ├── core/ # 核心框架
│ │ ├── agent/ # Agent系统
│ │ ├── insight/ # AI推理引擎
│ │ ├── ai_model/ # AI模型集成
│ │ ├── yaml/ # YAML脚本执行器
│ │ └── types.py # 核心类型定义
│ ├── web/ # Web集成
│ │ ├── selenium/ # Selenium集成
│ │ ├── playwright/ # Playwright集成
│ │ └── bridge/ # Bridge模式
│ ├── android/ # Android集成
│ │ ├── device.py # 设备管理
│ │ └── agent.py # Android Agent
│ ├── cli/ # 命令行工具
│ ├── mcp/ # MCP协议支持
│ ├── shared/ # 共享工具
│ └── visualizer/ # 可视化报告
├── examples/ # 示例代码
├── tests/ # 测试用例
└── docs/ # 文档
```
## 技术栈
- **Python 3.9+**:核心运行环境
- **Pydantic**:数据验证和序列化
- **Selenium/Playwright**:Web 自动化
- **OpenCV/Pillow**:图像处理
- **HTTPX/AIOHTTP**:HTTP 客户端
- **Typer**:CLI 框架
- **Loguru**:日志记录
## 快速开始
### 安装
```bash
pip install midscene-python
```
### 基础用法
```python
from midscene import Agent
from midscene.web import SeleniumWebPage
# 创建 Web Agent
with SeleniumWebPage.create() as page:
agent = Agent(page)
# 使用自然语言进行自动化操作
await agent.ai_action("点击登录按钮")
await agent.ai_action("输入用户名 'test@example.com'")
await agent.ai_action("输入密码 'password123'")
await agent.ai_action("点击提交按钮")
# 数据提取
user_info = await agent.ai_extract("提取用户个人信息")
# 断言验证
await agent.ai_assert("页面显示欢迎信息")
```
## 主要特性
### 🤖 AI 驱动的自动化
使用自然语言描述操作,AI 自动理解并执行:
```python
await agent.ai_action("在搜索框中输入'Python教程'并搜索")
```
### 🔍 智能元素定位
支持多种定位策略,自动选择最优方案:
```python
element = await agent.ai_locate("登录按钮")
```
### 📊 数据提取
从页面提取结构化数据:
```python
products = await agent.ai_extract({
"products": [
{"name": "产品名称", "price": "价格", "rating": "评分"}
]
})
```
### ✅ 智能断言
AI 理解页面状态,进行智能断言:
```python
await agent.ai_assert("用户已成功登录")
```
## 许可证
MIT License
Raw data
{
"_id": null,
"home_page": null,
"name": "midscene-python",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.9",
"maintainer_email": null,
"keywords": "AI, android, automation, playwright, selenium, testing, ui, web",
"author": "Midscene Team",
"author_email": null,
"download_url": "https://files.pythonhosted.org/packages/f2/7a/6d2fcf8baf5d75e6d035ba1cd58fbbae2891b5a18bc8a93c6447ed8743e1/midscene_python-0.1.1.tar.gz",
"platform": null,
"description": "# Midscene Python\n\nMidscene Python \u662f\u4e00\u4e2a\u57fa\u4e8e AI \u7684\u81ea\u52a8\u5316\u6846\u67b6\uff0c\u652f\u6301 Web \u548c Android \u5e73\u53f0\u7684 UI \u81ea\u52a8\u5316\u64cd\u4f5c\u3002\n\n## \u6982\u8ff0\n\nMidscene Python \u63d0\u4f9b\u5168\u9762\u7684 UI \u81ea\u52a8\u5316\u80fd\u529b\uff0c\u5177\u6709\u4ee5\u4e0b\u6838\u5fc3\u7279\u6027\uff1a\n\n- **\u81ea\u7136\u8bed\u8a00\u9a71\u52a8**\uff1a\u4f7f\u7528\u81ea\u7136\u8bed\u8a00\u63cf\u8ff0\u81ea\u52a8\u5316\u4efb\u52a1\n- **\u591a\u5e73\u53f0\u652f\u6301**\uff1a\u652f\u6301 Web\uff08Selenium/Playwright\uff09\u548c Android\uff08ADB\uff09\n- **AI \u6a21\u578b\u96c6\u6210**\uff1a\u652f\u6301 GPT-4V\u3001Qwen2.5-VL\u3001Gemini \u7b49\u591a\u79cd\u89c6\u89c9\u8bed\u8a00\u6a21\u578b\n- **\u53ef\u89c6\u5316\u8c03\u8bd5**\uff1a\u63d0\u4f9b\u8be6\u7ec6\u7684\u6267\u884c\u62a5\u544a\u548c\u8c03\u8bd5\u4fe1\u606f\n- **\u7f13\u5b58\u673a\u5236**\uff1a\u667a\u80fd\u7f13\u5b58\u63d0\u5347\u6267\u884c\u6548\u7387\n\n## \u9879\u76ee\u67b6\u6784\n\n```\nmidscene-python/\n\u251c\u2500\u2500 midscene/ # \u6838\u5fc3\u6846\u67b6\n\u2502 \u251c\u2500\u2500 core/ # \u6838\u5fc3\u6846\u67b6\n\u2502 \u2502 \u251c\u2500\u2500 agent/ # Agent\u7cfb\u7edf\n\u2502 \u2502 \u251c\u2500\u2500 insight/ # AI\u63a8\u7406\u5f15\u64ce\n\u2502 \u2502 \u251c\u2500\u2500 ai_model/ # AI\u6a21\u578b\u96c6\u6210\n\u2502 \u2502 \u251c\u2500\u2500 yaml/ # YAML\u811a\u672c\u6267\u884c\u5668\n\u2502 \u2502 \u2514\u2500\u2500 types.py # \u6838\u5fc3\u7c7b\u578b\u5b9a\u4e49\n\u2502 \u251c\u2500\u2500 web/ # Web\u96c6\u6210\n\u2502 \u2502 \u251c\u2500\u2500 selenium/ # Selenium\u96c6\u6210\n\u2502 \u2502 \u251c\u2500\u2500 playwright/ # Playwright\u96c6\u6210\n\u2502 \u2502 \u2514\u2500\u2500 bridge/ # Bridge\u6a21\u5f0f\n\u2502 \u251c\u2500\u2500 android/ # Android\u96c6\u6210\n\u2502 \u2502 \u251c\u2500\u2500 device.py # \u8bbe\u5907\u7ba1\u7406\n\u2502 \u2502 \u2514\u2500\u2500 agent.py # Android Agent\n\u2502 \u251c\u2500\u2500 cli/ # \u547d\u4ee4\u884c\u5de5\u5177\n\u2502 \u251c\u2500\u2500 mcp/ # MCP\u534f\u8bae\u652f\u6301\n\u2502 \u251c\u2500\u2500 shared/ # \u5171\u4eab\u5de5\u5177\n\u2502 \u2514\u2500\u2500 visualizer/ # \u53ef\u89c6\u5316\u62a5\u544a\n\u251c\u2500\u2500 examples/ # \u793a\u4f8b\u4ee3\u7801\n\u251c\u2500\u2500 tests/ # \u6d4b\u8bd5\u7528\u4f8b\n\u2514\u2500\u2500 docs/ # \u6587\u6863\n```\n\n## \u6280\u672f\u6808\n\n- **Python 3.9+**\uff1a\u6838\u5fc3\u8fd0\u884c\u73af\u5883\n- **Pydantic**\uff1a\u6570\u636e\u9a8c\u8bc1\u548c\u5e8f\u5217\u5316\n- **Selenium/Playwright**\uff1aWeb \u81ea\u52a8\u5316\n- **OpenCV/Pillow**\uff1a\u56fe\u50cf\u5904\u7406\n- **HTTPX/AIOHTTP**\uff1aHTTP \u5ba2\u6237\u7aef\n- **Typer**\uff1aCLI \u6846\u67b6\n- **Loguru**\uff1a\u65e5\u5fd7\u8bb0\u5f55\n\n## \u5feb\u901f\u5f00\u59cb\n\n### \u5b89\u88c5\n\n```bash\npip install midscene-python\n```\n\n### \u57fa\u7840\u7528\u6cd5\n\n```python\nfrom midscene import Agent\nfrom midscene.web import SeleniumWebPage\n\n# \u521b\u5efa Web Agent\nwith SeleniumWebPage.create() as page:\n agent = Agent(page)\n \n # \u4f7f\u7528\u81ea\u7136\u8bed\u8a00\u8fdb\u884c\u81ea\u52a8\u5316\u64cd\u4f5c\n await agent.ai_action(\"\u70b9\u51fb\u767b\u5f55\u6309\u94ae\")\n await agent.ai_action(\"\u8f93\u5165\u7528\u6237\u540d 'test@example.com'\")\n await agent.ai_action(\"\u8f93\u5165\u5bc6\u7801 'password123'\")\n await agent.ai_action(\"\u70b9\u51fb\u63d0\u4ea4\u6309\u94ae\")\n \n # \u6570\u636e\u63d0\u53d6\n user_info = await agent.ai_extract(\"\u63d0\u53d6\u7528\u6237\u4e2a\u4eba\u4fe1\u606f\")\n \n # \u65ad\u8a00\u9a8c\u8bc1\n await agent.ai_assert(\"\u9875\u9762\u663e\u793a\u6b22\u8fce\u4fe1\u606f\")\n```\n\n## \u4e3b\u8981\u7279\u6027\n\n### \ud83e\udd16 AI \u9a71\u52a8\u7684\u81ea\u52a8\u5316\n\n\u4f7f\u7528\u81ea\u7136\u8bed\u8a00\u63cf\u8ff0\u64cd\u4f5c\uff0cAI \u81ea\u52a8\u7406\u89e3\u5e76\u6267\u884c\uff1a\n\n```python\nawait agent.ai_action(\"\u5728\u641c\u7d22\u6846\u4e2d\u8f93\u5165'Python\u6559\u7a0b'\u5e76\u641c\u7d22\")\n```\n\n### \ud83d\udd0d \u667a\u80fd\u5143\u7d20\u5b9a\u4f4d\n\n\u652f\u6301\u591a\u79cd\u5b9a\u4f4d\u7b56\u7565\uff0c\u81ea\u52a8\u9009\u62e9\u6700\u4f18\u65b9\u6848\uff1a\n\n```python\nelement = await agent.ai_locate(\"\u767b\u5f55\u6309\u94ae\")\n```\n\n### \ud83d\udcca \u6570\u636e\u63d0\u53d6\n\n\u4ece\u9875\u9762\u63d0\u53d6\u7ed3\u6784\u5316\u6570\u636e\uff1a\n\n```python\nproducts = await agent.ai_extract({\n \"products\": [\n {\"name\": \"\u4ea7\u54c1\u540d\u79f0\", \"price\": \"\u4ef7\u683c\", \"rating\": \"\u8bc4\u5206\"}\n ]\n})\n```\n\n### \u2705 \u667a\u80fd\u65ad\u8a00\n\nAI \u7406\u89e3\u9875\u9762\u72b6\u6001\uff0c\u8fdb\u884c\u667a\u80fd\u65ad\u8a00\uff1a\n\n```python\nawait agent.ai_assert(\"\u7528\u6237\u5df2\u6210\u529f\u767b\u5f55\")\n```\n\n## \u8bb8\u53ef\u8bc1\n\nMIT License",
"bugtrack_url": null,
"license": null,
"summary": "\u57fa\u4e8eAI\u7684Web\u548cAndroid\u81ea\u52a8\u5316\u6846\u67b6\uff0c\u652f\u6301\u81ea\u7136\u8bed\u8a00\u9a71\u52a8\u7684UI\u64cd\u4f5c",
"version": "0.1.1",
"project_urls": {
"Bug Tracker": "https://github.com/Python51888/midscene-python.git/issues",
"Documentation": "https://github.com/Python51888/Midscene-Python/blob/master/README.md",
"Homepage": "https://github.com/Python51888/midscene-python.git",
"Repository": "https://github.com/Python51888/midscene-python.git"
},
"split_keywords": [
"ai",
" android",
" automation",
" playwright",
" selenium",
" testing",
" ui",
" web"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "b0a7e034843feb1bcabe61f5e03cb81eb4d1f3bae723716f0a6aa4f4652b787a",
"md5": "07925b4f59f89372b14d6d34a7772c89",
"sha256": "ac0c3990694284954ada2ea9f7139083091c68f4c5bc359021f6bb34353daf5f"
},
"downloads": -1,
"filename": "midscene_python-0.1.1-py3-none-any.whl",
"has_sig": false,
"md5_digest": "07925b4f59f89372b14d6d34a7772c89",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.9",
"size": 45541,
"upload_time": "2025-09-03T06:40:40",
"upload_time_iso_8601": "2025-09-03T06:40:40.144292Z",
"url": "https://files.pythonhosted.org/packages/b0/a7/e034843feb1bcabe61f5e03cb81eb4d1f3bae723716f0a6aa4f4652b787a/midscene_python-0.1.1-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "f27a6d2fcf8baf5d75e6d035ba1cd58fbbae2891b5a18bc8a93c6447ed8743e1",
"md5": "857969f3c4de5438114d30ee0815b666",
"sha256": "ae04db5ed56e1b67c116247bfec542e73ec8358cb988887b47fcbf2e3ea4dc5b"
},
"downloads": -1,
"filename": "midscene_python-0.1.1.tar.gz",
"has_sig": false,
"md5_digest": "857969f3c4de5438114d30ee0815b666",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.9",
"size": 79034,
"upload_time": "2025-09-03T06:40:42",
"upload_time_iso_8601": "2025-09-03T06:40:42.181103Z",
"url": "https://files.pythonhosted.org/packages/f2/7a/6d2fcf8baf5d75e6d035ba1cd58fbbae2891b5a18bc8a93c6447ed8743e1/midscene_python-0.1.1.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-09-03 06:40:42",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "Python51888",
"github_project": "midscene-python",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"requirements": [
{
"name": "aiohappyeyeballs",
"specs": [
[
"==",
"2.6.1"
]
]
},
{
"name": "aiohttp",
"specs": [
[
"==",
"3.12.15"
]
]
},
{
"name": "aiosignal",
"specs": [
[
"==",
"1.4.0"
]
]
},
{
"name": "annotated-types",
"specs": [
[
"==",
"0.7.0"
]
]
},
{
"name": "anthropic",
"specs": [
[
"==",
"0.64.0"
]
]
},
{
"name": "anyio",
"specs": [
[
"==",
"4.10.0"
]
]
},
{
"name": "asyncio-mqtt",
"specs": [
[
"==",
"0.16.2"
]
]
},
{
"name": "attrs",
"specs": [
[
"==",
"25.3.0"
]
]
},
{
"name": "babel",
"specs": [
[
"==",
"2.17.0"
]
]
},
{
"name": "backrefs",
"specs": [
[
"==",
"5.9"
]
]
},
{
"name": "black",
"specs": [
[
"==",
"25.1.0"
]
]
},
{
"name": "cachetools",
"specs": [
[
"==",
"5.5.2"
]
]
},
{
"name": "certifi",
"specs": [
[
"==",
"2025.8.3"
]
]
},
{
"name": "cffi",
"specs": [
[
"==",
"1.17.1"
]
]
},
{
"name": "cfgv",
"specs": [
[
"==",
"3.4.0"
]
]
},
{
"name": "charset-normalizer",
"specs": [
[
"==",
"3.4.3"
]
]
},
{
"name": "click",
"specs": [
[
"==",
"8.2.1"
]
]
},
{
"name": "colorama",
"specs": [
[
"==",
"0.4.6"
]
]
},
{
"name": "coverage",
"specs": [
[
"==",
"7.10.6"
]
]
},
{
"name": "cryptography",
"specs": [
[
"==",
"45.0.7"
]
]
},
{
"name": "dashscope",
"specs": [
[
"==",
"1.24.2"
]
]
},
{
"name": "distlib",
"specs": [
[
"==",
"0.4.0"
]
]
},
{
"name": "distro",
"specs": [
[
"==",
"1.9.0"
]
]
},
{
"name": "filelock",
"specs": [
[
"==",
"3.19.1"
]
]
},
{
"name": "frozenlist",
"specs": [
[
"==",
"1.7.0"
]
]
},
{
"name": "ghp-import",
"specs": [
[
"==",
"2.1.0"
]
]
},
{
"name": "google-ai-generativelanguage",
"specs": [
[
"==",
"0.6.15"
]
]
},
{
"name": "google-api-core",
"specs": [
[
"==",
"2.25.1"
]
]
},
{
"name": "google-api-python-client",
"specs": [
[
"==",
"2.179.0"
]
]
},
{
"name": "google-auth",
"specs": [
[
"==",
"2.40.3"
]
]
},
{
"name": "google-auth-httplib2",
"specs": [
[
"==",
"0.2.0"
]
]
},
{
"name": "google-generativeai",
"specs": [
[
"==",
"0.8.5"
]
]
},
{
"name": "googleapis-common-protos",
"specs": [
[
"==",
"1.70.0"
]
]
},
{
"name": "greenlet",
"specs": [
[
"==",
"3.2.4"
]
]
},
{
"name": "griffe",
"specs": [
[
"==",
"1.13.0"
]
]
},
{
"name": "grpcio",
"specs": [
[
"==",
"1.74.0"
]
]
},
{
"name": "grpcio-status",
"specs": [
[
"==",
"1.71.2"
]
]
},
{
"name": "h11",
"specs": [
[
"==",
"0.16.0"
]
]
},
{
"name": "httpcore",
"specs": [
[
"==",
"1.0.9"
]
]
},
{
"name": "httplib2",
"specs": [
[
"==",
"0.30.0"
]
]
},
{
"name": "httpx",
"specs": [
[
"==",
"0.28.1"
]
]
},
{
"name": "identify",
"specs": [
[
"==",
"2.6.13"
]
]
},
{
"name": "idna",
"specs": [
[
"==",
"3.10"
]
]
},
{
"name": "iniconfig",
"specs": [
[
"==",
"2.1.0"
]
]
},
{
"name": "isort",
"specs": [
[
"==",
"6.0.1"
]
]
},
{
"name": "jinja2",
"specs": [
[
"==",
"3.1.6"
]
]
},
{
"name": "jiter",
"specs": [
[
"==",
"0.10.0"
]
]
},
{
"name": "loguru",
"specs": [
[
"==",
"0.7.3"
]
]
},
{
"name": "markdown",
"specs": [
[
"==",
"3.8.2"
]
]
},
{
"name": "markdown-it-py",
"specs": [
[
"==",
"4.0.0"
]
]
},
{
"name": "markupsafe",
"specs": [
[
"==",
"3.0.2"
]
]
},
{
"name": "mdurl",
"specs": [
[
"==",
"0.1.2"
]
]
},
{
"name": "mergedeep",
"specs": [
[
"==",
"1.3.4"
]
]
},
{
"name": "mkdocs",
"specs": [
[
"==",
"1.6.1"
]
]
},
{
"name": "mkdocs-autorefs",
"specs": [
[
"==",
"1.4.3"
]
]
},
{
"name": "mkdocs-get-deps",
"specs": [
[
"==",
"0.2.0"
]
]
},
{
"name": "mkdocs-material",
"specs": [
[
"==",
"9.6.18"
]
]
},
{
"name": "mkdocs-material-extensions",
"specs": [
[
"==",
"1.3.1"
]
]
},
{
"name": "mkdocstrings",
"specs": [
[
"==",
"0.30.0"
]
]
},
{
"name": "mkdocstrings-python",
"specs": [
[
"==",
"1.18.2"
]
]
},
{
"name": "multidict",
"specs": [
[
"==",
"6.6.4"
]
]
},
{
"name": "mypy",
"specs": [
[
"==",
"1.17.1"
]
]
},
{
"name": "mypy-extensions",
"specs": [
[
"==",
"1.1.0"
]
]
},
{
"name": "nodeenv",
"specs": [
[
"==",
"1.9.1"
]
]
},
{
"name": "numpy",
"specs": [
[
"==",
"1.26.4"
]
]
},
{
"name": "openai",
"specs": [
[
"==",
"1.102.0"
]
]
},
{
"name": "opencv-python",
"specs": [
[
"==",
"4.11.0.86"
]
]
},
{
"name": "outcome",
"specs": [
[
"==",
"1.3.0.post0"
]
]
},
{
"name": "packaging",
"specs": [
[
"==",
"25.0"
]
]
},
{
"name": "paginate",
"specs": [
[
"==",
"0.5.7"
]
]
},
{
"name": "paho-mqtt",
"specs": [
[
"==",
"2.1.0"
]
]
},
{
"name": "pathspec",
"specs": [
[
"==",
"0.12.1"
]
]
},
{
"name": "pillow",
"specs": [
[
"==",
"10.4.0"
]
]
},
{
"name": "platformdirs",
"specs": [
[
"==",
"4.4.0"
]
]
},
{
"name": "playwright",
"specs": [
[
"==",
"1.55.0"
]
]
},
{
"name": "pluggy",
"specs": [
[
"==",
"1.6.0"
]
]
},
{
"name": "pre-commit",
"specs": [
[
"==",
"4.3.0"
]
]
},
{
"name": "propcache",
"specs": [
[
"==",
"0.3.2"
]
]
},
{
"name": "proto-plus",
"specs": [
[
"==",
"1.26.1"
]
]
},
{
"name": "protobuf",
"specs": [
[
"==",
"5.29.5"
]
]
},
{
"name": "pure-python-adb",
"specs": [
[
"==",
"0.3.0.dev0"
]
]
},
{
"name": "pyasn1",
"specs": [
[
"==",
"0.6.1"
]
]
},
{
"name": "pyasn1-modules",
"specs": [
[
"==",
"0.4.2"
]
]
},
{
"name": "pycparser",
"specs": [
[
"==",
"2.22"
]
]
},
{
"name": "pydantic",
"specs": [
[
"==",
"2.11.7"
]
]
},
{
"name": "pydantic-core",
"specs": [
[
"==",
"2.33.2"
]
]
},
{
"name": "pyee",
"specs": [
[
"==",
"13.0.0"
]
]
},
{
"name": "pygments",
"specs": [
[
"==",
"2.19.2"
]
]
},
{
"name": "pymdown-extensions",
"specs": [
[
"==",
"10.16.1"
]
]
},
{
"name": "pyparsing",
"specs": [
[
"==",
"3.2.3"
]
]
},
{
"name": "pysocks",
"specs": [
[
"==",
"1.7.1"
]
]
},
{
"name": "pytest",
"specs": [
[
"==",
"8.4.1"
]
]
},
{
"name": "pytest-asyncio",
"specs": [
[
"==",
"1.1.0"
]
]
},
{
"name": "pytest-cov",
"specs": [
[
"==",
"6.2.1"
]
]
},
{
"name": "python-dateutil",
"specs": [
[
"==",
"2.9.0.post0"
]
]
},
{
"name": "pyyaml",
"specs": [
[
"==",
"6.0.2"
]
]
},
{
"name": "pyyaml-env-tag",
"specs": [
[
"==",
"1.1"
]
]
},
{
"name": "requests",
"specs": [
[
"==",
"2.32.5"
]
]
},
{
"name": "rich",
"specs": [
[
"==",
"14.1.0"
]
]
},
{
"name": "rsa",
"specs": [
[
"==",
"4.9.1"
]
]
},
{
"name": "ruff",
"specs": [
[
"==",
"0.12.11"
]
]
},
{
"name": "selenium",
"specs": [
[
"==",
"4.35.0"
]
]
},
{
"name": "shellingham",
"specs": [
[
"==",
"1.5.4"
]
]
},
{
"name": "six",
"specs": [
[
"==",
"1.17.0"
]
]
},
{
"name": "sniffio",
"specs": [
[
"==",
"1.3.1"
]
]
},
{
"name": "sortedcontainers",
"specs": [
[
"==",
"2.4.0"
]
]
},
{
"name": "tqdm",
"specs": [
[
"==",
"4.67.1"
]
]
},
{
"name": "trio",
"specs": [
[
"==",
"0.30.0"
]
]
},
{
"name": "trio-websocket",
"specs": [
[
"==",
"0.12.2"
]
]
},
{
"name": "typer",
"specs": [
[
"==",
"0.17.3"
]
]
},
{
"name": "typing-extensions",
"specs": [
[
"==",
"4.14.1"
]
]
},
{
"name": "typing-inspection",
"specs": [
[
"==",
"0.4.1"
]
]
},
{
"name": "uritemplate",
"specs": [
[
"==",
"4.2.0"
]
]
},
{
"name": "urllib3",
"specs": [
[
"==",
"2.5.0"
]
]
},
{
"name": "virtualenv",
"specs": [
[
"==",
"20.34.0"
]
]
},
{
"name": "watchdog",
"specs": [
[
"==",
"6.0.0"
]
]
},
{
"name": "websocket-client",
"specs": [
[
"==",
"1.8.0"
]
]
},
{
"name": "win32-setctime",
"specs": [
[
"==",
"1.2.0"
]
]
},
{
"name": "wsproto",
"specs": [
[
"==",
"1.2.0"
]
]
},
{
"name": "yarl",
"specs": [
[
"==",
"1.20.1"
]
]
}
],
"lcname": "midscene-python"
}