SunDoge's Blog

What TripleZ don't know

0%

TypedArgs v0.4.0 released!

TypedArgs v0.4.0 发布了。大部分接口与 v0.3.x 没有差别,但是少了一个 attribute,所以必须升一个 minor version。这篇博客主要记录我的几个设计失误。

argparse.ArgumentParser 不能被 pickle

TypedArgs 内部是使用 Python 标准库 argparse 实现的。一个标准的 argparse 使用流程如下:

1
2
3
4
5
6
7
import argparse

parser = argparse.ArgumentParser(prog='PROG')
parser.add_argument('data', help='path to data')
args = parser.parse_args(['data-path'])

assert args.data == 'data-path'

首先,ArgumentParser 支持指定显示的 program 名,那 TypedArgs也应该支持。那一个很自然的想法就是让 parser 成为 class TypedArgs 的一个 attribute,这样解析 arguments 的时候就能自由访问。

1
2
3
4
5
6
7
from dataclasses import dataclass, field
from typed_args import TypedArgs
import argparse

@dataclass
class Args(TypedArgs):
parser: field(default_factory=lambda: argparse.ArgumentParser(prog='PROG'))

但是这带来了一个问题,我并没有意识到 ArgumentParser 是不能被 pickle(序列化)的。虽然平时使用没有问题,但是到了多进程环境(比如 PyTorch 的 DistributedDataParallel)就会报错。为此。v0.3.x 临时打了一个 patch,在解析完 arguements 之后,将 self.parser = None。其实这个时候已经造成了 API 变动,minor version 应该 + 1,但是当时思想出了问题,只升了 patch version。当然,没有人会访问 parser,所以理论上问题不大。

v0.4.0 从根本上解决了这个问题,parser 只在解析 arguments 被生成,解析完就回收,不再作为 TypedArgs 上的一个 attribute。

如何让 IDE 正确识别出类型

PyCharm 和 VS Code 对于类型推倒总是有不同的想法。PyCharm 认为 = 后面的才是正确类型,直接忽略了我的 annotation。VS Code 就蠢一点,认为我的 annotation 是对的,但是使用的时候又自作聪明不显示我标注的类型。最后我采用了现在的方案:

1
2
3
4
foo: str = func()

def func() -> Any:
pass

这样写,两个 IDE 都能正确推导类型,而且也比较符合常识。

使用 GitHub Action 自动发布到 pypi.org

GitHub 很贴心,GitHub 整个模板都给你弄好了,你只需要去 Settings > Secrets 填两个参数(PYPI_USERNAMEPYPI_PASSWORD)。之后每次 push 带 tag,或者在 GitHub 上创建 release 的时候(创建 release 会创建一个 tag),就会触发这个 GitHub Action,将这个库发布到 pypi.org