llama-stack 0.3.5__py3-none-any.whl → 0.4.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.
Files changed (458) hide show
  1. llama_stack/__init__.py +0 -5
  2. llama_stack/cli/llama.py +3 -3
  3. llama_stack/cli/stack/_list_deps.py +12 -23
  4. llama_stack/cli/stack/list_stacks.py +37 -18
  5. llama_stack/cli/stack/run.py +121 -11
  6. llama_stack/cli/stack/utils.py +0 -127
  7. llama_stack/core/access_control/access_control.py +69 -28
  8. llama_stack/core/access_control/conditions.py +15 -5
  9. llama_stack/core/admin.py +267 -0
  10. llama_stack/core/build.py +6 -74
  11. llama_stack/core/client.py +1 -1
  12. llama_stack/core/configure.py +6 -6
  13. llama_stack/core/conversations/conversations.py +28 -25
  14. llama_stack/core/datatypes.py +271 -79
  15. llama_stack/core/distribution.py +15 -16
  16. llama_stack/core/external.py +3 -3
  17. llama_stack/core/inspect.py +98 -15
  18. llama_stack/core/library_client.py +73 -61
  19. llama_stack/core/prompts/prompts.py +12 -11
  20. llama_stack/core/providers.py +17 -11
  21. llama_stack/core/resolver.py +65 -56
  22. llama_stack/core/routers/__init__.py +8 -12
  23. llama_stack/core/routers/datasets.py +1 -4
  24. llama_stack/core/routers/eval_scoring.py +7 -4
  25. llama_stack/core/routers/inference.py +55 -271
  26. llama_stack/core/routers/safety.py +52 -24
  27. llama_stack/core/routers/tool_runtime.py +6 -48
  28. llama_stack/core/routers/vector_io.py +130 -51
  29. llama_stack/core/routing_tables/benchmarks.py +24 -20
  30. llama_stack/core/routing_tables/common.py +1 -4
  31. llama_stack/core/routing_tables/datasets.py +22 -22
  32. llama_stack/core/routing_tables/models.py +119 -6
  33. llama_stack/core/routing_tables/scoring_functions.py +7 -7
  34. llama_stack/core/routing_tables/shields.py +1 -2
  35. llama_stack/core/routing_tables/toolgroups.py +17 -7
  36. llama_stack/core/routing_tables/vector_stores.py +51 -16
  37. llama_stack/core/server/auth.py +5 -3
  38. llama_stack/core/server/auth_providers.py +36 -20
  39. llama_stack/core/server/fastapi_router_registry.py +84 -0
  40. llama_stack/core/server/quota.py +2 -2
  41. llama_stack/core/server/routes.py +79 -27
  42. llama_stack/core/server/server.py +102 -87
  43. llama_stack/core/stack.py +201 -58
  44. llama_stack/core/storage/datatypes.py +26 -3
  45. llama_stack/{providers/utils → core/storage}/kvstore/__init__.py +2 -0
  46. llama_stack/{providers/utils → core/storage}/kvstore/kvstore.py +55 -24
  47. llama_stack/{providers/utils → core/storage}/kvstore/mongodb/mongodb.py +13 -10
  48. llama_stack/{providers/utils → core/storage}/kvstore/postgres/postgres.py +28 -17
  49. llama_stack/{providers/utils → core/storage}/kvstore/redis/redis.py +41 -16
  50. llama_stack/{providers/utils → core/storage}/kvstore/sqlite/sqlite.py +1 -1
  51. llama_stack/core/storage/sqlstore/__init__.py +17 -0
  52. llama_stack/{providers/utils → core/storage}/sqlstore/authorized_sqlstore.py +69 -49
  53. llama_stack/{providers/utils → core/storage}/sqlstore/sqlalchemy_sqlstore.py +47 -17
  54. llama_stack/{providers/utils → core/storage}/sqlstore/sqlstore.py +25 -8
  55. llama_stack/core/store/registry.py +1 -1
  56. llama_stack/core/utils/config.py +8 -2
  57. llama_stack/core/utils/config_resolution.py +32 -29
  58. llama_stack/core/utils/context.py +4 -10
  59. llama_stack/core/utils/exec.py +9 -0
  60. llama_stack/core/utils/type_inspection.py +45 -0
  61. llama_stack/distributions/dell/{run.yaml → config.yaml} +3 -2
  62. llama_stack/distributions/dell/dell.py +2 -2
  63. llama_stack/distributions/dell/run-with-safety.yaml +3 -2
  64. llama_stack/distributions/meta-reference-gpu/{run.yaml → config.yaml} +3 -2
  65. llama_stack/distributions/meta-reference-gpu/meta_reference.py +2 -2
  66. llama_stack/distributions/meta-reference-gpu/run-with-safety.yaml +3 -2
  67. llama_stack/distributions/nvidia/{run.yaml → config.yaml} +4 -4
  68. llama_stack/distributions/nvidia/nvidia.py +1 -1
  69. llama_stack/distributions/nvidia/run-with-safety.yaml +4 -4
  70. llama_stack/{apis/datasetio → distributions/oci}/__init__.py +1 -1
  71. llama_stack/distributions/oci/config.yaml +134 -0
  72. llama_stack/distributions/oci/oci.py +108 -0
  73. llama_stack/distributions/open-benchmark/{run.yaml → config.yaml} +5 -4
  74. llama_stack/distributions/open-benchmark/open_benchmark.py +2 -3
  75. llama_stack/distributions/postgres-demo/{run.yaml → config.yaml} +4 -3
  76. llama_stack/distributions/starter/{run.yaml → config.yaml} +64 -13
  77. llama_stack/distributions/starter/run-with-postgres-store.yaml +64 -13
  78. llama_stack/distributions/starter/starter.py +8 -5
  79. llama_stack/distributions/starter-gpu/{run.yaml → config.yaml} +64 -13
  80. llama_stack/distributions/starter-gpu/run-with-postgres-store.yaml +64 -13
  81. llama_stack/distributions/template.py +13 -69
  82. llama_stack/distributions/watsonx/{run.yaml → config.yaml} +4 -3
  83. llama_stack/distributions/watsonx/watsonx.py +1 -1
  84. llama_stack/log.py +28 -11
  85. llama_stack/models/llama/checkpoint.py +6 -6
  86. llama_stack/models/llama/hadamard_utils.py +2 -0
  87. llama_stack/models/llama/llama3/generation.py +3 -1
  88. llama_stack/models/llama/llama3/interface.py +2 -5
  89. llama_stack/models/llama/llama3/multimodal/encoder_utils.py +3 -3
  90. llama_stack/models/llama/llama3/multimodal/image_transform.py +6 -6
  91. llama_stack/models/llama/llama3/prompt_templates/system_prompts.py +1 -1
  92. llama_stack/models/llama/llama3/tool_utils.py +2 -1
  93. llama_stack/models/llama/llama4/prompt_templates/system_prompts.py +1 -1
  94. llama_stack/providers/inline/agents/meta_reference/__init__.py +3 -3
  95. llama_stack/providers/inline/agents/meta_reference/agents.py +44 -261
  96. llama_stack/providers/inline/agents/meta_reference/config.py +6 -1
  97. llama_stack/providers/inline/agents/meta_reference/responses/openai_responses.py +207 -57
  98. llama_stack/providers/inline/agents/meta_reference/responses/streaming.py +308 -47
  99. llama_stack/providers/inline/agents/meta_reference/responses/tool_executor.py +162 -96
  100. llama_stack/providers/inline/agents/meta_reference/responses/types.py +23 -8
  101. llama_stack/providers/inline/agents/meta_reference/responses/utils.py +201 -33
  102. llama_stack/providers/inline/agents/meta_reference/safety.py +8 -13
  103. llama_stack/providers/inline/batches/reference/__init__.py +2 -4
  104. llama_stack/providers/inline/batches/reference/batches.py +78 -60
  105. llama_stack/providers/inline/datasetio/localfs/datasetio.py +2 -5
  106. llama_stack/providers/inline/eval/meta_reference/eval.py +16 -61
  107. llama_stack/providers/inline/files/localfs/files.py +37 -28
  108. llama_stack/providers/inline/inference/meta_reference/config.py +2 -2
  109. llama_stack/providers/inline/inference/meta_reference/generators.py +50 -60
  110. llama_stack/providers/inline/inference/meta_reference/inference.py +403 -19
  111. llama_stack/providers/inline/inference/meta_reference/model_parallel.py +7 -26
  112. llama_stack/providers/inline/inference/meta_reference/parallel_utils.py +2 -12
  113. llama_stack/providers/inline/inference/sentence_transformers/sentence_transformers.py +10 -15
  114. llama_stack/providers/inline/post_training/common/validator.py +1 -5
  115. llama_stack/providers/inline/post_training/huggingface/post_training.py +8 -8
  116. llama_stack/providers/inline/post_training/huggingface/recipes/finetune_single_device.py +18 -10
  117. llama_stack/providers/inline/post_training/huggingface/recipes/finetune_single_device_dpo.py +12 -9
  118. llama_stack/providers/inline/post_training/huggingface/utils.py +27 -6
  119. llama_stack/providers/inline/post_training/torchtune/common/checkpointer.py +1 -1
  120. llama_stack/providers/inline/post_training/torchtune/common/utils.py +1 -1
  121. llama_stack/providers/inline/post_training/torchtune/datasets/format_adapter.py +1 -1
  122. llama_stack/providers/inline/post_training/torchtune/post_training.py +8 -8
  123. llama_stack/providers/inline/post_training/torchtune/recipes/lora_finetuning_single_device.py +16 -16
  124. llama_stack/providers/inline/safety/code_scanner/code_scanner.py +13 -9
  125. llama_stack/providers/inline/safety/llama_guard/llama_guard.py +18 -15
  126. llama_stack/providers/inline/safety/prompt_guard/prompt_guard.py +9 -9
  127. llama_stack/providers/inline/scoring/basic/scoring.py +6 -13
  128. llama_stack/providers/inline/scoring/basic/scoring_fn/docvqa_scoring_fn.py +1 -2
  129. llama_stack/providers/inline/scoring/basic/scoring_fn/equality_scoring_fn.py +1 -2
  130. llama_stack/providers/inline/scoring/basic/scoring_fn/fn_defs/docvqa.py +2 -2
  131. llama_stack/providers/inline/scoring/basic/scoring_fn/fn_defs/equality.py +2 -2
  132. llama_stack/providers/inline/scoring/basic/scoring_fn/fn_defs/ifeval.py +2 -2
  133. llama_stack/providers/inline/scoring/basic/scoring_fn/fn_defs/regex_parser_math_response.py +2 -2
  134. llama_stack/providers/inline/scoring/basic/scoring_fn/fn_defs/regex_parser_multiple_choice_answer.py +2 -2
  135. llama_stack/providers/inline/scoring/basic/scoring_fn/fn_defs/subset_of.py +2 -2
  136. llama_stack/providers/inline/scoring/basic/scoring_fn/ifeval_scoring_fn.py +1 -2
  137. llama_stack/providers/inline/scoring/basic/scoring_fn/regex_parser_math_response_scoring_fn.py +1 -2
  138. llama_stack/providers/inline/scoring/basic/scoring_fn/regex_parser_scoring_fn.py +1 -2
  139. llama_stack/providers/inline/scoring/basic/scoring_fn/subset_of_scoring_fn.py +1 -2
  140. llama_stack/providers/inline/scoring/braintrust/braintrust.py +12 -15
  141. llama_stack/providers/inline/scoring/braintrust/scoring_fn/fn_defs/answer_correctness.py +2 -2
  142. llama_stack/providers/inline/scoring/braintrust/scoring_fn/fn_defs/answer_relevancy.py +2 -2
  143. llama_stack/providers/inline/scoring/braintrust/scoring_fn/fn_defs/answer_similarity.py +2 -2
  144. llama_stack/providers/inline/scoring/braintrust/scoring_fn/fn_defs/context_entity_recall.py +2 -2
  145. llama_stack/providers/inline/scoring/braintrust/scoring_fn/fn_defs/context_precision.py +2 -2
  146. llama_stack/providers/inline/scoring/braintrust/scoring_fn/fn_defs/context_recall.py +2 -2
  147. llama_stack/providers/inline/scoring/braintrust/scoring_fn/fn_defs/context_relevancy.py +2 -2
  148. llama_stack/providers/inline/scoring/braintrust/scoring_fn/fn_defs/factuality.py +2 -2
  149. llama_stack/providers/inline/scoring/braintrust/scoring_fn/fn_defs/faithfulness.py +2 -2
  150. llama_stack/providers/inline/scoring/llm_as_judge/scoring.py +7 -14
  151. llama_stack/providers/inline/scoring/llm_as_judge/scoring_fn/fn_defs/llm_as_judge_405b_simpleqa.py +2 -2
  152. llama_stack/providers/inline/scoring/llm_as_judge/scoring_fn/fn_defs/llm_as_judge_base.py +1 -2
  153. llama_stack/providers/inline/scoring/llm_as_judge/scoring_fn/llm_as_judge_scoring_fn.py +1 -3
  154. llama_stack/providers/inline/tool_runtime/rag/__init__.py +1 -1
  155. llama_stack/providers/inline/tool_runtime/rag/config.py +8 -1
  156. llama_stack/providers/inline/tool_runtime/rag/context_retriever.py +7 -6
  157. llama_stack/providers/inline/tool_runtime/rag/memory.py +64 -48
  158. llama_stack/providers/inline/vector_io/chroma/__init__.py +1 -1
  159. llama_stack/providers/inline/vector_io/chroma/config.py +1 -1
  160. llama_stack/providers/inline/vector_io/faiss/__init__.py +1 -1
  161. llama_stack/providers/inline/vector_io/faiss/config.py +1 -1
  162. llama_stack/providers/inline/vector_io/faiss/faiss.py +43 -28
  163. llama_stack/providers/inline/vector_io/milvus/__init__.py +1 -1
  164. llama_stack/providers/inline/vector_io/milvus/config.py +1 -1
  165. llama_stack/providers/inline/vector_io/qdrant/__init__.py +1 -1
  166. llama_stack/providers/inline/vector_io/qdrant/config.py +1 -1
  167. llama_stack/providers/inline/vector_io/sqlite_vec/__init__.py +1 -1
  168. llama_stack/providers/inline/vector_io/sqlite_vec/sqlite_vec.py +40 -33
  169. llama_stack/providers/registry/agents.py +7 -3
  170. llama_stack/providers/registry/batches.py +1 -1
  171. llama_stack/providers/registry/datasetio.py +1 -1
  172. llama_stack/providers/registry/eval.py +1 -1
  173. llama_stack/{apis/datasets/__init__.py → providers/registry/file_processors.py} +5 -1
  174. llama_stack/providers/registry/files.py +11 -2
  175. llama_stack/providers/registry/inference.py +22 -3
  176. llama_stack/providers/registry/post_training.py +1 -1
  177. llama_stack/providers/registry/safety.py +1 -1
  178. llama_stack/providers/registry/scoring.py +1 -1
  179. llama_stack/providers/registry/tool_runtime.py +2 -2
  180. llama_stack/providers/registry/vector_io.py +7 -7
  181. llama_stack/providers/remote/datasetio/huggingface/huggingface.py +2 -5
  182. llama_stack/providers/remote/datasetio/nvidia/datasetio.py +1 -4
  183. llama_stack/providers/remote/eval/nvidia/eval.py +15 -9
  184. llama_stack/providers/remote/files/openai/__init__.py +19 -0
  185. llama_stack/providers/remote/files/openai/config.py +28 -0
  186. llama_stack/providers/remote/files/openai/files.py +253 -0
  187. llama_stack/providers/remote/files/s3/files.py +52 -30
  188. llama_stack/providers/remote/inference/anthropic/anthropic.py +2 -1
  189. llama_stack/providers/remote/inference/anthropic/config.py +1 -1
  190. llama_stack/providers/remote/inference/azure/azure.py +1 -3
  191. llama_stack/providers/remote/inference/azure/config.py +8 -7
  192. llama_stack/providers/remote/inference/bedrock/__init__.py +1 -1
  193. llama_stack/providers/remote/inference/bedrock/bedrock.py +82 -105
  194. llama_stack/providers/remote/inference/bedrock/config.py +24 -3
  195. llama_stack/providers/remote/inference/cerebras/cerebras.py +5 -5
  196. llama_stack/providers/remote/inference/cerebras/config.py +12 -5
  197. llama_stack/providers/remote/inference/databricks/config.py +13 -6
  198. llama_stack/providers/remote/inference/databricks/databricks.py +16 -6
  199. llama_stack/providers/remote/inference/fireworks/config.py +5 -5
  200. llama_stack/providers/remote/inference/fireworks/fireworks.py +1 -1
  201. llama_stack/providers/remote/inference/gemini/config.py +1 -1
  202. llama_stack/providers/remote/inference/gemini/gemini.py +13 -14
  203. llama_stack/providers/remote/inference/groq/config.py +5 -5
  204. llama_stack/providers/remote/inference/groq/groq.py +1 -1
  205. llama_stack/providers/remote/inference/llama_openai_compat/config.py +5 -5
  206. llama_stack/providers/remote/inference/llama_openai_compat/llama.py +8 -6
  207. llama_stack/providers/remote/inference/nvidia/__init__.py +1 -1
  208. llama_stack/providers/remote/inference/nvidia/config.py +21 -11
  209. llama_stack/providers/remote/inference/nvidia/nvidia.py +115 -3
  210. llama_stack/providers/remote/inference/nvidia/utils.py +1 -1
  211. llama_stack/providers/remote/inference/oci/__init__.py +17 -0
  212. llama_stack/providers/remote/inference/oci/auth.py +79 -0
  213. llama_stack/providers/remote/inference/oci/config.py +75 -0
  214. llama_stack/providers/remote/inference/oci/oci.py +162 -0
  215. llama_stack/providers/remote/inference/ollama/config.py +7 -5
  216. llama_stack/providers/remote/inference/ollama/ollama.py +17 -8
  217. llama_stack/providers/remote/inference/openai/config.py +4 -4
  218. llama_stack/providers/remote/inference/openai/openai.py +1 -1
  219. llama_stack/providers/remote/inference/passthrough/__init__.py +2 -2
  220. llama_stack/providers/remote/inference/passthrough/config.py +5 -10
  221. llama_stack/providers/remote/inference/passthrough/passthrough.py +97 -75
  222. llama_stack/providers/remote/inference/runpod/config.py +12 -5
  223. llama_stack/providers/remote/inference/runpod/runpod.py +2 -20
  224. llama_stack/providers/remote/inference/sambanova/config.py +5 -5
  225. llama_stack/providers/remote/inference/sambanova/sambanova.py +1 -1
  226. llama_stack/providers/remote/inference/tgi/config.py +7 -6
  227. llama_stack/providers/remote/inference/tgi/tgi.py +19 -11
  228. llama_stack/providers/remote/inference/together/config.py +5 -5
  229. llama_stack/providers/remote/inference/together/together.py +15 -12
  230. llama_stack/providers/remote/inference/vertexai/config.py +1 -1
  231. llama_stack/providers/remote/inference/vllm/config.py +5 -5
  232. llama_stack/providers/remote/inference/vllm/vllm.py +13 -14
  233. llama_stack/providers/remote/inference/watsonx/config.py +4 -4
  234. llama_stack/providers/remote/inference/watsonx/watsonx.py +21 -94
  235. llama_stack/providers/remote/post_training/nvidia/post_training.py +4 -4
  236. llama_stack/providers/remote/post_training/nvidia/utils.py +1 -1
  237. llama_stack/providers/remote/safety/bedrock/bedrock.py +6 -6
  238. llama_stack/providers/remote/safety/bedrock/config.py +1 -1
  239. llama_stack/providers/remote/safety/nvidia/config.py +1 -1
  240. llama_stack/providers/remote/safety/nvidia/nvidia.py +11 -5
  241. llama_stack/providers/remote/safety/sambanova/config.py +1 -1
  242. llama_stack/providers/remote/safety/sambanova/sambanova.py +6 -6
  243. llama_stack/providers/remote/tool_runtime/bing_search/bing_search.py +11 -6
  244. llama_stack/providers/remote/tool_runtime/brave_search/brave_search.py +12 -7
  245. llama_stack/providers/remote/tool_runtime/model_context_protocol/config.py +8 -2
  246. llama_stack/providers/remote/tool_runtime/model_context_protocol/model_context_protocol.py +57 -15
  247. llama_stack/providers/remote/tool_runtime/tavily_search/tavily_search.py +11 -6
  248. llama_stack/providers/remote/tool_runtime/wolfram_alpha/wolfram_alpha.py +11 -6
  249. llama_stack/providers/remote/vector_io/chroma/__init__.py +1 -1
  250. llama_stack/providers/remote/vector_io/chroma/chroma.py +125 -20
  251. llama_stack/providers/remote/vector_io/chroma/config.py +1 -1
  252. llama_stack/providers/remote/vector_io/milvus/__init__.py +1 -1
  253. llama_stack/providers/remote/vector_io/milvus/config.py +1 -1
  254. llama_stack/providers/remote/vector_io/milvus/milvus.py +27 -21
  255. llama_stack/providers/remote/vector_io/pgvector/__init__.py +1 -1
  256. llama_stack/providers/remote/vector_io/pgvector/config.py +1 -1
  257. llama_stack/providers/remote/vector_io/pgvector/pgvector.py +26 -18
  258. llama_stack/providers/remote/vector_io/qdrant/__init__.py +1 -1
  259. llama_stack/providers/remote/vector_io/qdrant/config.py +1 -1
  260. llama_stack/providers/remote/vector_io/qdrant/qdrant.py +141 -24
  261. llama_stack/providers/remote/vector_io/weaviate/__init__.py +1 -1
  262. llama_stack/providers/remote/vector_io/weaviate/config.py +1 -1
  263. llama_stack/providers/remote/vector_io/weaviate/weaviate.py +26 -21
  264. llama_stack/providers/utils/common/data_schema_validator.py +1 -5
  265. llama_stack/providers/utils/files/form_data.py +1 -1
  266. llama_stack/providers/utils/inference/embedding_mixin.py +1 -1
  267. llama_stack/providers/utils/inference/inference_store.py +7 -8
  268. llama_stack/providers/utils/inference/litellm_openai_mixin.py +79 -79
  269. llama_stack/providers/utils/inference/model_registry.py +1 -3
  270. llama_stack/providers/utils/inference/openai_compat.py +44 -1171
  271. llama_stack/providers/utils/inference/openai_mixin.py +68 -42
  272. llama_stack/providers/utils/inference/prompt_adapter.py +50 -265
  273. llama_stack/providers/utils/inference/stream_utils.py +23 -0
  274. llama_stack/providers/utils/memory/__init__.py +2 -0
  275. llama_stack/providers/utils/memory/file_utils.py +1 -1
  276. llama_stack/providers/utils/memory/openai_vector_store_mixin.py +181 -84
  277. llama_stack/providers/utils/memory/vector_store.py +39 -38
  278. llama_stack/providers/utils/pagination.py +1 -1
  279. llama_stack/providers/utils/responses/responses_store.py +15 -25
  280. llama_stack/providers/utils/scoring/aggregation_utils.py +1 -2
  281. llama_stack/providers/utils/scoring/base_scoring_fn.py +1 -2
  282. llama_stack/providers/utils/tools/mcp.py +93 -11
  283. llama_stack/telemetry/constants.py +27 -0
  284. llama_stack/telemetry/helpers.py +43 -0
  285. llama_stack/testing/api_recorder.py +25 -16
  286. {llama_stack-0.3.5.dist-info → llama_stack-0.4.0.dist-info}/METADATA +56 -54
  287. llama_stack-0.4.0.dist-info/RECORD +588 -0
  288. llama_stack-0.4.0.dist-info/top_level.txt +2 -0
  289. llama_stack_api/__init__.py +945 -0
  290. llama_stack_api/admin/__init__.py +45 -0
  291. llama_stack_api/admin/api.py +72 -0
  292. llama_stack_api/admin/fastapi_routes.py +117 -0
  293. llama_stack_api/admin/models.py +113 -0
  294. llama_stack_api/agents.py +173 -0
  295. llama_stack_api/batches/__init__.py +40 -0
  296. llama_stack_api/batches/api.py +53 -0
  297. llama_stack_api/batches/fastapi_routes.py +113 -0
  298. llama_stack_api/batches/models.py +78 -0
  299. llama_stack_api/benchmarks/__init__.py +43 -0
  300. llama_stack_api/benchmarks/api.py +39 -0
  301. llama_stack_api/benchmarks/fastapi_routes.py +109 -0
  302. llama_stack_api/benchmarks/models.py +109 -0
  303. {llama_stack/apis → llama_stack_api}/common/content_types.py +1 -43
  304. {llama_stack/apis → llama_stack_api}/common/errors.py +0 -8
  305. {llama_stack/apis → llama_stack_api}/common/job_types.py +1 -1
  306. llama_stack_api/common/responses.py +77 -0
  307. {llama_stack/apis → llama_stack_api}/common/training_types.py +1 -1
  308. {llama_stack/apis → llama_stack_api}/common/type_system.py +2 -14
  309. llama_stack_api/connectors.py +146 -0
  310. {llama_stack/apis/conversations → llama_stack_api}/conversations.py +23 -39
  311. {llama_stack/apis/datasetio → llama_stack_api}/datasetio.py +4 -8
  312. llama_stack_api/datasets/__init__.py +61 -0
  313. llama_stack_api/datasets/api.py +35 -0
  314. llama_stack_api/datasets/fastapi_routes.py +104 -0
  315. llama_stack_api/datasets/models.py +152 -0
  316. {llama_stack/providers → llama_stack_api}/datatypes.py +166 -10
  317. {llama_stack/apis/eval → llama_stack_api}/eval.py +8 -40
  318. llama_stack_api/file_processors/__init__.py +27 -0
  319. llama_stack_api/file_processors/api.py +64 -0
  320. llama_stack_api/file_processors/fastapi_routes.py +78 -0
  321. llama_stack_api/file_processors/models.py +42 -0
  322. llama_stack_api/files/__init__.py +35 -0
  323. llama_stack_api/files/api.py +51 -0
  324. llama_stack_api/files/fastapi_routes.py +124 -0
  325. llama_stack_api/files/models.py +107 -0
  326. {llama_stack/apis/inference → llama_stack_api}/inference.py +90 -194
  327. llama_stack_api/inspect_api/__init__.py +37 -0
  328. llama_stack_api/inspect_api/api.py +25 -0
  329. llama_stack_api/inspect_api/fastapi_routes.py +76 -0
  330. llama_stack_api/inspect_api/models.py +28 -0
  331. {llama_stack/apis/agents → llama_stack_api/internal}/__init__.py +3 -1
  332. llama_stack/providers/utils/kvstore/api.py → llama_stack_api/internal/kvstore.py +5 -0
  333. llama_stack_api/internal/sqlstore.py +79 -0
  334. {llama_stack/apis/models → llama_stack_api}/models.py +11 -9
  335. {llama_stack/apis/agents → llama_stack_api}/openai_responses.py +184 -27
  336. {llama_stack/apis/post_training → llama_stack_api}/post_training.py +7 -11
  337. {llama_stack/apis/prompts → llama_stack_api}/prompts.py +3 -4
  338. llama_stack_api/providers/__init__.py +33 -0
  339. llama_stack_api/providers/api.py +16 -0
  340. llama_stack_api/providers/fastapi_routes.py +57 -0
  341. llama_stack_api/providers/models.py +24 -0
  342. {llama_stack/apis/tools → llama_stack_api}/rag_tool.py +2 -52
  343. {llama_stack/apis → llama_stack_api}/resource.py +1 -1
  344. llama_stack_api/router_utils.py +160 -0
  345. {llama_stack/apis/safety → llama_stack_api}/safety.py +6 -9
  346. {llama_stack → llama_stack_api}/schema_utils.py +94 -4
  347. {llama_stack/apis/scoring → llama_stack_api}/scoring.py +3 -3
  348. {llama_stack/apis/scoring_functions → llama_stack_api}/scoring_functions.py +9 -6
  349. {llama_stack/apis/shields → llama_stack_api}/shields.py +6 -7
  350. {llama_stack/apis/tools → llama_stack_api}/tools.py +26 -21
  351. {llama_stack/apis/vector_io → llama_stack_api}/vector_io.py +133 -152
  352. {llama_stack/apis/vector_stores → llama_stack_api}/vector_stores.py +1 -1
  353. llama_stack/apis/agents/agents.py +0 -894
  354. llama_stack/apis/batches/__init__.py +0 -9
  355. llama_stack/apis/batches/batches.py +0 -100
  356. llama_stack/apis/benchmarks/__init__.py +0 -7
  357. llama_stack/apis/benchmarks/benchmarks.py +0 -108
  358. llama_stack/apis/common/responses.py +0 -36
  359. llama_stack/apis/conversations/__init__.py +0 -31
  360. llama_stack/apis/datasets/datasets.py +0 -251
  361. llama_stack/apis/datatypes.py +0 -160
  362. llama_stack/apis/eval/__init__.py +0 -7
  363. llama_stack/apis/files/__init__.py +0 -7
  364. llama_stack/apis/files/files.py +0 -199
  365. llama_stack/apis/inference/__init__.py +0 -7
  366. llama_stack/apis/inference/event_logger.py +0 -43
  367. llama_stack/apis/inspect/__init__.py +0 -7
  368. llama_stack/apis/inspect/inspect.py +0 -94
  369. llama_stack/apis/models/__init__.py +0 -7
  370. llama_stack/apis/post_training/__init__.py +0 -7
  371. llama_stack/apis/prompts/__init__.py +0 -9
  372. llama_stack/apis/providers/__init__.py +0 -7
  373. llama_stack/apis/providers/providers.py +0 -69
  374. llama_stack/apis/safety/__init__.py +0 -7
  375. llama_stack/apis/scoring/__init__.py +0 -7
  376. llama_stack/apis/scoring_functions/__init__.py +0 -7
  377. llama_stack/apis/shields/__init__.py +0 -7
  378. llama_stack/apis/synthetic_data_generation/__init__.py +0 -7
  379. llama_stack/apis/synthetic_data_generation/synthetic_data_generation.py +0 -77
  380. llama_stack/apis/telemetry/__init__.py +0 -7
  381. llama_stack/apis/telemetry/telemetry.py +0 -423
  382. llama_stack/apis/tools/__init__.py +0 -8
  383. llama_stack/apis/vector_io/__init__.py +0 -7
  384. llama_stack/apis/vector_stores/__init__.py +0 -7
  385. llama_stack/core/server/tracing.py +0 -80
  386. llama_stack/core/ui/app.py +0 -55
  387. llama_stack/core/ui/modules/__init__.py +0 -5
  388. llama_stack/core/ui/modules/api.py +0 -32
  389. llama_stack/core/ui/modules/utils.py +0 -42
  390. llama_stack/core/ui/page/__init__.py +0 -5
  391. llama_stack/core/ui/page/distribution/__init__.py +0 -5
  392. llama_stack/core/ui/page/distribution/datasets.py +0 -18
  393. llama_stack/core/ui/page/distribution/eval_tasks.py +0 -20
  394. llama_stack/core/ui/page/distribution/models.py +0 -18
  395. llama_stack/core/ui/page/distribution/providers.py +0 -27
  396. llama_stack/core/ui/page/distribution/resources.py +0 -48
  397. llama_stack/core/ui/page/distribution/scoring_functions.py +0 -18
  398. llama_stack/core/ui/page/distribution/shields.py +0 -19
  399. llama_stack/core/ui/page/evaluations/__init__.py +0 -5
  400. llama_stack/core/ui/page/evaluations/app_eval.py +0 -143
  401. llama_stack/core/ui/page/evaluations/native_eval.py +0 -253
  402. llama_stack/core/ui/page/playground/__init__.py +0 -5
  403. llama_stack/core/ui/page/playground/chat.py +0 -130
  404. llama_stack/core/ui/page/playground/tools.py +0 -352
  405. llama_stack/distributions/dell/build.yaml +0 -33
  406. llama_stack/distributions/meta-reference-gpu/build.yaml +0 -32
  407. llama_stack/distributions/nvidia/build.yaml +0 -29
  408. llama_stack/distributions/open-benchmark/build.yaml +0 -36
  409. llama_stack/distributions/postgres-demo/__init__.py +0 -7
  410. llama_stack/distributions/postgres-demo/build.yaml +0 -23
  411. llama_stack/distributions/postgres-demo/postgres_demo.py +0 -125
  412. llama_stack/distributions/starter/build.yaml +0 -61
  413. llama_stack/distributions/starter-gpu/build.yaml +0 -61
  414. llama_stack/distributions/watsonx/build.yaml +0 -33
  415. llama_stack/providers/inline/agents/meta_reference/agent_instance.py +0 -1024
  416. llama_stack/providers/inline/agents/meta_reference/persistence.py +0 -228
  417. llama_stack/providers/inline/telemetry/__init__.py +0 -5
  418. llama_stack/providers/inline/telemetry/meta_reference/__init__.py +0 -21
  419. llama_stack/providers/inline/telemetry/meta_reference/config.py +0 -47
  420. llama_stack/providers/inline/telemetry/meta_reference/telemetry.py +0 -252
  421. llama_stack/providers/remote/inference/bedrock/models.py +0 -29
  422. llama_stack/providers/utils/kvstore/sqlite/config.py +0 -20
  423. llama_stack/providers/utils/sqlstore/__init__.py +0 -5
  424. llama_stack/providers/utils/sqlstore/api.py +0 -128
  425. llama_stack/providers/utils/telemetry/__init__.py +0 -5
  426. llama_stack/providers/utils/telemetry/trace_protocol.py +0 -142
  427. llama_stack/providers/utils/telemetry/tracing.py +0 -384
  428. llama_stack/strong_typing/__init__.py +0 -19
  429. llama_stack/strong_typing/auxiliary.py +0 -228
  430. llama_stack/strong_typing/classdef.py +0 -440
  431. llama_stack/strong_typing/core.py +0 -46
  432. llama_stack/strong_typing/deserializer.py +0 -877
  433. llama_stack/strong_typing/docstring.py +0 -409
  434. llama_stack/strong_typing/exception.py +0 -23
  435. llama_stack/strong_typing/inspection.py +0 -1085
  436. llama_stack/strong_typing/mapping.py +0 -40
  437. llama_stack/strong_typing/name.py +0 -182
  438. llama_stack/strong_typing/schema.py +0 -792
  439. llama_stack/strong_typing/serialization.py +0 -97
  440. llama_stack/strong_typing/serializer.py +0 -500
  441. llama_stack/strong_typing/slots.py +0 -27
  442. llama_stack/strong_typing/topological.py +0 -89
  443. llama_stack/ui/node_modules/flatted/python/flatted.py +0 -149
  444. llama_stack-0.3.5.dist-info/RECORD +0 -625
  445. llama_stack-0.3.5.dist-info/top_level.txt +0 -1
  446. /llama_stack/{providers/utils → core/storage}/kvstore/config.py +0 -0
  447. /llama_stack/{providers/utils → core/storage}/kvstore/mongodb/__init__.py +0 -0
  448. /llama_stack/{providers/utils → core/storage}/kvstore/postgres/__init__.py +0 -0
  449. /llama_stack/{providers/utils → core/storage}/kvstore/redis/__init__.py +0 -0
  450. /llama_stack/{providers/utils → core/storage}/kvstore/sqlite/__init__.py +0 -0
  451. /llama_stack/{apis → providers/inline/file_processor}/__init__.py +0 -0
  452. /llama_stack/{apis/common → telemetry}/__init__.py +0 -0
  453. {llama_stack-0.3.5.dist-info → llama_stack-0.4.0.dist-info}/WHEEL +0 -0
  454. {llama_stack-0.3.5.dist-info → llama_stack-0.4.0.dist-info}/entry_points.txt +0 -0
  455. {llama_stack-0.3.5.dist-info → llama_stack-0.4.0.dist-info}/licenses/LICENSE +0 -0
  456. {llama_stack/core/ui → llama_stack_api/common}/__init__.py +0 -0
  457. {llama_stack/strong_typing → llama_stack_api}/py.typed +0 -0
  458. {llama_stack/apis → llama_stack_api}/version.py +0 -0
@@ -1,1085 +0,0 @@
1
- # Copyright (c) Meta Platforms, Inc. and affiliates.
2
- # All rights reserved.
3
- #
4
- # This source code is licensed under the terms described in the LICENSE file in
5
- # the root directory of this source tree.
6
-
7
- """
8
- Type-safe data interchange for Python data classes.
9
-
10
- :see: https://github.com/hunyadi/strong_typing
11
- """
12
-
13
- import dataclasses
14
- import datetime
15
- import enum
16
- import importlib
17
- import importlib.machinery
18
- import importlib.util
19
- import inspect
20
- import re
21
- import sys
22
- import types
23
- import typing
24
- import uuid
25
- from typing import (
26
- Any,
27
- Callable,
28
- Dict,
29
- Iterable,
30
- List,
31
- Literal,
32
- NamedTuple,
33
- Optional,
34
- Protocol,
35
- Set,
36
- Tuple,
37
- Type,
38
- TypeVar,
39
- Union,
40
- runtime_checkable,
41
- )
42
-
43
- if sys.version_info >= (3, 9):
44
- from typing import Annotated
45
- else:
46
- from typing_extensions import Annotated
47
-
48
- if sys.version_info >= (3, 10):
49
- from typing import TypeGuard
50
- else:
51
- from typing_extensions import TypeGuard
52
-
53
-
54
- from pydantic import BaseModel
55
- from pydantic.fields import FieldInfo
56
-
57
- S = TypeVar("S")
58
- T = TypeVar("T")
59
- K = TypeVar("K")
60
- V = TypeVar("V")
61
-
62
-
63
- def _is_type_like(data_type: object) -> bool:
64
- """
65
- Checks if the object is a type or type-like object (e.g. generic type).
66
-
67
- :param data_type: The object to validate.
68
- :returns: True if the object is a type or type-like object.
69
- """
70
-
71
- if isinstance(data_type, type):
72
- # a standard type
73
- return True
74
- elif typing.get_origin(data_type) is not None:
75
- # a generic type such as `list`, `dict` or `set`
76
- return True
77
- elif hasattr(data_type, "__forward_arg__"):
78
- # an instance of `ForwardRef`
79
- return True
80
- elif data_type is Any:
81
- # the special form `Any`
82
- return True
83
- else:
84
- return False
85
-
86
-
87
- if sys.version_info >= (3, 9):
88
- TypeLike = Union[type, types.GenericAlias, typing.ForwardRef, Any]
89
-
90
- def is_type_like(
91
- data_type: object,
92
- ) -> TypeGuard[TypeLike]:
93
- """
94
- Checks if the object is a type or type-like object (e.g. generic type).
95
-
96
- :param data_type: The object to validate.
97
- :returns: True if the object is a type or type-like object.
98
- """
99
-
100
- return _is_type_like(data_type)
101
-
102
- else:
103
- TypeLike = object
104
-
105
- def is_type_like(
106
- data_type: object,
107
- ) -> bool:
108
- return _is_type_like(data_type)
109
-
110
-
111
- def evaluate_member_type(typ: Any, cls: type) -> Any:
112
- """
113
- Evaluates a forward reference type in a dataclass member.
114
-
115
- :param typ: The dataclass member type to convert.
116
- :param cls: The dataclass in which the member is defined.
117
- :returns: The evaluated type.
118
- """
119
-
120
- return evaluate_type(typ, sys.modules[cls.__module__])
121
-
122
-
123
- def evaluate_type(typ: Any, module: types.ModuleType) -> Any:
124
- """
125
- Evaluates a forward reference type.
126
-
127
- :param typ: The type to convert, typically a dataclass member type.
128
- :param module: The context for the type, i.e. the module in which the member is defined.
129
- :returns: The evaluated type.
130
- """
131
-
132
- if isinstance(typ, str):
133
- # evaluate data-class field whose type annotation is a string
134
- return eval(typ, module.__dict__, locals())
135
- if isinstance(typ, typing.ForwardRef):
136
- if sys.version_info >= (3, 9):
137
- return typ._evaluate(module.__dict__, locals(), recursive_guard=frozenset())
138
- else:
139
- return typ._evaluate(module.__dict__, locals())
140
- else:
141
- return typ
142
-
143
-
144
- @runtime_checkable
145
- class DataclassInstance(Protocol):
146
- __dataclass_fields__: typing.ClassVar[Dict[str, dataclasses.Field]]
147
-
148
-
149
- def is_dataclass_type(typ: Any) -> TypeGuard[Type[DataclassInstance]]:
150
- "True if the argument corresponds to a data class type (but not an instance)."
151
-
152
- typ = unwrap_annotated_type(typ)
153
- return isinstance(typ, type) and dataclasses.is_dataclass(typ)
154
-
155
-
156
- def is_dataclass_instance(obj: Any) -> TypeGuard[DataclassInstance]:
157
- "True if the argument corresponds to a data class instance (but not a type)."
158
-
159
- return not isinstance(obj, type) and dataclasses.is_dataclass(obj)
160
-
161
-
162
- @dataclasses.dataclass
163
- class DataclassField:
164
- name: str
165
- type: Any
166
- default: Any
167
-
168
- def __init__(self, name: str, type: Any, default: Any = dataclasses.MISSING) -> None:
169
- self.name = name
170
- self.type = type
171
- self.default = default
172
-
173
-
174
- def dataclass_fields(cls: Type[DataclassInstance]) -> Iterable[DataclassField]:
175
- "Generates the fields of a data-class resolving forward references."
176
-
177
- for field in dataclasses.fields(cls):
178
- yield DataclassField(field.name, evaluate_member_type(field.type, cls), field.default)
179
-
180
-
181
- def dataclass_field_by_name(cls: Type[DataclassInstance], name: str) -> DataclassField:
182
- "Looks up a field in a data-class by its field name."
183
-
184
- for field in dataclasses.fields(cls):
185
- if field.name == name:
186
- return DataclassField(field.name, evaluate_member_type(field.type, cls))
187
-
188
- raise LookupError(f"field `{name}` missing from class `{cls.__name__}`")
189
-
190
-
191
- def is_named_tuple_instance(obj: Any) -> TypeGuard[NamedTuple]:
192
- "True if the argument corresponds to a named tuple instance."
193
-
194
- return is_named_tuple_type(type(obj))
195
-
196
-
197
- def is_named_tuple_type(typ: Any) -> TypeGuard[Type[NamedTuple]]:
198
- """
199
- True if the argument corresponds to a named tuple type.
200
-
201
- Calling the function `collections.namedtuple` gives a new type that is a subclass of `tuple` (and no other classes)
202
- with a member named `_fields` that is a tuple whose items are all strings.
203
- """
204
-
205
- if not isinstance(typ, type):
206
- return False
207
-
208
- typ = unwrap_annotated_type(typ)
209
-
210
- b = getattr(typ, "__bases__", None)
211
- if b is None:
212
- return False
213
-
214
- if len(b) != 1 or b[0] != tuple:
215
- return False
216
-
217
- f = getattr(typ, "_fields", None)
218
- if not isinstance(f, tuple):
219
- return False
220
-
221
- return all(isinstance(n, str) for n in f)
222
-
223
-
224
- if sys.version_info >= (3, 11):
225
-
226
- def is_type_enum(typ: object) -> TypeGuard[Type[enum.Enum]]:
227
- "True if the specified type is an enumeration type."
228
-
229
- typ = unwrap_annotated_type(typ)
230
- return isinstance(typ, enum.EnumType)
231
-
232
- else:
233
-
234
- def is_type_enum(typ: object) -> TypeGuard[Type[enum.Enum]]:
235
- "True if the specified type is an enumeration type."
236
-
237
- typ = unwrap_annotated_type(typ)
238
-
239
- # use an explicit isinstance(..., type) check to filter out special forms like generics
240
- return isinstance(typ, type) and issubclass(typ, enum.Enum)
241
-
242
-
243
- def enum_value_types(enum_type: Type[enum.Enum]) -> List[type]:
244
- """
245
- Returns all unique value types of the `enum.Enum` type in definition order.
246
- """
247
-
248
- # filter unique enumeration value types by keeping definition order
249
- return list(dict.fromkeys(type(e.value) for e in enum_type))
250
-
251
-
252
- def extend_enum(
253
- source: Type[enum.Enum],
254
- ) -> Callable[[Type[enum.Enum]], Type[enum.Enum]]:
255
- """
256
- Creates a new enumeration type extending the set of values in an existing type.
257
-
258
- :param source: The existing enumeration type to be extended with new values.
259
- :returns: A new enumeration type with the extended set of values.
260
- """
261
-
262
- def wrap(extend: Type[enum.Enum]) -> Type[enum.Enum]:
263
- # create new enumeration type combining the values from both types
264
- values: Dict[str, Any] = {}
265
- values.update((e.name, e.value) for e in source)
266
- values.update((e.name, e.value) for e in extend)
267
- # mypy fails to determine that __name__ is always a string; hence the `ignore` directive.
268
- enum_class: Type[enum.Enum] = enum.Enum(extend.__name__, values) # type: ignore[misc]
269
-
270
- # assign the newly created type to the same module where the extending class is defined
271
- enum_class.__module__ = extend.__module__
272
- enum_class.__doc__ = extend.__doc__
273
- setattr(sys.modules[extend.__module__], extend.__name__, enum_class)
274
-
275
- return enum.unique(enum_class)
276
-
277
- return wrap
278
-
279
-
280
- if sys.version_info >= (3, 10):
281
-
282
- def _is_union_like(typ: object) -> bool:
283
- "True if type is a union such as `Union[T1, T2, ...]` or a union type `T1 | T2`."
284
-
285
- return typing.get_origin(typ) is Union or isinstance(typ, types.UnionType)
286
-
287
- else:
288
-
289
- def _is_union_like(typ: object) -> bool:
290
- "True if type is a union such as `Union[T1, T2, ...]` or a union type `T1 | T2`."
291
-
292
- return typing.get_origin(typ) is Union
293
-
294
-
295
- def is_type_optional(typ: object, strict: bool = False) -> TypeGuard[Type[Optional[Any]]]:
296
- """
297
- True if the type annotation corresponds to an optional type (e.g. `Optional[T]` or `Union[T1,T2,None]`).
298
-
299
- `Optional[T]` is represented as `Union[T, None]` is classic style, and is equivalent to `T | None` in new style.
300
-
301
- :param strict: True if only `Optional[T]` qualifies as an optional type but `Union[T1, T2, None]` does not.
302
- """
303
-
304
- typ = unwrap_annotated_type(typ)
305
-
306
- if _is_union_like(typ):
307
- args = typing.get_args(typ)
308
- if strict and len(args) != 2:
309
- return False
310
-
311
- return type(None) in args
312
-
313
- return False
314
-
315
-
316
- def unwrap_optional_type(typ: Type[Optional[T]]) -> Type[T]:
317
- """
318
- Extracts the inner type of an optional type.
319
-
320
- :param typ: The optional type `Optional[T]`.
321
- :returns: The inner type `T`.
322
- """
323
-
324
- return rewrap_annotated_type(_unwrap_optional_type, typ)
325
-
326
-
327
- def _unwrap_optional_type(typ: Type[Optional[T]]) -> Type[T]:
328
- "Extracts the type qualified as optional (e.g. returns `T` for `Optional[T]`)."
329
-
330
- # Optional[T] is represented internally as Union[T, None]
331
- if not _is_union_like(typ):
332
- raise TypeError("optional type must have un-subscripted type of Union")
333
-
334
- # will automatically unwrap Union[T] into T
335
- return Union[tuple(filter(lambda item: item is not type(None), typing.get_args(typ)))] # type: ignore[return-value]
336
-
337
-
338
- def is_type_union(typ: object) -> bool:
339
- "True if the type annotation corresponds to a union type (e.g. `Union[T1,T2,T3]`)."
340
-
341
- typ = unwrap_annotated_type(typ)
342
- if _is_union_like(typ):
343
- args = typing.get_args(typ)
344
- return len(args) > 2 or type(None) not in args
345
-
346
- return False
347
-
348
-
349
- def unwrap_union_types(typ: object) -> Tuple[object, ...]:
350
- """
351
- Extracts the inner types of a union type.
352
-
353
- :param typ: The union type `Union[T1, T2, ...]`.
354
- :returns: The inner types `T1`, `T2`, etc.
355
- """
356
-
357
- typ = unwrap_annotated_type(typ)
358
- return _unwrap_union_types(typ)
359
-
360
-
361
- def _unwrap_union_types(typ: object) -> Tuple[object, ...]:
362
- "Extracts the types in a union (e.g. returns a tuple of types `T1` and `T2` for `Union[T1, T2]`)."
363
-
364
- if not _is_union_like(typ):
365
- raise TypeError("union type must have un-subscripted type of Union")
366
-
367
- return typing.get_args(typ)
368
-
369
-
370
- def is_type_literal(typ: object) -> bool:
371
- "True if the specified type is a literal of one or more constant values, e.g. `Literal['string']` or `Literal[42]`."
372
-
373
- typ = unwrap_annotated_type(typ)
374
- return typing.get_origin(typ) is Literal
375
-
376
-
377
- def unwrap_literal_value(typ: object) -> Any:
378
- """
379
- Extracts the single constant value captured by a literal type.
380
-
381
- :param typ: The literal type `Literal[value]`.
382
- :returns: The values captured by the literal type.
383
- """
384
-
385
- args = unwrap_literal_values(typ)
386
- if len(args) != 1:
387
- raise TypeError("too many values in literal type")
388
-
389
- return args[0]
390
-
391
-
392
- def unwrap_literal_values(typ: object) -> Tuple[Any, ...]:
393
- """
394
- Extracts the constant values captured by a literal type.
395
-
396
- :param typ: The literal type `Literal[value, ...]`.
397
- :returns: A tuple of values captured by the literal type.
398
- """
399
-
400
- typ = unwrap_annotated_type(typ)
401
- return typing.get_args(typ)
402
-
403
-
404
- def unwrap_literal_types(typ: object) -> Tuple[type, ...]:
405
- """
406
- Extracts the types of the constant values captured by a literal type.
407
-
408
- :param typ: The literal type `Literal[value, ...]`.
409
- :returns: A tuple of item types `T` such that `type(value) == T`.
410
- """
411
-
412
- return tuple(type(t) for t in unwrap_literal_values(typ))
413
-
414
-
415
- def is_generic_list(typ: object) -> TypeGuard[Type[list]]:
416
- "True if the specified type is a generic list, i.e. `List[T]`."
417
-
418
- typ = unwrap_annotated_type(typ)
419
- return typing.get_origin(typ) is list
420
-
421
-
422
- def unwrap_generic_list(typ: Type[List[T]]) -> Type[T]:
423
- """
424
- Extracts the item type of a list type.
425
-
426
- :param typ: The list type `List[T]`.
427
- :returns: The item type `T`.
428
- """
429
-
430
- return rewrap_annotated_type(_unwrap_generic_list, typ)
431
-
432
-
433
- def _unwrap_generic_list(typ: Type[List[T]]) -> Type[T]:
434
- "Extracts the item type of a list type (e.g. returns `T` for `List[T]`)."
435
-
436
- (list_type,) = typing.get_args(typ) # unpack single tuple element
437
- return list_type # type: ignore[no-any-return]
438
-
439
-
440
- def is_generic_set(typ: object) -> TypeGuard[Type[set]]:
441
- "True if the specified type is a generic set, i.e. `Set[T]`."
442
-
443
- typ = unwrap_annotated_type(typ)
444
- return typing.get_origin(typ) is set
445
-
446
-
447
- def unwrap_generic_set(typ: Type[Set[T]]) -> Type[T]:
448
- """
449
- Extracts the item type of a set type.
450
-
451
- :param typ: The set type `Set[T]`.
452
- :returns: The item type `T`.
453
- """
454
-
455
- return rewrap_annotated_type(_unwrap_generic_set, typ)
456
-
457
-
458
- def _unwrap_generic_set(typ: Type[Set[T]]) -> Type[T]:
459
- "Extracts the item type of a set type (e.g. returns `T` for `Set[T]`)."
460
-
461
- (set_type,) = typing.get_args(typ) # unpack single tuple element
462
- return set_type # type: ignore[no-any-return]
463
-
464
-
465
- def is_generic_dict(typ: object) -> TypeGuard[Type[dict]]:
466
- "True if the specified type is a generic dictionary, i.e. `Dict[KeyType, ValueType]`."
467
-
468
- typ = unwrap_annotated_type(typ)
469
- return typing.get_origin(typ) is dict
470
-
471
-
472
- def unwrap_generic_dict(typ: Type[Dict[K, V]]) -> Tuple[Type[K], Type[V]]:
473
- """
474
- Extracts the key and value types of a dictionary type as a tuple.
475
-
476
- :param typ: The dictionary type `Dict[K, V]`.
477
- :returns: The key and value types `K` and `V`.
478
- """
479
-
480
- return _unwrap_generic_dict(unwrap_annotated_type(typ))
481
-
482
-
483
- def _unwrap_generic_dict(typ: Type[Dict[K, V]]) -> Tuple[Type[K], Type[V]]:
484
- "Extracts the key and value types of a dict type (e.g. returns (`K`, `V`) for `Dict[K, V]`)."
485
-
486
- key_type, value_type = typing.get_args(typ)
487
- return key_type, value_type
488
-
489
-
490
- def is_type_annotated(typ: TypeLike) -> bool:
491
- "True if the type annotation corresponds to an annotated type (i.e. `Annotated[T, ...]`)."
492
-
493
- return getattr(typ, "__metadata__", None) is not None
494
-
495
-
496
- def get_annotation(data_type: TypeLike, annotation_type: Type[T]) -> Optional[T]:
497
- """
498
- Returns the first annotation on a data type that matches the expected annotation type.
499
-
500
- :param data_type: The annotated type from which to extract the annotation.
501
- :param annotation_type: The annotation class to look for.
502
- :returns: The annotation class instance found (if any).
503
- """
504
-
505
- metadata = getattr(data_type, "__metadata__", None)
506
- if metadata is not None:
507
- for annotation in metadata:
508
- if isinstance(annotation, annotation_type):
509
- return annotation
510
-
511
- return None
512
-
513
-
514
- def unwrap_annotated_type(typ: T) -> T:
515
- "Extracts the wrapped type from an annotated type (e.g. returns `T` for `Annotated[T, ...]`)."
516
-
517
- if is_type_annotated(typ):
518
- # type is Annotated[T, ...]
519
- return typing.get_args(typ)[0] # type: ignore[no-any-return]
520
- else:
521
- # type is a regular type
522
- return typ
523
-
524
-
525
- def rewrap_annotated_type(transform: Callable[[Type[S]], Type[T]], typ: Type[S]) -> Type[T]:
526
- """
527
- Un-boxes, transforms and re-boxes an optionally annotated type.
528
-
529
- :param transform: A function that maps an un-annotated type to another type.
530
- :param typ: A type to un-box (if necessary), transform, and re-box (if necessary).
531
- """
532
-
533
- metadata = getattr(typ, "__metadata__", None)
534
- if metadata is not None:
535
- # type is Annotated[T, ...]
536
- inner_type = typing.get_args(typ)[0]
537
- else:
538
- # type is a regular type
539
- inner_type = typ
540
-
541
- transformed_type = transform(inner_type)
542
-
543
- if metadata is not None:
544
- return Annotated[(transformed_type, *metadata)] # type: ignore[return-value]
545
- else:
546
- return transformed_type
547
-
548
-
549
- def get_module_classes(module: types.ModuleType) -> List[type]:
550
- "Returns all classes declared directly in a module."
551
-
552
- def is_class_member(member: object) -> TypeGuard[type]:
553
- return inspect.isclass(member) and member.__module__ == module.__name__
554
-
555
- return [class_type for _, class_type in inspect.getmembers(module, is_class_member)]
556
-
557
-
558
- if sys.version_info >= (3, 9):
559
-
560
- def get_resolved_hints(typ: type) -> Dict[str, type]:
561
- return typing.get_type_hints(typ, include_extras=True)
562
-
563
- else:
564
-
565
- def get_resolved_hints(typ: type) -> Dict[str, type]:
566
- return typing.get_type_hints(typ)
567
-
568
-
569
- def get_class_properties(typ: type) -> Iterable[Tuple[str, type | str]]:
570
- "Returns all properties of a class."
571
-
572
- if is_dataclass_type(typ):
573
- return ((field.name, field.type) for field in dataclasses.fields(typ))
574
- elif hasattr(typ, "model_fields"):
575
- # Pydantic BaseModel - use model_fields to exclude ClassVar and other non-field attributes
576
- # Reconstruct Annotated type if discriminator exists to preserve metadata
577
- from typing import Annotated, Any
578
-
579
- from pydantic.fields import FieldInfo
580
-
581
- def get_field_type(name: str, field: Any) -> type | str:
582
- # If field has discriminator, wrap in Annotated to preserve it for schema generation
583
- if field.discriminator:
584
- field_info = FieldInfo(annotation=None, discriminator=field.discriminator)
585
- # Annotated returns _AnnotatedAlias which isn't a type but is valid here
586
- return Annotated[field.annotation, field_info] # type: ignore[return-value]
587
- # field.annotation can be Union types, Annotated, etc. which aren't type but are valid
588
- return field.annotation # type: ignore[return-value,no-any-return]
589
-
590
- return ((name, get_field_type(name, field)) for name, field in typ.model_fields.items())
591
- else:
592
- resolved_hints = get_resolved_hints(typ)
593
- return resolved_hints.items()
594
-
595
-
596
- def get_class_property(typ: type, name: str) -> Optional[type | str]:
597
- "Looks up the annotated type of a property in a class by its property name."
598
-
599
- for property_name, property_type in get_class_properties(typ):
600
- if name == property_name:
601
- return property_type
602
- return None
603
-
604
-
605
- @dataclasses.dataclass
606
- class _ROOT:
607
- pass
608
-
609
-
610
- def get_referenced_types(typ: TypeLike, module: Optional[types.ModuleType] = None) -> Set[type]:
611
- """
612
- Extracts types directly or indirectly referenced by this type.
613
-
614
- For example, extract `T` from `List[T]`, `Optional[T]` or `Annotated[T, ...]`, `K` and `V` from `Dict[K,V]`,
615
- `A` and `B` from `Union[A,B]`.
616
-
617
- :param typ: A type or special form.
618
- :param module: The context in which types are evaluated.
619
- :returns: Types referenced by the given type or special form.
620
- """
621
-
622
- collector = TypeCollector()
623
- collector.run(typ, _ROOT, module)
624
- return collector.references
625
-
626
-
627
- class TypeCollector:
628
- """
629
- Collects types directly or indirectly referenced by a type.
630
-
631
- :param graph: The type dependency graph, linking types to types they depend on.
632
- """
633
-
634
- graph: Dict[type, Set[type]]
635
-
636
- @property
637
- def references(self) -> Set[type]:
638
- "Types collected by the type collector."
639
-
640
- dependencies = set()
641
- for edges in self.graph.values():
642
- dependencies.update(edges)
643
- return dependencies
644
-
645
- def __init__(self) -> None:
646
- self.graph = {_ROOT: set()}
647
-
648
- def traverse(self, typ: type) -> None:
649
- "Finds all dependent types of a type."
650
-
651
- self.run(typ, _ROOT, sys.modules[typ.__module__])
652
-
653
- def traverse_all(self, types: Iterable[type]) -> None:
654
- "Finds all dependent types of a list of types."
655
-
656
- for typ in types:
657
- self.traverse(typ)
658
-
659
- def run(
660
- self,
661
- typ: TypeLike,
662
- cls: Type[DataclassInstance],
663
- module: Optional[types.ModuleType],
664
- ) -> None:
665
- """
666
- Extracts types indirectly referenced by this type.
667
-
668
- For example, extract `T` from `List[T]`, `Optional[T]` or `Annotated[T, ...]`, `K` and `V` from `Dict[K,V]`,
669
- `A` and `B` from `Union[A,B]`.
670
-
671
- :param typ: A type or special form.
672
- :param cls: A dataclass type being expanded for dependent types.
673
- :param module: The context in which types are evaluated.
674
- :returns: Types referenced by the given type or special form.
675
- """
676
-
677
- if typ is type(None) or typ is Any:
678
- return
679
-
680
- if isinstance(typ, type):
681
- self.graph[cls].add(typ)
682
-
683
- if typ in self.graph:
684
- return
685
-
686
- self.graph[typ] = set()
687
-
688
- metadata = getattr(typ, "__metadata__", None)
689
- if metadata is not None:
690
- # type is Annotated[T, ...]
691
- arg = typing.get_args(typ)[0]
692
- return self.run(arg, cls, module)
693
-
694
- # type is a forward reference
695
- if isinstance(typ, str) or isinstance(typ, typing.ForwardRef):
696
- if module is None:
697
- raise ValueError("missing context for evaluating types")
698
-
699
- evaluated_type = evaluate_type(typ, module)
700
- return self.run(evaluated_type, cls, module)
701
-
702
- # type is a special form
703
- origin = typing.get_origin(typ)
704
- if origin in [list, dict, frozenset, set, tuple, Union]:
705
- for arg in typing.get_args(typ):
706
- self.run(arg, cls, module)
707
- return
708
- elif origin is Literal:
709
- return
710
-
711
- # type is optional or a union type
712
- if is_type_optional(typ):
713
- return self.run(unwrap_optional_type(typ), cls, module)
714
- if is_type_union(typ):
715
- for union_type in unwrap_union_types(typ):
716
- self.run(union_type, cls, module)
717
- return
718
-
719
- # type is a regular type
720
- elif is_dataclass_type(typ) or is_type_enum(typ) or isinstance(typ, type):
721
- context = sys.modules[typ.__module__]
722
- if is_dataclass_type(typ):
723
- for field in dataclass_fields(typ):
724
- self.run(field.type, typ, context)
725
- else:
726
- for field_name, field_type in get_resolved_hints(typ).items():
727
- self.run(field_type, typ, context)
728
- return
729
-
730
- raise TypeError(f"expected: type-like; got: {typ}")
731
-
732
-
733
- if sys.version_info >= (3, 10):
734
-
735
- def get_signature(fn: Callable[..., Any]) -> inspect.Signature:
736
- "Extracts the signature of a function."
737
-
738
- return inspect.signature(fn, eval_str=True)
739
-
740
- else:
741
-
742
- def get_signature(fn: Callable[..., Any]) -> inspect.Signature:
743
- "Extracts the signature of a function."
744
-
745
- return inspect.signature(fn)
746
-
747
-
748
- def is_reserved_property(name: str) -> bool:
749
- "True if the name stands for an internal property."
750
-
751
- # filter built-in and special properties
752
- if re.match(r"^__.+__$", name):
753
- return True
754
-
755
- # filter built-in special names
756
- if name in ["_abc_impl"]:
757
- return True
758
-
759
- return False
760
-
761
-
762
- def create_module(name: str) -> types.ModuleType:
763
- """
764
- Creates a new module dynamically at run-time.
765
-
766
- :param name: Fully qualified name of the new module (with dot notation).
767
- """
768
-
769
- if name in sys.modules:
770
- raise KeyError(f"{name!r} already in sys.modules")
771
-
772
- spec = importlib.machinery.ModuleSpec(name, None)
773
- module = importlib.util.module_from_spec(spec)
774
- sys.modules[name] = module
775
- if spec.loader is not None:
776
- spec.loader.exec_module(module)
777
- return module
778
-
779
-
780
- if sys.version_info >= (3, 10):
781
-
782
- def create_data_type(class_name: str, fields: List[Tuple[str, type]]) -> type:
783
- """
784
- Creates a new data-class type dynamically.
785
-
786
- :param class_name: The name of new data-class type.
787
- :param fields: A list of fields (and their type) that the new data-class type is expected to have.
788
- :returns: The newly created data-class type.
789
- """
790
-
791
- # has the `slots` parameter
792
- return dataclasses.make_dataclass(class_name, fields, slots=True)
793
-
794
- else:
795
-
796
- def create_data_type(class_name: str, fields: List[Tuple[str, type]]) -> type:
797
- """
798
- Creates a new data-class type dynamically.
799
-
800
- :param class_name: The name of new data-class type.
801
- :param fields: A list of fields (and their type) that the new data-class type is expected to have.
802
- :returns: The newly created data-class type.
803
- """
804
-
805
- cls = dataclasses.make_dataclass(class_name, fields)
806
-
807
- cls_dict = dict(cls.__dict__)
808
- field_names = tuple(field.name for field in dataclasses.fields(cls))
809
-
810
- cls_dict["__slots__"] = field_names
811
-
812
- for field_name in field_names:
813
- cls_dict.pop(field_name, None)
814
- cls_dict.pop("__dict__", None)
815
-
816
- qualname = getattr(cls, "__qualname__", None)
817
- cls = type(cls)(cls.__name__, (), cls_dict)
818
- if qualname is not None:
819
- cls.__qualname__ = qualname
820
-
821
- return cls
822
-
823
-
824
- def create_object(typ: Type[T]) -> T:
825
- "Creates an instance of a type."
826
-
827
- if issubclass(typ, Exception):
828
- # exception types need special treatment
829
- e = typ.__new__(typ)
830
- return typing.cast(T, e)
831
- else:
832
- return object.__new__(typ)
833
-
834
-
835
- if sys.version_info >= (3, 9):
836
- TypeOrGeneric = Union[type, types.GenericAlias]
837
-
838
- else:
839
- TypeOrGeneric = object
840
-
841
-
842
- def is_generic_instance(obj: Any, typ: TypeLike) -> bool:
843
- """
844
- Returns whether an object is an instance of a generic class, a standard class or of a subclass thereof.
845
-
846
- This function checks the following items recursively:
847
- * items of a list
848
- * keys and values of a dictionary
849
- * members of a set
850
- * items of a tuple
851
- * members of a union type
852
-
853
- :param obj: The (possibly generic container) object to check recursively.
854
- :param typ: The expected type of the object.
855
- """
856
-
857
- if isinstance(typ, typing.ForwardRef):
858
- fwd: typing.ForwardRef = typ
859
- identifier = fwd.__forward_arg__
860
- typ = eval(identifier)
861
- if isinstance(typ, type):
862
- return isinstance(obj, typ)
863
- else:
864
- return False
865
-
866
- # generic types (e.g. list, dict, set, etc.)
867
- origin_type = typing.get_origin(typ)
868
- if origin_type is list:
869
- if not isinstance(obj, list):
870
- return False
871
- (list_item_type,) = typing.get_args(typ) # unpack single tuple element
872
- list_obj: list = obj
873
- return all(is_generic_instance(item, list_item_type) for item in list_obj)
874
- elif origin_type is dict:
875
- if not isinstance(obj, dict):
876
- return False
877
- key_type, value_type = typing.get_args(typ)
878
- dict_obj: dict = obj
879
- return all(
880
- is_generic_instance(key, key_type) and is_generic_instance(value, value_type)
881
- for key, value in dict_obj.items()
882
- )
883
- elif origin_type is set:
884
- if not isinstance(obj, set):
885
- return False
886
- (set_member_type,) = typing.get_args(typ) # unpack single tuple element
887
- set_obj: set = obj
888
- return all(is_generic_instance(item, set_member_type) for item in set_obj)
889
- elif origin_type is tuple:
890
- if not isinstance(obj, tuple):
891
- return False
892
- return all(
893
- is_generic_instance(item, tuple_item_type)
894
- for tuple_item_type, item in zip(
895
- (tuple_item_type for tuple_item_type in typing.get_args(typ)),
896
- (item for item in obj),
897
- strict=False,
898
- )
899
- )
900
- elif origin_type is Union:
901
- return any(is_generic_instance(obj, member_type) for member_type in typing.get_args(typ))
902
- elif isinstance(typ, type):
903
- return isinstance(obj, typ)
904
- else:
905
- raise TypeError(f"expected `type` but got: {typ}")
906
-
907
-
908
- class RecursiveChecker:
909
- _pred: Optional[Callable[[type, Any], bool]]
910
-
911
- def __init__(self, pred: Callable[[type, Any], bool]) -> None:
912
- """
913
- Creates a checker to verify if a predicate applies to all nested member properties of an object recursively.
914
-
915
- :param pred: The predicate to test on member properties. Takes a property type and a property value.
916
- """
917
-
918
- self._pred = pred
919
-
920
- def pred(self, typ: type, obj: Any) -> bool:
921
- "Acts as a workaround for the type checker mypy."
922
-
923
- assert self._pred is not None
924
- return self._pred(typ, obj)
925
-
926
- def check(self, typ: TypeLike, obj: Any) -> bool:
927
- """
928
- Checks if a predicate applies to all nested member properties of an object recursively.
929
-
930
- :param typ: The type to recurse into.
931
- :param obj: The object to inspect recursively. Must be an instance of the given type.
932
- :returns: True if all member properties pass the filter predicate.
933
- """
934
-
935
- # check for well-known types
936
- if (
937
- typ is type(None)
938
- or typ is bool
939
- or typ is int
940
- or typ is float
941
- or typ is str
942
- or typ is bytes
943
- or typ is datetime.datetime
944
- or typ is datetime.date
945
- or typ is datetime.time
946
- or typ is uuid.UUID
947
- ):
948
- return self.pred(typing.cast(type, typ), obj)
949
-
950
- # generic types (e.g. list, dict, set, etc.)
951
- origin_type = typing.get_origin(typ)
952
- if origin_type is list:
953
- if not isinstance(obj, list):
954
- raise TypeError(f"expected `list` but got: {obj}")
955
- (list_item_type,) = typing.get_args(typ) # unpack single tuple element
956
- list_obj: list = obj
957
- return all(self.check(list_item_type, item) for item in list_obj)
958
- elif origin_type is dict:
959
- if not isinstance(obj, dict):
960
- raise TypeError(f"expected `dict` but got: {obj}")
961
- key_type, value_type = typing.get_args(typ)
962
- dict_obj: dict = obj
963
- return all(self.check(value_type, item) for item in dict_obj.values())
964
- elif origin_type is set:
965
- if not isinstance(obj, set):
966
- raise TypeError(f"expected `set` but got: {obj}")
967
- (set_member_type,) = typing.get_args(typ) # unpack single tuple element
968
- set_obj: set = obj
969
- return all(self.check(set_member_type, item) for item in set_obj)
970
- elif origin_type is tuple:
971
- if not isinstance(obj, tuple):
972
- raise TypeError(f"expected `tuple` but got: {obj}")
973
- return all(
974
- self.check(tuple_item_type, item)
975
- for tuple_item_type, item in zip(
976
- (tuple_item_type for tuple_item_type in typing.get_args(typ)),
977
- (item for item in obj),
978
- strict=False,
979
- )
980
- )
981
- elif origin_type is Union:
982
- return self.pred(typ, obj) # type: ignore[arg-type]
983
-
984
- if not inspect.isclass(typ):
985
- raise TypeError(f"expected `type` but got: {typ}")
986
-
987
- # enumeration type
988
- if issubclass(typ, enum.Enum):
989
- if not isinstance(obj, enum.Enum):
990
- raise TypeError(f"expected `{typ}` but got: {obj}")
991
- return self.pred(typ, obj)
992
-
993
- # class types with properties
994
- if is_named_tuple_type(typ):
995
- if not isinstance(obj, tuple):
996
- raise TypeError(f"expected `NamedTuple` but got: {obj}")
997
- return all(
998
- self.check(field_type, getattr(obj, field_name))
999
- for field_name, field_type in typing.get_type_hints(typ).items()
1000
- )
1001
- elif is_dataclass_type(typ):
1002
- if not isinstance(obj, typ):
1003
- raise TypeError(f"expected `{typ}` but got: {obj}")
1004
- resolved_hints = get_resolved_hints(typ)
1005
- return all(
1006
- self.check(resolved_hints[field.name], getattr(obj, field.name)) for field in dataclasses.fields(typ)
1007
- )
1008
- else:
1009
- if not isinstance(obj, typ):
1010
- raise TypeError(f"expected `{typ}` but got: {obj}")
1011
- return all(
1012
- self.check(property_type, getattr(obj, property_name))
1013
- for property_name, property_type in get_class_properties(typ)
1014
- )
1015
-
1016
-
1017
- def check_recursive(
1018
- obj: object,
1019
- /,
1020
- *,
1021
- pred: Optional[Callable[[type, Any], bool]] = None,
1022
- type_pred: Optional[Callable[[type], bool]] = None,
1023
- value_pred: Optional[Callable[[Any], bool]] = None,
1024
- ) -> bool:
1025
- """
1026
- Checks if a predicate applies to all nested member properties of an object recursively.
1027
-
1028
- :param obj: The object to inspect recursively.
1029
- :param pred: The predicate to test on member properties. Takes a property type and a property value.
1030
- :param type_pred: Constrains the check to properties of an expected type. Properties of other types pass automatically.
1031
- :param value_pred: Verifies a condition on member property values (of an expected type).
1032
- :returns: True if all member properties pass the filter predicate(s).
1033
- """
1034
-
1035
- if type_pred is not None and value_pred is not None:
1036
- if pred is not None:
1037
- raise TypeError("filter predicate not permitted when type and value predicates are present")
1038
-
1039
- type_p: Callable[[Type[T]], bool] = type_pred
1040
- value_p: Callable[[T], bool] = value_pred
1041
- pred = lambda typ, obj: not type_p(typ) or value_p(obj) # noqa: E731
1042
-
1043
- elif value_pred is not None:
1044
- if pred is not None:
1045
- raise TypeError("filter predicate not permitted when value predicate is present")
1046
-
1047
- value_only_p: Callable[[T], bool] = value_pred
1048
- pred = lambda typ, obj: value_only_p(obj) # noqa: E731
1049
-
1050
- elif type_pred is not None:
1051
- raise TypeError("value predicate required when type predicate is present")
1052
-
1053
- elif pred is None:
1054
- pred = lambda typ, obj: True # noqa: E731
1055
-
1056
- return RecursiveChecker(pred).check(type(obj), obj)
1057
-
1058
-
1059
- def is_unwrapped_body_param(param_type: Any) -> bool:
1060
- """
1061
- Check if a parameter type represents an unwrapped body parameter.
1062
- An unwrapped body parameter is an Annotated type with Body(embed=False)
1063
-
1064
- This is used to determine whether request parameters should be flattened
1065
- in OpenAPI specs and client libraries (matching FastAPI's embed=False behavior).
1066
-
1067
- Args:
1068
- param_type: The parameter type annotation to check
1069
-
1070
- Returns:
1071
- True if the parameter should be treated as an unwrapped body parameter
1072
- """
1073
- # Check if it's Annotated with Body(embed=False)
1074
- if typing.get_origin(param_type) is Annotated:
1075
- args = typing.get_args(param_type)
1076
- base_type = args[0]
1077
- metadata = args[1:]
1078
-
1079
- # Look for Body annotation with embed=False
1080
- # Body() returns a FieldInfo object, so we check for that type and the embed attribute
1081
- for item in metadata:
1082
- if isinstance(item, FieldInfo) and hasattr(item, "embed") and not item.embed:
1083
- return inspect.isclass(base_type) and issubclass(base_type, BaseModel)
1084
-
1085
- return False