indexify 0.3.4__py3-none-any.whl → 0.3.5__py3-none-any.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.
indexify/cli/cli.py CHANGED
@@ -219,12 +219,13 @@ def executor(
219
219
  )
220
220
 
221
221
  id = nanoid.generate()
222
+ executor_version = version("indexify")
222
223
  logger.info(
223
224
  "starting executor",
224
225
  server_addr=server_addr,
225
226
  config_path=config_path,
226
227
  executor_id=id,
227
- executor_version=version("indexify"),
228
+ executor_version=executor_version,
228
229
  executor_cache=executor_cache,
229
230
  ports=ports,
230
231
  functions=function_uris,
@@ -247,7 +248,8 @@ def executor(
247
248
  exit(1)
248
249
 
249
250
  Executor(
250
- id,
251
+ id=id,
252
+ version=executor_version,
251
253
  server_addr=server_addr,
252
254
  config_path=config_path,
253
255
  code_path=executor_cache,
@@ -21,7 +21,8 @@ from .task_runner import TaskInput, TaskOutput, TaskRunner
21
21
  class Executor:
22
22
  def __init__(
23
23
  self,
24
- executor_id: str,
24
+ id: str,
25
+ version: str,
25
26
  code_path: Path,
26
27
  function_allowlist: Optional[List[FunctionURI]],
27
28
  function_executor_server_factory: FunctionExecutorServerFactory,
@@ -48,15 +49,16 @@ class Executor:
48
49
  code_path=code_path, base_url=self._base_url, config_path=config_path
49
50
  )
50
51
  self._task_fetcher = TaskFetcher(
52
+ executor_id=id,
53
+ executor_version=version,
54
+ function_allowlist=function_allowlist,
51
55
  protocol=protocol,
52
56
  indexify_server_addr=self._server_addr,
53
- executor_id=executor_id,
54
- function_allowlist=function_allowlist,
55
57
  config_path=config_path,
56
58
  )
57
59
  self._task_reporter = TaskReporter(
58
60
  base_url=self._base_url,
59
- executor_id=executor_id,
61
+ executor_id=id,
60
62
  config_path=self._config_path,
61
63
  )
62
64
 
@@ -4,7 +4,6 @@ from typing import Any, Optional
4
4
 
5
5
  from grpc.aio import AioRpcError
6
6
 
7
- from indexify.function_executor.proto.configuration import HEALTH_CHECK_TIMEOUT_SEC
8
7
  from indexify.function_executor.proto.function_executor_pb2 import (
9
8
  HealthCheckRequest,
10
9
  HealthCheckResponse,
@@ -13,6 +12,8 @@ from indexify.function_executor.proto.function_executor_pb2_grpc import (
13
12
  FunctionExecutorStub,
14
13
  )
15
14
 
15
+ from .server.client_configuration import HEALTH_CHECK_TIMEOUT_SEC
16
+
16
17
  HEALTH_CHECK_POLL_PERIOD_SEC = 10
17
18
 
18
19
 
@@ -0,0 +1,20 @@
1
+ # We send function inputs and outputs over gRPC.
2
+ # -1 means unlimited. We don't want to limit the size of data customers are using.
3
+ # The effective max message size in this case is about 1.9 GB, see the max payload test.
4
+ # This is due to internal hard gRPC limits. When we want to increase the message sizes
5
+ # we'll have to implement chunking for large messages.
6
+ _MAX_GRPC_MESSAGE_LENGTH = -1
7
+
8
+ # Optimize the channels for low latency connection establishement as we are running on the same host.
9
+ _RECONNECT_BACKOFF_MS = 100
10
+
11
+ GRPC_CHANNEL_OPTIONS = [
12
+ ("grpc.max_receive_message_length", _MAX_GRPC_MESSAGE_LENGTH),
13
+ ("grpc.max_send_message_length", _MAX_GRPC_MESSAGE_LENGTH),
14
+ ("grpc.min_reconnect_backoff_ms", _RECONNECT_BACKOFF_MS),
15
+ ("grpc.max_reconnect_backoff_ms", _RECONNECT_BACKOFF_MS),
16
+ ("grpc.initial_reconnect_backoff_ms", _RECONNECT_BACKOFF_MS),
17
+ ]
18
+
19
+ # If a health check takes more than this duration then the server is considered unhealthy.
20
+ HEALTH_CHECK_TIMEOUT_SEC = 5
@@ -3,8 +3,7 @@ from typing import Any
3
3
 
4
4
  import grpc
5
5
 
6
- from indexify.function_executor.proto.configuration import GRPC_CHANNEL_OPTIONS
7
-
6
+ from .client_configuration import GRPC_CHANNEL_OPTIONS
8
7
  from .function_executor_server import FunctionExecutorServer
9
8
 
10
9
 
@@ -22,11 +22,6 @@ class SubprocessFunctionExecutorServerFactory(FunctionExecutorServerFactory):
22
22
  async def create(
23
23
  self, config: FunctionExecutorServerConfiguration, logger: Any
24
24
  ) -> SubprocessFunctionExecutorServer:
25
- if config.image_uri is not None:
26
- raise ValueError(
27
- "SubprocessFunctionExecutorServerFactory doesn't support container images"
28
- )
29
-
30
25
  logger = logger.bind(module=__name__)
31
26
  port: Optional[int] = None
32
27
 
@@ -16,10 +16,11 @@ class TaskFetcher:
16
16
 
17
17
  def __init__(
18
18
  self,
19
- protocol: str,
20
- indexify_server_addr: str,
21
19
  executor_id: str,
20
+ executor_version: str,
22
21
  function_allowlist: Optional[List[FunctionURI]],
22
+ protocol: str,
23
+ indexify_server_addr: str,
23
24
  config_path: Optional[str] = None,
24
25
  ):
25
26
  self._protocol: str = protocol
@@ -30,7 +31,7 @@ class TaskFetcher:
30
31
  probe_info: ProbeInfo = RuntimeProbes().probe()
31
32
  self._executor_metadata: ExecutorMetadata = ExecutorMetadata(
32
33
  id=executor_id,
33
- executor_version=version("indexify"),
34
+ executor_version=executor_version,
34
35
  addr="",
35
36
  function_allowlist=function_allowlist,
36
37
  labels=probe_info.labels,
@@ -2,13 +2,12 @@ import io
2
2
  import sys
3
3
  import traceback
4
4
  from contextlib import redirect_stderr, redirect_stdout
5
- from typing import Any, Union
5
+ from typing import Any
6
6
 
7
7
  from tensorlake.functions_sdk.functions import (
8
8
  FunctionCallResult,
9
9
  GraphInvocationContext,
10
10
  RouterCallResult,
11
- TensorlakeCompute,
12
11
  TensorlakeFunctionWrapper,
13
12
  TensorlakeRouter,
14
13
  )
@@ -26,15 +25,20 @@ class Handler:
26
25
  graph_name: str,
27
26
  graph_version: str,
28
27
  function_name: str,
29
- function: Union[TensorlakeCompute, TensorlakeCompute],
30
28
  invocation_state: InvocationState,
29
+ function_wrapper: TensorlakeFunctionWrapper,
31
30
  logger: Any,
32
31
  ):
32
+ self._invocation_id: str = request.graph_invocation_id
33
+ self._graph_name: str = graph_name
34
+ self._graph_version: str = graph_version
33
35
  self._function_name: str = function_name
36
+ self._invocation_state: InvocationState = invocation_state
34
37
  self._logger = logger.bind(
35
38
  graph_invocation_id=request.graph_invocation_id,
36
39
  task_id=request.task_id,
37
40
  )
41
+ self._function_wrapper = function_wrapper
38
42
  self._input_loader = FunctionInputsLoader(request)
39
43
  self._response_helper = ResponseHelper(task_id=request.task_id)
40
44
  # TODO: use files for stdout, stderr capturing. This puts a natural and thus reasonable
@@ -42,16 +46,6 @@ class Handler:
42
46
  self._func_stdout: io.StringIO = io.StringIO()
43
47
  self._func_stderr: io.StringIO = io.StringIO()
44
48
 
45
- self._function_wrapper: TensorlakeFunctionWrapper = TensorlakeFunctionWrapper(
46
- indexify_function=function,
47
- context=GraphInvocationContext(
48
- invocation_id=request.graph_invocation_id,
49
- graph_name=graph_name,
50
- graph_version=graph_version,
51
- invocation_state=invocation_state,
52
- ),
53
- )
54
-
55
49
  def run(self) -> RunTaskResponse:
56
50
  """Runs the task.
57
51
 
@@ -81,9 +75,15 @@ class Handler:
81
75
  )
82
76
 
83
77
  def _run_func(self, inputs: FunctionInputs) -> RunTaskResponse:
78
+ ctx: GraphInvocationContext = GraphInvocationContext(
79
+ invocation_id=self._invocation_id,
80
+ graph_name=self._graph_name,
81
+ graph_version=self._graph_version,
82
+ invocation_state=self._invocation_state,
83
+ )
84
84
  if _is_router(self._function_wrapper):
85
85
  result: RouterCallResult = self._function_wrapper.invoke_router(
86
- self._function_name, inputs.input
86
+ ctx, self._function_name, inputs.input
87
87
  )
88
88
  return self._response_helper.router_response(
89
89
  result=result,
@@ -92,11 +92,11 @@ class Handler:
92
92
  )
93
93
  else:
94
94
  result: FunctionCallResult = self._function_wrapper.invoke_fn_ser(
95
- self._function_name, inputs.input, inputs.init_value
95
+ ctx, self._function_name, inputs.input, inputs.init_value
96
96
  )
97
97
  return self._response_helper.function_response(
98
98
  result=result,
99
- is_reducer=_func_is_reducer(self._function_wrapper),
99
+ is_reducer=_function_is_reducer(self._function_wrapper),
100
100
  stdout=self._func_stdout.getvalue(),
101
101
  stderr=self._func_stderr.getvalue(),
102
102
  )
@@ -122,5 +122,5 @@ def _is_router(func_wrapper: TensorlakeFunctionWrapper) -> bool:
122
122
  )
123
123
 
124
124
 
125
- def _func_is_reducer(func_wrapper: TensorlakeFunctionWrapper) -> bool:
125
+ def _function_is_reducer(func_wrapper: TensorlakeFunctionWrapper) -> bool:
126
126
  return func_wrapper.indexify_function.accumulate is not None
@@ -0,0 +1,16 @@
1
+ import importlib.metadata
2
+ import sys
3
+ from typing import Any, Dict
4
+
5
+
6
+ def info_response_kv_args() -> Dict[str, Any]:
7
+ sdk_version = importlib.metadata.version("tensorlake")
8
+ python_version = (
9
+ f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}"
10
+ )
11
+ return {
12
+ "version": "0.1.0",
13
+ "sdk_version": sdk_version,
14
+ "sdk_language": "python",
15
+ "sdk_language_version": python_version,
16
+ }
@@ -10,10 +10,11 @@ import argparse
10
10
 
11
11
  import structlog
12
12
 
13
+ from .info import info_response_kv_args
13
14
  from .server import Server
14
15
  from .service import Service
15
16
 
16
- logger = structlog.get_logger(module=__name__)
17
+ logger = structlog.get_logger(module=__name__).bind(**info_response_kv_args())
17
18
 
18
19
 
19
20
  def validate_args(args):
@@ -112,6 +112,22 @@ message HealthCheckResponse {
112
112
  optional bool healthy = 1;
113
113
  }
114
114
 
115
+ message InfoRequest {}
116
+
117
+ message InfoResponse {
118
+ // Internal version of this Function Executor.
119
+ // Semantic versioning schema is used with format 0.0.0.
120
+ // Used to support migrations.
121
+ optional string version = 1;
122
+ // The version of the SDK used in this Function Executor to run customer code.
123
+ optional string sdk_version = 2;
124
+ // The language of the SDK. Currently supported values:
125
+ // - "python"
126
+ optional string sdk_language = 3;
127
+ // The version of the SDK language. The language's versioning format is used.
128
+ optional string sdk_language_version = 4;
129
+ }
130
+
115
131
  service FunctionExecutor {
116
132
  // Initializes the Function Executor to run tasks
117
133
  // for a particular function. This method is called only
@@ -127,4 +143,6 @@ service FunctionExecutor {
127
143
  rpc run_task(RunTaskRequest) returns (RunTaskResponse);
128
144
  // Health check method to check if the Function Executor is healthy.
129
145
  rpc check_health(HealthCheckRequest) returns (HealthCheckResponse);
146
+ // Information about this Function Executor.
147
+ rpc get_info(InfoRequest) returns (InfoResponse);
130
148
  }
@@ -24,7 +24,7 @@ _sym_db = _symbol_database.Default()
24
24
 
25
25
 
26
26
  DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(
27
- b'\n8indexify/function_executor/proto/function_executor.proto\x12\x19\x66unction_executor_service"i\n\x10SerializedObject\x12\x0f\n\x05\x62ytes\x18\x01 \x01(\x0cH\x00\x12\x10\n\x06string\x18\x02 \x01(\tH\x00\x12\x19\n\x0c\x63ontent_type\x18\x03 \x01(\tH\x01\x88\x01\x01\x42\x06\n\x04\x64\x61taB\x0f\n\r_content_type"\x88\x02\n\x11InitializeRequest\x12\x16\n\tnamespace\x18\x01 \x01(\tH\x00\x88\x01\x01\x12\x17\n\ngraph_name\x18\x02 \x01(\tH\x01\x88\x01\x01\x12\x1a\n\rgraph_version\x18\x03 \x01(\tH\x02\x88\x01\x01\x12\x1a\n\rfunction_name\x18\x05 \x01(\tH\x03\x88\x01\x01\x12?\n\x05graph\x18\x07 \x01(\x0b\x32+.function_executor_service.SerializedObjectH\x04\x88\x01\x01\x42\x0c\n\n_namespaceB\r\n\x0b_graph_nameB\x10\n\x0e_graph_versionB\x10\n\x0e_function_nameB\x08\n\x06_graph"f\n\x12InitializeResponse\x12\x14\n\x07success\x18\x01 \x01(\x08H\x00\x88\x01\x01\x12\x1b\n\x0e\x63ustomer_error\x18\x02 \x01(\tH\x01\x88\x01\x01\x42\n\n\x08_successB\x11\n\x0f_customer_error"\x80\x01\n\x19SetInvocationStateRequest\x12\x10\n\x03key\x18\x01 \x01(\tH\x00\x88\x01\x01\x12?\n\x05value\x18\x02 \x01(\x0b\x32+.function_executor_service.SerializedObjectH\x01\x88\x01\x01\x42\x06\n\x04_keyB\x08\n\x06_value"\x1c\n\x1aSetInvocationStateResponse"5\n\x19GetInvocationStateRequest\x12\x10\n\x03key\x18\x01 \x01(\tH\x00\x88\x01\x01\x42\x06\n\x04_key"\x81\x01\n\x1aGetInvocationStateResponse\x12\x10\n\x03key\x18\x01 \x01(\tH\x00\x88\x01\x01\x12?\n\x05value\x18\x02 \x01(\x0b\x32+.function_executor_service.SerializedObjectH\x01\x88\x01\x01\x42\x06\n\x04_keyB\x08\n\x06_value"\xf7\x01\n\x16InvocationStateRequest\x12\x17\n\nrequest_id\x18\x01 \x01(\tH\x01\x88\x01\x01\x12\x14\n\x07task_id\x18\x02 \x01(\tH\x02\x88\x01\x01\x12\x43\n\x03set\x18\x03 \x01(\x0b\x32\x34.function_executor_service.SetInvocationStateRequestH\x00\x12\x43\n\x03get\x18\x04 \x01(\x0b\x32\x34.function_executor_service.GetInvocationStateRequestH\x00\x42\t\n\x07requestB\r\n\x0b_request_idB\n\n\x08_task_id"\xfb\x01\n\x17InvocationStateResponse\x12\x17\n\nrequest_id\x18\x01 \x01(\tH\x01\x88\x01\x01\x12\x14\n\x07success\x18\x02 \x01(\x08H\x02\x88\x01\x01\x12\x44\n\x03set\x18\x03 \x01(\x0b\x32\x35.function_executor_service.SetInvocationStateResponseH\x00\x12\x44\n\x03get\x18\x04 \x01(\x0b\x32\x35.function_executor_service.GetInvocationStateResponseH\x00\x42\n\n\x08responseB\r\n\x0b_request_idB\n\n\x08_success"N\n\x0e\x46unctionOutput\x12<\n\x07outputs\x18\x01 \x03(\x0b\x32+.function_executor_service.SerializedObject"\x1d\n\x0cRouterOutput\x12\r\n\x05\x65\x64ges\x18\x01 \x03(\t"\xda\x03\n\x0eRunTaskRequest\x12\x16\n\tnamespace\x18\x01 \x01(\tH\x00\x88\x01\x01\x12\x17\n\ngraph_name\x18\x02 \x01(\tH\x01\x88\x01\x01\x12\x1a\n\rgraph_version\x18\x03 \x01(\tH\x02\x88\x01\x01\x12\x1a\n\rfunction_name\x18\x04 \x01(\tH\x03\x88\x01\x01\x12 \n\x13graph_invocation_id\x18\x05 \x01(\tH\x04\x88\x01\x01\x12\x14\n\x07task_id\x18\x06 \x01(\tH\x05\x88\x01\x01\x12H\n\x0e\x66unction_input\x18\x07 \x01(\x0b\x32+.function_executor_service.SerializedObjectH\x06\x88\x01\x01\x12M\n\x13\x66unction_init_value\x18\x08 \x01(\x0b\x32+.function_executor_service.SerializedObjectH\x07\x88\x01\x01\x42\x0c\n\n_namespaceB\r\n\x0b_graph_nameB\x10\n\x0e_graph_versionB\x10\n\x0e_function_nameB\x16\n\x14_graph_invocation_idB\n\n\x08_task_idB\x11\n\x0f_function_inputB\x16\n\x14_function_init_value"\xf1\x02\n\x0fRunTaskResponse\x12\x14\n\x07task_id\x18\x01 \x01(\tH\x00\x88\x01\x01\x12G\n\x0f\x66unction_output\x18\x02 \x01(\x0b\x32).function_executor_service.FunctionOutputH\x01\x88\x01\x01\x12\x43\n\rrouter_output\x18\x03 \x01(\x0b\x32\'.function_executor_service.RouterOutputH\x02\x88\x01\x01\x12\x13\n\x06stdout\x18\x04 \x01(\tH\x03\x88\x01\x01\x12\x13\n\x06stderr\x18\x05 \x01(\tH\x04\x88\x01\x01\x12\x17\n\nis_reducer\x18\x06 \x01(\x08H\x05\x88\x01\x01\x12\x14\n\x07success\x18\x07 \x01(\x08H\x06\x88\x01\x01\x42\n\n\x08_task_idB\x12\n\x10_function_outputB\x10\n\x0e_router_outputB\t\n\x07_stdoutB\t\n\x07_stderrB\r\n\x0b_is_reducerB\n\n\x08_success"\x14\n\x12HealthCheckRequest"7\n\x13HealthCheckResponse\x12\x14\n\x07healthy\x18\x01 \x01(\x08H\x00\x88\x01\x01\x42\n\n\x08_healthy2\xe1\x03\n\x10\x46unctionExecutor\x12i\n\ninitialize\x12,.function_executor_service.InitializeRequest\x1a-.function_executor_service.InitializeResponse\x12\x8f\x01\n"initialize_invocation_state_server\x12\x32.function_executor_service.InvocationStateResponse\x1a\x31.function_executor_service.InvocationStateRequest(\x01\x30\x01\x12\x61\n\x08run_task\x12).function_executor_service.RunTaskRequest\x1a*.function_executor_service.RunTaskResponse\x12m\n\x0c\x63heck_health\x12-.function_executor_service.HealthCheckRequest\x1a..function_executor_service.HealthCheckResponseb\x06proto3'
27
+ b'\n8indexify/function_executor/proto/function_executor.proto\x12\x19\x66unction_executor_service"i\n\x10SerializedObject\x12\x0f\n\x05\x62ytes\x18\x01 \x01(\x0cH\x00\x12\x10\n\x06string\x18\x02 \x01(\tH\x00\x12\x19\n\x0c\x63ontent_type\x18\x03 \x01(\tH\x01\x88\x01\x01\x42\x06\n\x04\x64\x61taB\x0f\n\r_content_type"\x88\x02\n\x11InitializeRequest\x12\x16\n\tnamespace\x18\x01 \x01(\tH\x00\x88\x01\x01\x12\x17\n\ngraph_name\x18\x02 \x01(\tH\x01\x88\x01\x01\x12\x1a\n\rgraph_version\x18\x03 \x01(\tH\x02\x88\x01\x01\x12\x1a\n\rfunction_name\x18\x05 \x01(\tH\x03\x88\x01\x01\x12?\n\x05graph\x18\x07 \x01(\x0b\x32+.function_executor_service.SerializedObjectH\x04\x88\x01\x01\x42\x0c\n\n_namespaceB\r\n\x0b_graph_nameB\x10\n\x0e_graph_versionB\x10\n\x0e_function_nameB\x08\n\x06_graph"f\n\x12InitializeResponse\x12\x14\n\x07success\x18\x01 \x01(\x08H\x00\x88\x01\x01\x12\x1b\n\x0e\x63ustomer_error\x18\x02 \x01(\tH\x01\x88\x01\x01\x42\n\n\x08_successB\x11\n\x0f_customer_error"\x80\x01\n\x19SetInvocationStateRequest\x12\x10\n\x03key\x18\x01 \x01(\tH\x00\x88\x01\x01\x12?\n\x05value\x18\x02 \x01(\x0b\x32+.function_executor_service.SerializedObjectH\x01\x88\x01\x01\x42\x06\n\x04_keyB\x08\n\x06_value"\x1c\n\x1aSetInvocationStateResponse"5\n\x19GetInvocationStateRequest\x12\x10\n\x03key\x18\x01 \x01(\tH\x00\x88\x01\x01\x42\x06\n\x04_key"\x81\x01\n\x1aGetInvocationStateResponse\x12\x10\n\x03key\x18\x01 \x01(\tH\x00\x88\x01\x01\x12?\n\x05value\x18\x02 \x01(\x0b\x32+.function_executor_service.SerializedObjectH\x01\x88\x01\x01\x42\x06\n\x04_keyB\x08\n\x06_value"\xf7\x01\n\x16InvocationStateRequest\x12\x17\n\nrequest_id\x18\x01 \x01(\tH\x01\x88\x01\x01\x12\x14\n\x07task_id\x18\x02 \x01(\tH\x02\x88\x01\x01\x12\x43\n\x03set\x18\x03 \x01(\x0b\x32\x34.function_executor_service.SetInvocationStateRequestH\x00\x12\x43\n\x03get\x18\x04 \x01(\x0b\x32\x34.function_executor_service.GetInvocationStateRequestH\x00\x42\t\n\x07requestB\r\n\x0b_request_idB\n\n\x08_task_id"\xfb\x01\n\x17InvocationStateResponse\x12\x17\n\nrequest_id\x18\x01 \x01(\tH\x01\x88\x01\x01\x12\x14\n\x07success\x18\x02 \x01(\x08H\x02\x88\x01\x01\x12\x44\n\x03set\x18\x03 \x01(\x0b\x32\x35.function_executor_service.SetInvocationStateResponseH\x00\x12\x44\n\x03get\x18\x04 \x01(\x0b\x32\x35.function_executor_service.GetInvocationStateResponseH\x00\x42\n\n\x08responseB\r\n\x0b_request_idB\n\n\x08_success"N\n\x0e\x46unctionOutput\x12<\n\x07outputs\x18\x01 \x03(\x0b\x32+.function_executor_service.SerializedObject"\x1d\n\x0cRouterOutput\x12\r\n\x05\x65\x64ges\x18\x01 \x03(\t"\xda\x03\n\x0eRunTaskRequest\x12\x16\n\tnamespace\x18\x01 \x01(\tH\x00\x88\x01\x01\x12\x17\n\ngraph_name\x18\x02 \x01(\tH\x01\x88\x01\x01\x12\x1a\n\rgraph_version\x18\x03 \x01(\tH\x02\x88\x01\x01\x12\x1a\n\rfunction_name\x18\x04 \x01(\tH\x03\x88\x01\x01\x12 \n\x13graph_invocation_id\x18\x05 \x01(\tH\x04\x88\x01\x01\x12\x14\n\x07task_id\x18\x06 \x01(\tH\x05\x88\x01\x01\x12H\n\x0e\x66unction_input\x18\x07 \x01(\x0b\x32+.function_executor_service.SerializedObjectH\x06\x88\x01\x01\x12M\n\x13\x66unction_init_value\x18\x08 \x01(\x0b\x32+.function_executor_service.SerializedObjectH\x07\x88\x01\x01\x42\x0c\n\n_namespaceB\r\n\x0b_graph_nameB\x10\n\x0e_graph_versionB\x10\n\x0e_function_nameB\x16\n\x14_graph_invocation_idB\n\n\x08_task_idB\x11\n\x0f_function_inputB\x16\n\x14_function_init_value"\xf1\x02\n\x0fRunTaskResponse\x12\x14\n\x07task_id\x18\x01 \x01(\tH\x00\x88\x01\x01\x12G\n\x0f\x66unction_output\x18\x02 \x01(\x0b\x32).function_executor_service.FunctionOutputH\x01\x88\x01\x01\x12\x43\n\rrouter_output\x18\x03 \x01(\x0b\x32\'.function_executor_service.RouterOutputH\x02\x88\x01\x01\x12\x13\n\x06stdout\x18\x04 \x01(\tH\x03\x88\x01\x01\x12\x13\n\x06stderr\x18\x05 \x01(\tH\x04\x88\x01\x01\x12\x17\n\nis_reducer\x18\x06 \x01(\x08H\x05\x88\x01\x01\x12\x14\n\x07success\x18\x07 \x01(\x08H\x06\x88\x01\x01\x42\n\n\x08_task_idB\x12\n\x10_function_outputB\x10\n\x0e_router_outputB\t\n\x07_stdoutB\t\n\x07_stderrB\r\n\x0b_is_reducerB\n\n\x08_success"\x14\n\x12HealthCheckRequest"7\n\x13HealthCheckResponse\x12\x14\n\x07healthy\x18\x01 \x01(\x08H\x00\x88\x01\x01\x42\n\n\x08_healthy"\r\n\x0bInfoRequest"\xc2\x01\n\x0cInfoResponse\x12\x14\n\x07version\x18\x01 \x01(\tH\x00\x88\x01\x01\x12\x18\n\x0bsdk_version\x18\x02 \x01(\tH\x01\x88\x01\x01\x12\x19\n\x0csdk_language\x18\x03 \x01(\tH\x02\x88\x01\x01\x12!\n\x14sdk_language_version\x18\x04 \x01(\tH\x03\x88\x01\x01\x42\n\n\x08_versionB\x0e\n\x0c_sdk_versionB\x0f\n\r_sdk_languageB\x17\n\x15_sdk_language_version2\xbe\x04\n\x10\x46unctionExecutor\x12i\n\ninitialize\x12,.function_executor_service.InitializeRequest\x1a-.function_executor_service.InitializeResponse\x12\x8f\x01\n"initialize_invocation_state_server\x12\x32.function_executor_service.InvocationStateResponse\x1a\x31.function_executor_service.InvocationStateRequest(\x01\x30\x01\x12\x61\n\x08run_task\x12).function_executor_service.RunTaskRequest\x1a*.function_executor_service.RunTaskResponse\x12m\n\x0c\x63heck_health\x12-.function_executor_service.HealthCheckRequest\x1a..function_executor_service.HealthCheckResponse\x12[\n\x08get_info\x12&.function_executor_service.InfoRequest\x1a\'.function_executor_service.InfoResponseb\x06proto3'
28
28
  )
29
29
 
30
30
  _globals = globals()
@@ -64,6 +64,10 @@ if not _descriptor._USE_C_DESCRIPTORS:
64
64
  _globals["_HEALTHCHECKREQUEST"]._serialized_end = 2397
65
65
  _globals["_HEALTHCHECKRESPONSE"]._serialized_start = 2399
66
66
  _globals["_HEALTHCHECKRESPONSE"]._serialized_end = 2454
67
- _globals["_FUNCTIONEXECUTOR"]._serialized_start = 2457
68
- _globals["_FUNCTIONEXECUTOR"]._serialized_end = 2938
67
+ _globals["_INFOREQUEST"]._serialized_start = 2456
68
+ _globals["_INFOREQUEST"]._serialized_end = 2469
69
+ _globals["_INFORESPONSE"]._serialized_start = 2472
70
+ _globals["_INFORESPONSE"]._serialized_end = 2666
71
+ _globals["_FUNCTIONEXECUTOR"]._serialized_start = 2669
72
+ _globals["_FUNCTIONEXECUTOR"]._serialized_end = 3243
69
73
  # @@protoc_insertion_point(module_scope)
@@ -223,3 +223,25 @@ class HealthCheckResponse(_message.Message):
223
223
  HEALTHY_FIELD_NUMBER: _ClassVar[int]
224
224
  healthy: bool
225
225
  def __init__(self, healthy: bool = ...) -> None: ...
226
+
227
+ class InfoRequest(_message.Message):
228
+ __slots__ = ()
229
+ def __init__(self) -> None: ...
230
+
231
+ class InfoResponse(_message.Message):
232
+ __slots__ = ("version", "sdk_version", "sdk_language", "sdk_language_version")
233
+ VERSION_FIELD_NUMBER: _ClassVar[int]
234
+ SDK_VERSION_FIELD_NUMBER: _ClassVar[int]
235
+ SDK_LANGUAGE_FIELD_NUMBER: _ClassVar[int]
236
+ SDK_LANGUAGE_VERSION_FIELD_NUMBER: _ClassVar[int]
237
+ version: str
238
+ sdk_version: str
239
+ sdk_language: str
240
+ sdk_language_version: str
241
+ def __init__(
242
+ self,
243
+ version: _Optional[str] = ...,
244
+ sdk_version: _Optional[str] = ...,
245
+ sdk_language: _Optional[str] = ...,
246
+ sdk_language_version: _Optional[str] = ...,
247
+ ) -> None: ...
@@ -64,6 +64,12 @@ class FunctionExecutorStub(object):
64
64
  response_deserializer=indexify_dot_function__executor_dot_proto_dot_function__executor__pb2.HealthCheckResponse.FromString,
65
65
  _registered_method=True,
66
66
  )
67
+ self.get_info = channel.unary_unary(
68
+ "/function_executor_service.FunctionExecutor/get_info",
69
+ request_serializer=indexify_dot_function__executor_dot_proto_dot_function__executor__pb2.InfoRequest.SerializeToString,
70
+ response_deserializer=indexify_dot_function__executor_dot_proto_dot_function__executor__pb2.InfoResponse.FromString,
71
+ _registered_method=True,
72
+ )
67
73
 
68
74
 
69
75
  class FunctionExecutorServicer(object):
@@ -102,6 +108,12 @@ class FunctionExecutorServicer(object):
102
108
  context.set_details("Method not implemented!")
103
109
  raise NotImplementedError("Method not implemented!")
104
110
 
111
+ def get_info(self, request, context):
112
+ """Information about this Function Executor."""
113
+ context.set_code(grpc.StatusCode.UNIMPLEMENTED)
114
+ context.set_details("Method not implemented!")
115
+ raise NotImplementedError("Method not implemented!")
116
+
105
117
 
106
118
  def add_FunctionExecutorServicer_to_server(servicer, server):
107
119
  rpc_method_handlers = {
@@ -125,6 +137,11 @@ def add_FunctionExecutorServicer_to_server(servicer, server):
125
137
  request_deserializer=indexify_dot_function__executor_dot_proto_dot_function__executor__pb2.HealthCheckRequest.FromString,
126
138
  response_serializer=indexify_dot_function__executor_dot_proto_dot_function__executor__pb2.HealthCheckResponse.SerializeToString,
127
139
  ),
140
+ "get_info": grpc.unary_unary_rpc_method_handler(
141
+ servicer.get_info,
142
+ request_deserializer=indexify_dot_function__executor_dot_proto_dot_function__executor__pb2.InfoRequest.FromString,
143
+ response_serializer=indexify_dot_function__executor_dot_proto_dot_function__executor__pb2.InfoResponse.SerializeToString,
144
+ ),
128
145
  }
129
146
  generic_handler = grpc.method_handlers_generic_handler(
130
147
  "function_executor_service.FunctionExecutor", rpc_method_handlers
@@ -258,3 +275,33 @@ class FunctionExecutor(object):
258
275
  metadata,
259
276
  _registered_method=True,
260
277
  )
278
+
279
+ @staticmethod
280
+ def get_info(
281
+ request,
282
+ target,
283
+ options=(),
284
+ channel_credentials=None,
285
+ call_credentials=None,
286
+ insecure=False,
287
+ compression=None,
288
+ wait_for_ready=None,
289
+ timeout=None,
290
+ metadata=None,
291
+ ):
292
+ return grpc.experimental.unary_unary(
293
+ request,
294
+ target,
295
+ "/function_executor_service.FunctionExecutor/get_info",
296
+ indexify_dot_function__executor_dot_proto_dot_function__executor__pb2.InfoRequest.SerializeToString,
297
+ indexify_dot_function__executor_dot_proto_dot_function__executor__pb2.InfoResponse.FromString,
298
+ options,
299
+ channel_credentials,
300
+ insecure,
301
+ call_credentials,
302
+ compression,
303
+ wait_for_ready,
304
+ timeout,
305
+ metadata,
306
+ _registered_method=True,
307
+ )
@@ -17,8 +17,3 @@ GRPC_SERVER_OPTIONS = [
17
17
  ("grpc.max_send_message_length", _MAX_GRPC_MESSAGE_LENGTH),
18
18
  ("grpc.so_reuseport", _REUSE_SERVER_PORT),
19
19
  ]
20
-
21
- GRPC_CHANNEL_OPTIONS = GRPC_SERVER_OPTIONS
22
-
23
- # If a health check takes more than this duration then the server is considered unhealthy.
24
- HEALTH_CHECK_TIMEOUT_SEC = 5
@@ -2,8 +2,8 @@ from concurrent.futures import ThreadPoolExecutor
2
2
 
3
3
  import grpc
4
4
 
5
- from .proto.configuration import GRPC_SERVER_OPTIONS
6
5
  from .proto.function_executor_pb2_grpc import add_FunctionExecutorServicer_to_server
6
+ from .proto.server_configuration import GRPC_SERVER_OPTIONS
7
7
  from .service import Service
8
8
 
9
9
  # Temporary limit until we have a better way to control this.
@@ -1,20 +1,23 @@
1
- from typing import Iterator, Optional, Union
1
+ from typing import Iterator, Optional
2
2
 
3
3
  import grpc
4
4
  import structlog
5
- from tensorlake.functions_sdk.functions import TensorlakeCompute
5
+ from tensorlake.functions_sdk.functions import TensorlakeFunctionWrapper
6
6
  from tensorlake.functions_sdk.object_serializer import get_serializer
7
7
 
8
8
  from .handlers.run_function.handler import Handler as RunTaskHandler
9
9
  from .handlers.run_function.request_validator import (
10
10
  RequestValidator as RunTaskRequestValidator,
11
11
  )
12
+ from .info import info_response_kv_args
12
13
  from .initialize_request_validator import InitializeRequestValidator
13
14
  from .invocation_state.invocation_state_proxy_server import InvocationStateProxyServer
14
15
  from .invocation_state.proxied_invocation_state import ProxiedInvocationState
15
16
  from .proto.function_executor_pb2 import (
16
17
  HealthCheckRequest,
17
18
  HealthCheckResponse,
19
+ InfoRequest,
20
+ InfoResponse,
18
21
  InitializeRequest,
19
22
  InitializeResponse,
20
23
  InvocationStateResponse,
@@ -26,12 +29,14 @@ from .proto.function_executor_pb2_grpc import FunctionExecutorServicer
26
29
 
27
30
  class Service(FunctionExecutorServicer):
28
31
  def __init__(self):
29
- self._logger = structlog.get_logger(module=__name__)
32
+ self._logger = structlog.get_logger(module=__name__).bind(
33
+ **info_response_kv_args()
34
+ )
30
35
  self._namespace: Optional[str] = None
31
36
  self._graph_name: Optional[str] = None
32
37
  self._graph_version: Optional[str] = None
33
38
  self._function_name: Optional[str] = None
34
- self._function: Optional[Union[TensorlakeCompute, TensorlakeCompute]] = None
39
+ self._function_wrapper: Optional[TensorlakeFunctionWrapper] = None
35
40
  self._invocation_state_proxy_server: Optional[InvocationStateProxyServer] = None
36
41
 
37
42
  def initialize(
@@ -61,8 +66,10 @@ class Service(FunctionExecutorServicer):
61
66
  try:
62
67
  # Process user controlled input in a try-except block to not treat errors here as our
63
68
  # internal platform errors.
69
+ # TODO: capture stdout and stderr and report exceptions the same way as when we run a task.
64
70
  graph = graph_serializer.deserialize(request.graph.bytes)
65
- self._function = graph_serializer.deserialize(graph[request.function_name])
71
+ function = graph_serializer.deserialize(graph[request.function_name])
72
+ self._function_wrapper = TensorlakeFunctionWrapper(function)
66
73
  except Exception as e:
67
74
  return InitializeResponse(success=False, customer_error=str(e))
68
75
 
@@ -95,10 +102,10 @@ class Service(FunctionExecutorServicer):
95
102
  graph_name=self._graph_name,
96
103
  graph_version=self._graph_version,
97
104
  function_name=self._function_name,
98
- function=self._function,
99
105
  invocation_state=ProxiedInvocationState(
100
106
  request.task_id, self._invocation_state_proxy_server
101
107
  ),
108
+ function_wrapper=self._function_wrapper,
102
109
  logger=self._logger,
103
110
  ).run()
104
111
 
@@ -131,3 +138,8 @@ class Service(FunctionExecutorServicer):
131
138
  # - Didn't exhaust its thread pool.
132
139
  # - Is able to communicate over its server socket.
133
140
  return HealthCheckResponse(healthy=True)
141
+
142
+ def get_info(
143
+ self, request: InfoRequest, context: grpc.ServicerContext
144
+ ) -> InfoResponse:
145
+ return InfoResponse(**info_response_kv_args())
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: indexify
3
- Version: 0.3.4
3
+ Version: 0.3.5
4
4
  Summary: Open Source Indexify components and helper tools
5
5
  Home-page: https://github.com/tensorlakeai/indexify
6
6
  License: Apache 2.0
@@ -23,7 +23,7 @@ Requires-Dist: pydantic (==2.10.4)
23
23
  Requires-Dist: pyyaml (>=6,<7)
24
24
  Requires-Dist: rich (>=13.9.2,<14.0.0)
25
25
  Requires-Dist: structlog (>=24.4.0,<25.0.0)
26
- Requires-Dist: tensorlake (>=0.1.9)
26
+ Requires-Dist: tensorlake (>=0.1.11)
27
27
  Requires-Dist: typer (>=0.12,<0.13)
28
28
  Project-URL: Repository, https://github.com/tensorlakeai/indexify
29
29
  Description-Content-Type: text/markdown
@@ -1,45 +1,47 @@
1
- indexify/cli/cli.py,sha256=y6JNaMd5by7_v3jE1iah1krlvfzbN4r5A2WkgGTy1Ts,11427
1
+ indexify/cli/cli.py,sha256=WcQy4QrO2NM4Xfenzb11WzJbC8lOpMgE8GgHAkUNcZE,11504
2
2
  indexify/executor/README.md,sha256=ozC6_hMkhQQNVCMEpBxwiUALz6lwErPQxNxQfQDqnG4,2029
3
3
  indexify/executor/api_objects.py,sha256=k5tKYxaWml0sSECoEDzamCYeJnlD7zO2M7E_qGwyMrg,1032
4
4
  indexify/executor/downloader.py,sha256=Vrq1dAW4BifG62tlqFnImiMxdezIgOZcByTRnhDsnnw,6457
5
- indexify/executor/executor.py,sha256=lln0p0cVN2aNY3bsHFp7Phbaa2q9gnQABi1xEPxo1Nc,5859
5
+ indexify/executor/executor.py,sha256=hyAQKJ80IaPB-A_YRRld4yqYhAifLvMkQ8qYNMQimPI,5892
6
6
  indexify/executor/function_executor/function_executor.py,sha256=837r91kL1Nt5Ct9LVFdpB89fhtHctV-c2PrgbyVSFlE,5833
7
7
  indexify/executor/function_executor/function_executor_state.py,sha256=_85dpaudYM0sekOqwjMxKGdK7MNQdTGUhHi67sqVHyY,2853
8
- indexify/executor/function_executor/health_checker.py,sha256=JPpwXzLVzx4RbDXdPgSUAwUj-1qTwzha3uW0SHqX1CU,2764
8
+ indexify/executor/function_executor/health_checker.py,sha256=UzAqqWO2y0DLhxm639mTDrEIYNY7gZ3T_zdgPSDuVJ4,2747
9
9
  indexify/executor/function_executor/invocation_state_client.py,sha256=jxElxnYFfdwCxKfKvQsjLIE-Z_1386wxednJ2pGKSL0,8581
10
+ indexify/executor/function_executor/server/client_configuration.py,sha256=gOywMus0cotlX6NKIadEJwvOmBE-LbGE_wvoMi5-HzY,994
10
11
  indexify/executor/function_executor/server/function_executor_server.py,sha256=_DLivLDikupZusRk8gVWDk7fWPT9XjZ4un1yWSlOObs,883
11
12
  indexify/executor/function_executor/server/function_executor_server_factory.py,sha256=pGbJMQfC5TNvyWOs6VDKdqd2PK5OHQh5_wSDP-E7DbI,1677
12
- indexify/executor/function_executor/server/subprocess_function_executor_server.py,sha256=DxQMwAvQi03OGo2sFruUrxwcMPG8In4C62L3sped2FI,694
13
- indexify/executor/function_executor/server/subprocess_function_executor_server_factory.py,sha256=cVr2wXQL5zVlq-Ep44ZBXBFCQbrbZSMscjRmzVDakvk,4295
13
+ indexify/executor/function_executor/server/subprocess_function_executor_server.py,sha256=JekDOqF7oFD4J6zcN3xB0Dxd1cgpEXMOsb_rKZOeBlI,668
14
+ indexify/executor/function_executor/server/subprocess_function_executor_server_factory.py,sha256=FYExuYZZ7CUcznUobtnxvd2hVjUjpB9Dkav0FFcA0hM,4118
14
15
  indexify/executor/function_executor/single_task_runner.py,sha256=CwLN2pLJpORDjxgxME5-xQCBJ_mzmrdnrzjB7n4sqZo,7794
15
16
  indexify/executor/function_executor/task_input.py,sha256=8pBRuaQbBBPrDWwByOKZlOaXu6UDmJUO5w-6XxAYSgY,582
16
17
  indexify/executor/function_executor/task_output.py,sha256=3-qcT1aigmOFEp6QSJtUcQfqeJfrxvo265qgk9WAUVg,1064
17
18
  indexify/executor/runtime_probes.py,sha256=bo6Dq6AGZpJH099j0DHtVSDEH80tv3j9MXf3VXSx_p8,2182
18
- indexify/executor/task_fetcher.py,sha256=Cpm-LRZz1MSfW-xHJbIaKc1wxzRhIrud9GTOIxWODt0,2883
19
+ indexify/executor/task_fetcher.py,sha256=59Cn79bXpbPFEj2bZCVFRaLaNKPAeRyJeiEsZE3F7Ys,2911
19
20
  indexify/executor/task_reporter.py,sha256=eueJNHYJIwAm8lY8SQJrUOWC-Nk-DPesDis1YTR4k7c,6643
20
21
  indexify/executor/task_runner.py,sha256=RSFeJYhQ_agXXPBm8u13HErSUPZGsCGwV1stgS7g258,5035
21
22
  indexify/function_executor/README.md,sha256=TAcbYYe6noUMriaQabJAaZ8a2SAYzlXl7hIdTfULqYY,950
22
23
  indexify/function_executor/handlers/run_function/function_inputs_loader.py,sha256=StSJCp-kkOWUuUIzONnoqtcB37nzBYGcIVy2oTEwOIQ,1588
23
- indexify/function_executor/handlers/run_function/handler.py,sha256=DY_aIR8MZsa1cnFxbVEHhcxQSqBwW4cYRN9NhzuDDFo,5090
24
+ indexify/function_executor/handlers/run_function/handler.py,sha256=-GPM9G9GkkJtmB776RPKReFnus5hMoAw6IC0rV2WE5s,5209
24
25
  indexify/function_executor/handlers/run_function/request_validator.py,sha256=GS7_zxAlyNg0vpUrhot-DpVWFyI9Y9P8jvb7UuO4b1A,856
25
26
  indexify/function_executor/handlers/run_function/response_helper.py,sha256=FJVl-LyoRBx9HRaOo_umveiWzuh4anO7aXUmEMEki20,3074
27
+ indexify/function_executor/info.py,sha256=kR_i84pLqAQI5AKLYuXg3mEaVIMmHZK-Hx8Dmv-_slA,454
26
28
  indexify/function_executor/initialize_request_validator.py,sha256=agYWGRHUC-7IuYtm9NPjcVo5SVOWM4PxewA93dqdkJM,682
27
29
  indexify/function_executor/invocation_state/invocation_state_proxy_server.py,sha256=YEnxvWV8NFVK_CxHI_C-BNizuagalY3ieN62IOxNttU,7023
28
30
  indexify/function_executor/invocation_state/proxied_invocation_state.py,sha256=rjZ2192bSXonNKkaDaByeOL-wVx6x6Qrtio0UVzGSz8,944
29
31
  indexify/function_executor/invocation_state/response_validator.py,sha256=05Y9_5s010owaDb6OUia9W9Alx1r1zJ179HboEkT-Xk,896
30
- indexify/function_executor/main.py,sha256=uOzVUhl4LzGJ9Cw3kyyFddaEIMxRETEKFHPnvJVtc50,1152
31
- indexify/function_executor/proto/configuration.py,sha256=fX-WiV9zEiUXlpwpJ-kGBkNyZEwWq2YuvSFKnB-lp_8,1217
32
- indexify/function_executor/proto/function_executor.proto,sha256=dy614X8ZGi5glbbKStyE6m0JS7zY_H5aqcwZ-rsAy_8,4218
33
- indexify/function_executor/proto/function_executor_pb2.py,sha256=ZOosY_doqi7pRxubfu0EjYfzafFdulPxEuuz-NfA_cg,7859
34
- indexify/function_executor/proto/function_executor_pb2.pyi,sha256=_ezcOmtujDQpUWamFwsPEux6nlfmY6qUjrX7Ou1gPJU,7459
35
- indexify/function_executor/proto/function_executor_pb2_grpc.py,sha256=A4r9hZ1Kb_tiSBpgGqMVwpRtvlGPkeLeMhfF1B_zKr0,10772
32
+ indexify/function_executor/main.py,sha256=LvcEAPPi-yy2eyatNssihcJRXjAzz5GCcMftvLF9ciU,1224
33
+ indexify/function_executor/proto/function_executor.proto,sha256=GZ2cAkwrNQTC6GRFTckmyGo3P-ywgY8ZKsVuuQL-x8c,4915
34
+ indexify/function_executor/proto/function_executor_pb2.py,sha256=MtvY7kAxf-O6zu6XUkV3-IBew3Np19ceuPtmk-sxWsQ,8559
35
+ indexify/function_executor/proto/function_executor_pb2.pyi,sha256=QYZ3MH7Z72-xCsrzyMEeUVCcxRg2mjOIosV2bLlwSAI,8179
36
+ indexify/function_executor/proto/function_executor_pb2_grpc.py,sha256=OGSzzbZKtOSNGemTJLX0L96_jkxUiZSYJQM56LHzZ-o,12734
36
37
  indexify/function_executor/proto/message_validator.py,sha256=OKXPYgy5L9c-spnV9Zjv7PA_yxwzvykfhbYylYx8cwQ,1456
37
- indexify/function_executor/server.py,sha256=tJzUy_v4BT8Le9G3hgtiuDJo9YVFkAU2dVISSsX36II,1061
38
- indexify/function_executor/service.py,sha256=b1On_omDs3gH7bGloegjTDRBkWd2C5uIv6ZniFvf-pg,6036
38
+ indexify/function_executor/proto/server_configuration.py,sha256=FzrusxLU62IfvbZ42IjwmPROsDQMi5mCOu41hRA4E7s,1052
39
+ indexify/function_executor/server.py,sha256=gOAl_-cT8Z4yC_bjD4adaHY4EzsjRm9RuykeCNGp8Mc,1068
40
+ indexify/function_executor/service.py,sha256=OUqlh0lirRbHNsgpDOEwbaGpDptAs1-GoeKveYCq7zk,6506
39
41
  indexify/utils/README.md,sha256=2g8-H9GopacOW4YrViZc0QsaJPtK-Fox7GyfX01kcDk,86
40
42
  indexify/utils/http_client.py,sha256=deMlmAu4E_ZXV3blCdWNag3uO_cyD-GsMZjFFmO5r7s,3541
41
43
  indexify/utils/logging.py,sha256=c6NwzY7uVHMRJc8f2w2KF36rNkeZVoQfGdq7suIg9s8,2025
42
- indexify-0.3.4.dist-info/METADATA,sha256=DED1Lo70-J6OSpfru2s8SMY-6_U4MD1J6WIQsIQqe6c,1372
43
- indexify-0.3.4.dist-info/WHEEL,sha256=RaoafKOydTQ7I_I3JTrPCg6kUmTgtm4BornzOqyEfJ8,88
44
- indexify-0.3.4.dist-info/entry_points.txt,sha256=pJG0YRnypesbiNJHuObfHEkjk0p_ZvEDTyyTH0kGVTY,108
45
- indexify-0.3.4.dist-info/RECORD,,
44
+ indexify-0.3.5.dist-info/METADATA,sha256=bn5MHa523My7wk17i-8_ev8hnFrhABt1Q4GLXcsoKpk,1373
45
+ indexify-0.3.5.dist-info/WHEEL,sha256=RaoafKOydTQ7I_I3JTrPCg6kUmTgtm4BornzOqyEfJ8,88
46
+ indexify-0.3.5.dist-info/entry_points.txt,sha256=pJG0YRnypesbiNJHuObfHEkjk0p_ZvEDTyyTH0kGVTY,108
47
+ indexify-0.3.5.dist-info/RECORD,,