Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
Greenplum
Opencv
提交
f20edba9
O
Opencv
项目概览
Greenplum
/
Opencv
9 个月 前同步成功
通知
7
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
O
Opencv
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
前往新版Gitcode,体验更适合开发者的 AI 搜索 >>
提交
f20edba9
编写于
6月 20, 2023
作者:
V
Vadim Levin
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
fix: conditionally define generic NumPy NDArray alias
上级
fe4f5b53
变更
3
隐藏空白更改
内联
并排
Showing
3 changed file
with
177 addition
and
39 deletion
+177
-39
modules/python/src2/typing_stubs_generation/generation.py
modules/python/src2/typing_stubs_generation/generation.py
+38
-20
modules/python/src2/typing_stubs_generation/nodes/type_node.py
...es/python/src2/typing_stubs_generation/nodes/type_node.py
+118
-13
modules/python/src2/typing_stubs_generation/predefined_types.py
...s/python/src2/typing_stubs_generation/predefined_types.py
+21
-6
未找到文件。
modules/python/src2/typing_stubs_generation/generation.py
浏览文件 @
f20edba9
...
...
@@ -15,7 +15,8 @@ from .nodes import (ASTNode, ASTNodeType, NamespaceNode, ClassNode, FunctionNode
EnumerationNode
,
ConstantNode
)
from
.nodes.type_node
import
(
TypeNode
,
AliasTypeNode
,
AliasRefTypeNode
,
AggregatedTypeNode
,
ASTNodeTypeNode
)
AggregatedTypeNode
,
ASTNodeTypeNode
,
ConditionalAliasTypeNode
,
PrimitiveTypeNode
)
def
generate_typing_stubs
(
root
:
NamespaceNode
,
output_path
:
Path
):
...
...
@@ -682,28 +683,37 @@ def _generate_typing_module(root: NamespaceNode, output_path: Path) -> None:
f
"Provided type node '
{
type_node
.
ctype_name
}
' is not an aggregated type"
for
item
in
filter
(
lambda
i
:
isinstance
(
i
,
AliasRefTypeNode
),
type_node
):
register_alias
(
PREDEFINED_TYPES
[
item
.
ctype_name
])
# type: ignore
type_node
=
PREDEFINED_TYPES
[
item
.
ctype_name
]
if
isinstance
(
type_node
,
AliasTypeNode
):
register_alias
(
type_node
)
elif
isinstance
(
type_node
,
ConditionalAliasTypeNode
):
conditional_type_nodes
[
type_node
.
ctype_name
]
=
type_node
def
create_alias_for_enum_node
(
enum_node
:
ASTNode
)
->
AliasTypeNode
:
"""Create int alias corresponding to the given enum node.
def
create_alias_for_enum_node
(
enum_node
_alias
:
AliasTypeNode
)
->
Conditional
AliasTypeNode
:
"""Create
conditional
int alias corresponding to the given enum node.
Args:
enum_node (ASTNodeTypeNode): Enumeration node to create int alias for.
enum_node (AliasTypeNode): Enumeration node to create conditional
int alias for.
Returns:
AliasTypeNode: int alias node with same export name as enum.
ConditionalAliasTypeNode: conditional int alias node with same
export name as enum.
"""
enum_node
=
enum_node_alias
.
ast_node
assert
enum_node
.
node_type
==
ASTNodeType
.
Enumeration
,
\
f
"
{
enum_node
}
has wrong node type. Expected type: Enumeration."
enum_export_name
,
enum_module_name
=
get_enum_module_and_export_name
(
enum_node
)
enum_full_export_name
=
f
"
{
enum_module_name
}
.
{
enum_export_name
}
"
alias_node
=
AliasTypeNode
.
int_
(
enum_full_export_name
,
enum_export_name
)
type_checking_time_definitions
.
add
(
alias_node
)
return
alias_node
return
ConditionalAliasTypeNode
(
enum_export_name
,
"typing.TYPE_CHECKING"
,
positive_branch_type
=
enum_node_alias
,
negative_branch_type
=
PrimitiveTypeNode
.
int_
(
enum_export_name
),
condition_required_imports
=
(
"import typing"
,
)
)
def
register_alias
(
alias_node
:
AliasTypeNode
)
->
None
:
typename
=
alias_node
.
typename
...
...
@@ -726,11 +736,15 @@ def _generate_typing_module(root: NamespaceNode, output_path: Path) -> None:
continue
if
item
.
ast_node
.
node_type
!=
ASTNodeType
.
Enumeration
:
continue
alias_node
.
value
.
items
[
i
]
=
create_alias_for_enum_node
(
item
.
ast_node
)
enum_node
=
create_alias_for_enum_node
(
item
)
alias_node
.
value
.
items
[
i
]
=
enum_node
conditional_type_nodes
[
enum_node
.
ctype_name
]
=
enum_node
if
isinstance
(
alias_node
.
value
,
ASTNodeTypeNode
)
\
and
alias_node
.
value
.
ast_node
==
ASTNodeType
.
Enumeration
:
alias_node
.
value
=
create_alias_for_enum_node
(
alias_node
.
ast_node
)
enum_node
=
create_alias_for_enum_node
(
alias_node
.
ast_node
)
conditional_type_nodes
[
enum_node
.
ctype_name
]
=
enum_node
return
# Strip module prefix from aliased types
aliases
[
typename
]
=
alias_node
.
value
.
full_typename
.
replace
(
...
...
@@ -744,7 +758,7 @@ def _generate_typing_module(root: NamespaceNode, output_path: Path) -> None:
required_imports
:
Set
[
str
]
=
set
()
aliases
:
Dict
[
str
,
str
]
=
{}
type_checking_time_definitions
:
Set
[
AliasTypeNode
]
=
set
()
conditional_type_nodes
:
Dict
[
str
,
ConditionalAliasTypeNode
]
=
{}
# Resolve each node and register aliases
TypeNode
.
compatible_to_runtime_usage
=
True
...
...
@@ -752,6 +766,12 @@ def _generate_typing_module(root: NamespaceNode, output_path: Path) -> None:
node
.
resolve
(
root
)
if
isinstance
(
node
,
AliasTypeNode
):
register_alias
(
node
)
elif
isinstance
(
node
,
ConditionalAliasTypeNode
):
conditional_type_nodes
[
node
.
ctype_name
]
=
node
for
node
in
conditional_type_nodes
.
values
():
for
required_import
in
node
.
required_definition_imports
:
required_imports
.
add
(
required_import
)
output_stream
=
StringIO
()
output_stream
.
write
(
"__all__ = [
\n
"
)
...
...
@@ -762,12 +782,10 @@ def _generate_typing_module(root: NamespaceNode, output_path: Path) -> None:
_write_required_imports
(
required_imports
,
output_stream
)
# Add type checking time definitions as generated __init__.py content
for
alias
in
type_checking_time_definitions
:
output_stream
.
write
(
"if typing.TYPE_CHECKING:
\n
"
)
output_stream
.
write
(
f
"
{
alias
.
typename
}
=
{
alias
.
ctype_name
}
\n
else:
\n
"
)
output_stream
.
write
(
f
"
{
alias
.
typename
}
=
{
alias
.
value
.
ctype_name
}
\n
"
)
if
type_checking_time_definitions
:
output_stream
.
write
(
"
\n\n
"
)
for
_
,
type_node
in
conditional_type_nodes
.
items
():
output_stream
.
write
(
f
"if
{
type_node
.
condition
}
:
\n
"
)
output_stream
.
write
(
f
"
{
type_node
.
typename
}
=
{
type_node
.
positive_branch_type
.
full_typename
}
\n
else:
\n
"
)
output_stream
.
write
(
f
"
{
type_node
.
typename
}
=
{
type_node
.
negative_branch_type
.
full_typename
}
\n\n\n
"
)
for
alias_name
,
alias_type
in
aliases
.
items
():
output_stream
.
write
(
f
"
{
alias_name
}
=
{
alias_type
}
\n
"
)
...
...
modules/python/src2/typing_stubs_generation/nodes/type_node.py
浏览文件 @
f20edba9
...
...
@@ -307,14 +307,31 @@ class AliasTypeNode(TypeNode):
return
cls
(
ctype_name
,
PrimitiveTypeNode
.
float_
(),
export_name
,
doc
)
@
classmethod
def
array_
(
cls
,
ctype_name
:
str
,
shape
:
Optional
[
Tuple
[
int
,
...]],
dtype
:
Optional
[
str
]
=
None
,
export_name
:
Optional
[
str
]
=
None
,
doc
:
Optional
[
str
]
=
None
):
def
array_ref_
(
cls
,
ctype_name
:
str
,
array_ref_name
:
str
,
shape
:
Optional
[
Tuple
[
int
,
...]],
dtype
:
Optional
[
str
]
=
None
,
export_name
:
Optional
[
str
]
=
None
,
doc
:
Optional
[
str
]
=
None
):
"""Create alias to array reference alias `array_ref_name`.
This is required to preserve backward compatibility with Python < 3.9
and NumPy 1.20, when NumPy module introduces generics support.
Args:
ctype_name (str): Name of the alias.
array_ref_name (str): Name of the conditional array alias.
shape (Optional[Tuple[int, ...]]): Array shape.
dtype (Optional[str], optional): Array type. Defaults to None.
export_name (Optional[str], optional): Alias export name.
Defaults to None.
doc (Optional[str], optional): Documentation string for alias.
Defaults to None.
"""
if
doc
is
None
:
doc
=
"Shape: "
+
str
(
shape
)
doc
=
f
"NDArray(shape=
{
shape
}
, dtype=
{
dtype
}
)"
else
:
doc
+=
". Shape: "
+
str
(
shape
)
return
cls
(
ctype_name
,
NDArrayTypeNode
(
ctype_name
,
shape
,
dtyp
e
),
doc
+=
f
". NDArray(shape=
{
shape
}
, dtype=
{
dtype
}
)"
return
cls
(
ctype_name
,
AliasRefTypeNode
(
array_ref_nam
e
),
export_name
,
doc
)
@
classmethod
...
...
@@ -376,23 +393,111 @@ class AliasTypeNode(TypeNode):
export_name
,
doc
)
class
ConditionalAliasTypeNode
(
TypeNode
):
"""Type node representing an alias protected by condition checked in runtime.
Example:
```python
if numpy.lib.NumpyVersion(numpy.__version__) > "1.20.0" and sys.version_info >= (3, 9)
NumPyArray = numpy.ndarray[typing.Any, numpy.dtype[numpy.generic]]
else:
NumPyArray = numpy.ndarray
```
is defined as follows:
```python
ConditionalAliasTypeNode(
"NumPyArray",
'numpy.lib.NumpyVersion(numpy.__version__) > "1.20.0" and sys.version_info >= (3, 9)',
NDArrayTypeNode("NumPyArray"),
NDArrayTypeNode("NumPyArray", use_numpy_generics=False),
condition_required_imports=("import numpy", "import sys")
)
```
"""
def
__init__
(
self
,
ctype_name
:
str
,
condition
:
str
,
positive_branch_type
:
TypeNode
,
negative_branch_type
:
TypeNode
,
export_name
:
Optional
[
str
]
=
None
,
condition_required_imports
:
Sequence
[
str
]
=
())
->
None
:
super
().
__init__
(
ctype_name
)
self
.
condition
=
condition
self
.
positive_branch_type
=
positive_branch_type
self
.
positive_branch_type
.
ctype_name
=
self
.
ctype_name
self
.
negative_branch_type
=
negative_branch_type
self
.
negative_branch_type
.
ctype_name
=
self
.
ctype_name
self
.
_export_name
=
export_name
self
.
_condition_required_imports
=
condition_required_imports
@
property
def
typename
(
self
)
->
str
:
if
self
.
_export_name
is
not
None
:
return
self
.
_export_name
return
self
.
ctype_name
@
property
def
full_typename
(
self
)
->
str
:
return
"cv2.typing."
+
self
.
typename
@
property
def
required_definition_imports
(
self
)
->
Generator
[
str
,
None
,
None
]:
yield
from
self
.
positive_branch_type
.
required_usage_imports
yield
from
self
.
negative_branch_type
.
required_usage_imports
yield
from
self
.
_condition_required_imports
@
property
def
required_usage_imports
(
self
)
->
Generator
[
str
,
None
,
None
]:
yield
"import cv2.typing"
@
property
def
is_resolved
(
self
)
->
bool
:
return
self
.
positive_branch_type
.
is_resolved
\
and
self
.
negative_branch_type
.
is_resolved
def
resolve
(
self
,
root
:
ASTNode
):
try
:
self
.
positive_branch_type
.
resolve
(
root
)
self
.
negative_branch_type
.
resolve
(
root
)
except
TypeResolutionError
as
e
:
raise
TypeResolutionError
(
'Failed to resolve alias "{}" exposed as "{}"'
.
format
(
self
.
ctype_name
,
self
.
typename
)
)
from
e
@
classmethod
def
numpy_array_
(
cls
,
ctype_name
:
str
,
export_name
:
Optional
[
str
]
=
None
,
shape
:
Optional
[
Tuple
[
int
,
...]]
=
None
,
dtype
:
Optional
[
str
]
=
None
):
return
cls
(
ctype_name
,
(
'numpy.lib.NumpyVersion(numpy.__version__) > "1.20.0" '
'and sys.version_info >= (3, 9)'
),
NDArrayTypeNode
(
ctype_name
,
shape
,
dtype
),
NDArrayTypeNode
(
ctype_name
,
shape
,
dtype
,
use_numpy_generics
=
False
),
condition_required_imports
=
(
"import numpy"
,
"import sys"
)
)
class
NDArrayTypeNode
(
TypeNode
):
"""Type node representing NumPy ndarray.
"""
def
__init__
(
self
,
ctype_name
:
str
,
shape
:
Optional
[
Tuple
[
int
,
...]]
=
None
,
dtype
:
Optional
[
str
]
=
None
)
->
None
:
def
__init__
(
self
,
ctype_name
:
str
,
shape
:
Optional
[
Tuple
[
int
,
...]]
=
None
,
dtype
:
Optional
[
str
]
=
None
,
use_numpy_generics
:
bool
=
True
)
->
None
:
super
().
__init__
(
ctype_name
)
self
.
shape
=
shape
self
.
dtype
=
dtype
self
.
_use_numpy_generics
=
use_numpy_generics
@
property
def
typename
(
self
)
->
str
:
return
"numpy.ndarray[{shape}, numpy.dtype[{dtype}]]"
.
format
(
if
self
.
_use_numpy_generics
:
# NOTE: Shape is not fully supported yet
# shape=self.shape if self.shape is not None else "typing.Any",
shape
=
"typing.Any"
,
dtype
=
self
.
dtype
if
self
.
dtype
is
not
None
else
"numpy.generic"
)
dtype
=
self
.
dtype
if
self
.
dtype
is
not
None
else
"numpy.generic"
return
f
"numpy.ndarray[typing.Any, numpy.dtype[
{
dtype
}
]]"
return
"numpy.ndarray"
@
property
def
required_usage_imports
(
self
)
->
Generator
[
str
,
None
,
None
]:
...
...
modules/python/src2/typing_stubs_generation/predefined_types.py
浏览文件 @
f20edba9
from
.nodes.type_node
import
(
AliasTypeNode
,
AliasRefTypeNode
,
PrimitiveTypeNode
,
ASTNodeTypeNode
,
NDArrayTypeNode
,
NoneTypeNode
,
SequenceTypeNode
,
TupleTypeNode
,
UnionTypeNode
,
AnyTypeNode
TupleTypeNode
,
UnionTypeNode
,
AnyTypeNode
,
ConditionalAliasTypeNode
)
# Set of predefined types used to cover cases when library doesn't
...
...
@@ -30,12 +30,15 @@ _PREDEFINED_TYPES = (
PrimitiveTypeNode
.
str_
(
"char"
),
PrimitiveTypeNode
.
str_
(
"String"
),
PrimitiveTypeNode
.
str_
(
"c_string"
),
ConditionalAliasTypeNode
.
numpy_array_
(
"NumPyArrayGeneric"
),
ConditionalAliasTypeNode
.
numpy_array_
(
"NumPyArrayFloat32"
,
dtype
=
"numpy.float32"
),
ConditionalAliasTypeNode
.
numpy_array_
(
"NumPyArrayFloat64"
,
dtype
=
"numpy.float64"
),
NoneTypeNode
(
"void"
),
AliasTypeNode
.
int_
(
"void*"
,
"IntPointer"
,
"Represents an arbitrary pointer"
),
AliasTypeNode
.
union_
(
"Mat"
,
items
=
(
ASTNodeTypeNode
(
"Mat"
,
module_name
=
"cv2.mat_wrapper"
),
NDArrayTypeNode
(
"Mat
"
)),
AliasRefTypeNode
(
"NumPyArrayGeneric
"
)),
export_name
=
"MatLike"
),
AliasTypeNode
.
sequence_
(
"MatShape"
,
PrimitiveTypeNode
.
int_
()),
...
...
@@ -137,10 +140,22 @@ _PREDEFINED_TYPES = (
ASTNodeTypeNode
(
"gapi.wip.draw.Mosaic"
),
ASTNodeTypeNode
(
"gapi.wip.draw.Poly"
))),
SequenceTypeNode
(
"Prims"
,
AliasRefTypeNode
(
"Prim"
)),
AliasTypeNode
.
array_
(
"Matx33f"
,
(
3
,
3
),
"numpy.float32"
),
AliasTypeNode
.
array_
(
"Matx33d"
,
(
3
,
3
),
"numpy.float64"
),
AliasTypeNode
.
array_
(
"Matx44f"
,
(
4
,
4
),
"numpy.float32"
),
AliasTypeNode
.
array_
(
"Matx44d"
,
(
4
,
4
),
"numpy.float64"
),
AliasTypeNode
.
array_ref_
(
"Matx33f"
,
array_ref_name
=
"NumPyArrayFloat32"
,
shape
=
(
3
,
3
),
dtype
=
"numpy.float32"
),
AliasTypeNode
.
array_ref_
(
"Matx33d"
,
array_ref_name
=
"NumPyArrayFloat64"
,
shape
=
(
3
,
3
),
dtype
=
"numpy.float64"
),
AliasTypeNode
.
array_ref_
(
"Matx44f"
,
array_ref_name
=
"NumPyArrayFloat32"
,
shape
=
(
4
,
4
),
dtype
=
"numpy.float32"
),
AliasTypeNode
.
array_ref_
(
"Matx44d"
,
array_ref_name
=
"NumPyArrayFloat64"
,
shape
=
(
4
,
4
),
dtype
=
"numpy.float64"
),
NDArrayTypeNode
(
"vector<uchar>"
,
dtype
=
"numpy.uint8"
),
NDArrayTypeNode
(
"vector_uchar"
,
dtype
=
"numpy.uint8"
),
TupleTypeNode
(
"GMat2"
,
items
=
(
ASTNodeTypeNode
(
"GMat"
),
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录