cycls 0.0.2.66__py3-none-any.whl → 0.0.2.68__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.
cycls/runtime.py CHANGED
@@ -68,16 +68,22 @@ def _copy_path(src_path: Path, dest_path: Path):
68
68
  dest_path.parent.mkdir(parents=True, exist_ok=True)
69
69
  shutil.copy(src_path, dest_path)
70
70
 
71
+ # Pre-built base image with common dependencies
72
+ BASE_IMAGE = "ghcr.io/cycls/base:python3.12"
73
+ BASE_PACKAGES = {
74
+ "cloudpickle", "cryptography", "fastapi", "fastapi[standard]",
75
+ "pydantic", "pyjwt", "uvicorn", "uvicorn[standard]", "httpx"
76
+ }
77
+
71
78
  # --- Main Runtime Class ---
72
79
 
73
80
  class Runtime:
74
81
  """
75
82
  Handles building a Docker image and executing a function within a container.
76
83
  """
77
- def __init__(self, func, name, python_version=None, pip_packages=None, apt_packages=None, run_commands=None, copy=None, base_url=None, api_key=None):
84
+ def __init__(self, func, name, python_version=None, pip_packages=None, apt_packages=None, run_commands=None, copy=None, base_url=None, api_key=None, base_image=None):
78
85
  self.func = func
79
86
  self.python_version = python_version or f"{sys.version_info.major}.{sys.version_info.minor}"
80
- self.pip_packages = sorted(pip_packages or [])
81
87
  self.apt_packages = sorted(apt_packages or [])
82
88
  self.run_commands = sorted(run_commands or [])
83
89
  self.copy = copy or {}
@@ -85,6 +91,11 @@ class Runtime:
85
91
  self.base_url = base_url or "https://service-core-280879789566.me-central1.run.app"
86
92
  self.image_prefix = f"cycls/{name}"
87
93
 
94
+ # Use pre-built base image by default, filter out already-installed packages
95
+ self.base_image = base_image or BASE_IMAGE
96
+ all_pip = set(pip_packages or [])
97
+ self.pip_packages = sorted(all_pip - BASE_PACKAGES) if self.base_image == BASE_IMAGE else sorted(all_pip)
98
+
88
99
  # Standard paths and filenames used inside the container
89
100
  self.io_dir = "/app/io"
90
101
  self.runner_filename = "runner.py"
@@ -145,6 +156,7 @@ class Runtime:
145
156
  def _generate_base_tag(self) -> str:
146
157
  """Creates a unique tag for the base Docker image based on its dependencies."""
147
158
  signature_parts = [
159
+ self.base_image,
148
160
  "".join(self.python_version),
149
161
  "".join(self.pip_packages),
150
162
  "".join(self.apt_packages),
@@ -163,7 +175,11 @@ class Runtime:
163
175
 
164
176
  def _generate_dockerfile(self, port=None) -> str:
165
177
  """Generates a multi-stage Dockerfile string."""
166
- run_pip_install = f"RUN pip install --no-cache-dir cloudpickle {' '.join(self.pip_packages)}"
178
+ # Only install extra packages not in base image
179
+ run_pip_install = (
180
+ f"RUN pip install --no-cache-dir {' '.join(self.pip_packages)}"
181
+ if self.pip_packages else ""
182
+ )
167
183
  run_apt_install = (
168
184
  f"RUN apt-get update && apt-get install -y --no-install-recommends {' '.join(self.apt_packages)}"
169
185
  if self.apt_packages else ""
@@ -174,14 +190,14 @@ class Runtime:
174
190
 
175
191
  return f"""
176
192
  # STAGE 1: Base image with all dependencies
177
- FROM python:{self.python_version}-slim as base
193
+ FROM {self.base_image} as base
178
194
  ENV PIP_ROOT_USER_ACTION=ignore
179
195
  ENV PYTHONUNBUFFERED=1
180
196
  RUN mkdir -p {self.io_dir}
181
197
  {run_apt_install}
182
198
  {run_pip_install}
183
199
  {run_shell_commands}
184
- WORKDIR app
200
+ WORKDIR /app
185
201
  {copy_lines}
186
202
  COPY {self.runner_filename} {self.runner_path}
187
203
  ENTRYPOINT ["python", "{self.runner_path}", "{self.io_dir}"]
cycls/sdk.py CHANGED
@@ -1,6 +1,5 @@
1
- import json, time, modal, inspect, uvicorn
1
+ import time, inspect, uvicorn
2
2
  from .runtime import Runtime
3
- from modal.runner import run_app
4
3
  from .web import web, Config
5
4
  from .auth import PK_LIVE, PK_TEST, JWKS_PROD, JWKS_TEST
6
5
  import importlib.resources
@@ -123,6 +122,8 @@ class Agent:
123
122
  return
124
123
 
125
124
  def modal(self, prod=False):
125
+ import modal
126
+ from modal.runner import run_app
126
127
  self.client = modal.Client.from_credentials(*self.modal_keys)
127
128
  image = (modal.Image.debian_slim()
128
129
  .pip_install("fastapi[standard]", "pyjwt", "cryptography", *self.pip)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cycls
3
- Version: 0.0.2.66
3
+ Version: 0.0.2.68
4
4
  Summary: Distribute Intelligence
5
5
  Author: Mohammed J. AlRujayi
6
6
  Author-email: mj@cycls.com
@@ -4,9 +4,9 @@ cycls/default-theme/assets/index-B0ZKcm_V.css,sha256=wK9-NhEB8xPcN9Zv69zpOcfGTlF
4
4
  cycls/default-theme/assets/index-D5EDcI4J.js,sha256=sN4qRcAXa7DBd9JzmVcCoCwH4l8cNCM-U9QGUjBvWSo,1346506
5
5
  cycls/default-theme/index.html,sha256=bM-yW_g0cGrV40Q5yY3ccY0fM4zI1Wuu5I8EtGFJIxs,828
6
6
  cycls/dev-theme/index.html,sha256=QJBHkdNuMMiwQU7o8dN8__8YQeQB45D37D-NCXIWB2Q,11585
7
- cycls/runtime.py,sha256=hLBtwtGz0FCW1-EPCJy6kMdF2fB3i6Df_H8-bm7qeK0,18223
8
- cycls/sdk.py,sha256=jT6t2btthVI8Bdp0-BttS4apaH0k7GCobUHxE9BTUj4,6728
7
+ cycls/runtime.py,sha256=oAaqYbY58mIbXzQbWoNpbHyOA9py-7ZDnrEoPLXxHfE,18847
8
+ cycls/sdk.py,sha256=PqHIJdq1pvOTKm1c5vaG6DTMUsjdMzIjzcxrqw3aN9E,6744
9
9
  cycls/web.py,sha256=3M3qaWTNY3dpgd7Vq5aXREp-cIFsHrDqBQ1YkGrOaUk,4659
10
- cycls-0.0.2.66.dist-info/METADATA,sha256=g9ehLjsx8yYm6muJ_16lNlCzPtKchy2LlTjFP5nwzHk,7943
11
- cycls-0.0.2.66.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
12
- cycls-0.0.2.66.dist-info/RECORD,,
10
+ cycls-0.0.2.68.dist-info/METADATA,sha256=l8vds3aonBPjG6Q0oO8BkvDynM-3MEC9Yh4hFbb5I4M,7943
11
+ cycls-0.0.2.68.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
12
+ cycls-0.0.2.68.dist-info/RECORD,,