本文档是给
~/Pyrite-Project/pyrite-cli的改造清单。当前阶段不执行(等 mPyMacro 发布到 PyPI org 后再动手)。所有行号基于编写本文档时的 pyrite-cli 代码,实际改动前请重新核对。
让 pyrite-cli 把条件编译能力外置为对 mpymacro 包的依赖,删除内部重复实现,同时保留 pyrite 自身的设备 I/O 优势(板型自动识别、自动编译、串口刷写)。
改造后职责边界:
| 能力 | 归属 | 说明 |
|---|---|---|
@feature/@target 源码级裁剪 |
mPyMacro | preprocess() |
| manifest 文件级过滤 | mPyMacro | load_manifest() |
| machine/platform 字符串 → tags 映射 | mPyMacro | resolve_board_tags()(纯逻辑) |
| target/feature/no_feature 合并 | mPyMacro | resolve_active_tags() |
| board_tags 配置加载 | 两者兼容 | 读同一份 pyproject.toml [tool.pyrite.board_tags] |
| 读串口/设备 uname | pyrite | detect_tags() 的 self.run(...) 部分保留 |
| 自动编译 .py→.mpy | pyrite | mpy-cross 调用保留 |
| 串口刷写 | pyrite | flash_file/flash_entries 保留 |
mPyMacro >=0.2.0 已可安装(PyPI 或本地 pip install -e),暴露:
from mpymacro import (
preprocess, load_manifest, build_project,
resolve_active_tags, resolve_board_tags, load_board_tags,
DEFAULT_BOARD_TAGS,
)签名与 pyrite 现有内部实现完全一致,故多数接入点是「改 import」级改动:
preprocess(source, active_tags, filename="") -> strload_manifest(manifest_path, active_tags, base_dir=None) -> list[tuple[str, str]]
pyproject.toml:
dependencies = [
# ... 现有依赖 ...
"mpymacro>=0.2.0", # 新增
# libcst 可移除——已由 mpymacro 间接依赖;如其它模块直接用 libcst 则保留
]删除以下文件(逻辑已迁入 mpymacro):
cli/utils/preprocessor.pycli/utils/manifest_loader.py
cli/project/feature_stub.pyi 可保留随包,或改由 mpymacro stub -o cli/project/feature_stub.pyi 生成。
对应地从 pyproject.toml 的 [tool.pytest.ini_options].testpaths 移除 test/test_preprocessor.py、test/test_manifest_loader.py(这些用例已在 mPyMacro 仓库内覆盖)。
cli/utils/flash/core.py:1336-1346(flash_file)与 1540-1555(flash_entries):
# 改前
from ..preprocessor import preprocess
# 改后
from mpymacro import preprocess调用代码、参数、临时目录写出逻辑一律不动——preprocess(source, active_tags, filename) 签名一致。auto_compile(mpy-cross)仍在 preprocess 之后执行,顺序不变。
cli/utils/flash/core.py:1764(flash_program)cli/project/sync.py:57(ProjectSyncManager._collect_project_files)
# 改前
from ..manifest_loader import load_manifest # 或对应相对路径
# 改后
from mpymacro import load_manifest保留设备读取(这是 pyrite 的板型自动识别优势),仅把字符串→tags 的纯映射委托给 mpymacro:
def detect_tags(self) -> Set[str]:
"""从设备读取 board 信息,返回 active_tags 集合。"""
from mpymacro import resolve_board_tags
try:
out = self.run(
"import os,sys\nprint(os.uname().machine)\nprint(sys.platform)",
)
except Exception as e:
log.debug("设备 tag 检测失败: %s", e)
return set()
lines = [l.strip() for l in out.strip().splitlines() if l.strip()]
machine = lines[0] if lines else ""
platform = lines[1] if len(lines) > 1 else ""
# 纯映射逻辑外置到 mpymacro
return resolve_board_tags(machine, platform, self.config.board_tags)注意
resolve_board_tags把 machine+platform 拼接后大写匹配关键字,并追加 platform 自身(大写)——与原detect_tags行为等价。
原代码在 main.py 中重复约 7 处,全部替换为对 resolve_active_tags 的调用:
main.py:319-330(flash)main.py:388-400(flash_program)main.py:1188-1199(project flash)main.py:1332-1343(project run)main.py:1234-1244(project status)main.py:1279-1295(project pull,特殊:未指定任何选项时active_tags=None)main.py:1480-1496(_build_tag_args,被fs put使用)
通用替换(适用于前 5 处):
from mpymacro import resolve_active_tags
active_tags = resolve_active_tags(
target=target,
detected=(mp.detect_tags() if not target else None),
feature=feature,
no_feature=no_feature,
board_tags=mp.config.board_tags,
)
# 原 "无法识别设备 target" 的报错逻辑(detect 返回空集时)按需保留在调用处:
if not target and not active_tags:
log.error("无法识别设备 target,请使用 --target 手动指定")
raise typer.Exit(1)建议把上面这段封装进现有的 _build_tag_args(mp, target, feature, no_feature),让全部 5 处都调它,消除重复。
project pull 的特殊语义(main.py:1279-1295)必须保留:未指定 target/feature/no_feature 时 active_tags=None(表示"拉取全部、不裁剪")。resolve_active_tags 在无任何输入时返回空集而非 None,故这一处需要单独处理:
if not target and not feature and not no_feature:
active_tags = None # pull 全部,不做过滤/裁剪
else:
active_tags = resolve_active_tags(
target=target,
detected=(set() if (feature or no_feature) and not target else None),
feature=feature, no_feature=no_feature,
board_tags=mp.config.board_tags,
)pyrite 继续用自己的 cli/utils/config.py 加载 board_tags。mPyMacro 的 load_board_tags() 复刻了相同语义(读 pyproject.toml [tool.pyrite.board_tags],大写 key 合并进同一份默认表),因此:
- 用户在项目
pyproject.toml写一次[tool.pyrite.board_tags]; - 经 pyrite-cli 刷写、或用独立
mpymacroCLI 处理,得到的 active_tags 一致。
无需让 pyrite 改用 load_board_tags;但如果希望进一步减少重复,可让 pyrite 的 config.py 内部调用 mpymacro.load_board_tags(defaults=_DEFAULT_BOARD_TAGS) 来填充 cfg.board_tags(可选,非必须)。
pip install -e .能拉到mpymacro依赖。- pyrite 现有非删除测试仍通过:
test/test_config.py(board_tags 加载不变)、其余 flash/protocol 测试不受影响。 - 端到端:对一个含
@feature/@target与manifest.py(features=...)的项目执行pyrcli flash-program,对照改造前的输出字节码一致。 - 板型识别:连真实设备
pyrcli flash-program(不带--target),确认detect_tags()仍能识别并裁剪。 - 离线一致性:
mpymacro build -m manifest.py -o /tmp/dist --target ESP32的产物,与 pyrite 在同 target 下刷入的内容逐文件一致。
改动集中在「删 2 文件 + 改 4 处 import + 改 1 个 detect_tags + 收敛 7 处 tag 合并」。如需回滚,恢复被删的 preprocessor.py/manifest_loader.py 并还原 import 即可——mpymacro 与原实现 API 同构,不存在数据格式迁移。