coco-framework 0.1.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 (400) hide show
  1. coco/__init__.py +3 -0
  2. coco/agents/__init__.py +9 -0
  3. coco/agents/_subagent_transformer.py +307 -0
  4. coco/agents/factory.py +2164 -0
  5. coco/agents/middleware/__init__.py +100 -0
  6. coco/agents/middleware/_execution.py +385 -0
  7. coco/agents/middleware/_redaction.py +454 -0
  8. coco/agents/middleware/_retry.py +134 -0
  9. coco/agents/middleware/_trace_policy.py +61 -0
  10. coco/agents/middleware/context_editing.py +306 -0
  11. coco/agents/middleware/file_search.py +433 -0
  12. coco/agents/middleware/human_in_the_loop.py +680 -0
  13. coco/agents/middleware/internal_call_transformer.py +108 -0
  14. coco/agents/middleware/model_call_limit.py +267 -0
  15. coco/agents/middleware/model_fallback.py +417 -0
  16. coco/agents/middleware/model_retry.py +327 -0
  17. coco/agents/middleware/pii.py +878 -0
  18. coco/agents/middleware/provider_tool_search.py +307 -0
  19. coco/agents/middleware/shell_tool.py +949 -0
  20. coco/agents/middleware/summarization.py +910 -0
  21. coco/agents/middleware/todo.py +357 -0
  22. coco/agents/middleware/tool_call_limit.py +495 -0
  23. coco/agents/middleware/tool_emulator.py +251 -0
  24. coco/agents/middleware/tool_error.py +209 -0
  25. coco/agents/middleware/tool_retry.py +421 -0
  26. coco/agents/middleware/tool_selection.py +515 -0
  27. coco/agents/middleware/types.py +2201 -0
  28. coco/agents/structured_output.py +472 -0
  29. coco/chat_models/__init__.py +7 -0
  30. coco/chat_models/base.py +1082 -0
  31. coco/embeddings/__init__.py +18 -0
  32. coco/embeddings/base.py +279 -0
  33. coco/mcp/__init__.py +36 -0
  34. coco/mcp/adapter.py +245 -0
  35. coco/mcp/elicitation.py +394 -0
  36. coco/mcp/tools.py +307 -0
  37. coco/messages/__init__.py +73 -0
  38. coco/py.typed +0 -0
  39. coco/rate_limiters/__init__.py +13 -0
  40. coco/tools/__init__.py +22 -0
  41. coco/tools/tool_node.py +20 -0
  42. coco_anthropic/__init__.py +15 -0
  43. coco_anthropic/_client_utils.py +81 -0
  44. coco_anthropic/_compat.py +228 -0
  45. coco_anthropic/_sdk_compat.py +124 -0
  46. coco_anthropic/_version.py +3 -0
  47. coco_anthropic/chat_models.py +3349 -0
  48. coco_anthropic/data/__init__.py +1 -0
  49. coco_anthropic/data/_profiles.py +491 -0
  50. coco_anthropic/data/profile_augmentations.toml +69 -0
  51. coco_anthropic/experimental.py +140 -0
  52. coco_anthropic/llms.py +428 -0
  53. coco_anthropic/middleware/__init__.py +25 -0
  54. coco_anthropic/middleware/anthropic_tools.py +1197 -0
  55. coco_anthropic/middleware/bash.py +84 -0
  56. coco_anthropic/middleware/file_search.py +360 -0
  57. coco_anthropic/middleware/prompt_caching.py +276 -0
  58. coco_anthropic/output_parsers.py +93 -0
  59. coco_anthropic/py.typed +0 -0
  60. coco_core/__init__.py +20 -0
  61. coco_core/_api/__init__.py +87 -0
  62. coco_core/_api/beta_decorator.py +266 -0
  63. coco_core/_api/deprecation.py +637 -0
  64. coco_core/_api/internal.py +23 -0
  65. coco_core/_api/path.py +50 -0
  66. coco_core/_import_utils.py +41 -0
  67. coco_core/_protocol.py +625 -0
  68. coco_core/_security/__init__.py +36 -0
  69. coco_core/_security/_exceptions.py +9 -0
  70. coco_core/_security/_policy.py +313 -0
  71. coco_core/_security/_ssrf_protection.py +155 -0
  72. coco_core/_security/_transport.py +254 -0
  73. coco_core/agents.py +258 -0
  74. coco_core/caches.py +272 -0
  75. coco_core/callbacks/__init__.py +132 -0
  76. coco_core/callbacks/base.py +1229 -0
  77. coco_core/callbacks/file.py +266 -0
  78. coco_core/callbacks/manager.py +2826 -0
  79. coco_core/callbacks/stdout.py +123 -0
  80. coco_core/callbacks/streaming_stdout.py +154 -0
  81. coco_core/callbacks/usage.py +124 -0
  82. coco_core/chat_history.py +267 -0
  83. coco_core/chat_loaders.py +26 -0
  84. coco_core/chat_sessions.py +19 -0
  85. coco_core/cross_encoders.py +18 -0
  86. coco_core/document_loaders/__init__.py +36 -0
  87. coco_core/document_loaders/base.py +155 -0
  88. coco_core/document_loaders/blob_loaders.py +38 -0
  89. coco_core/documents/__init__.py +55 -0
  90. coco_core/documents/base.py +347 -0
  91. coco_core/documents/compressor.py +74 -0
  92. coco_core/documents/transformers.py +79 -0
  93. coco_core/embeddings/__init__.py +31 -0
  94. coco_core/embeddings/embeddings.py +78 -0
  95. coco_core/embeddings/fake.py +129 -0
  96. coco_core/env.py +22 -0
  97. coco_core/example_selectors/__init__.py +47 -0
  98. coco_core/example_selectors/base.py +60 -0
  99. coco_core/example_selectors/length_based.py +131 -0
  100. coco_core/example_selectors/semantic_similarity.py +366 -0
  101. coco_core/exceptions.py +166 -0
  102. coco_core/globals.py +72 -0
  103. coco_core/indexing/__init__.py +53 -0
  104. coco_core/indexing/api.py +954 -0
  105. coco_core/indexing/base.py +661 -0
  106. coco_core/indexing/in_memory.py +104 -0
  107. coco_core/language_models/__init__.py +116 -0
  108. coco_core/language_models/_compat_bridge.py +844 -0
  109. coco_core/language_models/_utils.py +343 -0
  110. coco_core/language_models/base.py +500 -0
  111. coco_core/language_models/chat_model_stream.py +1525 -0
  112. coco_core/language_models/chat_models.py +2748 -0
  113. coco_core/language_models/fake.py +137 -0
  114. coco_core/language_models/fake_chat_models.py +396 -0
  115. coco_core/language_models/llms.py +1569 -0
  116. coco_core/language_models/model_profile.py +183 -0
  117. coco_core/load/__init__.py +44 -0
  118. coco_core/load/_validation.py +191 -0
  119. coco_core/load/dump.py +120 -0
  120. coco_core/load/load.py +828 -0
  121. coco_core/load/mapping.py +1097 -0
  122. coco_core/load/serializable.py +406 -0
  123. coco_core/messages/__init__.py +198 -0
  124. coco_core/messages/ai.py +854 -0
  125. coco_core/messages/base.py +518 -0
  126. coco_core/messages/block_translators/__init__.py +112 -0
  127. coco_core/messages/block_translators/anthropic.py +534 -0
  128. coco_core/messages/block_translators/bedrock.py +108 -0
  129. coco_core/messages/block_translators/bedrock_converse.py +329 -0
  130. coco_core/messages/block_translators/coco_v0.py +303 -0
  131. coco_core/messages/block_translators/google_genai.py +610 -0
  132. coco_core/messages/block_translators/google_vertexai.py +21 -0
  133. coco_core/messages/block_translators/groq.py +157 -0
  134. coco_core/messages/block_translators/openai.py +1089 -0
  135. coco_core/messages/chat.py +64 -0
  136. coco_core/messages/content.py +1488 -0
  137. coco_core/messages/function.py +62 -0
  138. coco_core/messages/human.py +70 -0
  139. coco_core/messages/modifier.py +33 -0
  140. coco_core/messages/system.py +70 -0
  141. coco_core/messages/tool.py +418 -0
  142. coco_core/messages/utils.py +2442 -0
  143. coco_core/output_parsers/__init__.py +101 -0
  144. coco_core/output_parsers/base.py +361 -0
  145. coco_core/output_parsers/format_instructions.py +16 -0
  146. coco_core/output_parsers/json.py +139 -0
  147. coco_core/output_parsers/list.py +249 -0
  148. coco_core/output_parsers/openai_functions.py +324 -0
  149. coco_core/output_parsers/openai_tools.py +383 -0
  150. coco_core/output_parsers/pydantic.py +141 -0
  151. coco_core/output_parsers/string.py +63 -0
  152. coco_core/output_parsers/transform.py +175 -0
  153. coco_core/output_parsers/xml.py +301 -0
  154. coco_core/outputs/__init__.py +66 -0
  155. coco_core/outputs/chat_generation.py +147 -0
  156. coco_core/outputs/chat_result.py +39 -0
  157. coco_core/outputs/generation.py +80 -0
  158. coco_core/outputs/llm_result.py +112 -0
  159. coco_core/outputs/run_info.py +22 -0
  160. coco_core/prompt_values.py +161 -0
  161. coco_core/prompts/__init__.py +101 -0
  162. coco_core/prompts/base.py +508 -0
  163. coco_core/prompts/chat.py +1495 -0
  164. coco_core/prompts/dict.py +177 -0
  165. coco_core/prompts/few_shot.py +483 -0
  166. coco_core/prompts/few_shot_with_templates.py +239 -0
  167. coco_core/prompts/image.py +177 -0
  168. coco_core/prompts/loading.py +296 -0
  169. coco_core/prompts/message.py +97 -0
  170. coco_core/prompts/prompt.py +312 -0
  171. coco_core/prompts/string.py +399 -0
  172. coco_core/prompts/structured.py +214 -0
  173. coco_core/py.typed +0 -0
  174. coco_core/rate_limiters.py +254 -0
  175. coco_core/retrievers.py +328 -0
  176. coco_core/runnables/__init__.py +136 -0
  177. coco_core/runnables/base.py +6725 -0
  178. coco_core/runnables/branch.py +457 -0
  179. coco_core/runnables/config.py +712 -0
  180. coco_core/runnables/configurable.py +710 -0
  181. coco_core/runnables/fallbacks.py +663 -0
  182. coco_core/runnables/graph.py +741 -0
  183. coco_core/runnables/graph_ascii.py +366 -0
  184. coco_core/runnables/graph_mermaid.py +503 -0
  185. coco_core/runnables/graph_png.py +215 -0
  186. coco_core/runnables/history.py +631 -0
  187. coco_core/runnables/passthrough.py +849 -0
  188. coco_core/runnables/retry.py +379 -0
  189. coco_core/runnables/router.py +239 -0
  190. coco_core/runnables/schema.py +188 -0
  191. coco_core/runnables/utils.py +798 -0
  192. coco_core/stores.py +291 -0
  193. coco_core/structured_query.py +203 -0
  194. coco_core/sys_info.py +154 -0
  195. coco_core/tools/__init__.py +95 -0
  196. coco_core/tools/base.py +1948 -0
  197. coco_core/tools/convert.py +497 -0
  198. coco_core/tools/render.py +67 -0
  199. coco_core/tools/retriever.py +94 -0
  200. coco_core/tools/simple.py +208 -0
  201. coco_core/tools/structured.py +322 -0
  202. coco_core/tracers/__init__.py +47 -0
  203. coco_core/tracers/_compat.py +95 -0
  204. coco_core/tracers/_context.py +337 -0
  205. coco_core/tracers/_streaming.py +53 -0
  206. coco_core/tracers/base.py +955 -0
  207. coco_core/tracers/coco.py +279 -0
  208. coco_core/tracers/context.py +205 -0
  209. coco_core/tracers/core.py +766 -0
  210. coco_core/tracers/event_stream.py +1101 -0
  211. coco_core/tracers/log_stream.py +765 -0
  212. coco_core/tracers/memory_stream.py +200 -0
  213. coco_core/tracers/root_listeners.py +130 -0
  214. coco_core/tracers/run_collector.py +40 -0
  215. coco_core/tracers/schemas.py +14 -0
  216. coco_core/tracers/stdout.py +205 -0
  217. coco_core/utils/__init__.py +111 -0
  218. coco_core/utils/_gateway.py +274 -0
  219. coco_core/utils/_merge.py +218 -0
  220. coco_core/utils/aiter.py +357 -0
  221. coco_core/utils/env.py +86 -0
  222. coco_core/utils/formatting.py +80 -0
  223. coco_core/utils/function_calling.py +869 -0
  224. coco_core/utils/html.py +132 -0
  225. coco_core/utils/image.py +15 -0
  226. coco_core/utils/input.py +82 -0
  227. coco_core/utils/interactive_env.py +12 -0
  228. coco_core/utils/iter.py +229 -0
  229. coco_core/utils/json.py +230 -0
  230. coco_core/utils/json_schema.py +273 -0
  231. coco_core/utils/mustache.py +706 -0
  232. coco_core/utils/pydantic.py +631 -0
  233. coco_core/utils/strings.py +69 -0
  234. coco_core/utils/usage.py +61 -0
  235. coco_core/utils/utils.py +528 -0
  236. coco_core/utils/uuid.py +57 -0
  237. coco_core/vectorstores/__init__.py +53 -0
  238. coco_core/vectorstores/base.py +1111 -0
  239. coco_core/vectorstores/in_memory.py +546 -0
  240. coco_core/vectorstores/utils.py +163 -0
  241. coco_core/version.py +3 -0
  242. coco_framework-0.1.0.dist-info/METADATA +184 -0
  243. coco_framework-0.1.0.dist-info/RECORD +400 -0
  244. coco_framework-0.1.0.dist-info/WHEEL +4 -0
  245. coco_framework-0.1.0.dist-info/licenses/LICENSE +24 -0
  246. coco_framework-0.1.0.dist-info/licenses/NOTICE +15 -0
  247. coco_graph/_internal/__init__.py +4 -0
  248. coco_graph/_internal/_cache.py +31 -0
  249. coco_graph/_internal/_config.py +474 -0
  250. coco_graph/_internal/_constants.py +140 -0
  251. coco_graph/_internal/_fields.py +213 -0
  252. coco_graph/_internal/_future.py +220 -0
  253. coco_graph/_internal/_pydantic.py +275 -0
  254. coco_graph/_internal/_queue.py +124 -0
  255. coco_graph/_internal/_replay.py +90 -0
  256. coco_graph/_internal/_retry.py +29 -0
  257. coco_graph/_internal/_runnable.py +969 -0
  258. coco_graph/_internal/_scratchpad.py +19 -0
  259. coco_graph/_internal/_serde.py +253 -0
  260. coco_graph/_internal/_timeout.py +25 -0
  261. coco_graph/_internal/_typing.py +54 -0
  262. coco_graph/cache/base/__init__.py +48 -0
  263. coco_graph/cache/base/py.typed +0 -0
  264. coco_graph/cache/memory/__init__.py +73 -0
  265. coco_graph/cache/redis/__init__.py +144 -0
  266. coco_graph/cache/sqlite/__init__.py +120 -0
  267. coco_graph/callbacks.py +394 -0
  268. coco_graph/channels/__init__.py +29 -0
  269. coco_graph/channels/any_value.py +72 -0
  270. coco_graph/channels/base.py +121 -0
  271. coco_graph/channels/binop.py +155 -0
  272. coco_graph/channels/delta.py +202 -0
  273. coco_graph/channels/ephemeral_value.py +79 -0
  274. coco_graph/channels/last_value.py +151 -0
  275. coco_graph/channels/named_barrier_value.py +167 -0
  276. coco_graph/channels/topic.py +94 -0
  277. coco_graph/channels/untracked_value.py +73 -0
  278. coco_graph/checkpoint/base/__init__.py +861 -0
  279. coco_graph/checkpoint/base/id.py +109 -0
  280. coco_graph/checkpoint/base/py.typed +0 -0
  281. coco_graph/checkpoint/memory/__init__.py +698 -0
  282. coco_graph/checkpoint/memory/py.typed +0 -0
  283. coco_graph/checkpoint/postgres/__init__.py +602 -0
  284. coco_graph/checkpoint/postgres/_ainternal.py +23 -0
  285. coco_graph/checkpoint/postgres/_internal.py +21 -0
  286. coco_graph/checkpoint/postgres/aio.py +691 -0
  287. coco_graph/checkpoint/postgres/base.py +666 -0
  288. coco_graph/checkpoint/postgres/py.typed +0 -0
  289. coco_graph/checkpoint/postgres/shallow.py +967 -0
  290. coco_graph/checkpoint/serde/__init__.py +0 -0
  291. coco_graph/checkpoint/serde/_msgpack.py +97 -0
  292. coco_graph/checkpoint/serde/base.py +64 -0
  293. coco_graph/checkpoint/serde/encrypted.py +80 -0
  294. coco_graph/checkpoint/serde/event_hooks.py +52 -0
  295. coco_graph/checkpoint/serde/jsonplus.py +883 -0
  296. coco_graph/checkpoint/serde/py.typed +0 -0
  297. coco_graph/checkpoint/serde/types.py +68 -0
  298. coco_graph/checkpoint/sqlite/__init__.py +645 -0
  299. coco_graph/checkpoint/sqlite/_delta.py +172 -0
  300. coco_graph/checkpoint/sqlite/aio.py +738 -0
  301. coco_graph/checkpoint/sqlite/py.typed +0 -0
  302. coco_graph/checkpoint/sqlite/utils.py +116 -0
  303. coco_graph/config.py +196 -0
  304. coco_graph/constants.py +64 -0
  305. coco_graph/errors.py +241 -0
  306. coco_graph/func/__init__.py +620 -0
  307. coco_graph/graph/__init__.py +12 -0
  308. coco_graph/graph/_branch.py +225 -0
  309. coco_graph/graph/_node.py +103 -0
  310. coco_graph/graph/message.py +437 -0
  311. coco_graph/graph/state.py +1978 -0
  312. coco_graph/graph/ui.py +227 -0
  313. coco_graph/managed/__init__.py +3 -0
  314. coco_graph/managed/base.py +31 -0
  315. coco_graph/managed/is_last_step.py +24 -0
  316. coco_graph/prebuilt/__init__.py +23 -0
  317. coco_graph/prebuilt/_tool_call_stream.py +117 -0
  318. coco_graph/prebuilt/_tool_call_transformer.py +165 -0
  319. coco_graph/prebuilt/chat_agent_executor.py +1015 -0
  320. coco_graph/prebuilt/interrupt.py +105 -0
  321. coco_graph/prebuilt/py.typed +0 -0
  322. coco_graph/prebuilt/tool_node.py +2030 -0
  323. coco_graph/prebuilt/tool_validator.py +221 -0
  324. coco_graph/pregel/__init__.py +3 -0
  325. coco_graph/pregel/_algo.py +1460 -0
  326. coco_graph/pregel/_call.py +298 -0
  327. coco_graph/pregel/_checkpoint.py +331 -0
  328. coco_graph/pregel/_config.py +0 -0
  329. coco_graph/pregel/_draw.py +294 -0
  330. coco_graph/pregel/_executor.py +223 -0
  331. coco_graph/pregel/_io.py +174 -0
  332. coco_graph/pregel/_log.py +3 -0
  333. coco_graph/pregel/_loop.py +1988 -0
  334. coco_graph/pregel/_messages.py +461 -0
  335. coco_graph/pregel/_read.py +312 -0
  336. coco_graph/pregel/_retry.py +854 -0
  337. coco_graph/pregel/_runner.py +941 -0
  338. coco_graph/pregel/_tools.py +268 -0
  339. coco_graph/pregel/_utils.py +221 -0
  340. coco_graph/pregel/_validate.py +120 -0
  341. coco_graph/pregel/_write.py +192 -0
  342. coco_graph/pregel/debug.py +302 -0
  343. coco_graph/pregel/main.py +4364 -0
  344. coco_graph/pregel/protocol.py +288 -0
  345. coco_graph/pregel/types.py +38 -0
  346. coco_graph/py.typed +0 -0
  347. coco_graph/runtime.py +350 -0
  348. coco_graph/store/base/__init__.py +1322 -0
  349. coco_graph/store/base/batch.py +371 -0
  350. coco_graph/store/base/embed.py +436 -0
  351. coco_graph/store/base/py.typed +0 -0
  352. coco_graph/store/memory/__init__.py +592 -0
  353. coco_graph/store/memory/py.typed +0 -0
  354. coco_graph/store/postgres/__init__.py +4 -0
  355. coco_graph/store/postgres/aio.py +592 -0
  356. coco_graph/store/postgres/base.py +1480 -0
  357. coco_graph/store/postgres/py.typed +0 -0
  358. coco_graph/store/sqlite/__init__.py +4 -0
  359. coco_graph/store/sqlite/aio.py +632 -0
  360. coco_graph/store/sqlite/base.py +1514 -0
  361. coco_graph/stream/__init__.py +45 -0
  362. coco_graph/stream/_convert.py +32 -0
  363. coco_graph/stream/_mux.py +523 -0
  364. coco_graph/stream/_types.py +330 -0
  365. coco_graph/stream/run_stream.py +735 -0
  366. coco_graph/stream/stream_channel.py +341 -0
  367. coco_graph/stream/transformers.py +1039 -0
  368. coco_graph/types.py +1079 -0
  369. coco_graph/typing.py +48 -0
  370. coco_graph/utils/__init__.py +1 -0
  371. coco_graph/utils/config.py +4 -0
  372. coco_graph/utils/runnable.py +3 -0
  373. coco_graph/version.py +13 -0
  374. coco_graph/warnings.py +69 -0
  375. coco_openai/__init__.py +20 -0
  376. coco_openai/_compat.py +45 -0
  377. coco_openai/_version.py +3 -0
  378. coco_openai/chat_models/__init__.py +6 -0
  379. coco_openai/chat_models/_client_utils.py +684 -0
  380. coco_openai/chat_models/_compat.py +525 -0
  381. coco_openai/chat_models/azure.py +1227 -0
  382. coco_openai/chat_models/base.py +5654 -0
  383. coco_openai/chat_models/codex.py +557 -0
  384. coco_openai/chatgpt_oauth.py +1063 -0
  385. coco_openai/data/__init__.py +1 -0
  386. coco_openai/data/_profiles.py +1655 -0
  387. coco_openai/data/profile_augmentations.toml +127 -0
  388. coco_openai/embeddings/__init__.py +6 -0
  389. coco_openai/embeddings/azure.py +240 -0
  390. coco_openai/embeddings/base.py +820 -0
  391. coco_openai/llms/__init__.py +6 -0
  392. coco_openai/llms/azure.py +249 -0
  393. coco_openai/llms/base.py +919 -0
  394. coco_openai/middleware/__init__.py +11 -0
  395. coco_openai/middleware/openai_moderation.py +484 -0
  396. coco_openai/output_parsers/__init__.py +9 -0
  397. coco_openai/output_parsers/tools.py +9 -0
  398. coco_openai/py.typed +0 -0
  399. coco_openai/tools/__init__.py +5 -0
  400. coco_openai/tools/custom_tool.py +111 -0
@@ -0,0 +1,637 @@
1
+ """Helper functions for deprecating parts of the Coco API.
2
+
3
+ This module was adapted from matplotlib's [`_api/deprecation.py`](https://github.com/matplotlib/matplotlib/blob/main/lib/matplotlib/_api/deprecation.py)
4
+ module.
5
+
6
+ !!! warning
7
+
8
+ This module is for internal use only. Do not use it in your own code. We may change
9
+ the API at any time with no warning.
10
+ """
11
+
12
+ import contextlib
13
+ import functools
14
+ import inspect
15
+ import sys
16
+ import warnings
17
+ from collections.abc import Callable, Generator
18
+ from contextvars import ContextVar
19
+ from typing import (
20
+ TYPE_CHECKING,
21
+ Any,
22
+ ParamSpec,
23
+ TypeGuard,
24
+ TypeVar,
25
+ cast,
26
+ )
27
+
28
+ from pydantic.fields import FieldInfo
29
+
30
+ from coco_core._api.internal import is_caller_internal
31
+
32
+ if TYPE_CHECKING:
33
+ from pydantic.v1.fields import FieldInfo as FieldInfoV1
34
+
35
+
36
+ def _is_pydantic_v1_field_info(obj: Any) -> TypeGuard["FieldInfoV1"]:
37
+ """Check if `obj` is a `pydantic.v1.fields.FieldInfo` without forcing import.
38
+
39
+ Importing `pydantic.v1` emits a `UserWarning` on Python 3.14+. Skipping the
40
+ import entirely when no caller has constructed a v1 `FieldInfo` keeps that
41
+ warning out of `coco_core`'s import path. If a caller did construct one,
42
+ `pydantic.v1.fields` is already in `sys.modules` and isinstance is safe.
43
+ """
44
+ mod = sys.modules.get("pydantic.v1.fields")
45
+ if mod is None:
46
+ return False
47
+ return isinstance(obj, mod.FieldInfo)
48
+
49
+
50
+ def _build_deprecation_message(
51
+ *,
52
+ alternative: str = "",
53
+ alternative_import: str = "",
54
+ ) -> str:
55
+ """Build a simple deprecation message for `__deprecated__` attribute.
56
+
57
+ Args:
58
+ alternative: An alternative API name.
59
+ alternative_import: A fully qualified import path for the alternative.
60
+
61
+ Returns:
62
+ A deprecation message string for IDE/type checker display.
63
+ """
64
+ if alternative_import:
65
+ return f"Use {alternative_import} instead."
66
+ if alternative:
67
+ return f"Use {alternative} instead."
68
+ return "Deprecated."
69
+
70
+
71
+ class CocoDeprecationWarning(DeprecationWarning):
72
+ """A class for issuing deprecation warnings for Coco users."""
73
+
74
+
75
+ class CocoPendingDeprecationWarning(PendingDeprecationWarning):
76
+ """A class for issuing deprecation warnings for Coco users."""
77
+
78
+
79
+ # Tracks when callers intentionally silence Coco deprecation warnings.
80
+ # Suppressed warnings should not consume a deprecated callable's one-time
81
+ # warning state; otherwise an internal compatibility path can prevent the first
82
+ # user-visible call from warning.
83
+ _SUPPRESSING_COCO_DEPRECATION_WARNING = ContextVar(
84
+ "_SUPPRESSING_COCO_DEPRECATION_WARNING", default=False
85
+ )
86
+
87
+
88
+ # PUBLIC API
89
+
90
+
91
+ # Bound is `Any` (not `FieldInfoV1`) because importing `pydantic.v1` at module
92
+ # scope emits a `UserWarning` on Python 3.14+; v1 `FieldInfo` support is handled
93
+ # at runtime via `_is_pydantic_v1_field_info`.
94
+ T = TypeVar("T", bound=type | Callable[..., Any] | Any)
95
+
96
+
97
+ def _validate_deprecation_params(
98
+ removal: str,
99
+ alternative: str,
100
+ alternative_import: str,
101
+ *,
102
+ pending: bool,
103
+ ) -> None:
104
+ """Validate the deprecation parameters."""
105
+ if pending and removal:
106
+ msg = "A pending deprecation cannot have a scheduled removal"
107
+ raise ValueError(msg)
108
+ if alternative and alternative_import:
109
+ msg = "Cannot specify both alternative and alternative_import"
110
+ raise ValueError(msg)
111
+
112
+ if alternative_import and "." not in alternative_import:
113
+ msg = (
114
+ "alternative_import must be a fully qualified module path. Got "
115
+ f" {alternative_import}"
116
+ )
117
+ raise ValueError(msg)
118
+
119
+
120
+ def deprecated(
121
+ since: str,
122
+ *,
123
+ message: str = "",
124
+ name: str = "",
125
+ alternative: str = "",
126
+ alternative_import: str = "",
127
+ pending: bool = False,
128
+ obj_type: str = "",
129
+ addendum: str = "",
130
+ removal: str = "",
131
+ package: str = "",
132
+ ) -> Callable[[T], T]:
133
+ """Decorator to mark a function, a class, or a property as deprecated.
134
+
135
+ When deprecating a classmethod, a staticmethod, or a property, the `@deprecated`
136
+ decorator should go *under* `@classmethod` and `@staticmethod` (i.e., `deprecated`
137
+ should directly decorate the underlying callable), but *over* `@property`.
138
+
139
+ When deprecating a class `C` intended to be used as a base class in a multiple
140
+ inheritance hierarchy, `C` *must* define an `__init__` method (if `C` instead
141
+ inherited its `__init__` from its own base class, then `@deprecated` would mess up
142
+ `__init__` inheritance when installing its own (deprecation-emitting) `C.__init__`).
143
+
144
+ Parameters are the same as for `warn_deprecated`, except that *obj_type* defaults to
145
+ 'class' if decorating a class, 'attribute' if decorating a property, and 'function'
146
+ otherwise.
147
+
148
+ Args:
149
+ since: The release at which this API became deprecated.
150
+ message: Override the default deprecation message.
151
+
152
+ The `%(since)s`, `%(name)s`, `%(alternative)s`, `%(obj_type)s`,
153
+ `%(addendum)s`, and `%(removal)s` format specifiers will be replaced by the
154
+ values of the respective arguments passed to this function.
155
+ name: The name of the deprecated object.
156
+ alternative: An alternative API that the user may use in place of the deprecated
157
+ API.
158
+
159
+ The deprecation warning will tell the user about this alternative if
160
+ provided.
161
+ alternative_import: An alternative import that the user may use instead.
162
+ pending: If `True`, uses a `PendingDeprecationWarning` instead of a
163
+ `DeprecationWarning`.
164
+
165
+ Cannot be used together with removal.
166
+ obj_type: The object type being deprecated.
167
+ addendum: Additional text appended directly to the final message.
168
+ removal: The expected removal version.
169
+
170
+ With the default (an empty string), no removal version is shown in the
171
+ warning message.
172
+
173
+ Cannot be used together with pending.
174
+ package: The package of the deprecated object.
175
+
176
+ Returns:
177
+ A decorator to mark a function or class as deprecated.
178
+
179
+ Example:
180
+ ```python
181
+ @deprecated("1.4.0")
182
+ def the_function_to_deprecate():
183
+ pass
184
+ ```
185
+ """
186
+ _validate_deprecation_params(
187
+ removal, alternative, alternative_import, pending=pending
188
+ )
189
+
190
+ def deprecate(
191
+ obj: T,
192
+ *,
193
+ _obj_type: str = obj_type,
194
+ _name: str = name,
195
+ _message: str = message,
196
+ _alternative: str = alternative,
197
+ _alternative_import: str = alternative_import,
198
+ _pending: bool = pending,
199
+ _addendum: str = addendum,
200
+ _package: str = package,
201
+ ) -> T:
202
+ """Implementation of the decorator returned by `deprecated`."""
203
+
204
+ def emit_warning() -> None:
205
+ """Emit the warning."""
206
+ warn_deprecated(
207
+ since,
208
+ message=_message,
209
+ name=_name,
210
+ alternative=_alternative,
211
+ alternative_import=_alternative_import,
212
+ pending=_pending,
213
+ obj_type=_obj_type,
214
+ addendum=_addendum,
215
+ removal=removal,
216
+ package=_package,
217
+ )
218
+
219
+ warned = False
220
+
221
+ def warning_emitting_wrapper(*args: Any, **kwargs: Any) -> Any:
222
+ """Wrapper for the original wrapped callable that emits a warning.
223
+
224
+ Args:
225
+ *args: The positional arguments to the function.
226
+ **kwargs: The keyword arguments to the function.
227
+
228
+ Returns:
229
+ The return value of the function being wrapped.
230
+ """
231
+ nonlocal warned
232
+ if not warned and not is_caller_internal():
233
+ emit_warning()
234
+ # Only mark the warning as emitted if it was not intentionally
235
+ # suppressed by `suppress_coco_deprecation_warning()`.
236
+ warned = not _SUPPRESSING_COCO_DEPRECATION_WARNING.get()
237
+ return wrapped(*args, **kwargs)
238
+
239
+ async def awarning_emitting_wrapper(*args: Any, **kwargs: Any) -> Any:
240
+ """Same as warning_emitting_wrapper, but for async functions."""
241
+ nonlocal warned
242
+ if not warned and not is_caller_internal():
243
+ emit_warning()
244
+ # Only mark the warning as emitted if it was not intentionally
245
+ # suppressed by `suppress_coco_deprecation_warning()`.
246
+ warned = not _SUPPRESSING_COCO_DEPRECATION_WARNING.get()
247
+ return await wrapped(*args, **kwargs)
248
+
249
+ _package = _package or obj.__module__.split(".")[0].replace("_", "-")
250
+
251
+ if isinstance(obj, type):
252
+ if not _obj_type:
253
+ _obj_type = "class"
254
+ wrapped = obj.__init__ # type: ignore[misc]
255
+ _name = _name or obj.__qualname__
256
+ old_doc = obj.__doc__
257
+
258
+ def finalize(_: Callable[..., Any], new_doc: str, /) -> T:
259
+ """Finalize the deprecation of a class."""
260
+ # Can't set new_doc on some extension objects.
261
+ with contextlib.suppress(AttributeError):
262
+ obj.__doc__ = new_doc
263
+
264
+ def warn_if_direct_instance(
265
+ self: Any, *args: Any, **kwargs: Any
266
+ ) -> Any:
267
+ """Warn that the class is in beta."""
268
+ nonlocal warned
269
+ if not warned and type(self) is obj and not is_caller_internal():
270
+ emit_warning()
271
+ # Only mark the warning as emitted if it was not intentionally
272
+ # suppressed by `suppress_coco_deprecation_warning()`.
273
+ warned = not _SUPPRESSING_COCO_DEPRECATION_WARNING.get()
274
+ return wrapped(self, *args, **kwargs)
275
+
276
+ obj.__init__ = functools.wraps(obj.__init__)( # type: ignore[misc]
277
+ warn_if_direct_instance
278
+ )
279
+ # Set __deprecated__ for PEP 702 (IDE/type checker support)
280
+ obj.__deprecated__ = _build_deprecation_message( # type: ignore[attr-defined]
281
+ alternative=alternative,
282
+ alternative_import=alternative_import,
283
+ )
284
+ return obj
285
+
286
+ elif _is_pydantic_v1_field_info(obj):
287
+ wrapped = None
288
+ if not _obj_type:
289
+ _obj_type = "attribute"
290
+ if not _name:
291
+ msg = f"Field {obj} must have a name to be deprecated."
292
+ raise ValueError(msg)
293
+ old_doc = obj.description
294
+
295
+ def finalize(_: Callable[..., Any], new_doc: str, /) -> T:
296
+ from pydantic.v1.fields import FieldInfo as FieldInfoV1 # noqa: PLC0415
297
+
298
+ return cast(
299
+ "T",
300
+ FieldInfoV1(
301
+ default=obj.default,
302
+ default_factory=obj.default_factory,
303
+ description=new_doc,
304
+ alias=obj.alias,
305
+ exclude=obj.exclude,
306
+ ),
307
+ )
308
+
309
+ elif isinstance(obj, FieldInfo):
310
+ wrapped = None
311
+ if not _obj_type:
312
+ _obj_type = "attribute"
313
+ if not _name:
314
+ msg = f"Field {obj} must have a name to be deprecated."
315
+ raise ValueError(msg)
316
+ old_doc = obj.description
317
+
318
+ def finalize(_: Callable[..., Any], new_doc: str, /) -> T:
319
+ return cast(
320
+ "T",
321
+ FieldInfo(
322
+ default=obj.default,
323
+ default_factory=obj.default_factory,
324
+ description=new_doc,
325
+ alias=obj.alias,
326
+ exclude=obj.exclude,
327
+ ),
328
+ )
329
+
330
+ elif isinstance(obj, property):
331
+ if not _obj_type:
332
+ _obj_type = "attribute"
333
+ wrapped = None
334
+ _name = _name or cast("type", obj.fget).__qualname__
335
+ old_doc = obj.__doc__
336
+
337
+ class _DeprecatedProperty(property):
338
+ """A deprecated property."""
339
+
340
+ def __init__(
341
+ self,
342
+ fget: Callable[[Any], Any] | None = None,
343
+ fset: Callable[[Any, Any], None] | None = None,
344
+ fdel: Callable[[Any], None] | None = None,
345
+ doc: str | None = None,
346
+ ) -> None:
347
+ super().__init__(fget, fset, fdel, doc)
348
+ self.__orig_fget = fget
349
+ self.__orig_fset = fset
350
+ self.__orig_fdel = fdel
351
+
352
+ def __get__(self, instance: Any, owner: type | None = None) -> Any:
353
+ if instance is not None or owner is not None:
354
+ emit_warning()
355
+ if self.fget is None:
356
+ return None
357
+ return self.fget(instance)
358
+
359
+ def __set__(self, instance: Any, value: Any) -> None:
360
+ if instance is not None:
361
+ emit_warning()
362
+ if self.fset is not None:
363
+ self.fset(instance, value)
364
+
365
+ def __delete__(self, instance: Any) -> None:
366
+ if instance is not None:
367
+ emit_warning()
368
+ if self.fdel is not None:
369
+ self.fdel(instance)
370
+
371
+ def __set_name__(self, owner: type | None, set_name: str) -> None:
372
+ nonlocal _name
373
+ if _name == "<lambda>":
374
+ _name = set_name
375
+
376
+ def finalize(_: Callable[..., Any], new_doc: str, /) -> T:
377
+ """Finalize the property."""
378
+ prop = _DeprecatedProperty(
379
+ fget=obj.fget, fset=obj.fset, fdel=obj.fdel, doc=new_doc
380
+ )
381
+ # Set __deprecated__ for PEP 702 (IDE/type checker support)
382
+ prop.__deprecated__ = _build_deprecation_message( # type: ignore[attr-defined]
383
+ alternative=alternative,
384
+ alternative_import=alternative_import,
385
+ )
386
+ return cast("T", prop)
387
+
388
+ else:
389
+ _name = _name or cast("type", obj).__qualname__
390
+ if not _obj_type:
391
+ # edge case: when a function is within another function
392
+ # within a test, this will call it a "method" not a "function"
393
+ _obj_type = "function" if "." not in _name else "method"
394
+ wrapped = obj
395
+ old_doc = wrapped.__doc__
396
+
397
+ def finalize(wrapper: Callable[..., Any], new_doc: str, /) -> T:
398
+ """Wrap the wrapped function using the wrapper and update the docstring.
399
+
400
+ Args:
401
+ wrapper: The wrapper function.
402
+ new_doc: The new docstring.
403
+
404
+ Returns:
405
+ The wrapped function.
406
+ """
407
+ wrapper = functools.wraps(wrapped)(wrapper)
408
+ wrapper.__doc__ = new_doc
409
+ # Set __deprecated__ for PEP 702 (IDE/type checker support)
410
+ wrapper.__deprecated__ = _build_deprecation_message( # type: ignore[attr-defined]
411
+ alternative=alternative,
412
+ alternative_import=alternative_import,
413
+ )
414
+ return cast("T", wrapper)
415
+
416
+ old_doc = inspect.cleandoc(old_doc or "").strip("\n")
417
+
418
+ # old_doc can be None
419
+ if not old_doc:
420
+ old_doc = ""
421
+
422
+ # Modify the docstring to include a deprecation notice.
423
+ if (
424
+ _alternative
425
+ and _alternative.rsplit(".", maxsplit=1)[-1].lower()
426
+ == _alternative.rsplit(".", maxsplit=1)[-1]
427
+ ) or _alternative:
428
+ _alternative = f"`{_alternative}`"
429
+
430
+ if (
431
+ _alternative_import
432
+ and _alternative_import.rsplit(".", maxsplit=1)[-1].lower()
433
+ == _alternative_import.rsplit(".", maxsplit=1)[-1]
434
+ ) or _alternative_import:
435
+ _alternative_import = f"`{_alternative_import}`"
436
+
437
+ components = [
438
+ _message,
439
+ f"Use {_alternative} instead." if _alternative else "",
440
+ f"Use {_alternative_import} instead." if _alternative_import else "",
441
+ _addendum,
442
+ ]
443
+ details = " ".join([component.strip() for component in components if component])
444
+ package = _package or (
445
+ _name.split(".")[0].replace("_", "-") if "." in _name else None
446
+ )
447
+ if removal:
448
+ if removal.startswith("1.") and package and package.startswith("coco"):
449
+ removal_str = f"It will not be removed until {package}=={removal}."
450
+ else:
451
+ removal_str = f"It will be removed in {package}=={removal}."
452
+ else:
453
+ removal_str = ""
454
+ new_doc = f"""\
455
+ !!! deprecated "{since} {details} {removal_str}"
456
+
457
+ {old_doc}\
458
+ """
459
+
460
+ if inspect.iscoroutinefunction(obj):
461
+ return finalize(awarning_emitting_wrapper, new_doc)
462
+ return finalize(warning_emitting_wrapper, new_doc)
463
+
464
+ return deprecate
465
+
466
+
467
+ @contextlib.contextmanager
468
+ def suppress_coco_deprecation_warning() -> Generator[None, None, None]:
469
+ """Context manager to suppress `CocoDeprecationWarning`."""
470
+ token = _SUPPRESSING_COCO_DEPRECATION_WARNING.set(True)
471
+ try:
472
+ with warnings.catch_warnings():
473
+ warnings.simplefilter("ignore", CocoDeprecationWarning)
474
+ warnings.simplefilter("ignore", CocoPendingDeprecationWarning)
475
+ yield
476
+ finally:
477
+ _SUPPRESSING_COCO_DEPRECATION_WARNING.reset(token)
478
+
479
+
480
+ def warn_deprecated(
481
+ since: str,
482
+ *,
483
+ message: str = "",
484
+ name: str = "",
485
+ alternative: str = "",
486
+ alternative_import: str = "",
487
+ pending: bool = False,
488
+ obj_type: str = "",
489
+ addendum: str = "",
490
+ removal: str = "",
491
+ package: str = "",
492
+ ) -> None:
493
+ """Display a standardized deprecation.
494
+
495
+ Args:
496
+ since: The release at which this API became deprecated.
497
+ message: Override the default deprecation message.
498
+
499
+ The `%(since)s`, `%(name)s`, `%(alternative)s`, `%(obj_type)s`,
500
+ `%(addendum)s`, and `%(removal)s` format specifiers will be replaced by the
501
+ values of the respective arguments passed to this function.
502
+ name: The name of the deprecated object.
503
+ alternative: An alternative API that the user may use in place of the
504
+ deprecated API.
505
+
506
+ The deprecation warning will tell the user about this alternative if
507
+ provided.
508
+ alternative_import: An alternative import that the user may use instead.
509
+ pending: If `True`, uses a `PendingDeprecationWarning` instead of a
510
+ `DeprecationWarning`.
511
+
512
+ Cannot be used together with removal.
513
+ obj_type: The object type being deprecated.
514
+ addendum: Additional text appended directly to the final message.
515
+ removal: The expected removal version.
516
+
517
+ With the default (an empty string), no removal version is shown in the
518
+ warning message.
519
+
520
+ Cannot be used together with pending.
521
+ package: The package of the deprecated object.
522
+ """
523
+ if not pending and removal:
524
+ removal = f"in {removal}"
525
+
526
+ if not message:
527
+ message = ""
528
+ package_ = (
529
+ package or name.split(".", maxsplit=1)[0].replace("_", "-")
530
+ if "." in name
531
+ else "Coco"
532
+ )
533
+
534
+ if obj_type:
535
+ message += f"The {obj_type} `{name}`"
536
+ else:
537
+ message += f"`{name}`"
538
+
539
+ if pending:
540
+ message += " will be deprecated in a future version"
541
+ else:
542
+ message += f" was deprecated in {package_} {since}"
543
+
544
+ if removal:
545
+ message += f" and will be removed {removal}"
546
+
547
+ if alternative_import:
548
+ alt_package = alternative_import.split(".", maxsplit=1)[0].replace("_", "-")
549
+ if alt_package == package_:
550
+ message += f". Use {alternative_import} instead."
551
+ else:
552
+ alt_module, alt_name = alternative_import.rsplit(".", 1)
553
+ message += (
554
+ f". An updated version of the {obj_type} exists in the "
555
+ f"{alt_package} package and should be used instead. To use it run "
556
+ f"`pip install -U {alt_package}` and import as "
557
+ f"`from {alt_module} import {alt_name}`."
558
+ )
559
+ elif alternative:
560
+ message += f". Use {alternative} instead."
561
+
562
+ if addendum:
563
+ message += f" {addendum}"
564
+
565
+ warning_cls = (
566
+ CocoPendingDeprecationWarning if pending else CocoDeprecationWarning
567
+ )
568
+ warning = warning_cls(message)
569
+ warnings.warn(warning, category=CocoDeprecationWarning, stacklevel=4)
570
+
571
+
572
+ def surface_coco_deprecation_warnings() -> None:
573
+ """Unmute Coco deprecation warnings."""
574
+ warnings.filterwarnings(
575
+ "default",
576
+ category=CocoPendingDeprecationWarning,
577
+ )
578
+
579
+ warnings.filterwarnings(
580
+ "default",
581
+ category=CocoDeprecationWarning,
582
+ )
583
+
584
+
585
+ _P = ParamSpec("_P")
586
+ _R = TypeVar("_R")
587
+
588
+
589
+ def rename_parameter(
590
+ *,
591
+ since: str,
592
+ removal: str,
593
+ old: str,
594
+ new: str,
595
+ ) -> Callable[[Callable[_P, _R]], Callable[_P, _R]]:
596
+ """Decorator indicating that parameter *old* of *func* is renamed to *new*.
597
+
598
+ The actual implementation of *func* should use *new*, not *old*. If *old* is passed
599
+ to *func*, a `DeprecationWarning` is emitted, and its value is used, even if *new*
600
+ is also passed by keyword.
601
+
602
+ Args:
603
+ since: The version in which the parameter was renamed.
604
+ removal: The version in which the old parameter will be removed.
605
+ old: The old parameter name.
606
+ new: The new parameter name.
607
+
608
+ Returns:
609
+ A decorator indicating that a parameter was renamed.
610
+
611
+ Example:
612
+ ```python
613
+ @_api.rename_parameter("3.1", "bad_name", "good_name")
614
+ def func(good_name): ...
615
+ ```
616
+ """
617
+
618
+ def decorator(f: Callable[_P, _R]) -> Callable[_P, _R]:
619
+ @functools.wraps(f)
620
+ def wrapper(*args: _P.args, **kwargs: _P.kwargs) -> _R:
621
+ if new in kwargs and old in kwargs:
622
+ msg = f"{f.__name__}() got multiple values for argument {new!r}"
623
+ raise TypeError(msg)
624
+ if old in kwargs:
625
+ warn_deprecated(
626
+ since,
627
+ removal=removal,
628
+ message=f"The parameter `{old}` of `{f.__name__}` was "
629
+ f"deprecated in {since} and will be removed "
630
+ f"in {removal} Use `{new}` instead.",
631
+ )
632
+ kwargs[new] = kwargs.pop(old)
633
+ return f(*args, **kwargs)
634
+
635
+ return wrapper
636
+
637
+ return decorator
@@ -0,0 +1,23 @@
1
+ import inspect
2
+ from typing import cast
3
+
4
+
5
+ def is_caller_internal(depth: int = 2) -> bool:
6
+ """Return whether the caller at `depth` of this function is internal."""
7
+ try:
8
+ frame = inspect.currentframe()
9
+ except AttributeError:
10
+ return False
11
+ if frame is None:
12
+ return False
13
+ try:
14
+ for _ in range(depth):
15
+ frame = frame.f_back
16
+ if frame is None:
17
+ return False
18
+ # Directly access the module name from the frame's global variables
19
+ module_globals = frame.f_globals
20
+ caller_module_name = cast("str", module_globals.get("__name__", ""))
21
+ return caller_module_name.startswith("coco")
22
+ finally:
23
+ del frame