cocoindex 0.1.43__cp311-cp311-macosx_11_0_arm64.whl → 0.1.45__cp311-cp311-macosx_11_0_arm64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
cocoindex/convert.py CHANGED
@@ -1,35 +1,48 @@
1
1
  """
2
2
  Utilities to convert between Python and engine values.
3
3
  """
4
+
4
5
  import dataclasses
5
6
  import datetime
6
7
  import inspect
7
8
  import uuid
8
9
 
9
10
  from enum import Enum
10
- from typing import Any, Callable, get_origin
11
- from .typing import analyze_type_info, encode_enriched_type, is_namedtuple_type, TABLE_TYPES, KEY_FIELD_NAME
11
+ from typing import Any, Callable, get_origin, Mapping
12
+ from .typing import (
13
+ analyze_type_info,
14
+ encode_enriched_type,
15
+ is_namedtuple_type,
16
+ TABLE_TYPES,
17
+ KEY_FIELD_NAME,
18
+ )
12
19
 
13
20
 
14
21
  def encode_engine_value(value: Any) -> Any:
15
22
  """Encode a Python value to an engine value."""
16
23
  if dataclasses.is_dataclass(value):
17
- return [encode_engine_value(getattr(value, f.name)) for f in dataclasses.fields(value)]
24
+ return [
25
+ encode_engine_value(getattr(value, f.name))
26
+ for f in dataclasses.fields(value)
27
+ ]
18
28
  if is_namedtuple_type(type(value)):
19
29
  return [encode_engine_value(getattr(value, name)) for name in value._fields]
20
30
  if isinstance(value, (list, tuple)):
21
31
  return [encode_engine_value(v) for v in value]
22
32
  if isinstance(value, dict):
23
- return [[encode_engine_value(k)] + encode_engine_value(v) for k, v in value.items()]
33
+ return [
34
+ [encode_engine_value(k)] + encode_engine_value(v) for k, v in value.items()
35
+ ]
24
36
  if isinstance(value, uuid.UUID):
25
37
  return value.bytes
26
38
  return value
27
39
 
40
+
28
41
  def make_engine_value_decoder(
29
- field_path: list[str],
30
- src_type: dict[str, Any],
31
- dst_annotation,
32
- ) -> Callable[[Any], Any]:
42
+ field_path: list[str],
43
+ src_type: dict[str, Any],
44
+ dst_annotation: Any,
45
+ ) -> Callable[[Any], Any]:
33
46
  """
34
47
  Make a decoder from an engine value to a Python value.
35
48
 
@@ -42,12 +55,18 @@ def make_engine_value_decoder(
42
55
  A decoder from an engine value to a Python value.
43
56
  """
44
57
 
45
- src_type_kind = src_type['kind']
58
+ src_type_kind = src_type["kind"]
46
59
 
47
- if dst_annotation is None or dst_annotation is inspect.Parameter.empty or dst_annotation is Any:
48
- if src_type_kind == 'Struct' or src_type_kind in TABLE_TYPES:
49
- raise ValueError(f"Missing type annotation for `{''.join(field_path)}`."
50
- f"It's required for {src_type_kind} type.")
60
+ if (
61
+ dst_annotation is None
62
+ or dst_annotation is inspect.Parameter.empty
63
+ or dst_annotation is Any
64
+ ):
65
+ if src_type_kind == "Struct" or src_type_kind in TABLE_TYPES:
66
+ raise ValueError(
67
+ f"Missing type annotation for `{''.join(field_path)}`."
68
+ f"It's required for {src_type_kind} type."
69
+ )
51
70
  return lambda value: value
52
71
 
53
72
  dst_type_info = analyze_type_info(dst_annotation)
@@ -55,96 +74,118 @@ def make_engine_value_decoder(
55
74
  if src_type_kind != dst_type_info.kind:
56
75
  raise ValueError(
57
76
  f"Type mismatch for `{''.join(field_path)}`: "
58
- f"passed in {src_type_kind}, declared {dst_annotation} ({dst_type_info.kind})")
77
+ f"passed in {src_type_kind}, declared {dst_annotation} ({dst_type_info.kind})"
78
+ )
59
79
 
60
80
  if dst_type_info.struct_type is not None:
61
81
  return _make_engine_struct_value_decoder(
62
- field_path, src_type['fields'], dst_type_info.struct_type)
82
+ field_path, src_type["fields"], dst_type_info.struct_type
83
+ )
63
84
 
64
85
  if src_type_kind in TABLE_TYPES:
65
- field_path.append('[*]')
86
+ field_path.append("[*]")
66
87
  elem_type_info = analyze_type_info(dst_type_info.elem_type)
67
88
  if elem_type_info.struct_type is None:
68
- raise ValueError(f"Type mismatch for `{''.join(field_path)}`: "
69
- f"declared `{dst_type_info.kind}`, a dataclass or NamedTuple type expected")
70
- engine_fields_schema = src_type['row']['fields']
89
+ raise ValueError(
90
+ f"Type mismatch for `{''.join(field_path)}`: "
91
+ f"declared `{dst_type_info.kind}`, a dataclass or NamedTuple type expected"
92
+ )
93
+ engine_fields_schema = src_type["row"]["fields"]
71
94
  if elem_type_info.key_type is not None:
72
95
  key_field_schema = engine_fields_schema[0]
73
96
  field_path.append(f".{key_field_schema.get('name', KEY_FIELD_NAME)}")
74
97
  key_decoder = make_engine_value_decoder(
75
- field_path, key_field_schema['type'], elem_type_info.key_type)
98
+ field_path, key_field_schema["type"], elem_type_info.key_type
99
+ )
76
100
  field_path.pop()
77
101
  value_decoder = _make_engine_struct_value_decoder(
78
- field_path, engine_fields_schema[1:], elem_type_info.struct_type)
79
- def decode(value):
102
+ field_path, engine_fields_schema[1:], elem_type_info.struct_type
103
+ )
104
+
105
+ def decode(value: Any) -> Any | None:
80
106
  if value is None:
81
107
  return None
82
108
  return {key_decoder(v[0]): value_decoder(v[1:]) for v in value}
83
109
  else:
84
110
  elem_decoder = _make_engine_struct_value_decoder(
85
- field_path, engine_fields_schema, elem_type_info.struct_type)
86
- def decode(value):
111
+ field_path, engine_fields_schema, elem_type_info.struct_type
112
+ )
113
+
114
+ def decode(value: Any) -> Any | None:
87
115
  if value is None:
88
116
  return None
89
117
  return [elem_decoder(v) for v in value]
118
+
90
119
  field_path.pop()
91
120
  return decode
92
121
 
93
- if src_type_kind == 'Uuid':
122
+ if src_type_kind == "Uuid":
94
123
  return lambda value: uuid.UUID(bytes=value)
95
124
 
96
125
  return lambda value: value
97
126
 
127
+
98
128
  def _make_engine_struct_value_decoder(
99
- field_path: list[str],
100
- src_fields: list[dict[str, Any]],
101
- dst_struct_type: type,
102
- ) -> Callable[[list], Any]:
129
+ field_path: list[str],
130
+ src_fields: list[dict[str, Any]],
131
+ dst_struct_type: type,
132
+ ) -> Callable[[list[Any]], Any]:
103
133
  """Make a decoder from an engine field values to a Python value."""
104
134
 
105
- src_name_to_idx = {f['name']: i for i, f in enumerate(src_fields)}
106
-
107
- is_dataclass = dataclasses.is_dataclass(dst_struct_type)
108
- is_namedtuple = is_namedtuple_type(dst_struct_type)
109
-
110
- if is_dataclass:
135
+ src_name_to_idx = {f["name"]: i for i, f in enumerate(src_fields)}
136
+
137
+ parameters: Mapping[str, inspect.Parameter]
138
+ if dataclasses.is_dataclass(dst_struct_type):
111
139
  parameters = inspect.signature(dst_struct_type).parameters
112
- elif is_namedtuple:
113
- defaults = getattr(dst_struct_type, '_field_defaults', {})
140
+ elif is_namedtuple_type(dst_struct_type):
141
+ defaults = getattr(dst_struct_type, "_field_defaults", {})
142
+ fields = getattr(dst_struct_type, "_fields", ())
114
143
  parameters = {
115
144
  name: inspect.Parameter(
116
145
  name=name,
117
146
  kind=inspect.Parameter.POSITIONAL_OR_KEYWORD,
118
147
  default=defaults.get(name, inspect.Parameter.empty),
119
- annotation=dst_struct_type.__annotations__.get(name, inspect.Parameter.empty)
148
+ annotation=dst_struct_type.__annotations__.get(
149
+ name, inspect.Parameter.empty
150
+ ),
120
151
  )
121
- for name in dst_struct_type._fields
152
+ for name in fields
122
153
  }
123
154
  else:
124
155
  raise ValueError(f"Unsupported struct type: {dst_struct_type}")
125
156
 
126
- def make_closure_for_value(name: str, param: inspect.Parameter) -> Callable[[list], Any]:
157
+ def make_closure_for_value(
158
+ name: str, param: inspect.Parameter
159
+ ) -> Callable[[list[Any]], Any]:
127
160
  src_idx = src_name_to_idx.get(name)
128
161
  if src_idx is not None:
129
- field_path.append(f'.{name}')
162
+ field_path.append(f".{name}")
130
163
  field_decoder = make_engine_value_decoder(
131
- field_path, src_fields[src_idx]['type'], param.annotation)
164
+ field_path, src_fields[src_idx]["type"], param.annotation
165
+ )
132
166
  field_path.pop()
133
- return lambda values: field_decoder(values[src_idx]) if len(values) > src_idx else param.default
167
+ return (
168
+ lambda values: field_decoder(values[src_idx])
169
+ if len(values) > src_idx
170
+ else param.default
171
+ )
134
172
 
135
173
  default_value = param.default
136
174
  if default_value is inspect.Parameter.empty:
137
175
  raise ValueError(
138
- f"Field without default value is missing in input: {''.join(field_path)}")
176
+ f"Field without default value is missing in input: {''.join(field_path)}"
177
+ )
139
178
 
140
179
  return lambda _: default_value
141
180
 
142
181
  field_value_decoder = [
143
- make_closure_for_value(name, param)
144
- for (name, param) in parameters.items()]
182
+ make_closure_for_value(name, param) for (name, param) in parameters.items()
183
+ ]
145
184
 
146
185
  return lambda values: dst_struct_type(
147
- *(decoder(values) for decoder in field_value_decoder))
186
+ *(decoder(values) for decoder in field_value_decoder)
187
+ )
188
+
148
189
 
149
190
  def dump_engine_object(v: Any) -> Any:
150
191
  """Recursively dump an object for engine. Engine side uses `Pythonized` to catch."""
@@ -158,14 +199,14 @@ def dump_engine_object(v: Any) -> Any:
158
199
  total_secs = v.total_seconds()
159
200
  secs = int(total_secs)
160
201
  nanos = int((total_secs - secs) * 1e9)
161
- return {'secs': secs, 'nanos': nanos}
162
- elif hasattr(v, '__dict__'):
202
+ return {"secs": secs, "nanos": nanos}
203
+ elif hasattr(v, "__dict__"):
163
204
  s = {k: dump_engine_object(v) for k, v in v.__dict__.items()}
164
- if hasattr(v, 'kind') and 'kind' not in s:
165
- s['kind'] = v.kind
205
+ if hasattr(v, "kind") and "kind" not in s:
206
+ s["kind"] = v.kind
166
207
  return s
167
208
  elif isinstance(v, (list, tuple)):
168
209
  return [dump_engine_object(item) for item in v]
169
210
  elif isinstance(v, dict):
170
211
  return {k: dump_engine_object(v) for k, v in v.items()}
171
- return v
212
+ return v