indexify 0.3.1__py3-none-any.whl → 0.3.3__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
@@ -6,6 +6,8 @@ from indexify.utils.logging import (
6
6
 
7
7
  configure_logging_early()
8
8
 
9
+ import importlib.metadata
10
+ import json
9
11
  import os
10
12
  import shutil
11
13
  import signal
@@ -17,6 +19,7 @@ from importlib.metadata import version
17
19
  from pathlib import Path
18
20
  from typing import Annotated, List, Optional, Tuple
19
21
 
22
+ import docker
20
23
  import nanoid
21
24
  import structlog
22
25
  import typer
@@ -190,7 +193,9 @@ def executor(
190
193
  "--function",
191
194
  "-f",
192
195
  help="Function that the executor will run "
193
- "specified as <namespace>:<workflow>:<function>:<version>",
196
+ "specified as <namespace>:<workflow>:<function>:<version>"
197
+ "version is optional, not specifying it will make the server send any version"
198
+ "of the function",
194
199
  ),
195
200
  ] = None,
196
201
  config_path: Optional[str] = typer.Option(
@@ -261,16 +266,23 @@ def _parse_function_uris(uri_strs: Optional[List[str]]) -> Optional[List[Functio
261
266
  uris: List[FunctionURI] = []
262
267
  for uri_str in uri_strs:
263
268
  tokens = uri_str.split(":")
264
- if len(tokens) != 4:
269
+ # FIXME bring this back when we have a dynamic scheduler
270
+ # if len(tokens) != 4:
271
+ if len(tokens) < 3 and len(tokens) > 4:
265
272
  raise typer.BadParameter(
266
- "Function should be specified as <namespace>:<workflow>:<function>:<version>"
273
+ "Function should be specified as <namespace>:<workflow>:<function>:<version> or"
274
+ "<namespace>:<workflow>:<function>"
267
275
  )
276
+ try:
277
+ version = tokens[3]
278
+ except IndexError:
279
+ version = None
268
280
  uris.append(
269
281
  FunctionURI(
270
282
  namespace=tokens[0],
271
283
  compute_graph=tokens[1],
272
284
  compute_fn=tokens[2],
273
- version=tokens[3],
285
+ version=version,
274
286
  )
275
287
  )
276
288
  return uris
@@ -285,7 +297,57 @@ def _create_image(image: Image, python_sdk_path):
285
297
 
286
298
 
287
299
  def _build_image(image: Image, python_sdk_path: Optional[str] = None):
288
- built_image, output = image.build(python_sdk_path=python_sdk_path)
289
- for line in output:
290
- print(line)
291
- print(f"built image: {built_image.tags[0]}")
300
+ docker_file = _generate_dockerfile(image, python_sdk_path=python_sdk_path)
301
+ image_name = f"{image._image_name}:{image._tag}"
302
+
303
+ # low_level_client = docker.APIClient(base_url=docker_client.api.base_url)
304
+ docker_host = os.getenv("DOCKER_HOST", "unix:///var/run/docker.sock")
305
+ low_level_client = docker.APIClient(base_url=docker_host)
306
+ docker.api.build.process_dockerfile = lambda dockerfile, path: (
307
+ "Dockerfile",
308
+ dockerfile,
309
+ )
310
+ generator = low_level_client.build(
311
+ dockerfile=docker_file,
312
+ rm=True,
313
+ path=".",
314
+ tag=image_name,
315
+ )
316
+
317
+ for output in generator:
318
+ for line in output.decode().splitlines():
319
+ json_line = json.loads(line)
320
+ if "stream" in json_line:
321
+ print(json_line["stream"], end="")
322
+
323
+ elif "errorDetail" in json_line:
324
+ print(json_line["errorDetail"]["message"])
325
+
326
+
327
+ def _generate_dockerfile(image, python_sdk_path: Optional[str] = None):
328
+ docker_contents = [
329
+ f"FROM {image._base_image}",
330
+ "RUN mkdir -p ~/.indexify",
331
+ f"RUN echo {image._image_name} > ~/.indexify/image_name", # TODO: Do we still use this in executors?
332
+ f"RUN echo {image.hash()} > ~/.indexify/image_hash", # TODO: Do we still use this in executors?
333
+ "WORKDIR /app",
334
+ ]
335
+
336
+ for build_op in image._build_ops:
337
+ docker_contents.append(build_op.render())
338
+
339
+ if python_sdk_path is not None:
340
+ print(f"Building image {image._image_name} with local version of the SDK")
341
+
342
+ if not os.path.exists(python_sdk_path):
343
+ print(f"error: {python_sdk_path} does not exist")
344
+ os.exit(1)
345
+ docker_contents.append(f"COPY {python_sdk_path} /app/python-sdk")
346
+ docker_contents.append("RUN (cd /app/python-sdk && pip install .)")
347
+ else:
348
+ docker_contents.append(
349
+ f"RUN pip install indexify=={importlib.metadata.version('indexify')}"
350
+ )
351
+
352
+ docker_file = "\n".join(docker_contents)
353
+ return docker_file
@@ -20,7 +20,7 @@ class FunctionURI(BaseModel):
20
20
  namespace: str
21
21
  compute_graph: str
22
22
  compute_fn: str
23
- version: str
23
+ version: Optional[str] = None
24
24
 
25
25
 
26
26
  class ExecutorMetadata(BaseModel):
@@ -86,33 +86,37 @@ class Service(FunctionExecutorServicer):
86
86
  # If our code raises an exception the grpc framework converts it into GRPC_STATUS_UNKNOWN
87
87
  # error with the exception message. Differentiating errors is not needed for now.
88
88
  RunTaskRequestValidator(request=request).check()
89
+ self._check_task_routed_correctly(request)
89
90
 
91
+ return RunTaskHandler(
92
+ request=request,
93
+ graph_name=self._graph_name,
94
+ graph_version=self._graph_version,
95
+ function_name=self._function_name,
96
+ function=self._function,
97
+ invocation_state=ProxiedInvocationState(
98
+ request.task_id, self._invocation_state_proxy_server
99
+ ),
100
+ logger=self._logger,
101
+ ).run()
102
+
103
+ def _check_task_routed_correctly(self, request: RunTaskRequest):
90
104
  # Fail with internal error as this happened due to wrong task routing to this Server.
105
+ # If we run the wrongly routed task then it can steal data from this Server if it belongs
106
+ # to a different customer.
91
107
  if request.namespace != self._namespace:
92
108
  raise ValueError(
93
109
  f"This Function Executor is not initialized for this namespace {request.namespace}"
94
110
  )
95
111
  if request.graph_name != self._graph_name:
96
112
  raise ValueError(
97
- f"This Function Executor is not initialized for this graph {request.graph_name}"
113
+ f"This Function Executor is not initialized for this graph_name {request.graph_name}"
98
114
  )
99
115
  if request.graph_version != self._graph_version:
100
116
  raise ValueError(
101
- f"This Function Executor is not initialized for this graph version {request.graph_version}"
117
+ f"This Function Executor is not initialized for this graph_version {request.graph_version}"
102
118
  )
103
119
  if request.function_name != self._function_name:
104
120
  raise ValueError(
105
- f"This Function Executor is not initialized for this function {request.function_name}"
121
+ f"This Function Executor is not initialized for this function_name {request.function_name}"
106
122
  )
107
-
108
- return RunTaskHandler(
109
- request=request,
110
- graph_name=self._graph_name,
111
- graph_version=self._graph_version,
112
- function_name=self._function_name,
113
- function=self._function,
114
- invocation_state=ProxiedInvocationState(
115
- request.task_id, self._invocation_state_proxy_server
116
- ),
117
- logger=self._logger,
118
- ).run()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: indexify
3
- Version: 0.3.1
3
+ Version: 0.3.3
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
@@ -1,6 +1,6 @@
1
- indexify/cli/cli.py,sha256=II73vJlVeEy51pPLnrnBcYJbZQxCPItkFRFEN8MD37c,9122
1
+ indexify/cli/cli.py,sha256=y6JNaMd5by7_v3jE1iah1krlvfzbN4r5A2WkgGTy1Ts,11427
2
2
  indexify/executor/README.md,sha256=ozC6_hMkhQQNVCMEpBxwiUALz6lwErPQxNxQfQDqnG4,2029
3
- indexify/executor/api_objects.py,sha256=QeXOZpS7nkVA_dsRQFlS3EuMvqFvLGaw1Spcr0c-5lA,1015
3
+ indexify/executor/api_objects.py,sha256=k5tKYxaWml0sSECoEDzamCYeJnlD7zO2M7E_qGwyMrg,1032
4
4
  indexify/executor/downloader.py,sha256=Vrq1dAW4BifG62tlqFnImiMxdezIgOZcByTRnhDsnnw,6457
5
5
  indexify/executor/executor.py,sha256=lln0p0cVN2aNY3bsHFp7Phbaa2q9gnQABi1xEPxo1Nc,5859
6
6
  indexify/executor/function_executor/function_executor.py,sha256=a9pAWQWDLJL-i5bp1PEMD2eMYOTvXAh_1jQsXcL_JCQ,5226
@@ -34,11 +34,11 @@ indexify/function_executor/proto/function_executor_pb2.pyi,sha256=TQEOl3W1s4fxtp
34
34
  indexify/function_executor/proto/function_executor_pb2_grpc.py,sha256=xrqIDrcl1PTyQTGAAGrgSDKEtZilC445Op0tJ7LmS5Q,8716
35
35
  indexify/function_executor/proto/message_validator.py,sha256=OKXPYgy5L9c-spnV9Zjv7PA_yxwzvykfhbYylYx8cwQ,1456
36
36
  indexify/function_executor/server.py,sha256=tJzUy_v4BT8Le9G3hgtiuDJo9YVFkAU2dVISSsX36II,1061
37
- indexify/function_executor/service.py,sha256=3JYcMcWiCgvxXhRPReUUBjTBNLIqUbhhsGZIsqIcVw4,5343
37
+ indexify/function_executor/service.py,sha256=i3bI7RSKSr3cDiNFoZdl4TSY_SMKlXBXPdExjvaAoBY,5606
38
38
  indexify/utils/README.md,sha256=2g8-H9GopacOW4YrViZc0QsaJPtK-Fox7GyfX01kcDk,86
39
39
  indexify/utils/http_client.py,sha256=deMlmAu4E_ZXV3blCdWNag3uO_cyD-GsMZjFFmO5r7s,3541
40
40
  indexify/utils/logging.py,sha256=c6NwzY7uVHMRJc8f2w2KF36rNkeZVoQfGdq7suIg9s8,2025
41
- indexify-0.3.1.dist-info/METADATA,sha256=4UcqDjQRLNcVGFezaIROqWdtJxCsPP0hLq8-hlFvDn0,1383
42
- indexify-0.3.1.dist-info/WHEEL,sha256=RaoafKOydTQ7I_I3JTrPCg6kUmTgtm4BornzOqyEfJ8,88
43
- indexify-0.3.1.dist-info/entry_points.txt,sha256=pJG0YRnypesbiNJHuObfHEkjk0p_ZvEDTyyTH0kGVTY,108
44
- indexify-0.3.1.dist-info/RECORD,,
41
+ indexify-0.3.3.dist-info/METADATA,sha256=VLMu3g8ZamLGLCjjqwPrBxqg8ZStvSZooP9ITl-BbHw,1383
42
+ indexify-0.3.3.dist-info/WHEEL,sha256=RaoafKOydTQ7I_I3JTrPCg6kUmTgtm4BornzOqyEfJ8,88
43
+ indexify-0.3.3.dist-info/entry_points.txt,sha256=pJG0YRnypesbiNJHuObfHEkjk0p_ZvEDTyyTH0kGVTY,108
44
+ indexify-0.3.3.dist-info/RECORD,,