Skip to content

Commit 0e18f1c

Browse files
authored
Support type annotations for both List and Table in Python SDK. (#66)
1 parent 794ec2f commit 0e18f1c

File tree

2 files changed

+38
-10
lines changed

2 files changed

+38
-10
lines changed

examples/manual_extraction/manual_extraction.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,21 +38,21 @@ class ArgInfo:
3838
@dataclasses.dataclass
3939
class MethodInfo:
4040
name: str
41-
args: list[ArgInfo]
41+
args: cocoindex.typing.List[ArgInfo]
4242
description: str
4343

4444
@dataclasses.dataclass
4545
class ClassInfo:
4646
name: str
4747
description: str
48-
methods: list[MethodInfo]
48+
methods: cocoindex.typing.List[MethodInfo]
4949

5050
@dataclasses.dataclass
5151
class ManualInfo:
5252
title: str
5353
description: str
54-
classes: list[ClassInfo]
55-
methods: list[MethodInfo]
54+
classes: cocoindex.typing.Table[ClassInfo]
55+
methods: cocoindex.typing.Table[MethodInfo]
5656

5757

5858
class ExtractManual(cocoindex.op.FunctionSpec):

python/cocoindex/typing.py

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import typing
22
import collections
33
import dataclasses
4-
from typing import Annotated, NamedTuple, Any
4+
from typing import Annotated, NamedTuple, Any, TypeVar, TYPE_CHECKING
55

66
class Vector(NamedTuple):
77
dim: int | None
@@ -21,6 +21,28 @@ def __init__(self, key: str, value: Any):
2121
Range = Annotated[tuple[int, int], TypeKind('Range')]
2222
Json = Annotated[Any, TypeKind('Json')]
2323

24+
R = TypeVar("R")
25+
26+
if TYPE_CHECKING:
27+
Table = Annotated[list[R], TypeKind('Table')]
28+
List = Annotated[list[R], TypeKind('List')]
29+
else:
30+
# pylint: disable=too-few-public-methods
31+
class Table: # type: ignore[unreachable]
32+
"""
33+
A Table type, which has a list of rows. The first field of each row is the key.
34+
"""
35+
def __class_getitem__(cls, item: type[R]):
36+
return Annotated[list[item], TypeKind('Table')]
37+
38+
# pylint: disable=too-few-public-methods
39+
class List: # type: ignore[unreachable]
40+
"""
41+
A List type, which has a list of ordered rows.
42+
"""
43+
def __class_getitem__(cls, item: type[R]):
44+
return Annotated[list[item], TypeKind('List')]
45+
2446
def _find_annotation(metadata, cls):
2547
for m in iter(metadata):
2648
if isinstance(m, cls):
@@ -43,6 +65,7 @@ def _dump_fields_schema(cls: type) -> list[dict[str, Any]]:
4365

4466
def _dump_type(t, metadata):
4567
origin_type = typing.get_origin(t)
68+
type_kind = _find_annotation(metadata, TypeKind)
4669
if origin_type is collections.abc.Sequence or origin_type is list:
4770
args = typing.get_args(t)
4871
elem_type, elem_type_metadata = _get_origin_type_and_metadata(args[0])
@@ -54,10 +77,16 @@ def _dump_type(t, metadata):
5477
'dimension': vector_annot.dim,
5578
}
5679
elif dataclasses.is_dataclass(elem_type):
57-
encoded_type = {
58-
'kind': 'List',
59-
'row': { 'fields': _dump_fields_schema(elem_type) },
60-
}
80+
if type_kind is not None and type_kind.kind == 'Table':
81+
encoded_type = {
82+
'kind': 'Table',
83+
'row': { 'fields': _dump_fields_schema(elem_type) },
84+
}
85+
else:
86+
encoded_type = {
87+
'kind': 'List',
88+
'row': { 'fields': _dump_fields_schema(elem_type) },
89+
}
6190
else:
6291
raise ValueError(f"Unsupported type: {t}")
6392
elif dataclasses.is_dataclass(t):
@@ -66,7 +95,6 @@ def _dump_type(t, metadata):
6695
'fields': _dump_fields_schema(t),
6796
}
6897
else:
69-
type_kind = _find_annotation(metadata, TypeKind)
7098
if type_kind is not None:
7199
kind = type_kind.kind
72100
else:

0 commit comments

Comments
 (0)