truss 0.10.0rc1__py3-none-any.whl → 0.60.0__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.

Files changed (362) hide show
  1. truss/__init__.py +10 -3
  2. truss/api/__init__.py +123 -0
  3. truss/api/definitions.py +51 -0
  4. truss/base/constants.py +116 -0
  5. truss/base/custom_types.py +29 -0
  6. truss/{errors.py → base/errors.py} +4 -0
  7. truss/base/trt_llm_config.py +310 -0
  8. truss/{truss_config.py → base/truss_config.py} +344 -31
  9. truss/{truss_spec.py → base/truss_spec.py} +20 -6
  10. truss/{validation.py → base/validation.py} +60 -11
  11. truss/cli/cli.py +841 -88
  12. truss/{remote → cli}/remote_cli.py +2 -7
  13. truss/contexts/docker_build_setup.py +67 -0
  14. truss/contexts/image_builder/cache_warmer.py +2 -8
  15. truss/contexts/image_builder/image_builder.py +1 -1
  16. truss/contexts/image_builder/serving_image_builder.py +292 -46
  17. truss/contexts/image_builder/util.py +1 -3
  18. truss/contexts/local_loader/docker_build_emulator.py +58 -0
  19. truss/contexts/local_loader/load_model_local.py +2 -2
  20. truss/contexts/local_loader/truss_module_loader.py +1 -1
  21. truss/contexts/local_loader/utils.py +1 -1
  22. truss/local/local_config.py +2 -6
  23. truss/local/local_config_handler.py +20 -5
  24. truss/patch/__init__.py +1 -0
  25. truss/patch/hash.py +4 -70
  26. truss/patch/signature.py +4 -16
  27. truss/patch/truss_dir_patch_applier.py +3 -78
  28. truss/remote/baseten/api.py +308 -23
  29. truss/remote/baseten/auth.py +3 -3
  30. truss/remote/baseten/core.py +257 -50
  31. truss/remote/baseten/custom_types.py +44 -0
  32. truss/remote/baseten/error.py +4 -0
  33. truss/remote/baseten/remote.py +369 -118
  34. truss/remote/baseten/service.py +118 -11
  35. truss/remote/baseten/utils/status.py +29 -0
  36. truss/remote/baseten/utils/tar.py +34 -22
  37. truss/remote/baseten/utils/transfer.py +36 -23
  38. truss/remote/remote_factory.py +14 -5
  39. truss/remote/truss_remote.py +72 -45
  40. truss/templates/base.Dockerfile.jinja +18 -16
  41. truss/templates/cache.Dockerfile.jinja +3 -3
  42. truss/{server → templates/control}/control/application.py +14 -35
  43. truss/{server → templates/control}/control/endpoints.py +39 -9
  44. truss/{server/control/patch/types.py → templates/control/control/helpers/custom_types.py} +13 -52
  45. truss/{server → templates/control}/control/helpers/inference_server_controller.py +4 -8
  46. truss/{server → templates/control}/control/helpers/inference_server_process_controller.py +2 -4
  47. truss/{server → templates/control}/control/helpers/inference_server_starter.py +5 -10
  48. truss/{server/control → templates/control/control/helpers}/truss_patch/model_code_patch_applier.py +8 -6
  49. truss/{server/control/patch → templates/control/control/helpers/truss_patch}/model_container_patch_applier.py +18 -26
  50. truss/templates/control/control/helpers/truss_patch/requirement_name_identifier.py +66 -0
  51. truss/{server → templates/control}/control/server.py +11 -6
  52. truss/templates/control/requirements.txt +9 -0
  53. truss/templates/custom_python_dx/my_model.py +28 -0
  54. truss/templates/docker_server/proxy.conf.jinja +42 -0
  55. truss/templates/docker_server/supervisord.conf.jinja +27 -0
  56. truss/templates/docker_server_requirements.txt +1 -0
  57. truss/templates/server/common/errors.py +231 -0
  58. truss/{server → templates/server}/common/patches/whisper/patch.py +1 -0
  59. truss/{server/common/patches/__init__.py → templates/server/common/patches.py} +1 -3
  60. truss/{server → templates/server}/common/retry.py +1 -0
  61. truss/{server → templates/server}/common/schema.py +11 -9
  62. truss/templates/server/common/tracing.py +157 -0
  63. truss/templates/server/main.py +9 -0
  64. truss/templates/server/model_wrapper.py +961 -0
  65. truss/templates/server/requirements.txt +21 -0
  66. truss/templates/server/truss_server.py +447 -0
  67. truss/templates/server.Dockerfile.jinja +62 -14
  68. truss/templates/shared/dynamic_config_resolver.py +28 -0
  69. truss/templates/shared/lazy_data_resolver.py +164 -0
  70. truss/templates/shared/log_config.py +125 -0
  71. truss/{server → templates}/shared/secrets_resolver.py +1 -2
  72. truss/{server → templates}/shared/serialization.py +31 -9
  73. truss/{server → templates}/shared/util.py +3 -13
  74. truss/templates/trtllm-audio/model/model.py +49 -0
  75. truss/templates/trtllm-audio/packages/sigint_patch.py +14 -0
  76. truss/templates/trtllm-audio/packages/whisper_trt/__init__.py +215 -0
  77. truss/templates/trtllm-audio/packages/whisper_trt/assets.py +25 -0
  78. truss/templates/trtllm-audio/packages/whisper_trt/batching.py +52 -0
  79. truss/templates/trtllm-audio/packages/whisper_trt/custom_types.py +26 -0
  80. truss/templates/trtllm-audio/packages/whisper_trt/modeling.py +184 -0
  81. truss/templates/trtllm-audio/packages/whisper_trt/tokenizer.py +185 -0
  82. truss/templates/trtllm-audio/packages/whisper_trt/utils.py +245 -0
  83. truss/templates/trtllm-briton/src/extension.py +64 -0
  84. truss/tests/conftest.py +302 -94
  85. truss/tests/contexts/image_builder/test_serving_image_builder.py +74 -31
  86. truss/tests/contexts/local_loader/test_load_local.py +2 -2
  87. truss/tests/contexts/local_loader/test_truss_module_finder.py +1 -1
  88. truss/tests/patch/test_calc_patch.py +439 -127
  89. truss/tests/patch/test_dir_signature.py +3 -12
  90. truss/tests/patch/test_hash.py +1 -1
  91. truss/tests/patch/test_signature.py +1 -1
  92. truss/tests/patch/test_truss_dir_patch_applier.py +23 -11
  93. truss/tests/patch/test_types.py +2 -2
  94. truss/tests/remote/baseten/test_api.py +153 -58
  95. truss/tests/remote/baseten/test_auth.py +2 -1
  96. truss/tests/remote/baseten/test_core.py +160 -12
  97. truss/tests/remote/baseten/test_remote.py +489 -77
  98. truss/tests/remote/baseten/test_service.py +55 -0
  99. truss/tests/remote/test_remote_factory.py +16 -18
  100. truss/tests/remote/test_truss_remote.py +26 -17
  101. truss/tests/templates/control/control/helpers/test_context_managers.py +11 -0
  102. truss/tests/templates/control/control/helpers/test_model_container_patch_applier.py +184 -0
  103. truss/tests/templates/control/control/helpers/test_requirement_name_identifier.py +89 -0
  104. truss/tests/{server → templates/control}/control/test_server.py +79 -24
  105. truss/tests/{server → templates/control}/control/test_server_integration.py +24 -16
  106. truss/tests/templates/core/server/test_dynamic_config_resolver.py +108 -0
  107. truss/tests/templates/core/server/test_lazy_data_resolver.py +329 -0
  108. truss/tests/templates/core/server/test_lazy_data_resolver_v2.py +79 -0
  109. truss/tests/{server → templates}/core/server/test_secrets_resolver.py +1 -1
  110. truss/tests/{server → templates/server}/common/test_retry.py +3 -3
  111. truss/tests/templates/server/test_model_wrapper.py +248 -0
  112. truss/tests/{server → templates/server}/test_schema.py +3 -5
  113. truss/tests/{server/core/server/common → templates/server}/test_truss_server.py +8 -5
  114. truss/tests/test_build.py +9 -52
  115. truss/tests/test_config.py +336 -77
  116. truss/tests/test_context_builder_image.py +3 -11
  117. truss/tests/test_control_truss_patching.py +7 -12
  118. truss/tests/test_custom_server.py +38 -0
  119. truss/tests/test_data/context_builder_image_test/test.py +3 -0
  120. truss/tests/test_data/happy.ipynb +56 -0
  121. truss/tests/test_data/model_load_failure_test/config.yaml +2 -0
  122. truss/tests/test_data/model_load_failure_test/model/__init__.py +0 -0
  123. truss/tests/test_data/patch_ping_test_server/__init__.py +0 -0
  124. truss/{test_data → tests/test_data}/patch_ping_test_server/app.py +3 -9
  125. truss/{test_data → tests/test_data}/server.Dockerfile +20 -21
  126. truss/tests/test_data/server_conformance_test_truss/__init__.py +0 -0
  127. truss/tests/test_data/server_conformance_test_truss/model/__init__.py +0 -0
  128. truss/{test_data → tests/test_data}/server_conformance_test_truss/model/model.py +1 -3
  129. truss/tests/test_data/test_async_truss/__init__.py +0 -0
  130. truss/tests/test_data/test_async_truss/model/__init__.py +0 -0
  131. truss/tests/test_data/test_basic_truss/__init__.py +0 -0
  132. truss/tests/test_data/test_basic_truss/config.yaml +16 -0
  133. truss/tests/test_data/test_basic_truss/model/__init__.py +0 -0
  134. truss/tests/test_data/test_build_commands/__init__.py +0 -0
  135. truss/tests/test_data/test_build_commands/config.yaml +13 -0
  136. truss/tests/test_data/test_build_commands/model/__init__.py +0 -0
  137. truss/{test_data/test_streaming_async_generator_truss → tests/test_data/test_build_commands}/model/model.py +2 -3
  138. truss/tests/test_data/test_build_commands_failure/__init__.py +0 -0
  139. truss/tests/test_data/test_build_commands_failure/config.yaml +14 -0
  140. truss/tests/test_data/test_build_commands_failure/model/__init__.py +0 -0
  141. truss/tests/test_data/test_build_commands_failure/model/model.py +17 -0
  142. truss/tests/test_data/test_concurrency_truss/__init__.py +0 -0
  143. truss/tests/test_data/test_concurrency_truss/config.yaml +4 -0
  144. truss/tests/test_data/test_concurrency_truss/model/__init__.py +0 -0
  145. truss/tests/test_data/test_custom_server_truss/__init__.py +0 -0
  146. truss/tests/test_data/test_custom_server_truss/config.yaml +20 -0
  147. truss/tests/test_data/test_custom_server_truss/test_docker_image/Dockerfile +17 -0
  148. truss/tests/test_data/test_custom_server_truss/test_docker_image/README.md +10 -0
  149. truss/tests/test_data/test_custom_server_truss/test_docker_image/VERSION +1 -0
  150. truss/tests/test_data/test_custom_server_truss/test_docker_image/__init__.py +0 -0
  151. truss/tests/test_data/test_custom_server_truss/test_docker_image/app.py +19 -0
  152. truss/tests/test_data/test_custom_server_truss/test_docker_image/build_upload_new_image.sh +6 -0
  153. truss/tests/test_data/test_openai/__init__.py +0 -0
  154. truss/{test_data/test_basic_truss → tests/test_data/test_openai}/config.yaml +1 -2
  155. truss/tests/test_data/test_openai/model/__init__.py +0 -0
  156. truss/tests/test_data/test_openai/model/model.py +15 -0
  157. truss/tests/test_data/test_pyantic_v1/__init__.py +0 -0
  158. truss/tests/test_data/test_pyantic_v1/model/__init__.py +0 -0
  159. truss/tests/test_data/test_pyantic_v1/model/model.py +28 -0
  160. truss/tests/test_data/test_pyantic_v1/requirements.txt +1 -0
  161. truss/tests/test_data/test_pyantic_v2/__init__.py +0 -0
  162. truss/tests/test_data/test_pyantic_v2/config.yaml +13 -0
  163. truss/tests/test_data/test_pyantic_v2/model/__init__.py +0 -0
  164. truss/tests/test_data/test_pyantic_v2/model/model.py +30 -0
  165. truss/tests/test_data/test_pyantic_v2/requirements.txt +1 -0
  166. truss/tests/test_data/test_requirements_file_truss/__init__.py +0 -0
  167. truss/tests/test_data/test_requirements_file_truss/config.yaml +13 -0
  168. truss/tests/test_data/test_requirements_file_truss/model/__init__.py +0 -0
  169. truss/{test_data → tests/test_data}/test_requirements_file_truss/model/model.py +1 -0
  170. truss/tests/test_data/test_streaming_async_generator_truss/__init__.py +0 -0
  171. truss/tests/test_data/test_streaming_async_generator_truss/config.yaml +4 -0
  172. truss/tests/test_data/test_streaming_async_generator_truss/model/__init__.py +0 -0
  173. truss/tests/test_data/test_streaming_async_generator_truss/model/model.py +7 -0
  174. truss/tests/test_data/test_streaming_read_timeout/__init__.py +0 -0
  175. truss/tests/test_data/test_streaming_read_timeout/model/__init__.py +0 -0
  176. truss/tests/test_data/test_streaming_truss/__init__.py +0 -0
  177. truss/tests/test_data/test_streaming_truss/config.yaml +4 -0
  178. truss/tests/test_data/test_streaming_truss/model/__init__.py +0 -0
  179. truss/tests/test_data/test_streaming_truss_with_error/__init__.py +0 -0
  180. truss/tests/test_data/test_streaming_truss_with_error/model/__init__.py +0 -0
  181. truss/{test_data → tests/test_data}/test_streaming_truss_with_error/model/model.py +3 -11
  182. truss/tests/test_data/test_streaming_truss_with_error/packages/__init__.py +0 -0
  183. truss/tests/test_data/test_streaming_truss_with_error/packages/helpers_1.py +5 -0
  184. truss/tests/test_data/test_streaming_truss_with_error/packages/helpers_2.py +2 -0
  185. truss/tests/test_data/test_streaming_truss_with_tracing/__init__.py +0 -0
  186. truss/tests/test_data/test_streaming_truss_with_tracing/config.yaml +43 -0
  187. truss/tests/test_data/test_streaming_truss_with_tracing/model/__init__.py +0 -0
  188. truss/tests/test_data/test_streaming_truss_with_tracing/model/model.py +65 -0
  189. truss/tests/test_data/test_trt_llm_truss/__init__.py +0 -0
  190. truss/tests/test_data/test_trt_llm_truss/config.yaml +15 -0
  191. truss/tests/test_data/test_trt_llm_truss/model/__init__.py +0 -0
  192. truss/tests/test_data/test_trt_llm_truss/model/model.py +15 -0
  193. truss/tests/test_data/test_truss/__init__.py +0 -0
  194. truss/tests/test_data/test_truss/config.yaml +4 -0
  195. truss/tests/test_data/test_truss/model/__init__.py +0 -0
  196. truss/tests/test_data/test_truss/model/dummy +0 -0
  197. truss/tests/test_data/test_truss/packages/__init__.py +0 -0
  198. truss/tests/test_data/test_truss/packages/test_package/__init__.py +0 -0
  199. truss/tests/test_data/test_truss_server_caching_truss/__init__.py +0 -0
  200. truss/tests/test_data/test_truss_server_caching_truss/model/__init__.py +0 -0
  201. truss/tests/test_data/test_truss_with_error/__init__.py +0 -0
  202. truss/tests/test_data/test_truss_with_error/config.yaml +4 -0
  203. truss/tests/test_data/test_truss_with_error/model/__init__.py +0 -0
  204. truss/tests/test_data/test_truss_with_error/model/model.py +8 -0
  205. truss/tests/test_data/test_truss_with_error/packages/__init__.py +0 -0
  206. truss/tests/test_data/test_truss_with_error/packages/helpers_1.py +5 -0
  207. truss/tests/test_data/test_truss_with_error/packages/helpers_2.py +2 -0
  208. truss/tests/test_docker.py +2 -1
  209. truss/tests/test_model_inference.py +1340 -292
  210. truss/tests/test_model_schema.py +33 -26
  211. truss/tests/test_testing_utilities_for_other_tests.py +50 -5
  212. truss/tests/test_truss_gatherer.py +3 -5
  213. truss/tests/test_truss_handle.py +62 -59
  214. truss/tests/test_util.py +2 -1
  215. truss/tests/test_validation.py +15 -13
  216. truss/tests/trt_llm/test_trt_llm_config.py +41 -0
  217. truss/tests/trt_llm/test_validation.py +91 -0
  218. truss/tests/util/test_config_checks.py +40 -0
  219. truss/tests/util/test_env_vars.py +14 -0
  220. truss/tests/util/test_path.py +10 -23
  221. truss/trt_llm/config_checks.py +43 -0
  222. truss/trt_llm/validation.py +42 -0
  223. truss/truss_handle/__init__.py +0 -0
  224. truss/truss_handle/build.py +122 -0
  225. truss/{decorators.py → truss_handle/decorators.py} +1 -1
  226. truss/truss_handle/patch/__init__.py +0 -0
  227. truss/{patch → truss_handle/patch}/calc_patch.py +146 -92
  228. truss/{types.py → truss_handle/patch/custom_types.py} +35 -27
  229. truss/{patch → truss_handle/patch}/dir_signature.py +1 -1
  230. truss/truss_handle/patch/hash.py +71 -0
  231. truss/{patch → truss_handle/patch}/local_truss_patch_applier.py +6 -4
  232. truss/truss_handle/patch/signature.py +22 -0
  233. truss/truss_handle/patch/truss_dir_patch_applier.py +87 -0
  234. truss/{readme_generator.py → truss_handle/readme_generator.py} +3 -2
  235. truss/{truss_gatherer.py → truss_handle/truss_gatherer.py} +3 -2
  236. truss/{truss_handle.py → truss_handle/truss_handle.py} +174 -78
  237. truss/util/.truss_ignore +3 -0
  238. truss/{docker.py → util/docker.py} +6 -2
  239. truss/util/download.py +6 -15
  240. truss/util/env_vars.py +41 -0
  241. truss/util/log_utils.py +52 -0
  242. truss/util/path.py +20 -20
  243. truss/util/requirements.py +11 -0
  244. {truss-0.10.0rc1.dist-info → truss-0.60.0.dist-info}/METADATA +18 -16
  245. truss-0.60.0.dist-info/RECORD +324 -0
  246. {truss-0.10.0rc1.dist-info → truss-0.60.0.dist-info}/WHEEL +1 -1
  247. truss-0.60.0.dist-info/entry_points.txt +4 -0
  248. truss_chains/__init__.py +71 -0
  249. truss_chains/definitions.py +756 -0
  250. truss_chains/deployment/__init__.py +0 -0
  251. truss_chains/deployment/code_gen.py +816 -0
  252. truss_chains/deployment/deployment_client.py +871 -0
  253. truss_chains/framework.py +1480 -0
  254. truss_chains/public_api.py +231 -0
  255. truss_chains/py.typed +0 -0
  256. truss_chains/pydantic_numpy.py +131 -0
  257. truss_chains/reference_code/reference_chainlet.py +34 -0
  258. truss_chains/reference_code/reference_model.py +10 -0
  259. truss_chains/remote_chainlet/__init__.py +0 -0
  260. truss_chains/remote_chainlet/model_skeleton.py +60 -0
  261. truss_chains/remote_chainlet/stub.py +380 -0
  262. truss_chains/remote_chainlet/utils.py +332 -0
  263. truss_chains/streaming.py +378 -0
  264. truss_chains/utils.py +178 -0
  265. CODE_OF_CONDUCT.md +0 -131
  266. CONTRIBUTING.md +0 -48
  267. README.md +0 -137
  268. context_builder.Dockerfile +0 -24
  269. truss/blob/blob_backend.py +0 -10
  270. truss/blob/blob_backend_registry.py +0 -23
  271. truss/blob/http_public_blob_backend.py +0 -23
  272. truss/build/__init__.py +0 -2
  273. truss/build/build.py +0 -143
  274. truss/build/configure.py +0 -63
  275. truss/cli/__init__.py +0 -2
  276. truss/cli/console.py +0 -5
  277. truss/cli/create.py +0 -5
  278. truss/config/trt_llm.py +0 -81
  279. truss/constants.py +0 -61
  280. truss/model_inference.py +0 -123
  281. truss/patch/types.py +0 -30
  282. truss/pytest.ini +0 -7
  283. truss/server/common/errors.py +0 -100
  284. truss/server/common/termination_handler_middleware.py +0 -64
  285. truss/server/common/truss_server.py +0 -389
  286. truss/server/control/patch/model_code_patch_applier.py +0 -46
  287. truss/server/control/patch/requirement_name_identifier.py +0 -17
  288. truss/server/inference_server.py +0 -29
  289. truss/server/model_wrapper.py +0 -434
  290. truss/server/shared/logging.py +0 -81
  291. truss/templates/trtllm/model/model.py +0 -97
  292. truss/templates/trtllm/packages/build_engine_utils.py +0 -34
  293. truss/templates/trtllm/packages/constants.py +0 -11
  294. truss/templates/trtllm/packages/schema.py +0 -216
  295. truss/templates/trtllm/packages/tensorrt_llm_model_repository/ensemble/config.pbtxt +0 -246
  296. truss/templates/trtllm/packages/tensorrt_llm_model_repository/postprocessing/1/model.py +0 -181
  297. truss/templates/trtllm/packages/tensorrt_llm_model_repository/postprocessing/config.pbtxt +0 -64
  298. truss/templates/trtllm/packages/tensorrt_llm_model_repository/preprocessing/1/model.py +0 -260
  299. truss/templates/trtllm/packages/tensorrt_llm_model_repository/preprocessing/config.pbtxt +0 -99
  300. truss/templates/trtllm/packages/tensorrt_llm_model_repository/tensorrt_llm/config.pbtxt +0 -208
  301. truss/templates/trtllm/packages/triton_client.py +0 -150
  302. truss/templates/trtllm/packages/utils.py +0 -43
  303. truss/test_data/context_builder_image_test/test.py +0 -4
  304. truss/test_data/happy.ipynb +0 -54
  305. truss/test_data/model_load_failure_test/config.yaml +0 -2
  306. truss/test_data/test_concurrency_truss/config.yaml +0 -2
  307. truss/test_data/test_streaming_async_generator_truss/config.yaml +0 -2
  308. truss/test_data/test_streaming_truss/config.yaml +0 -3
  309. truss/test_data/test_truss/config.yaml +0 -2
  310. truss/tests/server/common/test_termination_handler_middleware.py +0 -93
  311. truss/tests/server/control/test_model_container_patch_applier.py +0 -203
  312. truss/tests/server/core/server/common/test_util.py +0 -19
  313. truss/tests/server/test_model_wrapper.py +0 -87
  314. truss/util/data_structures.py +0 -16
  315. truss-0.10.0rc1.dist-info/RECORD +0 -216
  316. truss-0.10.0rc1.dist-info/entry_points.txt +0 -3
  317. truss/{server/shared → base}/__init__.py +0 -0
  318. truss/{server → templates/control}/control/helpers/context_managers.py +0 -0
  319. truss/{server/control → templates/control/control/helpers}/errors.py +0 -0
  320. truss/{server/control/patch → templates/control/control/helpers/truss_patch}/__init__.py +0 -0
  321. truss/{server/control/patch → templates/control/control/helpers/truss_patch}/system_packages.py +0 -0
  322. truss/{test_data/annotated_types_truss/model → templates/server}/__init__.py +0 -0
  323. truss/{server → templates/server}/common/__init__.py +0 -0
  324. truss/{test_data/gcs_fix/model → templates/shared}/__init__.py +0 -0
  325. truss/templates/{trtllm → trtllm-briton}/README.md +0 -0
  326. truss/{test_data/server_conformance_test_truss/model → tests/test_data}/__init__.py +0 -0
  327. truss/{test_data/test_basic_truss/model → tests/test_data/annotated_types_truss}/__init__.py +0 -0
  328. truss/{test_data → tests/test_data}/annotated_types_truss/config.yaml +0 -0
  329. truss/{test_data/test_requirements_file_truss → tests/test_data/annotated_types_truss}/model/__init__.py +0 -0
  330. truss/{test_data → tests/test_data}/annotated_types_truss/model/model.py +0 -0
  331. truss/{test_data → tests/test_data}/auto-mpg.data +0 -0
  332. truss/{test_data → tests/test_data}/context_builder_image_test/Dockerfile +0 -0
  333. truss/{test_data/test_truss/model → tests/test_data/context_builder_image_test}/__init__.py +0 -0
  334. truss/{test_data/test_truss_server_caching_truss/model → tests/test_data/gcs_fix}/__init__.py +0 -0
  335. truss/{test_data → tests/test_data}/gcs_fix/config.yaml +0 -0
  336. truss/tests/{local → test_data/gcs_fix/model}/__init__.py +0 -0
  337. truss/{test_data → tests/test_data}/gcs_fix/model/model.py +0 -0
  338. truss/{test_data/test_truss/model/dummy → tests/test_data/model_load_failure_test/__init__.py} +0 -0
  339. truss/{test_data → tests/test_data}/model_load_failure_test/model/model.py +0 -0
  340. truss/{test_data → tests/test_data}/pima-indians-diabetes.csv +0 -0
  341. truss/{test_data → tests/test_data}/readme_int_example.md +0 -0
  342. truss/{test_data → tests/test_data}/readme_no_example.md +0 -0
  343. truss/{test_data → tests/test_data}/readme_str_example.md +0 -0
  344. truss/{test_data → tests/test_data}/server_conformance_test_truss/config.yaml +0 -0
  345. truss/{test_data → tests/test_data}/test_async_truss/config.yaml +0 -0
  346. truss/{test_data → tests/test_data}/test_async_truss/model/model.py +3 -3
  347. /truss/{test_data → tests/test_data}/test_basic_truss/model/model.py +0 -0
  348. /truss/{test_data → tests/test_data}/test_concurrency_truss/model/model.py +0 -0
  349. /truss/{test_data/test_requirements_file_truss → tests/test_data/test_pyantic_v1}/config.yaml +0 -0
  350. /truss/{test_data → tests/test_data}/test_requirements_file_truss/requirements.txt +0 -0
  351. /truss/{test_data → tests/test_data}/test_streaming_read_timeout/config.yaml +0 -0
  352. /truss/{test_data → tests/test_data}/test_streaming_read_timeout/model/model.py +0 -0
  353. /truss/{test_data → tests/test_data}/test_streaming_truss/model/model.py +0 -0
  354. /truss/{test_data → tests/test_data}/test_streaming_truss_with_error/config.yaml +0 -0
  355. /truss/{test_data → tests/test_data}/test_truss/examples.yaml +0 -0
  356. /truss/{test_data → tests/test_data}/test_truss/model/model.py +0 -0
  357. /truss/{test_data → tests/test_data}/test_truss/packages/test_package/test.py +0 -0
  358. /truss/{test_data → tests/test_data}/test_truss_server_caching_truss/config.yaml +0 -0
  359. /truss/{test_data → tests/test_data}/test_truss_server_caching_truss/model/model.py +0 -0
  360. /truss/{patch → truss_handle/patch}/constants.py +0 -0
  361. /truss/{notebook.py → util/notebook.py} +0 -0
  362. {truss-0.10.0rc1.dist-info → truss-0.60.0.dist-info}/LICENSE +0 -0
@@ -1,12 +1,91 @@
1
- from typing import Dict, Optional
2
-
1
+ import enum
2
+ import time
3
+ import urllib.parse
4
+ import warnings
5
+ from typing import Any, Dict, Iterator, NamedTuple, Optional
6
+
7
+ import requests
8
+ from tenacity import retry, stop_after_delay, wait_fixed
9
+ from truss.base.errors import RemoteNetworkError
10
+ from truss.remote.baseten.api import BasetenApi
3
11
  from truss.remote.baseten.auth import AuthService
4
12
  from truss.remote.truss_remote import TrussService
5
- from truss.truss_handle import TrussHandle
13
+ from truss.truss_handle.truss_handle import TrussHandle
14
+
15
+ # "classes created inside an enum will not become a member" -> intended here anyway.
16
+ warnings.filterwarnings("ignore", category=DeprecationWarning, message=".*enum.*")
6
17
 
7
18
  DEFAULT_STREAM_ENCODING = "utf-8"
8
19
 
9
20
 
21
+ def _add_model_subdomain(rest_api_url: str, model_subdomain: str) -> str:
22
+ """E.g. `https://api.baseten.co` -> `https://{model_subdomain}.api.baseten.co`"""
23
+ parsed_url = urllib.parse.urlparse(rest_api_url)
24
+ new_netloc = f"{model_subdomain}.{parsed_url.netloc}"
25
+ model_url = parsed_url._replace(netloc=new_netloc)
26
+ return str(urllib.parse.urlunparse(model_url))
27
+
28
+
29
+ class URLConfig(enum.Enum):
30
+ class Data(NamedTuple):
31
+ prefix: str
32
+ invoke_endpoint: str
33
+ app_endpoint: str
34
+
35
+ MODEL = Data("model", "predict", "models")
36
+ CHAIN = Data("chain", "run_remote", "chains")
37
+
38
+ @staticmethod
39
+ def invocation_url(
40
+ api_url: str, # E.g. https://api.baseten.co
41
+ config: "URLConfig",
42
+ entity_id: str,
43
+ entity_version_id: str,
44
+ is_draft,
45
+ ) -> str:
46
+ """Get the URL for the predict/run_remote endpoint."""
47
+ # E.g. `https://api.baseten.co` -> `https://model-{model_id}.api.baseten.co`
48
+ url = _add_model_subdomain(api_url, f"{config.value.prefix}-{entity_id}")
49
+ if is_draft:
50
+ # "https://model-{model_id}.api.baseten.co/development".
51
+ url = f"{url}/development/{config.value.invoke_endpoint}"
52
+ else:
53
+ # "https://model-{model_id}.api.baseten.co/deployment/{deployment_id}".
54
+ url = f"{url}/deployment/{entity_version_id}/{config.value.invoke_endpoint}"
55
+ return url
56
+
57
+ @staticmethod
58
+ def status_page_url(
59
+ app_url: str, # E.g. https://app.baseten.co/
60
+ config: "URLConfig",
61
+ entity_id: str,
62
+ ) -> str:
63
+ return f"{app_url}/{config.value.app_endpoint}/{entity_id}/overview"
64
+
65
+ @staticmethod
66
+ def model_logs_url(
67
+ app_url: str, # E.g. https://app.baseten.co/
68
+ model_id: str,
69
+ model_version_id: str,
70
+ ) -> str:
71
+ return (
72
+ f"{app_url}/{URLConfig.MODEL.value.app_endpoint}/{model_id}/logs/"
73
+ f"{model_version_id}"
74
+ )
75
+
76
+ @staticmethod
77
+ def chainlet_logs_url(
78
+ app_url: str, # E.g. https://app.baseten.co/
79
+ chain_id: str,
80
+ chain_deployment_id: str,
81
+ chainlet_id: str,
82
+ ) -> str:
83
+ return (
84
+ f"{app_url}/{URLConfig.CHAIN.value.app_endpoint}/{chain_id}/logs/"
85
+ f"{chain_deployment_id}/{chainlet_id}"
86
+ )
87
+
88
+
10
89
  class BasetenService(TrussService):
11
90
  def __init__(
12
91
  self,
@@ -15,12 +94,14 @@ class BasetenService(TrussService):
15
94
  is_draft: bool,
16
95
  api_key: str,
17
96
  service_url: str,
97
+ api: BasetenApi,
18
98
  truss_handle: Optional[TrussHandle] = None,
19
99
  ):
20
100
  super().__init__(is_draft=is_draft, service_url=service_url)
21
101
  self._model_id = model_id
22
102
  self._model_version_id = model_version_id
23
103
  self._auth_service = AuthService(api_key=api_key)
104
+ self._api = api
24
105
  self._truss_handle = truss_handle
25
106
 
26
107
  def is_live(self) -> bool:
@@ -41,12 +122,9 @@ class BasetenService(TrussService):
41
122
  def invocation_url(self) -> str:
42
123
  return f"{self._service_url}/predict"
43
124
 
44
- def predict(
45
- self,
46
- model_request_body: Dict,
47
- ):
125
+ def predict(self, model_request_body: Dict) -> Any:
48
126
  response = self._send_request(
49
- self.invocation_url, "POST", data=model_request_body, stream=True
127
+ self.predict_url, "POST", data=model_request_body, stream=True
50
128
  )
51
129
 
52
130
  if response.headers.get("transfer-encoding") == "chunked":
@@ -73,10 +151,39 @@ class BasetenService(TrussService):
73
151
  # will be a json with an `error` key.
74
152
  return parsed_response
75
153
 
76
- return response.json()["model_output"]
154
+ return response.json()
77
155
 
78
156
  def authenticate(self) -> dict:
79
157
  return self._auth_service.authenticate().header()
80
158
 
81
- def logs_url(self, base_url: str) -> str:
82
- return f"{base_url}/models/{self._model_id}/logs/{self._model_version_id}"
159
+ @property
160
+ def logs_url(self) -> str:
161
+ return URLConfig.model_logs_url(
162
+ self._api.app_url, self.model_id, self.model_version_id
163
+ )
164
+
165
+ @property
166
+ def predict_url(self) -> str:
167
+ return URLConfig.invocation_url(
168
+ self._api.rest_api_url,
169
+ URLConfig.MODEL,
170
+ self.model_id,
171
+ self._model_version_id,
172
+ self.is_draft,
173
+ )
174
+
175
+ @retry(stop=stop_after_delay(60), wait=wait_fixed(1), reraise=True)
176
+ def _fetch_deployment(self) -> Any:
177
+ return self._api.get_deployment(self._model_id, self._model_version_id)
178
+
179
+ def poll_deployment_status(self, sleep_secs: int = 1) -> Iterator[str]:
180
+ """
181
+ Wait for the service to be deployed.
182
+ """
183
+ while True:
184
+ time.sleep(sleep_secs)
185
+ try:
186
+ deployment = self._fetch_deployment()
187
+ yield deployment["status"]
188
+ except requests.exceptions.RequestException:
189
+ raise RemoteNetworkError("Could not reach backend.")
@@ -0,0 +1,29 @@
1
+ STATUS_TO_DISPLAYABLE = {
2
+ "BUILDING_MODEL": "BUILDING",
3
+ "DEPLOYING_MODEL": "DEPLOYING",
4
+ "MODEL_DEPLOY_FAILED": "DEPLOY_FAILED",
5
+ "MODEL_LOADING": "LOADING_MODEL",
6
+ "MODEL_READY": "ACTIVE",
7
+ "MODEL_UNHEALTHY": "UNHEALTHY",
8
+ "BUILDING_MODEL_FAILED": "BUILD_FAILED",
9
+ "BUILDING_MODEL_STOPPED": "BUILD_STOPPED",
10
+ "DEACTIVATING_MODEL": "DEACTIVATING",
11
+ "DEACTIVATED_MODEL": "INACTIVE",
12
+ "MODEL_DNE_ERROR": "FAILED",
13
+ "UPDATING": "UPDATING",
14
+ "MIGRATING_WORKLOAD_PLANES": "UPDATING",
15
+ "SCALED_TO_ZERO": "SCALED_TO_ZERO",
16
+ "SCALING_FROM_ZERO": "WAKING_UP",
17
+ }
18
+
19
+
20
+ def get_displayable_status(status: str) -> str:
21
+ """
22
+ TODO: Remove this method once Chains is supported in the REST API
23
+
24
+ This is used by the `truss chains deploy` command right now to
25
+ print the right status. Once Chains are supported by the REST API, the
26
+ Baseten REST API will return status strings matching the ones here, so we don't
27
+ need to do any mapping.
28
+ """
29
+ return STATUS_TO_DISPLAYABLE.get(status, "UNKNOWN")
@@ -1,9 +1,12 @@
1
+ import contextlib
1
2
  import tarfile
2
3
  import tempfile
3
4
  from pathlib import Path
4
- from typing import IO, Any, Callable, List
5
+ from typing import IO, TYPE_CHECKING, Any, Callable, List, Optional, Type
6
+
7
+ if TYPE_CHECKING:
8
+ from rich import progress
5
9
 
6
- from rich.progress import Progress
7
10
  from truss.util.path import is_ignored
8
11
 
9
12
 
@@ -24,37 +27,46 @@ class ReadProgressIndicatorFileHandle:
24
27
 
25
28
 
26
29
  def create_tar_with_progress_bar(
27
- source_dir: Path, ignore_patterns: List[str] = [], delete=True
30
+ source_dir: Path,
31
+ ignore_patterns: Optional[List[str]] = None,
32
+ delete=True,
33
+ progress_bar: Optional[Type["progress.Progress"]] = None,
28
34
  ):
29
- # Exclude files that match the ignore_patterns
30
35
  files_to_include = [
31
36
  f
32
37
  for f in source_dir.rglob("*")
33
- if f.is_file() and not is_ignored(f, ignore_patterns, source_dir)
38
+ if f.is_file() and not is_ignored(f, ignore_patterns or [], source_dir)
34
39
  ]
35
40
 
36
41
  total_size = sum(f.stat().st_size for f in files_to_include)
37
42
  temp_file = tempfile.NamedTemporaryFile(suffix=".tgz", delete=delete)
38
43
 
39
- with tarfile.open(temp_file.name, "w:") as tar:
40
-
41
- progress = Progress()
42
-
43
- task_id = progress.add_task("[cyan]Compressing...", total=total_size)
44
+ progress_context = (
45
+ progress_bar(transient=True) if progress_bar else contextlib.nullcontext()
46
+ )
47
+ # Trailing spaces are to align with `multipart_upload_boto3` message.
48
+ task_id = (
49
+ progress_context.add_task("[cyan]Packing Truss ", total=total_size)
50
+ if not isinstance(progress_context, contextlib.nullcontext)
51
+ else None
52
+ )
44
53
 
45
- with progress:
54
+ def file_read_progress_callback(bytes_read: int):
55
+ if not isinstance(progress_context, contextlib.nullcontext):
56
+ assert task_id is not None
57
+ progress_context.update(task_id, advance=bytes_read)
46
58
 
47
- def file_read_progress_callback(bytes_read: int):
48
- progress.update(task_id, advance=bytes_read)
49
-
50
- for file_path in files_to_include:
51
- arcname = str(file_path.relative_to(source_dir))
52
- with file_path.open("rb") as file_obj:
53
- file_obj_with_progress = ReadProgressIndicatorFileHandle(
59
+ with tarfile.open(temp_file.name, "w:") as tar, progress_context:
60
+ for file_path in files_to_include:
61
+ arcname = str(file_path.relative_to(source_dir))
62
+ with file_path.open("rb") as file_obj:
63
+ file_obj_with_progress = (
64
+ ReadProgressIndicatorFileHandle(
54
65
  file_obj, file_read_progress_callback
55
66
  )
56
- tarinfo = tar.gettarinfo(name=str(file_path), arcname=arcname)
57
- tar.addfile(
58
- tarinfo=tarinfo, fileobj=file_obj_with_progress # type: ignore[arg-type]
59
- )
67
+ if progress_bar
68
+ else file_obj
69
+ )
70
+ tarinfo = tar.gettarinfo(name=str(file_path), arcname=arcname)
71
+ tar.addfile(tarinfo=tarinfo, fileobj=file_obj_with_progress) # type: ignore[arg-type] # `ReadProgressIndicatorFileHandle` implements `IO[bytes]`.
60
72
  return temp_file
@@ -1,37 +1,50 @@
1
1
  import base64
2
+ import contextlib
2
3
  import json
3
4
  import os
5
+ from typing import TYPE_CHECKING, Optional, Type
4
6
 
5
7
  import boto3
6
8
  from boto3.s3.transfer import TransferConfig
7
- from rich.progress import Progress
9
+ from truss.util.env_vars import override_env_vars
10
+
11
+ if TYPE_CHECKING:
12
+ from rich import progress
8
13
 
9
14
 
10
15
  def base64_encoded_json_str(obj):
11
16
  return base64.b64encode(str.encode(json.dumps(obj))).decode("utf-8")
12
17
 
13
18
 
14
- def multipart_upload_boto3(file_path, bucket_name, key, credentials):
15
- s3_resource = boto3.resource("s3", **credentials)
16
- filesize = os.stat(file_path).st_size
17
-
18
- # Create a new progress bar
19
- progress = Progress()
20
-
21
- # Add a new task to the progress bar
22
- task_id = progress.add_task("[cyan]Uploading...", total=filesize)
23
-
24
- with progress:
19
+ def multipart_upload_boto3(
20
+ file_path,
21
+ bucket_name: str,
22
+ key: str,
23
+ credentials: dict,
24
+ progress_bar: Optional[Type["progress.Progress"]],
25
+ ) -> None:
26
+ # In the CLI flow, ignore any local ~/.aws/config files,
27
+ # which can interfere with uploading the Truss to S3.
28
+ with override_env_vars({"AWS_CONFIG_FILE": ""}):
29
+ s3_resource = boto3.resource("s3", **credentials)
30
+ filesize = os.stat(file_path).st_size
31
+
32
+ progress_context = (
33
+ progress_bar(transient=True) if progress_bar else contextlib.nullcontext()
34
+ )
35
+ task_id = (
36
+ progress_context.add_task("[cyan]Uploading Truss", total=filesize)
37
+ if not isinstance(progress_context, contextlib.nullcontext)
38
+ else None
39
+ )
25
40
 
26
41
  def callback(bytes_transferred):
27
- # Update the progress bar
28
- progress.update(task_id, advance=bytes_transferred)
29
-
30
- s3_resource.Object(bucket_name, key).upload_file(
31
- file_path,
32
- Config=TransferConfig(
33
- max_concurrency=10,
34
- use_threads=True,
35
- ),
36
- Callback=callback,
37
- )
42
+ if progress_bar:
43
+ progress_context.update(task_id, advance=bytes_transferred)
44
+
45
+ with progress_context:
46
+ s3_resource.Object(bucket_name, key).upload_file(
47
+ file_path,
48
+ Config=TransferConfig(max_concurrency=10, use_threads=True),
49
+ Callback=callback,
50
+ )
@@ -1,5 +1,14 @@
1
1
  import inspect
2
- from configparser import DEFAULTSECT, SafeConfigParser
2
+ import os
3
+
4
+ try:
5
+ from configparser import DEFAULTSECT, ConfigParser # type: ignore
6
+ except ImportError:
7
+ # We need to do this for old python.
8
+ from configparser import DEFAULTSECT
9
+ from configparser import SafeConfigParser as ConfigParser
10
+
11
+
3
12
  from functools import partial
4
13
  from operator import is_not
5
14
  from pathlib import Path
@@ -8,16 +17,16 @@ from typing import Dict, List, Type
8
17
  from truss.remote.baseten import BasetenRemote
9
18
  from truss.remote.truss_remote import RemoteConfig, TrussRemote
10
19
 
11
- USER_TRUSSRC_PATH = Path("~/.trussrc").expanduser()
20
+ USER_TRUSSRC_PATH = Path(os.environ.get("USER_TRUSSRC_PATH", "~/.trussrc")).expanduser()
12
21
 
13
22
 
14
- def load_config() -> SafeConfigParser:
15
- config = SafeConfigParser()
23
+ def load_config() -> ConfigParser:
24
+ config = ConfigParser()
16
25
  config.read(USER_TRUSSRC_PATH)
17
26
  return config
18
27
 
19
28
 
20
- def update_config(config: SafeConfigParser):
29
+ def update_config(config: ConfigParser):
21
30
  with open(USER_TRUSSRC_PATH, "w") as configfile:
22
31
  config.write(configfile)
23
32
 
@@ -1,16 +1,31 @@
1
1
  from abc import ABC, abstractmethod
2
2
  from dataclasses import dataclass, field
3
- from typing import Dict, Optional
3
+ from typing import TYPE_CHECKING, Any, Dict, Iterator, Optional
4
4
 
5
5
  import requests
6
- from truss.truss_handle import TrussHandle
6
+
7
+ if TYPE_CHECKING:
8
+ from rich import console as rich_console
9
+ from truss.truss_handle.truss_handle import TrussHandle
10
+
11
+
12
+ class RemoteUser:
13
+ """Class to hold information about the remote user"""
14
+
15
+ workspace_name: str
16
+ user_email: str
17
+
18
+ def __init__(self, workspace_name: str, user_email: str):
19
+ self.workspace_name = workspace_name
20
+ self.user_email = user_email
7
21
 
8
22
 
9
23
  class TrussService(ABC):
10
24
  """
11
25
  Define the abstract base class for a TrussService.
12
26
 
13
- A TrussService interacts with a service at a given URL and can either be in draft or non-dreaf mode.
27
+ A TrussService interacts with a service at a given URL and can either be in
28
+ draft or non-draft mode.
14
29
 
15
30
  Attributes:
16
31
  _service_url: The URL of the service.
@@ -23,7 +38,7 @@ class TrussService(ABC):
23
38
 
24
39
  """
25
40
 
26
- def __init__(self, service_url: str, is_draft: bool, **kwargs):
41
+ def __init__(self, service_url: str, is_draft: bool, **kwargs) -> None:
27
42
  self._service_url = service_url
28
43
  self._is_draft = is_draft
29
44
 
@@ -34,7 +49,7 @@ class TrussService(ABC):
34
49
  headers: Optional[Dict] = None,
35
50
  data: Optional[Dict] = None,
36
51
  stream: Optional[bool] = False,
37
- ):
52
+ ) -> Any:
38
53
  """
39
54
  Send a HTTP request.
40
55
 
@@ -75,7 +90,7 @@ class TrussService(ABC):
75
90
  return response
76
91
 
77
92
  @property
78
- def is_draft(self):
93
+ def is_draft(self) -> bool:
79
94
  """
80
95
  Check if the service is in draft mode.
81
96
 
@@ -89,7 +104,8 @@ class TrussService(ABC):
89
104
  """
90
105
  Check if the service is live.
91
106
 
92
- Sends a GET request to the root of the service and returns whether it is successful.
107
+ Sends a GET request to the root of the service and returns whether it
108
+ is successful.
93
109
 
94
110
  Returns:
95
111
  A boolean indicating if the service is live.
@@ -103,7 +119,8 @@ class TrussService(ABC):
103
119
  """
104
120
  Check if the service is ready.
105
121
 
106
- Sends a GET request to the model path of the service and returns whether it is successful.
122
+ Sends a GET request to the model path of the service and returns whether it
123
+ is successful.
107
124
 
108
125
  Returns:
109
126
  A boolean indicating if the service is ready.
@@ -112,21 +129,20 @@ class TrussService(ABC):
112
129
  response = self._send_request(readiness_url, "GET", {})
113
130
  return response.status_code == 200
114
131
 
115
- def predict(self, model_request_body: Dict):
132
+ def predict(self, model_request_body: Dict) -> Any:
116
133
  """
117
134
  Send a prediction request to the service.
118
135
 
119
136
  Args:
120
- model_request_body: A dictionary representing the body of the prediction request.
137
+ model_request_body: A dictionary representing the body of the
138
+ prediction request.
121
139
 
122
140
  Returns:
123
141
  A Response object resulting from the prediction request.
124
142
  """
125
- invocation_url = f"{self._service_url}/v1/models/model:predict"
126
- response = self._send_request(invocation_url, "POST", data=model_request_body)
127
- return response
143
+ return self._send_request(self.predict_url, "POST", data=model_request_body)
128
144
 
129
- def patch(self):
145
+ def patch(self) -> None:
130
146
  """
131
147
  Patch the service. TrussServices in draft mode can be patched.
132
148
  """
@@ -137,25 +153,42 @@ class TrussService(ABC):
137
153
  """
138
154
  Authenticate to the service.
139
155
 
140
- This method should be implemented in subclasses and return a dictionary of headers
141
- to include in requests to the service with authentication information.
156
+ This method should be implemented in subclasses and return a dictionary
157
+ of headers to include in requests to the service with authentication
158
+ information.
142
159
  """
143
160
  return {}
144
161
 
162
+ @property
145
163
  @abstractmethod
146
- def logs_url(self, base_url: str) -> str:
164
+ def logs_url(self) -> str:
147
165
  """
148
166
  Get the URL for the service logs.
149
167
  """
150
168
  pass
151
169
 
170
+ @property
171
+ @abstractmethod
172
+ def predict_url(self) -> str:
173
+ """
174
+ Get the URL for the prediction endpoint.
175
+ """
176
+ pass
177
+
178
+ @abstractmethod
179
+ def poll_deployment_status(self, sleep_secs: int = 1) -> Iterator[str]:
180
+ """
181
+ Poll for a deployment status.
182
+ """
183
+ pass
184
+
152
185
 
153
186
  class TrussRemote(ABC):
154
187
  """
155
188
  Define the abstract base class for a remote Truss service.
156
189
 
157
- A remote Truss service is a service that can push a TrussHandle to a remote location.
158
- The `push` and `authenticate` methods should be implemented in subclasses.
190
+ A remote Truss service is a service that can push a TrussHandle to a remote
191
+ location. The `push` and `authenticate` methods should be implemented in subclasses.
159
192
 
160
193
  Attributes:
161
194
  _remote_url: The URL of the remote service.
@@ -166,11 +199,15 @@ class TrussRemote(ABC):
166
199
 
167
200
  """
168
201
 
169
- def __init__(self, remote_url: str, **kwargs):
202
+ def __init__(self, remote_url: str) -> None:
170
203
  self._remote_url = remote_url
171
204
 
205
+ @property
206
+ def remote_url(self) -> str:
207
+ return self._remote_url
208
+
172
209
  @abstractmethod
173
- def push(self, truss_handle: TrussHandle, **kwargs):
210
+ def push(self, truss_handle: TrussHandle, **kwargs) -> TrussService:
174
211
  """
175
212
  Push a TrussHandle to the remote service.
176
213
 
@@ -182,24 +219,19 @@ class TrussRemote(ABC):
182
219
  **kwargs: Additional keyword arguments for the push operation.
183
220
 
184
221
  """
185
- pass
186
222
 
187
223
  @abstractmethod
188
- def authenticate(self, **kwargs):
224
+ def whoami(self) -> RemoteUser:
189
225
  """
190
- Authenticate the user to push to the remote service.
226
+ Returns account information for the current user.
227
+
228
+ This method should be implemented in subclasses and return a RemoteUser.
191
229
 
192
- This method should be implemented in subclasses. It should check whether
193
- the user has valid authentication credentials to push to the remote service.
194
- If not, it should raise an exception.
195
230
 
196
- Args:
197
- **kwargs: Additional keyword arguments for the authentication operation.
198
231
  """
199
- pass
200
232
 
201
233
  @abstractmethod
202
- def get_service(self, **kwargs):
234
+ def get_service(self, **kwargs) -> TrussService:
203
235
  """
204
236
  Get a TrussService object for interacting with the remote service.
205
237
 
@@ -211,20 +243,15 @@ class TrussRemote(ABC):
211
243
  **kwargs: Keyword arguments for the get_service operation.
212
244
 
213
245
  """
214
- pass
215
246
 
216
247
  @abstractmethod
217
- def get_remote_logs_url(self, service: TrussService) -> str:
218
- """
219
- Get the URL for the remote service logs.
220
-
221
- Args:
222
- service: The TrussService object for interacting with the remote service.
223
- """
224
- pass
225
-
226
- @abstractmethod
227
- def sync_truss_to_dev_version_by_name(self, model_name: str, target_directory: str):
248
+ def sync_truss_to_dev_version_by_name(
249
+ self,
250
+ model_name: str,
251
+ target_directory: str,
252
+ console: "rich_console.Console",
253
+ error_console: "rich_console.Console",
254
+ ) -> None:
228
255
  """
229
256
  This method watches for changes to files in the `target_directory`,
230
257
  and syncs them to the development version of the model, identified
@@ -233,10 +260,10 @@ class TrussRemote(ABC):
233
260
  Args:
234
261
  model_name: The name of the model to sync to the dev version
235
262
  target_directory: The directory to sync the model to
263
+ console: For printing informative output.
264
+ error_console: For printing errors.
236
265
  """
237
266
 
238
- pass
239
-
240
267
 
241
268
  @dataclass
242
269
  class RemoteConfig: