跳转到主要内容

Python类型存根的回滚版本

项目描述

unpy

统一Python

将Python 3.13的.pyi存根转换到Python 3.10

unpy - PyPI unpy - Python Versions unpy - license

unpy - CI unpy - pre-commit unpy - basedmypy unpy - basedpyright unpy - ruff


[!IMPORTANT] 此项目处于alpha阶段:您可能不应该在生产环境中使用它。

安装

$ pip install unpy

使用

$ unpy --help
Usage: unpy [OPTIONS] SOURCE [OUTPUT]

Arguments:
  SOURCE    Path to the input .pyi file or '-' to read from stdin.  [required]
  [OUTPUT]  Path to the output .pyi file. Defaults to stdout.

Options:
  --version                       Show the version and exit
  --diff                          Show the changes between the input and
                                  output in unified diff format
  --target [3.10|3.11|3.12|3.13]  The minimum Python version that should be
                                  supported.  [default: 3.10]
  --help                          Show this message and exit.

示例

一些Python 3.13存根的简单示例,这些存根被回滚到Python 3.10。

导入

$ unpy --target 3.10 --diff examples/imports.pyi
+++ -
@@ -1,6 +1,4 @@
- from types import CapsuleType
- from typing import override
- from warnings import deprecated
+ from typing_extensions import CapsuleType, deprecated, override

  @deprecated("RTFM")
  class Spam:
      __pyx_capi__: dict[str, CapsuleType]
      @override
      def __hash__(self, /) -> int: ...

注意生成的导入的字母顺序。

类型别名

$ unpy --target 3.10 --diff examples/type_aliases.pyi
+++ -
@@ -1,7 +1,15 @@
  from collections.abc import Callable
+ from typing import ParamSpec, TypeAlias, TypeVar
+ from typing_extensions import TypeAliasType, TypeVarTuple, Unpack

- type Binary = bytes | bytearray | memoryview
- type Vector[R: float] = tuple[R, ...]
- type tciD[V, K] = dict[K, V]
- type Things[*Ts] = tuple[*Ts]
- type Callback[**Tss] = Callable[Tss, None]
+ _R = TypeVar("_R", bound=float)
+ _V = TypeVar("_V")
+ _K = TypeVar("_K")
+ _Ts = TypeVarTuple("_Ts")
+ _Tss = ParamSpec("_Tss")
+
+ Binary: TypeAlias = bytes | bytearray | memoryview
+ Vector: TypeAlias = tuple[_R, ...]
+ tciD = TypeAliasType("tciD", dict[_K, _V], type_params=(_V, _K))
+ Things: TypeAlias = tuple[Unpack[_Ts]]
+ Callback: TypeAlias = Callable[_Tss, None]

请注意,TypeAlias不能与tciD一起使用,因为类型参数(在左侧)的定义顺序与它们被访问(在右侧)的顺序不匹配,必须使用回滚的TypeAliasType

函数

$ unpy --target 3.10 --diff examples/functions.pyi
+++ -
@@ -1,6 +1,11 @@
+ _T = TypeVar("_T")
+ _S = TypeVar("_S", str, bytes)
+ _X = TypeVar("_X")
+ _Theta = ParamSpec("_Theta")
+ _Y = TypeVar("_Y")
  from collections.abc import Callable as Def
- from typing import Concatenate as Concat
+ from typing import Concatenate as Concat, ParamSpec, TypeVar

- def noop[T](x: T, /) -> T: ...
- def concat[S: (str, bytes)](left: S, right: S) -> S: ...
- def curry[X, **Theta, Y](f: Def[Concat[X, Theta], Y], /) -> Def[[X], Def[Theta, Y]]: ...
+ def noop(x: _T, /) -> _T: ...
+ def concat(left: _S, right: _S) -> _S: ...
+ def curry(f: Def[Concat[_X, _Theta], _Y], /) -> Def[[_X], Def[_Theta, _Y]]: ...

泛型类和协议

$ unpy --target 3.10 --diff examples/generics.pyi
+++ -
@@ -1,17 +1,25 @@
- from typing import Protocol, overload
+ from typing import Generic, Protocol, overload
+ from typing_extensions import TypeVar
+
+ _T_contra = TypeVar("_T_contra", contravariant=True)
+ _T_co = TypeVar("_T_co", covariant=True)
+ _T = TypeVar("_T", infer_variance=True)
+ _D = TypeVar("_D")
+ _NameT = TypeVar("_NameT", infer_variance=True, bound=str)
+ _QualNameT = TypeVar("_QualNameT", infer_variance=True, bound=str, default=_NameT)

  class Boring: ...

- class CanGetItem[T_contra, T_co](Protocol):
-     def __getitem__(self, k: T_contra, /) -> T_co: ...
+ class CanGetItem(Protocol[_T_contra, _T_co]):
+     def __getitem__(self, k: _T_contra, /) -> _T_co: ...

- class Stack[T]:
-     def push(self, value: T, /) -> None: ...
+ class Stack(Generic[_T, _D]):
+     def push(self, value: _T, /) -> None: ...
      @overload
-     def pop(self, /) -> T: ...
+     def pop(self, /) -> _T: ...
      @overload
-     def pop[D](self, default: D, /) -> T | D: ...
+     def pop(self, default: _D, /) -> _T | _D: ...

- class Named[NameT: str, QualNameT: str = NameT]:
-     __name__: NameT
-     __qualname__: QualNameT
+ class Named(Generic[_NameT, _QualNameT]):
+     __name__: _NameT
+     __qualname__: _QualNameT

注意这里如何(仅)从typing_extensions导入TypeVar,这与上一个示例不同。这是由于添加了infer_variance参数的结果,该参数在Python 3.12中已添加。

项目目标

这是unpy潜在目标的初步想法的原型草图的alpha版本。

  1. 回顾过去
    • 存根scipy时感到沮丧
    • 将Python 3.13的.pyi存根转换为Python 3.10存根
    • 包级分析和转换
    • 仅存根项目的集成工具
    • scipy-stubs 中使用此功能
    • 逐步引入到 numpy
  2. 面向未来
    • 超越Python: $\text{Unpy} \supset \text{Python}$
    • 为所有 .py 项目提供语言支持和工具
  3. 相互靠近
    • 统一类型检查:快速、合理且语言无关

功能

工具

  • 目标Python版本
    • 3.13
    • 3.12
    • 3.11
    • 3.10
    • 3.9
  • 语言支持
    • .pyi
    • .py
  • 转换
    • stdin => stdout
    • module => module
    • package => package
    • project => project (包括 pyproject.toml)
  • 配置
    • --diff: 统一差异
    • --target: 目标Python版本,默认为 3.10
    • pyproject.toml 下的 [tools.unpy] 中进行基于项目的配置
    • ...
  • 集成
    • 文件监视器
    • Pre-commit
    • LSP
    • UV
    • VSCode 扩展
    • (基于)mypy 插件
    • 项目构建工具
    • 可配置的类型检查器集成
    • 可配置的格式化器集成,例如 ruff format
  • 性能
    • 限制转换到已更改的文件

存根回退

  • Python 3.13 => 3.12
    • PEP 742
      • typing.TypeIs => typing_extensions.TypeIs
    • PEP 705
      • typing.ReadOnly => typing_extensions.ReadOnly
    • PEP 702
      • warnings.deprecated => typing_extensions.deprecated
    • PEP 696
      • 回退带有默认值的 PEP 695 类型签名
      • typing.NoDefault => typing_extensions.NoDefault
    • 异常
      • asyncio.QueueShutDown => builtins.Exception
      • pathlib.UnsupportedOperation => builtins.NotImplementedError
      • queue.ShutDown => builtins.Exception
      • re.PatternError => re.error
    • 类型
      • types.CapsuleType => typing_extensions.CapsuleType
      • typing.{ClassVar,Final} => typing_extensions.{ClassVar,Final} 当嵌套时
  • Python 3.12 => 3.11
    • PEP 698
      • typing.override => typing_extensions.override
    • PEP 695
      • 回退 type _ 别名
      • 回退泛型函数
      • 回退泛型类和协议
      • typing.TypeAliasType => typing_extensions.TypeAliasType
    • PEP 688
      • collections.abc.Buffer => typing_extensions.Buffer
      • inspect.BufferFlags => int
  • Python 3.11 => 3.10
    • PEP 681
      • typing.dataclass_transform => typing_extensions.dataclass_transform
    • PEP 675
      • typing.LiteralString => typing_extensions.LiteralString
    • PEP 673
      • typing.Self => typing_extensions.Self
    • PEP 655
      • typing.[Not]Required => typing_extensions.[Not]Required
    • PEP 654
      • builtins.BaseExceptionGroup
      • builtins.ExceptionGroup
    • PEP 646
      • typing.TypeVarTuple => typing_extensions.TypeVarTuple
      • typing.Unpack => typing_extensions.Unpack
      • *Ts => typing_extensions.Unpack[Ts] with Ts: TypeVarTuple
    • asyncio
      • asyncio.TaskGroup
    • enum
      • enum.ReprEnum => enum.Enum
      • enum.StrEnum => str & enum.Enum
    • typing
      • typing.Any => typing_extensions.Any if subclassed (not recommended)
  • 生成的 TypeVar
    • 如果有相同名称且等效的提取类型变量,则去重
    • 提取类型变量名称前缀为 _
    • 重命名具有相同名称的不兼容类型变量(jorenham/unpy#86)

简化与重构

  • 泛型类型参数
    • default=Anybound=T 转换为 default=T
    • 删除 bound=Anybound=object
    • 推断 PEP 695 类型参数的方差(jorenham/unpy#44)
      • 如果从未使用,它是多余的(且二价)
      • 如果指定了约束,则是 invariant
      • 如果后缀为 _co/_contra,则是 covariant/contravariant
      • 如果用作公共实例属性,则是 invariant
      • 如果仅用作返回类型(不包括 __init____new__),或用于只读属性,则是 covariant
      • 如果仅用作参数类型,则是 contravariant
      • 否则,假设它是 invariant
  • 方法
    • 特定“特殊方法”的默认返回类型(jorenham/unpy#55)
    • self 方法参数转换为仅位置参数
  • 类型运算符
    • type[S] | type[T] => type[S | T]
    • 平展并去重字面量联合
    • 移除冗余联合值,例如 bool | int => int

超越 Python

  • @sealed 类型(jorenham/unpy/#42)
  • 统一类型忽略注释(jorenham/unpy/#68)
  • 基于集合的 Literal 语法(jorenham/unpy/#76)
  • 可重用方法签名定义
  • 类型映射,是 @overload 的 DRY 替代方案
  • 交集类型(如 basedmypy 中实现)
  • 高阶类型(见 python/typing#548)
  • 内联可调用类型(受 PEP 677 启发)

项目详情


下载文件

下载适用于您平台的应用程序。如果您不确定要选择哪个,请了解更多关于 安装包 的信息。

源分发

unpy-0.3.0.tar.gz (29.8 kB 查看哈希值

上传时间:

构建分发

unpy-0.3.0-py3-none-any.whl (29.1 kB 查看哈希值

上传时间: Python 3

由以下机构支持

AWS AWS 云计算和安全赞助商 Datadog Datadog 监控 Fastly Fastly CDN Google Google 下载分析 Microsoft Microsoft PSF 赞助商 Pingdom Pingdom 监控 Sentry Sentry 错误记录 StatusPage StatusPage 状态页