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
@@ -23,9 +23,7 @@ def inquire_remote_config() -> RemoteConfig:
23
23
  # can do so manually in the .trussrc file.
24
24
  remote_url = "https://app.baseten.co"
25
25
  api_key = inquirer.secret(
26
- message="🤫 Quietly paste your API_KEY:",
27
- qmark="",
28
- validate=NonEmptyValidator(),
26
+ message="🤫 Quietly paste your API_KEY:", qmark="", validate=NonEmptyValidator()
29
27
  ).execute()
30
28
 
31
29
  return RemoteConfig(
@@ -56,7 +54,4 @@ def inquire_remote_name(available_remotes: List[str]) -> str:
56
54
 
57
55
 
58
56
  def inquire_model_name() -> str:
59
- return inquirer.text(
60
- "📦 Name this model:",
61
- qmark="",
62
- ).execute()
57
+ return inquirer.text("📦 Name this model:", qmark="").execute()
@@ -0,0 +1,67 @@
1
+ import json
2
+ import logging
3
+ import os
4
+ import pathlib
5
+ import sys
6
+
7
+ import click
8
+ from truss.patch.hash import directory_content_hash
9
+ from truss.patch.truss_dir_patch_applier import TrussDirPatchApplier
10
+ from truss.templates.control.control.helpers.custom_types import Patch
11
+ from truss.truss_handle import truss_handle
12
+ from truss.truss_handle.patch import signature
13
+
14
+ logging.basicConfig(stream=sys.stdout, level=logging.INFO)
15
+
16
+ working_dir = pathlib.Path("/")
17
+
18
+ TRUSS_SRC_DIR = working_dir / "build/model_scaffold"
19
+ TRUSS_HASH_FILE = working_dir / "scaffold/truss_hash"
20
+ TRUSS_SIGNATURE_FILE = working_dir / "scaffold/truss_signature"
21
+ TRUSS_BUILD_CONTEXT_DIR = working_dir / "build/context"
22
+
23
+
24
+ @click.command()
25
+ @click.option("--truss_type", required=True)
26
+ def docker_build_setup(truss_type: str) -> None:
27
+ """
28
+ Prepares source and asset files in a build directory (build context), on which a
29
+ docker build command can be run.
30
+
31
+ This is to be run for remote builds on baseten.
32
+ Local builds use `TrussHandle.build_serving_docker_image`.
33
+ """
34
+ logging.info("Loading truss")
35
+ tr = truss_handle.TrussHandle(TRUSS_SRC_DIR)
36
+ logging.info("Truss is loaded")
37
+
38
+ if patches_dir := os.environ.get("PATCHES_DIR"):
39
+ logging.info("Applying patches")
40
+ logger = logging.getLogger("patch_applier")
41
+ patch_applier = TrussDirPatchApplier(TRUSS_SRC_DIR, logger)
42
+ patches = json.loads(pathlib.Path(patches_dir).read_text())
43
+ patch_applier([Patch.from_dict(patch) for patch in patches])
44
+
45
+ # Important to do this before making changes to truss, we want
46
+ # to capture hash of original truss.
47
+ logging.info("Recording truss hash")
48
+ TRUSS_HASH_FILE.write_text(directory_content_hash(TRUSS_SRC_DIR))
49
+
50
+ logging.info("Recording truss signature.")
51
+ sign = signature.calc_truss_signature(TRUSS_SRC_DIR)
52
+ TRUSS_SIGNATURE_FILE.write_text(json.dumps(sign.to_dict()))
53
+
54
+ if truss_type == "server_control":
55
+ tr.live_reload(enable=True)
56
+ else:
57
+ tr.live_reload(enable=False)
58
+
59
+ # check if we have a hf_secret
60
+ tr.docker_build_setup(
61
+ TRUSS_BUILD_CONTEXT_DIR, use_hf_secret="HUGGING_FACE_HUB_TOKEN" in os.environ
62
+ )
63
+ print("Docker build context is set up for the truss.")
64
+
65
+
66
+ if __name__ == "__main__":
67
+ docker_build_setup()
@@ -25,11 +25,7 @@ def _b10cp_path() -> Optional[str]:
25
25
  return os.environ.get(B10CP_PATH_TRUSS_ENV_VAR_NAME)
26
26
 
27
27
 
28
- def _download_from_url_using_b10cp(
29
- b10cp_path: str,
30
- url: str,
31
- download_to: Path,
32
- ):
28
+ def _download_from_url_using_b10cp(b10cp_path: str, url: str, download_to: Path):
33
29
  return subprocess.Popen(
34
30
  [
35
31
  b10cp_path,
@@ -157,9 +153,7 @@ class GCSFile(RepositoryFile):
157
153
 
158
154
  if is_private:
159
155
  url = blob.generate_signed_url(
160
- version="v4",
161
- expiration=datetime.timedelta(minutes=15),
162
- method="GET",
156
+ version="v4", expiration=datetime.timedelta(minutes=15), method="GET"
163
157
  )
164
158
  else:
165
159
  base_url = "https://storage.googleapis.com"
@@ -2,7 +2,7 @@ from abc import ABC, abstractmethod
2
2
  from pathlib import Path
3
3
  from typing import Optional
4
4
 
5
- from truss.docker import Docker
5
+ from truss.util.docker import Docker
6
6
  from truss.util.path import given_or_temporary_dir
7
7
 
8
8
 
@@ -6,24 +6,51 @@ from pathlib import Path
6
6
  from typing import Any, Dict, List, Optional, Tuple, Type
7
7
 
8
8
  import boto3
9
+ import yaml
9
10
  from botocore import UNSIGNED
10
11
  from botocore.client import Config
11
12
  from google.cloud import storage
12
13
  from huggingface_hub import get_hf_file_metadata, hf_hub_url, list_repo_files
13
14
  from huggingface_hub.utils import filter_repo_objects
14
- from truss.constants import (
15
+ from truss.base import constants
16
+ from truss.base.constants import (
17
+ BASE_SERVER_REQUIREMENTS_TXT_FILENAME,
15
18
  BASE_TRTLLM_REQUIREMENTS,
19
+ BEI_MAX_CONCURRENCY_TARGET_REQUESTS,
20
+ BEI_REQUIRED_MAX_NUM_TOKENS,
21
+ BEI_TRTLLM_BASE_IMAGE,
22
+ BEI_TRTLLM_CLIENT_BATCH_SIZE,
23
+ BEI_TRTLLM_PYTHON_EXECUTABLE,
24
+ CHAINS_CODE_DIR,
25
+ CONTROL_SERVER_CODE_DIR,
26
+ DOCKER_SERVER_TEMPLATES_DIR,
16
27
  FILENAME_CONSTANTS_MAP,
28
+ MAX_SUPPORTED_PYTHON_VERSION_IN_CUSTOM_BASE_IMAGE,
29
+ MIN_SUPPORTED_PYTHON_VERSION_IN_CUSTOM_BASE_IMAGE,
17
30
  MODEL_DOCKERFILE_NAME,
18
31
  REQUIREMENTS_TXT_FILENAME,
32
+ SERVER_CODE_DIR,
19
33
  SERVER_DOCKERFILE_TEMPLATE_NAME,
34
+ SERVER_REQUIREMENTS_TXT_FILENAME,
35
+ SHARED_SERVING_AND_TRAINING_CODE_DIR,
36
+ SHARED_SERVING_AND_TRAINING_CODE_DIR_NAME,
20
37
  SYSTEM_PACKAGES_TXT_FILENAME,
21
38
  TEMPLATES_DIR,
22
39
  TRTLLM_BASE_IMAGE,
40
+ TRTLLM_PREDICT_CONCURRENCY,
41
+ TRTLLM_PYTHON_EXECUTABLE,
23
42
  TRTLLM_TRUSS_DIR,
24
- TRUSS_PACKAGE_DIR,
43
+ TRUSSLESS_MAX_PAYLOAD_SIZE,
25
44
  USER_SUPPLIED_REQUIREMENTS_TXT_FILENAME,
26
45
  )
46
+ from truss.base.trt_llm_config import TRTLLMConfiguration, TrussTRTLLMModel
47
+ from truss.base.truss_config import (
48
+ DEFAULT_BUNDLED_PACKAGES_DIR,
49
+ BaseImage,
50
+ DockerServer,
51
+ TrussConfig,
52
+ )
53
+ from truss.base.truss_spec import TrussSpec
27
54
  from truss.contexts.image_builder.cache_warmer import (
28
55
  AWSCredentials,
29
56
  parse_s3_credentials_file,
@@ -37,9 +64,7 @@ from truss.contexts.image_builder.util import (
37
64
  truss_base_image_tag,
38
65
  )
39
66
  from truss.contexts.truss_context import TrussContext
40
- from truss.patch.hash import directory_content_hash
41
- from truss.truss_config import BaseImage, ModelServer, TrussConfig
42
- from truss.truss_spec import TrussSpec
67
+ from truss.truss_handle.patch.hash import directory_content_hash
43
68
  from truss.util.jinja import read_template_from_fs
44
69
  from truss.util.path import (
45
70
  build_truss_target_directory,
@@ -48,12 +73,16 @@ from truss.util.path import (
48
73
  load_trussignore_patterns,
49
74
  )
50
75
 
76
+ BUILD_SERVER_DIR_NAME = "server"
77
+ BUILD_CONTROL_SERVER_DIR_NAME = "control"
78
+ BUILD_SERVER_EXTENSIONS_PATH = "extensions"
79
+ BUILD_CHAINS_DIR_NAME = "truss_chains"
80
+
51
81
  CONFIG_FILE = "config.yaml"
52
82
  USER_TRUSS_IGNORE_FILE = ".truss_ignore"
53
83
  GCS_CREDENTIALS = "service_account.json"
54
84
  S3_CREDENTIALS = "s3_credentials.json"
55
85
 
56
- HF_ACCESS_TOKEN_SECRET_NAME = "hf_access_token"
57
86
  HF_ACCESS_TOKEN_FILE_NAME = "hf-access-token"
58
87
 
59
88
  CLOUD_BUCKET_CACHE = Path("/app/model_cache/")
@@ -131,7 +160,7 @@ class GCSCache(RemoteCache):
131
160
 
132
161
 
133
162
  class S3Cache(RemoteCache):
134
- def list_files(self, revision=None):
163
+ def list_files(self, revision=None) -> List[str]:
135
164
  s3_credentials_file = self.data_dir / S3_CREDENTIALS
136
165
 
137
166
  if s3_credentials_file.exists():
@@ -279,6 +308,49 @@ def update_config_and_gather_files(
279
308
  return get_files_to_cache(config, truss_dir, build_dir)
280
309
 
281
310
 
311
+ def generate_docker_server_nginx_config(build_dir, config):
312
+ nginx_template = read_template_from_fs(
313
+ DOCKER_SERVER_TEMPLATES_DIR, "proxy.conf.jinja"
314
+ )
315
+
316
+ assert config.docker_server.predict_endpoint is not None, (
317
+ "docker_server.predict_endpoint is required to use custom server"
318
+ )
319
+ assert config.docker_server.server_port is not None, (
320
+ "docker_server.server_port is required to use custom server"
321
+ )
322
+ assert config.docker_server.readiness_endpoint is not None, (
323
+ "docker_server.readiness_endpoint is required to use custom server"
324
+ )
325
+ assert config.docker_server.liveness_endpoint is not None, (
326
+ "docker_server.liveness_endpoint is required to use custom server"
327
+ )
328
+
329
+ nginx_content = nginx_template.render(
330
+ server_endpoint=config.docker_server.predict_endpoint,
331
+ readiness_endpoint=config.docker_server.readiness_endpoint,
332
+ liveness_endpoint=config.docker_server.liveness_endpoint,
333
+ server_port=config.docker_server.server_port,
334
+ client_max_body_size=TRUSSLESS_MAX_PAYLOAD_SIZE,
335
+ )
336
+ nginx_filepath = build_dir / "proxy.conf"
337
+ nginx_filepath.write_text(nginx_content)
338
+
339
+
340
+ def generate_docker_server_supervisord_config(build_dir, config):
341
+ supervisord_template = read_template_from_fs(
342
+ DOCKER_SERVER_TEMPLATES_DIR, "supervisord.conf.jinja"
343
+ )
344
+ assert config.docker_server.start_command is not None, (
345
+ "docker_server.start_command is required to use custom server"
346
+ )
347
+ supervisord_contents = supervisord_template.render(
348
+ start_command=config.docker_server.start_command
349
+ )
350
+ supervisord_filepath = build_dir / "supervisord.conf"
351
+ supervisord_filepath.write_text(supervisord_contents)
352
+
353
+
282
354
  class ServingImageBuilderContext(TrussContext):
283
355
  @staticmethod
284
356
  def run(truss_dir: Path):
@@ -294,6 +366,99 @@ class ServingImageBuilder(ImageBuilder):
294
366
  def default_tag(self):
295
367
  return f"{self._spec.model_framework_name}-model:latest"
296
368
 
369
+ def _copy_into_build_dir(
370
+ self, from_path: Path, build_dir: Path, path_in_build_dir: str
371
+ ):
372
+ copy_tree_or_file(from_path, build_dir / path_in_build_dir) # type: ignore[operator]
373
+
374
+ def prepare_trtllm_bei_encoder_build_dir(self, build_dir: Path):
375
+ """prepares the build directory for a trtllm ENCODER model to launch a Baseten Embeddings Inference (BEI) server"""
376
+ config = self._spec.config
377
+ assert (
378
+ config.trt_llm
379
+ and config.trt_llm.build
380
+ and config.trt_llm.build.base_model == TrussTRTLLMModel.ENCODER
381
+ ), (
382
+ "prepare_trtllm_bei_encoder_build_dir should only be called for ENCODER tensorrt-llm model"
383
+ )
384
+ # TRTLLM has performance degradation with batch size >> 32, so we limit the runtime settings
385
+ # runtime batch size may not be higher than what the build settings of the model allow
386
+ # to 32 even if the engine.rank0 allows for higher batch_size
387
+ runtime_max_batch_size = min(config.trt_llm.build.max_batch_size, 32)
388
+ # make sure the user gets good performance, enforcing max_num_tokens here and in engine-builder
389
+ runtime_max_batch_tokens = max(
390
+ config.trt_llm.build.max_num_tokens, BEI_REQUIRED_MAX_NUM_TOKENS
391
+ )
392
+ port = 7997
393
+ start_command = " ".join(
394
+ [
395
+ "truss-transfer-cli && text-embeddings-router",
396
+ f"--port {port}",
397
+ # assert the max_batch_size is within trt-engine limits
398
+ f"--max-batch-requests {runtime_max_batch_size}",
399
+ # assert the max_num_tokens is within trt-engine limits
400
+ f"--max-batch-tokens {runtime_max_batch_tokens}",
401
+ # how many sentences can be in a single json payload.
402
+ # limited default to improve request based autoscaling.
403
+ f"--max-client-batch-size {BEI_TRTLLM_CLIENT_BATCH_SIZE}",
404
+ # how many concurrent requests can be handled by the server until 429 is returned.
405
+ # limited by https://docs.baseten.co/performance/concurrency#concurrency-target
406
+ # 2048 is a safe max value for the server
407
+ f"--max-concurrent-requests {BEI_MAX_CONCURRENCY_TARGET_REQUESTS}",
408
+ ]
409
+ )
410
+ self._spec.config.docker_server = DockerServer(
411
+ start_command=f"/bin/sh -c '{start_command}'",
412
+ server_port=port,
413
+ predict_endpoint="/v1/embeddings",
414
+ readiness_endpoint="/health",
415
+ liveness_endpoint="/health",
416
+ )
417
+ copy_tree_path(DOCKER_SERVER_TEMPLATES_DIR, build_dir, ignore_patterns=[])
418
+
419
+ config.base_image = BaseImage(
420
+ image=BEI_TRTLLM_BASE_IMAGE,
421
+ python_executable_path=BEI_TRTLLM_PYTHON_EXECUTABLE,
422
+ )
423
+
424
+ def prepare_trtllm_decoder_build_dir(self, build_dir: Path):
425
+ """prepares the build directory for a trtllm decoder-like models to launch BRITON server"""
426
+ config = self._spec.config
427
+ assert (
428
+ config.trt_llm
429
+ and config.trt_llm.build
430
+ and config.trt_llm.build.base_model != TrussTRTLLMModel.ENCODER
431
+ ), (
432
+ "prepare_trtllm_decoder_build_dir should only be called for decoder tensorrt-llm model"
433
+ )
434
+
435
+ # trt_llm is treated as an extension at model run time.
436
+ self._copy_into_build_dir(
437
+ TRTLLM_TRUSS_DIR / "src",
438
+ build_dir,
439
+ f"{BUILD_SERVER_DIR_NAME}/{BUILD_SERVER_EXTENSIONS_PATH}/trt_llm",
440
+ )
441
+ # TODO(pankaj) Do this differently. This is not ideal, user
442
+ # supplied code in bundled packages can conflict with those from
443
+ # the trtllm extension. We don't want to put this in the build
444
+ # directory directly either because of chances of conflict there
445
+ # as well and the noise it can create there. We need to find a
446
+ # new place that's made available in model's pythonpath. This is
447
+ # a bigger lift and feels overkill right now. Worth revisiting
448
+ # if we come across cases of actual conflicts.
449
+ self._copy_into_build_dir(
450
+ TRTLLM_TRUSS_DIR / DEFAULT_BUNDLED_PACKAGES_DIR,
451
+ build_dir,
452
+ DEFAULT_BUNDLED_PACKAGES_DIR,
453
+ )
454
+
455
+ config.runtime.predict_concurrency = TRTLLM_PREDICT_CONCURRENCY
456
+
457
+ config.base_image = BaseImage(
458
+ image=TRTLLM_BASE_IMAGE, python_executable_path=TRTLLM_PYTHON_EXECUTABLE
459
+ )
460
+ config.requirements.extend(BASE_TRTLLM_REQUIREMENTS)
461
+
297
462
  def prepare_image_build_dir(
298
463
  self, build_dir: Optional[Path] = None, use_hf_secret: bool = False
299
464
  ):
@@ -310,17 +475,6 @@ class ServingImageBuilder(ImageBuilder):
310
475
 
311
476
  data_dir = build_dir / config.data_dir # type: ignore[operator]
312
477
 
313
- def copy_into_build_dir(from_path: Path, path_in_build_dir: str):
314
- # using default ignore patterns ignores the `build` dir in truss
315
- copy_tree_or_file(from_path, build_dir / path_in_build_dir, ignore_files=False) # type: ignore[operator]
316
-
317
- # Copy truss package from the context builder image to build dir
318
- copy_into_build_dir(TRUSS_PACKAGE_DIR, "truss/")
319
- copy_into_build_dir(
320
- TRUSS_PACKAGE_DIR.parent / "pyproject.toml", "./pyproject.toml"
321
- )
322
- copy_into_build_dir(TRUSS_PACKAGE_DIR.parent / "README.md", "./README.md")
323
-
324
478
  truss_ignore_patterns = []
325
479
  if (truss_dir / USER_TRUSS_IGNORE_FILE).exists():
326
480
  truss_ignore_patterns = load_trussignore_patterns(
@@ -329,36 +483,37 @@ class ServingImageBuilder(ImageBuilder):
329
483
 
330
484
  # Copy over truss
331
485
  copy_tree_path(truss_dir, build_dir, ignore_patterns=truss_ignore_patterns)
332
- # Copy over template truss for TRT-LLM (we overwrite the model and packages dir)
333
- if config.build.model_server is ModelServer.TRT_LLM:
334
- copy_tree_path(TRTLLM_TRUSS_DIR, build_dir, ignore_patterns=[])
335
-
336
- # Check to see if TP and GPU count are the same
337
- # TODO(Abu): Consolidate these config parameters so that we don't have to
338
- # keep truss + template in sync if we change th einterface
339
- if "tensor_parallel_count" in config.build.arguments:
340
- if (
341
- config.build.arguments["tensor_parallel_count"]
342
- != config.resources.accelerator.count
343
- ):
344
- raise ValueError(
345
- "Tensor parallelism and GPU count must be the same for TRT-LLM"
346
- )
347
-
348
- config.base_image = BaseImage(
349
- image=TRTLLM_BASE_IMAGE, python_executable_path="/usr/bin/python3"
486
+ if (
487
+ isinstance(config.trt_llm, TRTLLMConfiguration)
488
+ and config.trt_llm.build is not None
489
+ ):
490
+ if config.trt_llm.build.base_model == TrussTRTLLMModel.ENCODER:
491
+ # Run the specific encoder build
492
+ self.prepare_trtllm_bei_encoder_build_dir(build_dir=build_dir)
493
+ else:
494
+ self.prepare_trtllm_decoder_build_dir(build_dir=build_dir)
495
+
496
+ if config.docker_server is not None:
497
+ self._copy_into_build_dir(
498
+ TEMPLATES_DIR / "docker_server_requirements.txt",
499
+ build_dir,
500
+ "docker_server_requirements.txt",
350
501
  )
351
- config.requirements.extend(BASE_TRTLLM_REQUIREMENTS)
502
+
503
+ generate_docker_server_nginx_config(build_dir, config)
504
+
505
+ generate_docker_server_supervisord_config(build_dir, config)
506
+
507
+ # Override config.yml
508
+ with (build_dir / CONFIG_FILE).open("w") as config_file:
509
+ yaml.dump(config.to_dict(verbose=True), config_file)
352
510
 
353
511
  external_data_files: list = []
354
512
  data_dir = Path("/app/data/")
355
513
  if self._spec.external_data is not None:
356
514
  for ext_file in self._spec.external_data.items:
357
515
  external_data_files.append(
358
- (
359
- ext_file.url,
360
- (data_dir / ext_file.local_data_path).resolve(),
361
- )
516
+ (ext_file.url, (data_dir / ext_file.local_data_path).resolve())
362
517
  )
363
518
 
364
519
  # Download from HuggingFace
@@ -366,12 +521,74 @@ class ServingImageBuilder(ImageBuilder):
366
521
  config, truss_dir, build_dir
367
522
  )
368
523
 
369
- user_provided_python_requirements = (
370
- spec.requirements_txt if spec.requirements else ""
524
+ # Copy inference server code
525
+ self._copy_into_build_dir(SERVER_CODE_DIR, build_dir, BUILD_SERVER_DIR_NAME)
526
+ self._copy_into_build_dir(
527
+ SHARED_SERVING_AND_TRAINING_CODE_DIR,
528
+ build_dir,
529
+ BUILD_SERVER_DIR_NAME + "/" + SHARED_SERVING_AND_TRAINING_CODE_DIR_NAME,
530
+ )
531
+
532
+ # Copy control server code
533
+ if config.live_reload:
534
+ self._copy_into_build_dir(
535
+ CONTROL_SERVER_CODE_DIR, build_dir, BUILD_CONTROL_SERVER_DIR_NAME
536
+ )
537
+ self._copy_into_build_dir(
538
+ SHARED_SERVING_AND_TRAINING_CODE_DIR,
539
+ build_dir,
540
+ BUILD_CONTROL_SERVER_DIR_NAME
541
+ + "/control/"
542
+ + SHARED_SERVING_AND_TRAINING_CODE_DIR_NAME,
543
+ )
544
+
545
+ if config.use_local_chains_src:
546
+ self._copy_into_build_dir(CHAINS_CODE_DIR, build_dir, BUILD_CHAINS_DIR_NAME)
547
+
548
+ # Copy base TrussServer requirements if supplied custom base image
549
+ base_truss_server_reqs_filepath = SERVER_CODE_DIR / REQUIREMENTS_TXT_FILENAME
550
+ if config.base_image:
551
+ self._copy_into_build_dir(
552
+ base_truss_server_reqs_filepath,
553
+ build_dir,
554
+ BASE_SERVER_REQUIREMENTS_TXT_FILENAME,
555
+ )
556
+
557
+ # Copy model framework specific requirements file
558
+ server_reqs_filepath = (
559
+ TEMPLATES_DIR / model_framework_name / REQUIREMENTS_TXT_FILENAME
371
560
  )
561
+ should_install_server_requirements = file_is_not_empty(server_reqs_filepath)
562
+ if should_install_server_requirements:
563
+ self._copy_into_build_dir(
564
+ server_reqs_filepath, build_dir, SERVER_REQUIREMENTS_TXT_FILENAME
565
+ )
566
+
567
+ with open(base_truss_server_reqs_filepath, "r") as f:
568
+ base_server_requirements = f.read()
569
+
570
+ if config.docker_server:
571
+ # when docker server is enabled, no need to install truss requirements
572
+ # only install user-provided python requirements
573
+ user_provided_python_requirements = spec.requirements_txt
574
+ else:
575
+ # If the user has provided python requirements,
576
+ # append the truss server requirements, so that any conflicts
577
+ # are detected and cause a build failure. If there are no
578
+ # requirements provided, we just pass an empty string,
579
+ # as there's no need to install anything.
580
+ # TODO (BT-10217): above reasoning leads to inconsistencies. To get consistent
581
+ # images tentatively add server requirements always. This whole point needs
582
+ # more thought and potentially a re-design.
583
+ user_provided_python_requirements = (
584
+ base_server_requirements + spec.requirements_txt
585
+ if spec.requirements
586
+ else base_server_requirements
587
+ )
372
588
  if spec.requirements_file is not None:
373
- copy_into_build_dir(
589
+ self._copy_into_build_dir(
374
590
  truss_dir / spec.requirements_file,
591
+ build_dir,
375
592
  USER_SUPPLIED_REQUIREMENTS_TXT_FILENAME,
376
593
  )
377
594
  (build_dir / REQUIREMENTS_TXT_FILENAME).write_text(
@@ -381,24 +598,28 @@ class ServingImageBuilder(ImageBuilder):
381
598
 
382
599
  self._render_dockerfile(
383
600
  build_dir,
601
+ should_install_server_requirements,
384
602
  model_files,
385
603
  use_hf_secret,
386
604
  cached_files,
387
605
  external_data_files,
606
+ self._spec.build_commands,
388
607
  )
389
608
 
390
609
  def _render_dockerfile(
391
610
  self,
392
611
  build_dir: Path,
612
+ should_install_server_requirements: bool,
393
613
  model_files: Dict[str, Any],
394
614
  use_hf_secret: bool,
395
615
  cached_files: List[str],
396
616
  external_data_files: List[Tuple[str, str]],
617
+ build_commands: List[str],
397
618
  ):
398
619
  config = self._spec.config
399
620
  data_dir = build_dir / config.data_dir
621
+ model_dir = build_dir / config.model_module_dir
400
622
  bundled_packages_dir = build_dir / config.bundled_packages_dir
401
-
402
623
  dockerfile_template = read_template_from_fs(
403
624
  TEMPLATES_DIR, SERVER_DOCKERFILE_TEMPLATE_NAME
404
625
  )
@@ -423,9 +644,31 @@ class ServingImageBuilder(ImageBuilder):
423
644
  build_dir / USER_SUPPLIED_REQUIREMENTS_TXT_FILENAME
424
645
  )
425
646
 
426
- hf_access_token = config.secrets.get(HF_ACCESS_TOKEN_SECRET_NAME)
647
+ max_supported_python_version_in_custom_base_image = (
648
+ MAX_SUPPORTED_PYTHON_VERSION_IN_CUSTOM_BASE_IMAGE
649
+ )
650
+ min_supported_python_version_in_custom_base_image = (
651
+ MIN_SUPPORTED_PYTHON_VERSION_IN_CUSTOM_BASE_IMAGE
652
+ )
653
+ max_supported_python_minor_version_in_custom_base_image = (
654
+ MAX_SUPPORTED_PYTHON_VERSION_IN_CUSTOM_BASE_IMAGE.split(".")[1]
655
+ )
656
+ min_supported_python_minor_version_in_custom_base_image = (
657
+ MIN_SUPPORTED_PYTHON_VERSION_IN_CUSTOM_BASE_IMAGE.split(".")[1]
658
+ )
659
+ supported_python_major_version_in_custom_base_image = (
660
+ MIN_SUPPORTED_PYTHON_VERSION_IN_CUSTOM_BASE_IMAGE.split(".")[0]
661
+ )
662
+
663
+ hf_access_token = config.secrets.get(constants.HF_ACCESS_TOKEN_KEY)
427
664
  dockerfile_contents = dockerfile_template.render(
665
+ should_install_server_requirements=should_install_server_requirements,
428
666
  base_image_name_and_tag=base_image_name_and_tag,
667
+ max_supported_python_version_in_custom_base_image=max_supported_python_version_in_custom_base_image,
668
+ min_supported_python_version_in_custom_base_image=min_supported_python_version_in_custom_base_image,
669
+ max_supported_python_minor_version_in_custom_base_image=max_supported_python_minor_version_in_custom_base_image,
670
+ min_supported_python_minor_version_in_custom_base_image=min_supported_python_minor_version_in_custom_base_image,
671
+ supported_python_major_version_in_custom_base_image=supported_python_major_version_in_custom_base_image,
429
672
  should_install_system_requirements=should_install_system_requirements,
430
673
  should_install_requirements=should_install_python_requirements,
431
674
  should_install_user_requirements_file=should_install_user_requirements_file,
@@ -433,6 +676,7 @@ class ServingImageBuilder(ImageBuilder):
433
676
  python_version=python_version,
434
677
  live_reload=config.live_reload,
435
678
  data_dir_exists=data_dir.exists(),
679
+ model_dir_exists=model_dir.exists(),
436
680
  bundled_packages_dir_exists=bundled_packages_dir.exists(),
437
681
  truss_hash=directory_content_hash(
438
682
  self._truss_dir, self._spec.hash_ignore_patterns
@@ -445,6 +689,8 @@ class ServingImageBuilder(ImageBuilder):
445
689
  hf_access_token=hf_access_token,
446
690
  hf_access_token_file_name=HF_ACCESS_TOKEN_FILE_NAME,
447
691
  external_data_files=external_data_files,
692
+ build_commands=build_commands,
693
+ use_local_chains_src=config.use_local_chains_src,
448
694
  **FILENAME_CONSTANTS_MAP,
449
695
  )
450
696
  docker_file_path = build_dir / MODEL_DOCKERFILE_NAME
@@ -36,9 +36,7 @@ def truss_base_image_name(job_type: str) -> str:
36
36
 
37
37
 
38
38
  def truss_base_image_tag(
39
- python_version: str,
40
- use_gpu: bool,
41
- version_tag: Optional[str] = None,
39
+ python_version: str, use_gpu: bool, version_tag: Optional[str] = None
42
40
  ) -> str:
43
41
  if version_tag is None:
44
42
  version_tag = f"v{__version__}"
@@ -0,0 +1,58 @@
1
+ from dataclasses import dataclass, field
2
+ from pathlib import Path
3
+ from typing import Dict, List
4
+
5
+ from truss.util.path import copy_tree_or_file
6
+
7
+
8
+ @dataclass
9
+ class DockerBuildEmulatorResult:
10
+ workdir: Path = field(default_factory=lambda: Path("/"))
11
+ env: Dict = field(default_factory=dict)
12
+ entrypoint: List = field(default_factory=list)
13
+
14
+
15
+ class DockerBuildEmulator:
16
+ """Emulates Docker Builds
17
+
18
+ As running docker builds is expensive, this class emulates the docker build
19
+ by parsing the docker file and applying certain commands to create an
20
+ appropriate enviroment in a directory to simulate the root of the file system.
21
+
22
+ Support COPY, ENV, ENTRYPOINT, WORKDIR commands. All other commands are ignored.
23
+ """
24
+
25
+ def __init__(self, dockerfile_path: Path, context_dir: Path) -> None:
26
+ import dockerfile
27
+
28
+ self._commands = dockerfile.parse_file(str(dockerfile_path))
29
+ self._context_dir = context_dir
30
+
31
+ def run(self, fs_root_dir: Path) -> DockerBuildEmulatorResult:
32
+ def _resolve_env(key: str) -> str:
33
+ if key.startswith("$"):
34
+ key = key.replace("$", "", 1)
35
+ v = result.env[key]
36
+ return v
37
+ return key
38
+
39
+ def _resolve_values(keys: List[str]) -> List[str]:
40
+ return list(map(_resolve_env, keys))
41
+
42
+ result = DockerBuildEmulatorResult()
43
+ for cmd in self._commands:
44
+ if cmd.cmd not in ["ENV", "ENTRYPOINT", "COPY", "WORKDIR"]:
45
+ continue
46
+ values = _resolve_values(cmd.value)
47
+ if cmd.cmd == "ENV":
48
+ result.env[values[0]] = values[1]
49
+ if cmd.cmd == "ENTRYPOINT":
50
+ result.entrypoint = list(values)
51
+ if cmd.cmd == "COPY":
52
+ src, dst = values
53
+ src = src.replace("./", "", 1)
54
+ dst = dst.replace("/", "", 1)
55
+ copy_tree_or_file(self._context_dir / src, fs_root_dir / dst)
56
+ if cmd.cmd == "WORKDIR":
57
+ result.workdir = result.workdir / values[0]
58
+ return result
@@ -1,14 +1,14 @@
1
1
  import inspect
2
2
  from pathlib import Path
3
3
 
4
+ from truss.base.truss_spec import TrussSpec
4
5
  from truss.contexts.local_loader.truss_module_loader import truss_module_loaded
5
6
  from truss.contexts.local_loader.utils import (
6
7
  prepare_secrets,
7
8
  signature_accepts_keyword_arg,
8
9
  )
9
10
  from truss.contexts.truss_context import TrussContext
10
- from truss.server.common.patches import apply_patches
11
- from truss.truss_spec import TrussSpec
11
+ from truss.templates.server.common.patches import apply_patches
12
12
 
13
13
 
14
14
  class LoadModelLocal(TrussContext):