indexify 0.4.30__py3-none-any.whl → 0.4.31__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.
@@ -4,8 +4,7 @@ from typing import Any, Generator, Tuple
4
4
  import click
5
5
  import docker
6
6
  import docker.api.build
7
- import docker.models
8
- import docker.models.images
7
+ from docker.errors import BuildError
9
8
  from tensorlake.functions_sdk.image import Image
10
9
  from tensorlake.functions_sdk.workflow_module import (
11
10
  WorkflowModuleInfo,
@@ -16,7 +15,6 @@ from tensorlake.functions_sdk.workflow_module import (
16
15
  @click.command(
17
16
  short_help="Build images for graphs/workflows defined in the workflow file"
18
17
  )
19
- # Path to the file where the graphs/workflows are defined as global variables
20
18
  @click.argument(
21
19
  "workflow-file-path",
22
20
  type=click.Path(exists=True, file_okay=True, dir_okay=False),
@@ -31,6 +29,11 @@ def build_image(
31
29
  workflow_file_path: str,
32
30
  image_names: tuple[str, ...] = None,
33
31
  ):
32
+ """
33
+ Build the images associated to an Indexify workflow
34
+
35
+ A workflow is defined in a Python file, and the images are built using the local Docker daemon.
36
+ """
34
37
  try:
35
38
  workflow_module_info: WorkflowModuleInfo = load_workflow_module_info(
36
39
  workflow_file_path
@@ -48,7 +51,7 @@ def build_image(
48
51
  indexify_version: str = importlib.metadata.version("indexify")
49
52
  for image in workflow_module_info.images.keys():
50
53
  image: Image
51
- if image_names is not None and image.image_name not in image_names:
54
+ if len(image_names) > 0 and image.image_name not in image_names:
52
55
  click.echo(
53
56
  f"Skipping image `{image.image_name}` as it is not in the provided image names."
54
57
  )
@@ -57,28 +60,65 @@ def build_image(
57
60
  click.echo(f"Building image `{image.image_name}`")
58
61
 
59
62
  image.run(f"pip install 'indexify=={indexify_version}'")
60
- built_image, logs_generator = image.build()
61
- built_image: docker.models.images.Image
62
- for output in logs_generator:
63
- click.secho(output)
63
+ built_image, logs_generator = _build(image=image, docker_client=docker_client)
64
+ try:
65
+ built_image, logs_generator = _build(
66
+ image=image, docker_client=docker_client
67
+ )
68
+ _print_build_log(logs_generator)
69
+ click.secho(f"built image: {built_image.tags[0]}", fg="green")
70
+ except BuildError as e:
71
+ raise click.Abort() from e
64
72
 
65
73
  click.secho(f"built image: {built_image.tags[0]}", fg="green")
66
74
 
67
75
 
68
- def build(
76
+ def _build(
69
77
  image: Image, docker_client: docker.DockerClient
70
78
  ) -> Tuple[docker.models.images.Image, Generator[str, Any, None]]:
71
79
  docker_file = image.dockerfile()
72
- image_name = f"{image.image_name}:{image.image_tag}"
80
+ image_name = (
81
+ image.image_name
82
+ if ":" in image.image_name
83
+ else f"{image.image_name}:{image.image_tag}"
84
+ )
73
85
 
74
86
  docker.api.build.process_dockerfile = lambda dockerfile, path: (
75
87
  "Dockerfile",
76
88
  dockerfile,
77
89
  )
78
90
 
79
- return docker_client.images.build(
80
- path=".",
81
- dockerfile=docker_file,
82
- tag=image_name,
83
- rm=True,
84
- )
91
+ try:
92
+ built_image, logs_generator = docker_client.images.build(
93
+ path=".",
94
+ dockerfile=docker_file,
95
+ tag=image_name,
96
+ rm=True,
97
+ # pull=True, # optional: ensures fresh base images
98
+ # forcerm=True, # optional: always remove intermediate containers
99
+ )
100
+ return built_image, logs_generator
101
+ except BuildError as e:
102
+ click.secho("Docker build failed:", fg="red")
103
+ _print_build_log(e.build_log or [])
104
+ click.secho(str(e), fg="red")
105
+ raise
106
+
107
+
108
+ def _print_build_log(build_logs):
109
+ for log_entry in build_logs:
110
+ if isinstance(log_entry, dict):
111
+ if "stream" in log_entry:
112
+ click.echo(log_entry["stream"].rstrip("\n"))
113
+ elif "status" in log_entry:
114
+ if "id" in log_entry:
115
+ click.echo(f"{log_entry['status']}: {log_entry['id']}")
116
+ else:
117
+ click.echo(log_entry["status"])
118
+ if "errorDetail" in log_entry:
119
+ # This is the most useful bit when a RUN command fails
120
+ msg = log_entry["errorDetail"].get("message") or log_entry.get("error")
121
+ if msg:
122
+ click.secho(msg.rstrip("\n"), fg="red")
123
+ elif isinstance(log_entry, str):
124
+ click.echo(log_entry.rstrip("\n"))
indexify/cli/deploy.py CHANGED
@@ -18,7 +18,7 @@ from tensorlake.functions_sdk.workflow_module import (
18
18
  )
19
19
  @click.option(
20
20
  "-u",
21
- "--upgrade-queued-requests",
21
+ "--upgrade-queued-invocations",
22
22
  is_flag=True,
23
23
  default=False,
24
24
  help="Upgrade invocations that are already queued or running to use the deployed version of the graphs/workflows",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: indexify
3
- Version: 0.4.30
3
+ Version: 0.4.31
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
1
  indexify/cli/__init__.py,sha256=ELFLx_Z_oWm30jwOpYjbD6Ori3Nzz4ldkvmGVK7QMgw,426
2
- indexify/cli/build_image.py,sha256=QLhhYz8WZtOL_xm1LvviTNJucGnYjksnMIVmeEQ8zzA,2505
3
- indexify/cli/deploy.py,sha256=0cs68KXH4Cw0KmYAoqYZ60oErQ5J9LI0KbohSG_Mj8g,1847
2
+ indexify/cli/build_image.py,sha256=FPP8hdj0E5IsEKokS4IBWKSx9PWZ66ZY5GqEI9oHj7k,4139
3
+ indexify/cli/deploy.py,sha256=f3CX1PhnkrbNzrqv4BY_C6YZHYxSJKr0sAjDsw1rKBs,1850
4
4
  indexify/cli/executor.py,sha256=0go8YUPFCwg77pYbCaoWuPraqW7KBgZ6Fyx6sQzT4aM,6286
5
5
  indexify/executor/README.md,sha256=ozC6_hMkhQQNVCMEpBxwiUALz6lwErPQxNxQfQDqnG4,2029
6
6
  indexify/executor/blob_store/blob_store.py,sha256=lrSGTZa_H4Cs1BFwADp-aluvD3LpmE1XO76ZJMX5alU,5798
@@ -69,7 +69,7 @@ indexify/proto/executor_api.proto,sha256=YwLeLjyLHhs5qoWLA50uHY2KdKRGfBQBKZwE8VX
69
69
  indexify/proto/executor_api_pb2.py,sha256=vTG1-2Pp4OnTWFD4GYphgJ3cUbTbDjCOKstKrLBXB-E,16472
70
70
  indexify/proto/executor_api_pb2.pyi,sha256=-6P-ef-fBJF0CTc4UucIzrDLCBVZpIEhEz2qhexvwjk,23175
71
71
  indexify/proto/executor_api_pb2_grpc.py,sha256=u9GEQV4nm_GvApRxjVo806CkgBMBVReb5IVrcaDaliY,7520
72
- indexify-0.4.30.dist-info/METADATA,sha256=rtJwA6hJc1w8kSC0HTsesyum276C4gH1iXKg_jK45rY,1390
73
- indexify-0.4.30.dist-info/WHEEL,sha256=RaoafKOydTQ7I_I3JTrPCg6kUmTgtm4BornzOqyEfJ8,88
74
- indexify-0.4.30.dist-info/entry_points.txt,sha256=rMJqbE5KPZIXTPIfAtVIM4zpUElqYVgEYd6i7N23zzg,49
75
- indexify-0.4.30.dist-info/RECORD,,
72
+ indexify-0.4.31.dist-info/METADATA,sha256=XQZTmN_xg_dU5OBebaGknra6fs4JPBwKlotK5211Hxw,1390
73
+ indexify-0.4.31.dist-info/WHEEL,sha256=RaoafKOydTQ7I_I3JTrPCg6kUmTgtm4BornzOqyEfJ8,88
74
+ indexify-0.4.31.dist-info/entry_points.txt,sha256=rMJqbE5KPZIXTPIfAtVIM4zpUElqYVgEYd6i7N23zzg,49
75
+ indexify-0.4.31.dist-info/RECORD,,