truss 0.11.8rc2__py3-none-any.whl → 0.11.8rc4__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.

Potentially problematic release.


This version of truss might be problematic. Click here for more details.

truss/cli/train/core.py CHANGED
@@ -156,7 +156,7 @@ def display_training_projects(projects: list[dict], remote_url: str) -> None:
156
156
  latest_job = project.get("latest_job") or {}
157
157
  if latest_job_id := latest_job.get("id", ""):
158
158
  latest_job_link = cli_common.format_link(
159
- status_page_url(remote_url, latest_job_id), "link"
159
+ status_page_url(remote_url, project["id"], latest_job_id), "link"
160
160
  )
161
161
  else:
162
162
  latest_job_link = ""
@@ -305,8 +305,11 @@ def display_training_job(
305
305
  table.add_row("Created", cli_common.format_localized_time(job["created_at"]))
306
306
  table.add_row("Last Modified", cli_common.format_localized_time(job["updated_at"]))
307
307
  table.add_row(
308
- "Status Page",
309
- cli_common.format_link(status_page_url(remote_url, job["id"]), "link"),
308
+ "Job Page",
309
+ cli_common.format_link(
310
+ status_page_url(remote_url, job["training_project"]["id"], job["id"]),
311
+ "link",
312
+ ),
310
313
  )
311
314
 
312
315
  # Add error message if present
@@ -417,8 +420,8 @@ def download_checkpoint_artifacts(
417
420
  return urls_file
418
421
 
419
422
 
420
- def status_page_url(remote_url: str, training_job_id: str) -> str:
421
- return f"{remote_url}/training/jobs/{training_job_id}"
423
+ def status_page_url(remote_url: str, project_id: str, training_job_id: str) -> str:
424
+ return f"{remote_url}/training/{project_id}/logs/{training_job_id}"
422
425
 
423
426
 
424
427
  def _get_all_train_init_example_options(
@@ -41,13 +41,14 @@ truss_cli.add_command(train)
41
41
 
42
42
  def _print_training_job_success_message(
43
43
  job_id: str,
44
+ project_id: str,
44
45
  project_name: str,
45
- job_object: TrainingJob,
46
+ job_object: Optional[TrainingJob],
46
47
  remote_provider: BasetenRemote,
47
48
  ) -> None:
48
49
  """Print success message and helpful commands for a training job."""
49
50
  console.print("✨ Training job successfully created!", style="green")
50
- should_print_cache_summary = (
51
+ should_print_cache_summary = job_object and (
51
52
  job_object.runtime.enable_cache
52
53
  or job_object.runtime.cache_config
53
54
  and job_object.runtime.cache_config.enabled
@@ -64,7 +65,7 @@ def _print_training_job_success_message(
64
65
  f"🔍 View metrics for your job via "
65
66
  f"[cyan]'truss train metrics --job-id {job_id}'[/cyan]\n"
66
67
  f"{cache_summary_snippet}"
67
- f"🌐 Status page: {common.format_link(core.status_page_url(remote_provider.remote_url, job_id))}"
68
+ f"🌐 View job in the UI: {common.format_link(core.status_page_url(remote_provider.remote_url, project_id, job_id))}"
68
69
  )
69
70
 
70
71
 
@@ -80,8 +81,13 @@ def _handle_post_create_logic(
80
81
  style="green",
81
82
  )
82
83
  else:
84
+ # recreate currently doesn't pass back a job object.
83
85
  _print_training_job_success_message(
84
- job_id, project_name, job_resp["job_object"], remote_provider
86
+ job_id,
87
+ project_id,
88
+ project_name,
89
+ job_resp.get("job_object"),
90
+ remote_provider,
85
91
  )
86
92
 
87
93
  if tail:
@@ -156,11 +162,16 @@ def recreate_training_job(job_id: Optional[str], remote: Optional[str], tail: bo
156
162
  @train.command(name="logs")
157
163
  @click.option("--remote", type=str, required=False, help="Remote to use")
158
164
  @click.option("--project-id", type=str, required=False, help="Project ID.")
165
+ @click.option("--project", type=str, required=False, help="Project name or project id.")
159
166
  @click.option("--job-id", type=str, required=False, help="Job ID.")
160
167
  @click.option("--tail", is_flag=True, help="Tail for ongoing logs.")
161
168
  @common.common_options()
162
169
  def get_job_logs(
163
- remote: Optional[str], project_id: Optional[str], job_id: Optional[str], tail: bool
170
+ remote: Optional[str],
171
+ project_id: Optional[str],
172
+ project: Optional[str],
173
+ job_id: Optional[str],
174
+ tail: bool,
164
175
  ):
165
176
  """Fetch logs for a training job"""
166
177
 
@@ -170,6 +181,10 @@ def get_job_logs(
170
181
  remote_provider: BasetenRemote = cast(
171
182
  BasetenRemote, RemoteFactory.create(remote=remote)
172
183
  )
184
+ project_id = _maybe_resolve_project_id_from_id_or_name(
185
+ remote_provider, project_id=project_id, project=project
186
+ )
187
+
173
188
  project_id, job_id = train_common.get_most_recent_job(
174
189
  remote_provider, project_id, job_id
175
190
  )
@@ -188,12 +203,17 @@ def get_job_logs(
188
203
 
189
204
  @train.command(name="stop")
190
205
  @click.option("--project-id", type=str, required=False, help="Project ID.")
206
+ @click.option("--project", type=str, required=False, help="Project name or project id.")
191
207
  @click.option("--job-id", type=str, required=False, help="Job ID.")
192
208
  @click.option("--all", is_flag=True, help="Stop all running jobs.")
193
209
  @click.option("--remote", type=str, required=False, help="Remote to use")
194
210
  @common.common_options()
195
211
  def stop_job(
196
- project_id: Optional[str], job_id: Optional[str], all: bool, remote: Optional[str]
212
+ project_id: Optional[str],
213
+ project: Optional[str],
214
+ job_id: Optional[str],
215
+ all: bool,
216
+ remote: Optional[str],
197
217
  ):
198
218
  """Stop a training job"""
199
219
 
@@ -203,6 +223,9 @@ def stop_job(
203
223
  remote_provider: BasetenRemote = cast(
204
224
  BasetenRemote, RemoteFactory.create(remote=remote)
205
225
  )
226
+ project_id = _maybe_resolve_project_id_from_id_or_name(
227
+ remote_provider, project_id=project_id, project=project
228
+ )
206
229
  if all:
207
230
  train_cli.stop_all_jobs(remote_provider, project_id)
208
231
  else:
@@ -217,13 +240,17 @@ def stop_job(
217
240
  @click.option(
218
241
  "--project-id", type=str, required=False, help="View training jobs for a project."
219
242
  )
243
+ @click.option("--project", type=str, required=False, help="Project name or project id.")
220
244
  @click.option(
221
245
  "--job-id", type=str, required=False, help="View a specific training job."
222
246
  )
223
247
  @click.option("--remote", type=str, required=False, help="Remote to use")
224
248
  @common.common_options()
225
249
  def view_training(
226
- project_id: Optional[str], job_id: Optional[str], remote: Optional[str]
250
+ project_id: Optional[str],
251
+ project: Optional[str],
252
+ job_id: Optional[str],
253
+ remote: Optional[str],
227
254
  ):
228
255
  """List all training jobs for a project"""
229
256
 
@@ -233,16 +260,24 @@ def view_training(
233
260
  remote_provider: BasetenRemote = cast(
234
261
  BasetenRemote, RemoteFactory.create(remote=remote)
235
262
  )
263
+ project_id = _maybe_resolve_project_id_from_id_or_name(
264
+ remote_provider, project_id=project_id, project=project
265
+ )
266
+
236
267
  train_cli.view_training_details(remote_provider, project_id, job_id)
237
268
 
238
269
 
239
270
  @train.command(name="metrics")
240
271
  @click.option("--project-id", type=str, required=False, help="Project ID.")
272
+ @click.option("--project", type=str, required=False, help="Project name or project id.")
241
273
  @click.option("--job-id", type=str, required=False, help="Job ID.")
242
274
  @click.option("--remote", type=str, required=False, help="Remote to use")
243
275
  @common.common_options()
244
276
  def get_job_metrics(
245
- project_id: Optional[str], job_id: Optional[str], remote: Optional[str]
277
+ project_id: Optional[str],
278
+ project: Optional[str],
279
+ job_id: Optional[str],
280
+ remote: Optional[str],
246
281
  ):
247
282
  """Get metrics for a training job"""
248
283
 
@@ -252,11 +287,15 @@ def get_job_metrics(
252
287
  remote_provider: BasetenRemote = cast(
253
288
  BasetenRemote, RemoteFactory.create(remote=remote)
254
289
  )
290
+ project_id = _maybe_resolve_project_id_from_id_or_name(
291
+ remote_provider, project_id=project_id, project=project
292
+ )
255
293
  train_cli.view_training_job_metrics(remote_provider, project_id, job_id)
256
294
 
257
295
 
258
296
  @train.command(name="deploy_checkpoints")
259
297
  @click.option("--project-id", type=str, required=False, help="Project ID.")
298
+ @click.option("--project", type=str, required=False, help="Project name or project id.")
260
299
  @click.option("--job-id", type=str, required=False, help="Job ID.")
261
300
  @click.option(
262
301
  "--config",
@@ -271,6 +310,7 @@ def get_job_metrics(
271
310
  @common.common_options()
272
311
  def deploy_checkpoints(
273
312
  project_id: Optional[str],
313
+ project: Optional[str],
274
314
  job_id: Optional[str],
275
315
  config: Optional[str],
276
316
  remote: Optional[str],
@@ -286,6 +326,9 @@ def deploy_checkpoints(
286
326
  remote_provider: BasetenRemote = cast(
287
327
  BasetenRemote, RemoteFactory.create(remote=remote)
288
328
  )
329
+ project_id = _maybe_resolve_project_id_from_id_or_name(
330
+ remote_provider, project_id=project_id, project=project
331
+ )
289
332
  prepare_checkpoint_result = train_cli.prepare_checkpoint_deploy(
290
333
  remote_provider,
291
334
  train_cli.PrepareCheckpointArgs(
@@ -492,3 +535,15 @@ def view_cache_summary(project: str, remote: Optional[str], sort: str, order: st
492
535
  )
493
536
 
494
537
  train_cli.view_cache_summary_by_project(remote_provider, project, sort, order)
538
+
539
+
540
+ def _maybe_resolve_project_id_from_id_or_name(
541
+ remote_provider: BasetenRemote, project_id: Optional[str], project: Optional[str]
542
+ ) -> Optional[str]:
543
+ """resolve the project_id or project. `project` can be name or id"""
544
+ if project and project_id:
545
+ console.print("Both `project-id` and `project` provided. Using `project`.")
546
+ project_str = project or project_id
547
+ if not project_str:
548
+ return None
549
+ return train_cli.fetch_project_by_name_or_id(remote_provider, project_str)["id"]
@@ -33,7 +33,7 @@ RUN useradd -u {{ app_user_uid }} -ms /bin/bash {{ app_username }}
33
33
  ENV DEBIAN_FRONTEND=noninteractive
34
34
 
35
35
 
36
- {%- set UV_VERSION = "0.7.19" %}
36
+ {%- set UV_VERSION = "0.8.22" %}
37
37
  {#
38
38
  NB(nikhil): We use a semi-complex uv installation command across the board:
39
39
  - A generous UV_HTTP_TIMEOUT (5m) for packages that take a long time to install.
@@ -59,10 +59,12 @@ RUN {{ python_exec_path }} -c "import sys; \
59
59
  {% endblock %}
60
60
 
61
61
  {% block install_uv %}
62
- {# Install `uv` and `curl` if not already present in the image. #}
62
+ {# Install `uv` and `curl` if not already present in the image. We validate the expected location for `uv` at the very end
63
+ due to limitations with `pipefail` in Docker context. #}
63
64
  RUN if ! command -v uv >/dev/null 2>&1; then \
64
65
  command -v curl >/dev/null 2>&1 || (apt update && apt install -y curl) && \
65
- curl -LsSf --retry 5 --retry-delay 5 https://astral.sh/uv/{{ UV_VERSION }}/install.sh | sh; \
66
+ curl -LsSf --retry 5 --retry-delay 5 https://astral.sh/uv/{{ UV_VERSION }}/install.sh | sh && \
67
+ test -x ${HOME}/.local/bin/uv; \
66
68
  fi
67
69
  {# Add the user's local bin to the path, used by uv. #}
68
70
  ENV PATH=${PATH}:${HOME}/.local/bin
@@ -2,13 +2,15 @@ import asyncio
2
2
  import logging
3
3
  import logging.config
4
4
  import re
5
+ import traceback
6
+ from functools import wraps
5
7
  from pathlib import Path
6
- from typing import Dict
8
+ from typing import Any, Callable, Coroutine, Dict
7
9
 
8
10
  import httpx
9
11
  from endpoints import control_app
10
- from fastapi import FastAPI
11
- from fastapi.responses import JSONResponse
12
+ from fastapi import FastAPI, Request
13
+ from fastapi.responses import JSONResponse, Response
12
14
  from helpers.errors import ModelLoadFailed, PatchApplicatonError
13
15
  from helpers.inference_server_controller import InferenceServerController
14
16
  from helpers.inference_server_process_controller import InferenceServerProcessController
@@ -18,17 +20,43 @@ from shared import log_config
18
20
  from starlette.datastructures import State
19
21
 
20
22
 
23
+ def sanitized_exception_logging(
24
+ original_handler: Callable[[Request, Any], Coroutine[Any, Any, Response]],
25
+ ) -> Callable[[Request, Any], Coroutine[Any, Any, Response]]:
26
+ @wraps(original_handler)
27
+ async def wrapper(request: Request, error: Exception) -> Response:
28
+ logger = request.app.state.logger
29
+ traceback_error = traceback.extract_tb(error.__traceback__)
30
+
31
+ if traceback_error:
32
+ last_frame = traceback_error[-1]
33
+ concise_error = (
34
+ f' File "{last_frame.filename}", line {last_frame.lineno}, in {last_frame.name}\n'
35
+ f" {last_frame.line}"
36
+ )
37
+ else:
38
+ concise_error = f"{type(error).__name__}: {error}"
39
+
40
+ logger.error(concise_error)
41
+ return await original_handler(request, error)
42
+
43
+ return wrapper
44
+
45
+
46
+ @sanitized_exception_logging
21
47
  async def handle_patch_error(_, exc):
22
48
  error_type = _camel_to_snake_case(type(exc).__name__)
23
49
  return JSONResponse(content={"error": {"type": error_type, "msg": str(exc)}})
24
50
 
25
51
 
52
+ @sanitized_exception_logging
26
53
  async def generic_error_handler(_, exc):
27
54
  return JSONResponse(
28
55
  content={"error": {"type": "unknown", "msg": f"{type(exc)}: {exc}"}}
29
56
  )
30
57
 
31
58
 
59
+ @sanitized_exception_logging
32
60
  async def handle_model_load_failed(_, error):
33
61
  # Model load failures should result in 503 status
34
62
  return JSONResponse({"error": str(error)}, 503)
@@ -17,7 +17,8 @@ RUN /usr/local/bin/python3 -c "import sys; \
17
17
  || { echo "ERROR: Supplied base image does not have 3.8 <= python <= 3.13"; exit 1; }
18
18
  RUN if ! command -v uv >/dev/null 2>&1; then \
19
19
  command -v curl >/dev/null 2>&1 || (apt update && apt install -y curl) && \
20
- curl -LsSf --retry 5 --retry-delay 5 https://astral.sh/uv/0.7.19/install.sh | sh; \
20
+ curl -LsSf --retry 5 --retry-delay 5 https://astral.sh/uv/0.8.22/install.sh | sh && \
21
+ test -x ${HOME}/.local/bin/uv; \
21
22
  fi
22
23
  ENV PATH=${PATH}:${HOME}/.local/bin
23
24
  ENV PYTHONUNBUFFERED="True"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: truss
3
- Version: 0.11.8rc2
3
+ Version: 0.11.8rc4
4
4
  Summary: A seamless bridge from model development to model delivery
5
5
  Project-URL: Repository, https://github.com/basetenlabs/truss
6
6
  Project-URL: Homepage, https://truss.baseten.co
@@ -11,13 +11,13 @@ truss/base/truss_spec.py,sha256=jFVF79CXoEEspl2kXBAPyi-rwISReIGTdobGpaIhwJw,5979
11
11
  truss/cli/chains_commands.py,sha256=Kpa5mCg6URAJQE2ZmZfVQFhjBHEitKT28tKiW0H6XAI,17406
12
12
  truss/cli/cli.py,sha256=PaMkuwXZflkU7sa1tEoT_Zmy-iBkEZs1m4IVqcieaeo,30367
13
13
  truss/cli/remote_cli.py,sha256=G_xCKRXzgkCmkiZJhUFfsv5YSVgde1jLA5LPQitpZgI,1905
14
- truss/cli/train_commands.py,sha256=TZhtvofviWQF34pYppRCaQ6qayTsvPnx6afTrYbFpOM,17319
14
+ truss/cli/train_commands.py,sha256=sJN_Qpq-ejHY7KZ555n37PzpYEF-gZiQCVHW5JwUPHo,19303
15
15
  truss/cli/logs/base_watcher.py,sha256=KKyd7lIrdaEeDVt8EtjMioSPGVpLyOcF0ewyzE_GGdQ,2785
16
16
  truss/cli/logs/model_log_watcher.py,sha256=NACcP-wkcaroYa2Cb9BZC7Yr0554WZa_FSM2LXOf4A8,1263
17
17
  truss/cli/logs/training_log_watcher.py,sha256=r6HRqrLnz-PiKTUXiDYYxg4ZnP8vYcXlEX1YmgHhzlo,1173
18
18
  truss/cli/logs/utils.py,sha256=z-U_FG4BUzdZLbE3BnXb4DZQ0zt3LSZ3PiQpLaDuc3o,1031
19
19
  truss/cli/train/common.py,sha256=xTR41U5FeSndXfNBBHF9wF5XwZH1sOIVFlv-XHjsKIU,1547
20
- truss/cli/train/core.py,sha256=Xyl0SgCXIyvoQJLnkIvX6R2gWUVyeDiFHLB1caWJZjs,26154
20
+ truss/cli/train/core.py,sha256=cqE0iBEElqP3oMDpCimuwpCwFyqfOYEBhweCZat7GiI,26262
21
21
  truss/cli/train/deploy_from_checkpoint_config.yml,sha256=mktaVrfhN8Kjx1UveC4xr-gTW-kjwbHvq6bx_LpO-Wg,371
22
22
  truss/cli/train/deploy_from_checkpoint_config_whisper.yml,sha256=6GbOorYC8ml0UyOUvuBpFO_fuYtYE646JqsalR-D4oY,406
23
23
  truss/cli/train/metrics_watcher.py,sha256=smz-zrEsBj_-wJHI0pAZ-EAPrvfCWzq1eQjGiFNM-Mk,12755
@@ -66,14 +66,14 @@ truss/remote/baseten/utils/time.py,sha256=Ry9GMjYnbIGYVIGwtmv4V8ljWjvdcaCf5NOQzl
66
66
  truss/remote/baseten/utils/transfer.py,sha256=d3VptuQb6M1nyS6kz0BAfeOYDLkMKUjatJXpY-mp-As,1548
67
67
  truss/templates/README.md.jinja,sha256=N7CJdyldZuJamj5jLh47le0hFBdu9irVsTBqoxhPNPQ,2476
68
68
  truss/templates/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
69
- truss/templates/base.Dockerfile.jinja,sha256=93UgFjjDzmRILsWjvQBMcWuHY2j-HlP8pkCLmvZz_0o,5098
69
+ truss/templates/base.Dockerfile.jinja,sha256=DgvNqmkt5QRrqy7a9hw6HffmVTUrdGl06oVZ4eeha5Y,5253
70
70
  truss/templates/cache.Dockerfile.jinja,sha256=1qZqDo1phrcqi-Vwol-VafYJkADsBbQWU6huQ-_1x00,1146
71
71
  truss/templates/cache_requirements.txt,sha256=xoPoJ-OVnf1z6oq_RVM3vCr3ionByyqMLj7wGs61nUs,87
72
72
  truss/templates/copy_cache_files.Dockerfile.jinja,sha256=Os5zFdYLZ_AfCRGq4RcpVTObOTwL7zvmwYcvOzd_Zqo,126
73
73
  truss/templates/docker_server_requirements.txt,sha256=PyhOPKAmKW1N2vLvTfLMwsEtuGpoRrbWuNo7tT6v2Mc,18
74
74
  truss/templates/server.Dockerfile.jinja,sha256=CUYnF_hgxPGq2re7__0UPWlwzOHMoFkxp6NVKi3U16s,7071
75
75
  truss/templates/control/requirements.txt,sha256=nqqNmlTwFeV8sV4fqwItwzzd_egADBP_e-cEopXBJ4k,358
76
- truss/templates/control/control/application.py,sha256=jYeta6hWe1SkfLL3W4IDmdYjg3ZuKqI_UagWYs5RB_E,3793
76
+ truss/templates/control/control/application.py,sha256=Js6I1b5lxgi8Ylyj2-g3UeEqpKnSvvdYiXq-jSq2XX8,4803
77
77
  truss/templates/control/control/endpoints.py,sha256=VQ1lvZjFvR091yRkiFdvXw1Q7PiNGXT9rJwY7_sX6yg,11828
78
78
  truss/templates/control/control/server.py,sha256=R4Y219i1dcz0kkksN8obLoX-YXWGo9iW1igindyG50c,3128
79
79
  truss/templates/control/control/helpers/context_managers.py,sha256=W6dyFgLBhPa5meqrOb3w_phMtKfaJI-GhwUfpiycDc8,413
@@ -184,7 +184,7 @@ truss/tests/test_data/pima-indians-diabetes.csv,sha256=BvW3ws17ymhv2k-S6rX2Hn_2Q
184
184
  truss/tests/test_data/readme_int_example.md,sha256=fuHvpLtdkJy1f4NAR_djotVBdzusHYNXc-Fwh588XAE,1586
185
185
  truss/tests/test_data/readme_no_example.md,sha256=T2CzFMRvICXeX3_5XbFoqhHchcHGot-xM7izx34B3aQ,1607
186
186
  truss/tests/test_data/readme_str_example.md,sha256=fP4pvMqgLdIapaOf_BgRiV0H7pw4so0RNxrlq5lbROE,1726
187
- truss/tests/test_data/server.Dockerfile,sha256=64M9aAB-Ar5Yl0k9r5WFxVb-4iUShm_OR1w9pKJfDgg,1985
187
+ truss/tests/test_data/server.Dockerfile,sha256=3rWiU3RxBh0PIh8pS23FnP8UA-ErmzxTlgf_J22mMQ8,2024
188
188
  truss/tests/test_data/annotated_types_truss/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
189
189
  truss/tests/test_data/annotated_types_truss/config.yaml,sha256=B-ZyyjLLqtxGfXj2tkH68Hy7NOMB_coYvoWyWom61g0,147
190
190
  truss/tests/test_data/annotated_types_truss/model/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -368,8 +368,8 @@ truss_train/deployment.py,sha256=lWWANSuzBWu2M4oK4qD7n-oVR1JKdmw2Pn5BJQHg-Ck,307
368
368
  truss_train/loader.py,sha256=0o66EjBaHc2YY4syxxHVR4ordJWs13lNXnKjKq2wq0U,1630
369
369
  truss_train/public_api.py,sha256=9N_NstiUlmBuLUwH_fNG_1x7OhGCytZLNvqKXBlStrM,1220
370
370
  truss_train/restore_from_checkpoint.py,sha256=8hdPm-WSgkt74HDPjvCjZMBpvA9MwtoYsxVjOoa7BaM,1176
371
- truss-0.11.8rc2.dist-info/METADATA,sha256=NIPV3aMNwl9z0RIyWN2JObtaNyTFnxccFdJObD4T0Hc,6680
372
- truss-0.11.8rc2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
373
- truss-0.11.8rc2.dist-info/entry_points.txt,sha256=-MwKfHHQHQ6j0HqIgvxrz3CehCmczDLTD-OsRHnjjuU,130
374
- truss-0.11.8rc2.dist-info/licenses/LICENSE,sha256=FTqGzu85i-uw1Gi8E_o0oD60bH9yQ_XIGtZbA1QUYiw,1064
375
- truss-0.11.8rc2.dist-info/RECORD,,
371
+ truss-0.11.8rc4.dist-info/METADATA,sha256=L17Z01_P_5zrhwF9d9sK1tGmAS-_vLI1YoVAVs0Vpvk,6680
372
+ truss-0.11.8rc4.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
373
+ truss-0.11.8rc4.dist-info/entry_points.txt,sha256=-MwKfHHQHQ6j0HqIgvxrz3CehCmczDLTD-OsRHnjjuU,130
374
+ truss-0.11.8rc4.dist-info/licenses/LICENSE,sha256=FTqGzu85i-uw1Gi8E_o0oD60bH9yQ_XIGtZbA1QUYiw,1064
375
+ truss-0.11.8rc4.dist-info/RECORD,,