anthropic 0.75.0__py3-none-any.whl → 0.77.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 (81) hide show
  1. anthropic/_base_client.py +145 -13
  2. anthropic/_client.py +4 -12
  3. anthropic/_compat.py +3 -3
  4. anthropic/_models.py +16 -1
  5. anthropic/_streaming.py +78 -76
  6. anthropic/_types.py +12 -2
  7. anthropic/_utils/_json.py +35 -0
  8. anthropic/_version.py +1 -1
  9. anthropic/lib/_parse/_response.py +29 -1
  10. anthropic/lib/streaming/__init__.py +3 -0
  11. anthropic/lib/streaming/_messages.py +74 -40
  12. anthropic/lib/streaming/_types.py +42 -2
  13. anthropic/lib/tools/_beta_compaction_control.py +2 -2
  14. anthropic/lib/tools/_beta_runner.py +17 -0
  15. anthropic/resources/beta/messages/messages.py +229 -83
  16. anthropic/resources/messages/messages.py +409 -5
  17. anthropic/types/__init__.py +7 -0
  18. anthropic/types/beta/beta_code_execution_tool_20250522_param.py +1 -0
  19. anthropic/types/beta/beta_code_execution_tool_20250825_param.py +1 -0
  20. anthropic/types/beta/beta_container.py +4 -0
  21. anthropic/types/beta/beta_container_params.py +2 -0
  22. anthropic/types/beta/beta_container_upload_block.py +2 -0
  23. anthropic/types/beta/beta_container_upload_block_param.py +5 -0
  24. anthropic/types/beta/beta_direct_caller.py +2 -0
  25. anthropic/types/beta/beta_direct_caller_param.py +2 -0
  26. anthropic/types/beta/beta_mcp_tool_config_param.py +2 -0
  27. anthropic/types/beta/beta_mcp_tool_default_config_param.py +2 -0
  28. anthropic/types/beta/beta_mcp_toolset_param.py +6 -0
  29. anthropic/types/beta/beta_memory_tool_20250818_param.py +1 -0
  30. anthropic/types/beta/beta_output_config_param.py +15 -1
  31. anthropic/types/beta/beta_server_tool_caller.py +2 -0
  32. anthropic/types/beta/beta_server_tool_caller_param.py +2 -0
  33. anthropic/types/beta/beta_server_tool_use_block.py +4 -4
  34. anthropic/types/beta/beta_skill.py +2 -0
  35. anthropic/types/beta/beta_skill_params.py +2 -0
  36. anthropic/types/beta/beta_tool_bash_20241022_param.py +1 -0
  37. anthropic/types/beta/beta_tool_bash_20250124_param.py +1 -0
  38. anthropic/types/beta/beta_tool_choice_any_param.py +2 -0
  39. anthropic/types/beta/beta_tool_choice_auto_param.py +2 -0
  40. anthropic/types/beta/beta_tool_choice_none_param.py +2 -0
  41. anthropic/types/beta/beta_tool_choice_tool_param.py +2 -0
  42. anthropic/types/beta/beta_tool_computer_use_20241022_param.py +1 -0
  43. anthropic/types/beta/beta_tool_computer_use_20250124_param.py +1 -0
  44. anthropic/types/beta/beta_tool_computer_use_20251124_param.py +1 -0
  45. anthropic/types/beta/beta_tool_param.py +6 -0
  46. anthropic/types/beta/beta_tool_reference_block_param.py +2 -0
  47. anthropic/types/beta/beta_tool_search_tool_bm25_20251119_param.py +1 -0
  48. anthropic/types/beta/beta_tool_search_tool_regex_20251119_param.py +1 -0
  49. anthropic/types/beta/beta_tool_text_editor_20241022_param.py +1 -0
  50. anthropic/types/beta/beta_tool_text_editor_20250124_param.py +1 -0
  51. anthropic/types/beta/beta_tool_text_editor_20250429_param.py +1 -0
  52. anthropic/types/beta/beta_tool_text_editor_20250728_param.py +1 -0
  53. anthropic/types/beta/beta_web_fetch_tool_20250910_param.py +1 -0
  54. anthropic/types/beta/beta_web_search_tool_20250305_param.py +6 -0
  55. anthropic/types/beta/beta_web_search_tool_result_error_code.py +1 -1
  56. anthropic/types/beta/message_count_tokens_params.py +9 -5
  57. anthropic/types/beta/message_create_params.py +9 -5
  58. anthropic/types/beta/messages/batch_create_params.py +2 -9
  59. anthropic/types/beta/messages/beta_message_batch_individual_response.py +4 -0
  60. anthropic/types/json_output_format_param.py +15 -0
  61. anthropic/types/message_count_tokens_params.py +4 -0
  62. anthropic/types/message_create_params.py +4 -0
  63. anthropic/types/messages/message_batch_individual_response.py +4 -0
  64. anthropic/types/output_config_param.py +19 -0
  65. anthropic/types/parsed_message.py +56 -0
  66. anthropic/types/tool_bash_20250124_param.py +3 -0
  67. anthropic/types/tool_choice_any_param.py +2 -0
  68. anthropic/types/tool_choice_auto_param.py +2 -0
  69. anthropic/types/tool_choice_none_param.py +2 -0
  70. anthropic/types/tool_choice_tool_param.py +2 -0
  71. anthropic/types/tool_param.py +8 -0
  72. anthropic/types/tool_text_editor_20250124_param.py +3 -0
  73. anthropic/types/tool_text_editor_20250429_param.py +3 -0
  74. anthropic/types/tool_text_editor_20250728_param.py +3 -0
  75. anthropic/types/web_search_tool_20250305_param.py +8 -0
  76. anthropic/types/web_search_tool_request_error_param.py +8 -1
  77. anthropic/types/web_search_tool_result_error.py +8 -1
  78. {anthropic-0.75.0.dist-info → anthropic-0.77.0.dist-info}/METADATA +4 -2
  79. {anthropic-0.75.0.dist-info → anthropic-0.77.0.dist-info}/RECORD +81 -77
  80. {anthropic-0.75.0.dist-info → anthropic-0.77.0.dist-info}/WHEEL +0 -0
  81. {anthropic-0.75.0.dist-info → anthropic-0.77.0.dist-info}/licenses/LICENSE +0 -0
anthropic/_base_client.py CHANGED
@@ -10,6 +10,7 @@ import asyncio
10
10
  import inspect
11
11
  import logging
12
12
  import platform
13
+ import warnings
13
14
  import email.utils
14
15
  from types import TracebackType
15
16
  from random import random
@@ -54,9 +55,11 @@ from ._types import (
54
55
  ResponseT,
55
56
  AnyMapping,
56
57
  PostParser,
58
+ BinaryTypes,
57
59
  RequestFiles,
58
60
  HttpxSendArgs,
59
61
  RequestOptions,
62
+ AsyncBinaryTypes,
60
63
  HttpxRequestFiles,
61
64
  ModelBuilderProtocol,
62
65
  not_given,
@@ -86,6 +89,7 @@ from ._exceptions import (
86
89
  APIConnectionError,
87
90
  APIResponseValidationError,
88
91
  )
92
+ from ._utils._json import openapi_dumps
89
93
  from ._utils._httpx import get_environment_proxies
90
94
  from ._legacy_response import LegacyAPIResponse
91
95
 
@@ -490,8 +494,19 @@ class BaseClient(Generic[_HttpxClientT, _DefaultStreamT]):
490
494
  retries_taken: int = 0,
491
495
  ) -> httpx.Request:
492
496
  if log.isEnabledFor(logging.DEBUG):
493
- log.debug("Request options: %s", model_dump(options, exclude_unset=True))
494
-
497
+ log.debug(
498
+ "Request options: %s",
499
+ model_dump(
500
+ options,
501
+ exclude_unset=True,
502
+ # Pydantic v1 can't dump every type we support in content, so we exclude it for now.
503
+ exclude={
504
+ "content",
505
+ }
506
+ if PYDANTIC_V1
507
+ else {},
508
+ ),
509
+ )
495
510
  kwargs: dict[str, Any] = {}
496
511
 
497
512
  json_data = options.json_data
@@ -545,10 +560,18 @@ class BaseClient(Generic[_HttpxClientT, _DefaultStreamT]):
545
560
  is_body_allowed = options.method.lower() != "get"
546
561
 
547
562
  if is_body_allowed:
548
- if isinstance(json_data, bytes):
563
+ if options.content is not None and json_data is not None:
564
+ raise TypeError("Passing both `content` and `json_data` is not supported")
565
+ if options.content is not None and files is not None:
566
+ raise TypeError("Passing both `content` and `files` is not supported")
567
+ if options.content is not None:
568
+ kwargs["content"] = options.content
569
+ elif isinstance(json_data, bytes):
549
570
  kwargs["content"] = json_data
550
- else:
551
- kwargs["json"] = json_data if is_given(json_data) else None
571
+ elif not files:
572
+ # Don't set content when JSON is sent as multipart/form-data,
573
+ # since httpx's content param overrides other body arguments
574
+ kwargs["content"] = openapi_dumps(json_data) if is_given(json_data) and json_data is not None else None
552
575
  kwargs["files"] = files
553
576
  else:
554
577
  headers.pop("Content-Type", None)
@@ -1278,6 +1301,7 @@ class SyncAPIClient(BaseClient[httpx.Client, Stream[Any]]):
1278
1301
  *,
1279
1302
  cast_to: Type[ResponseT],
1280
1303
  body: Body | None = None,
1304
+ content: BinaryTypes | None = None,
1281
1305
  options: RequestOptions = {},
1282
1306
  files: RequestFiles | None = None,
1283
1307
  stream: Literal[False] = False,
@@ -1290,6 +1314,7 @@ class SyncAPIClient(BaseClient[httpx.Client, Stream[Any]]):
1290
1314
  *,
1291
1315
  cast_to: Type[ResponseT],
1292
1316
  body: Body | None = None,
1317
+ content: BinaryTypes | None = None,
1293
1318
  options: RequestOptions = {},
1294
1319
  files: RequestFiles | None = None,
1295
1320
  stream: Literal[True],
@@ -1303,6 +1328,7 @@ class SyncAPIClient(BaseClient[httpx.Client, Stream[Any]]):
1303
1328
  *,
1304
1329
  cast_to: Type[ResponseT],
1305
1330
  body: Body | None = None,
1331
+ content: BinaryTypes | None = None,
1306
1332
  options: RequestOptions = {},
1307
1333
  files: RequestFiles | None = None,
1308
1334
  stream: bool,
@@ -1315,13 +1341,25 @@ class SyncAPIClient(BaseClient[httpx.Client, Stream[Any]]):
1315
1341
  *,
1316
1342
  cast_to: Type[ResponseT],
1317
1343
  body: Body | None = None,
1344
+ content: BinaryTypes | None = None,
1318
1345
  options: RequestOptions = {},
1319
1346
  files: RequestFiles | None = None,
1320
1347
  stream: bool = False,
1321
1348
  stream_cls: type[_StreamT] | None = None,
1322
1349
  ) -> ResponseT | _StreamT:
1350
+ if body is not None and content is not None:
1351
+ raise TypeError("Passing both `body` and `content` is not supported")
1352
+ if files is not None and content is not None:
1353
+ raise TypeError("Passing both `files` and `content` is not supported")
1354
+ if isinstance(body, bytes):
1355
+ warnings.warn(
1356
+ "Passing raw bytes as `body` is deprecated and will be removed in a future version. "
1357
+ "Please pass raw bytes via the `content` parameter instead.",
1358
+ DeprecationWarning,
1359
+ stacklevel=2,
1360
+ )
1323
1361
  opts = FinalRequestOptions.construct(
1324
- method="post", url=path, json_data=body, files=to_httpx_files(files), **options
1362
+ method="post", url=path, json_data=body, content=content, files=to_httpx_files(files), **options
1325
1363
  )
1326
1364
  return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls))
1327
1365
 
@@ -1331,9 +1369,24 @@ class SyncAPIClient(BaseClient[httpx.Client, Stream[Any]]):
1331
1369
  *,
1332
1370
  cast_to: Type[ResponseT],
1333
1371
  body: Body | None = None,
1372
+ content: BinaryTypes | None = None,
1373
+ files: RequestFiles | None = None,
1334
1374
  options: RequestOptions = {},
1335
1375
  ) -> ResponseT:
1336
- opts = FinalRequestOptions.construct(method="patch", url=path, json_data=body, **options)
1376
+ if body is not None and content is not None:
1377
+ raise TypeError("Passing both `body` and `content` is not supported")
1378
+ if files is not None and content is not None:
1379
+ raise TypeError("Passing both `files` and `content` is not supported")
1380
+ if isinstance(body, bytes):
1381
+ warnings.warn(
1382
+ "Passing raw bytes as `body` is deprecated and will be removed in a future version. "
1383
+ "Please pass raw bytes via the `content` parameter instead.",
1384
+ DeprecationWarning,
1385
+ stacklevel=2,
1386
+ )
1387
+ opts = FinalRequestOptions.construct(
1388
+ method="patch", url=path, json_data=body, content=content, files=to_httpx_files(files), **options
1389
+ )
1337
1390
  return self.request(cast_to, opts)
1338
1391
 
1339
1392
  def put(
@@ -1342,11 +1395,23 @@ class SyncAPIClient(BaseClient[httpx.Client, Stream[Any]]):
1342
1395
  *,
1343
1396
  cast_to: Type[ResponseT],
1344
1397
  body: Body | None = None,
1398
+ content: BinaryTypes | None = None,
1345
1399
  files: RequestFiles | None = None,
1346
1400
  options: RequestOptions = {},
1347
1401
  ) -> ResponseT:
1402
+ if body is not None and content is not None:
1403
+ raise TypeError("Passing both `body` and `content` is not supported")
1404
+ if files is not None and content is not None:
1405
+ raise TypeError("Passing both `files` and `content` is not supported")
1406
+ if isinstance(body, bytes):
1407
+ warnings.warn(
1408
+ "Passing raw bytes as `body` is deprecated and will be removed in a future version. "
1409
+ "Please pass raw bytes via the `content` parameter instead.",
1410
+ DeprecationWarning,
1411
+ stacklevel=2,
1412
+ )
1348
1413
  opts = FinalRequestOptions.construct(
1349
- method="put", url=path, json_data=body, files=to_httpx_files(files), **options
1414
+ method="put", url=path, json_data=body, content=content, files=to_httpx_files(files), **options
1350
1415
  )
1351
1416
  return self.request(cast_to, opts)
1352
1417
 
@@ -1356,9 +1421,19 @@ class SyncAPIClient(BaseClient[httpx.Client, Stream[Any]]):
1356
1421
  *,
1357
1422
  cast_to: Type[ResponseT],
1358
1423
  body: Body | None = None,
1424
+ content: BinaryTypes | None = None,
1359
1425
  options: RequestOptions = {},
1360
1426
  ) -> ResponseT:
1361
- opts = FinalRequestOptions.construct(method="delete", url=path, json_data=body, **options)
1427
+ if body is not None and content is not None:
1428
+ raise TypeError("Passing both `body` and `content` is not supported")
1429
+ if isinstance(body, bytes):
1430
+ warnings.warn(
1431
+ "Passing raw bytes as `body` is deprecated and will be removed in a future version. "
1432
+ "Please pass raw bytes via the `content` parameter instead.",
1433
+ DeprecationWarning,
1434
+ stacklevel=2,
1435
+ )
1436
+ opts = FinalRequestOptions.construct(method="delete", url=path, json_data=body, content=content, **options)
1362
1437
  return self.request(cast_to, opts)
1363
1438
 
1364
1439
  def get_api_list(
@@ -1854,6 +1929,7 @@ class AsyncAPIClient(BaseClient[httpx.AsyncClient, AsyncStream[Any]]):
1854
1929
  *,
1855
1930
  cast_to: Type[ResponseT],
1856
1931
  body: Body | None = None,
1932
+ content: AsyncBinaryTypes | None = None,
1857
1933
  files: RequestFiles | None = None,
1858
1934
  options: RequestOptions = {},
1859
1935
  stream: Literal[False] = False,
@@ -1866,6 +1942,7 @@ class AsyncAPIClient(BaseClient[httpx.AsyncClient, AsyncStream[Any]]):
1866
1942
  *,
1867
1943
  cast_to: Type[ResponseT],
1868
1944
  body: Body | None = None,
1945
+ content: AsyncBinaryTypes | None = None,
1869
1946
  files: RequestFiles | None = None,
1870
1947
  options: RequestOptions = {},
1871
1948
  stream: Literal[True],
@@ -1879,6 +1956,7 @@ class AsyncAPIClient(BaseClient[httpx.AsyncClient, AsyncStream[Any]]):
1879
1956
  *,
1880
1957
  cast_to: Type[ResponseT],
1881
1958
  body: Body | None = None,
1959
+ content: AsyncBinaryTypes | None = None,
1882
1960
  files: RequestFiles | None = None,
1883
1961
  options: RequestOptions = {},
1884
1962
  stream: bool,
@@ -1891,13 +1969,25 @@ class AsyncAPIClient(BaseClient[httpx.AsyncClient, AsyncStream[Any]]):
1891
1969
  *,
1892
1970
  cast_to: Type[ResponseT],
1893
1971
  body: Body | None = None,
1972
+ content: AsyncBinaryTypes | None = None,
1894
1973
  files: RequestFiles | None = None,
1895
1974
  options: RequestOptions = {},
1896
1975
  stream: bool = False,
1897
1976
  stream_cls: type[_AsyncStreamT] | None = None,
1898
1977
  ) -> ResponseT | _AsyncStreamT:
1978
+ if body is not None and content is not None:
1979
+ raise TypeError("Passing both `body` and `content` is not supported")
1980
+ if files is not None and content is not None:
1981
+ raise TypeError("Passing both `files` and `content` is not supported")
1982
+ if isinstance(body, bytes):
1983
+ warnings.warn(
1984
+ "Passing raw bytes as `body` is deprecated and will be removed in a future version. "
1985
+ "Please pass raw bytes via the `content` parameter instead.",
1986
+ DeprecationWarning,
1987
+ stacklevel=2,
1988
+ )
1899
1989
  opts = FinalRequestOptions.construct(
1900
- method="post", url=path, json_data=body, files=await async_to_httpx_files(files), **options
1990
+ method="post", url=path, json_data=body, content=content, files=await async_to_httpx_files(files), **options
1901
1991
  )
1902
1992
  return await self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)
1903
1993
 
@@ -1907,9 +1997,29 @@ class AsyncAPIClient(BaseClient[httpx.AsyncClient, AsyncStream[Any]]):
1907
1997
  *,
1908
1998
  cast_to: Type[ResponseT],
1909
1999
  body: Body | None = None,
2000
+ content: AsyncBinaryTypes | None = None,
2001
+ files: RequestFiles | None = None,
1910
2002
  options: RequestOptions = {},
1911
2003
  ) -> ResponseT:
1912
- opts = FinalRequestOptions.construct(method="patch", url=path, json_data=body, **options)
2004
+ if body is not None and content is not None:
2005
+ raise TypeError("Passing both `body` and `content` is not supported")
2006
+ if files is not None and content is not None:
2007
+ raise TypeError("Passing both `files` and `content` is not supported")
2008
+ if isinstance(body, bytes):
2009
+ warnings.warn(
2010
+ "Passing raw bytes as `body` is deprecated and will be removed in a future version. "
2011
+ "Please pass raw bytes via the `content` parameter instead.",
2012
+ DeprecationWarning,
2013
+ stacklevel=2,
2014
+ )
2015
+ opts = FinalRequestOptions.construct(
2016
+ method="patch",
2017
+ url=path,
2018
+ json_data=body,
2019
+ content=content,
2020
+ files=await async_to_httpx_files(files),
2021
+ **options,
2022
+ )
1913
2023
  return await self.request(cast_to, opts)
1914
2024
 
1915
2025
  async def put(
@@ -1918,11 +2028,23 @@ class AsyncAPIClient(BaseClient[httpx.AsyncClient, AsyncStream[Any]]):
1918
2028
  *,
1919
2029
  cast_to: Type[ResponseT],
1920
2030
  body: Body | None = None,
2031
+ content: AsyncBinaryTypes | None = None,
1921
2032
  files: RequestFiles | None = None,
1922
2033
  options: RequestOptions = {},
1923
2034
  ) -> ResponseT:
2035
+ if body is not None and content is not None:
2036
+ raise TypeError("Passing both `body` and `content` is not supported")
2037
+ if files is not None and content is not None:
2038
+ raise TypeError("Passing both `files` and `content` is not supported")
2039
+ if isinstance(body, bytes):
2040
+ warnings.warn(
2041
+ "Passing raw bytes as `body` is deprecated and will be removed in a future version. "
2042
+ "Please pass raw bytes via the `content` parameter instead.",
2043
+ DeprecationWarning,
2044
+ stacklevel=2,
2045
+ )
1924
2046
  opts = FinalRequestOptions.construct(
1925
- method="put", url=path, json_data=body, files=await async_to_httpx_files(files), **options
2047
+ method="put", url=path, json_data=body, content=content, files=await async_to_httpx_files(files), **options
1926
2048
  )
1927
2049
  return await self.request(cast_to, opts)
1928
2050
 
@@ -1932,9 +2054,19 @@ class AsyncAPIClient(BaseClient[httpx.AsyncClient, AsyncStream[Any]]):
1932
2054
  *,
1933
2055
  cast_to: Type[ResponseT],
1934
2056
  body: Body | None = None,
2057
+ content: AsyncBinaryTypes | None = None,
1935
2058
  options: RequestOptions = {},
1936
2059
  ) -> ResponseT:
1937
- opts = FinalRequestOptions.construct(method="delete", url=path, json_data=body, **options)
2060
+ if body is not None and content is not None:
2061
+ raise TypeError("Passing both `body` and `content` is not supported")
2062
+ if isinstance(body, bytes):
2063
+ warnings.warn(
2064
+ "Passing raw bytes as `body` is deprecated and will be removed in a future version. "
2065
+ "Please pass raw bytes via the `content` parameter instead.",
2066
+ DeprecationWarning,
2067
+ stacklevel=2,
2068
+ )
2069
+ opts = FinalRequestOptions.construct(method="delete", url=path, json_data=body, content=content, **options)
1938
2070
  return await self.request(cast_to, opts)
1939
2071
 
1940
2072
  def get_api_list(
anthropic/_client.py CHANGED
@@ -187,14 +187,10 @@ class Anthropic(SyncAPIClient):
187
187
  # valid
188
188
  return
189
189
 
190
- if self.api_key and headers.get("X-Api-Key"):
191
- return
192
- if isinstance(custom_headers.get("X-Api-Key"), Omit):
190
+ if headers.get("X-Api-Key") or isinstance(custom_headers.get("X-Api-Key"), Omit):
193
191
  return
194
192
 
195
- if self.auth_token and headers.get("Authorization"):
196
- return
197
- if isinstance(custom_headers.get("Authorization"), Omit):
193
+ if headers.get("Authorization") or isinstance(custom_headers.get("Authorization"), Omit):
198
194
  return
199
195
 
200
196
  raise TypeError(
@@ -431,14 +427,10 @@ class AsyncAnthropic(AsyncAPIClient):
431
427
  # valid
432
428
  return
433
429
 
434
- if self.api_key and headers.get("X-Api-Key"):
435
- return
436
- if isinstance(custom_headers.get("X-Api-Key"), Omit):
430
+ if headers.get("X-Api-Key") or isinstance(custom_headers.get("X-Api-Key"), Omit):
437
431
  return
438
432
 
439
- if self.auth_token and headers.get("Authorization"):
440
- return
441
- if isinstance(custom_headers.get("Authorization"), Omit):
433
+ if headers.get("Authorization") or isinstance(custom_headers.get("Authorization"), Omit):
442
434
  return
443
435
 
444
436
  raise TypeError(
anthropic/_compat.py CHANGED
@@ -145,6 +145,7 @@ def model_dump(
145
145
  exclude_defaults: bool = False,
146
146
  warnings: bool = True,
147
147
  mode: Literal["json", "python"] = "python",
148
+ by_alias: bool | None = None,
148
149
  ) -> dict[str, Any]:
149
150
  if (not PYDANTIC_V1) or hasattr(model, "model_dump"):
150
151
  return model.model_dump(
@@ -154,13 +155,12 @@ def model_dump(
154
155
  exclude_defaults=exclude_defaults,
155
156
  # warnings are not supported in Pydantic v1
156
157
  warnings=True if PYDANTIC_V1 else warnings,
158
+ by_alias=by_alias,
157
159
  )
158
160
  return cast(
159
161
  "dict[str, Any]",
160
162
  model.dict( # pyright: ignore[reportDeprecated, reportUnnecessaryCast]
161
- exclude=exclude,
162
- exclude_unset=exclude_unset,
163
- exclude_defaults=exclude_defaults,
163
+ exclude=exclude, exclude_unset=exclude_unset, exclude_defaults=exclude_defaults, by_alias=bool(by_alias)
164
164
  ),
165
165
  )
166
166
 
anthropic/_models.py CHANGED
@@ -3,7 +3,20 @@ from __future__ import annotations
3
3
  import os
4
4
  import inspect
5
5
  import weakref
6
- from typing import TYPE_CHECKING, Any, Type, Union, Generic, TypeVar, Callable, Optional, cast
6
+ from typing import (
7
+ IO,
8
+ TYPE_CHECKING,
9
+ Any,
10
+ Type,
11
+ Union,
12
+ Generic,
13
+ TypeVar,
14
+ Callable,
15
+ Iterable,
16
+ Optional,
17
+ AsyncIterable,
18
+ cast,
19
+ )
7
20
  from datetime import date, datetime
8
21
  from typing_extensions import (
9
22
  List,
@@ -833,6 +846,7 @@ class FinalRequestOptionsInput(TypedDict, total=False):
833
846
  timeout: float | Timeout | None
834
847
  files: HttpxRequestFiles | None
835
848
  idempotency_key: str
849
+ content: Union[bytes, bytearray, IO[bytes], Iterable[bytes], AsyncIterable[bytes], None]
836
850
  json_data: Body
837
851
  extra_json: AnyMapping
838
852
  follow_redirects: bool
@@ -851,6 +865,7 @@ class FinalRequestOptions(pydantic.BaseModel):
851
865
  post_parser: Union[Callable[[Any], Any], NotGiven] = NotGiven()
852
866
  follow_redirects: Union[bool, None] = None
853
867
 
868
+ content: Union[bytes, bytearray, IO[bytes], Iterable[bytes], AsyncIterable[bytes], None] = None
854
869
  # It should be noted that we cannot use `json` here as that would override
855
870
  # a BaseModel method in an incompatible fashion.
856
871
  json_data: Union[Body, None] = None
anthropic/_streaming.py CHANGED
@@ -77,44 +77,45 @@ class Stream(Generic[_T], metaclass=_SyncStreamMeta):
77
77
  process_data = self._client._process_response_data
78
78
  iterator = self._iter_events()
79
79
 
80
- for sse in iterator:
81
- if sse.event == "completion":
82
- yield process_data(data=sse.json(), cast_to=cast_to, response=response)
83
-
84
- if (
85
- sse.event == "message_start"
86
- or sse.event == "message_delta"
87
- or sse.event == "message_stop"
88
- or sse.event == "content_block_start"
89
- or sse.event == "content_block_delta"
90
- or sse.event == "content_block_stop"
91
- ):
92
- data = sse.json()
93
- if is_dict(data) and "type" not in data:
94
- data["type"] = sse.event
95
-
96
- yield process_data(data=data, cast_to=cast_to, response=response)
97
-
98
- if sse.event == "ping":
99
- continue
100
-
101
- if sse.event == "error":
102
- body = sse.data
103
-
104
- try:
105
- body = sse.json()
106
- err_msg = f"{body}"
107
- except Exception:
108
- err_msg = sse.data or f"Error code: {response.status_code}"
109
-
110
- raise self._client._make_status_error(
111
- err_msg,
112
- body=body,
113
- response=self.response,
114
- )
115
-
116
- # As we might not fully consume the response stream, we need to close it explicitly
117
- response.close()
80
+ try:
81
+ for sse in iterator:
82
+ if sse.event == "completion":
83
+ yield process_data(data=sse.json(), cast_to=cast_to, response=response)
84
+
85
+ if (
86
+ sse.event == "message_start"
87
+ or sse.event == "message_delta"
88
+ or sse.event == "message_stop"
89
+ or sse.event == "content_block_start"
90
+ or sse.event == "content_block_delta"
91
+ or sse.event == "content_block_stop"
92
+ ):
93
+ data = sse.json()
94
+ if is_dict(data) and "type" not in data:
95
+ data["type"] = sse.event
96
+
97
+ yield process_data(data=data, cast_to=cast_to, response=response)
98
+
99
+ if sse.event == "ping":
100
+ continue
101
+
102
+ if sse.event == "error":
103
+ body = sse.data
104
+
105
+ try:
106
+ body = sse.json()
107
+ err_msg = f"{body}"
108
+ except Exception:
109
+ err_msg = sse.data or f"Error code: {response.status_code}"
110
+
111
+ raise self._client._make_status_error(
112
+ err_msg,
113
+ body=body,
114
+ response=self.response,
115
+ )
116
+ finally:
117
+ # Ensure the response is closed even if the consumer doesn't read all data
118
+ response.close()
118
119
 
119
120
  def __enter__(self) -> Self:
120
121
  return self
@@ -194,44 +195,45 @@ class AsyncStream(Generic[_T], metaclass=_AsyncStreamMeta):
194
195
  process_data = self._client._process_response_data
195
196
  iterator = self._iter_events()
196
197
 
197
- async for sse in iterator:
198
- if sse.event == "completion":
199
- yield process_data(data=sse.json(), cast_to=cast_to, response=response)
200
-
201
- if (
202
- sse.event == "message_start"
203
- or sse.event == "message_delta"
204
- or sse.event == "message_stop"
205
- or sse.event == "content_block_start"
206
- or sse.event == "content_block_delta"
207
- or sse.event == "content_block_stop"
208
- ):
209
- data = sse.json()
210
- if is_dict(data) and "type" not in data:
211
- data["type"] = sse.event
212
-
213
- yield process_data(data=data, cast_to=cast_to, response=response)
214
-
215
- if sse.event == "ping":
216
- continue
217
-
218
- if sse.event == "error":
219
- body = sse.data
220
-
221
- try:
222
- body = sse.json()
223
- err_msg = f"{body}"
224
- except Exception:
225
- err_msg = sse.data or f"Error code: {response.status_code}"
226
-
227
- raise self._client._make_status_error(
228
- err_msg,
229
- body=body,
230
- response=self.response,
231
- )
232
-
233
- # As we might not fully consume the response stream, we need to close it explicitly
234
- await response.aclose()
198
+ try:
199
+ async for sse in iterator:
200
+ if sse.event == "completion":
201
+ yield process_data(data=sse.json(), cast_to=cast_to, response=response)
202
+
203
+ if (
204
+ sse.event == "message_start"
205
+ or sse.event == "message_delta"
206
+ or sse.event == "message_stop"
207
+ or sse.event == "content_block_start"
208
+ or sse.event == "content_block_delta"
209
+ or sse.event == "content_block_stop"
210
+ ):
211
+ data = sse.json()
212
+ if is_dict(data) and "type" not in data:
213
+ data["type"] = sse.event
214
+
215
+ yield process_data(data=data, cast_to=cast_to, response=response)
216
+
217
+ if sse.event == "ping":
218
+ continue
219
+
220
+ if sse.event == "error":
221
+ body = sse.data
222
+
223
+ try:
224
+ body = sse.json()
225
+ err_msg = f"{body}"
226
+ except Exception:
227
+ err_msg = sse.data or f"Error code: {response.status_code}"
228
+
229
+ raise self._client._make_status_error(
230
+ err_msg,
231
+ body=body,
232
+ response=self.response,
233
+ )
234
+ finally:
235
+ # Ensure the response is closed even if the consumer doesn't read all data
236
+ await response.aclose()
235
237
 
236
238
  async def __aenter__(self) -> Self:
237
239
  return self
anthropic/_types.py CHANGED
@@ -13,9 +13,11 @@ from typing import (
13
13
  Mapping,
14
14
  TypeVar,
15
15
  Callable,
16
+ Iterable,
16
17
  Iterator,
17
18
  Optional,
18
19
  Sequence,
20
+ AsyncIterable,
19
21
  )
20
22
  from typing_extensions import (
21
23
  Set,
@@ -57,6 +59,13 @@ if TYPE_CHECKING:
57
59
  else:
58
60
  Base64FileInput = Union[IO[bytes], PathLike]
59
61
  FileContent = Union[IO[bytes], bytes, PathLike] # PathLike is not subscriptable in Python 3.8.
62
+
63
+
64
+ # Used for sending raw binary data / streaming data in request bodies
65
+ # e.g. for file uploads without multipart encoding
66
+ BinaryTypes = Union[bytes, bytearray, IO[bytes], Iterable[bytes]]
67
+ AsyncBinaryTypes = Union[bytes, bytearray, IO[bytes], AsyncIterable[bytes]]
68
+
60
69
  FileTypes = Union[
61
70
  # file (or bytes)
62
71
  FileContent,
@@ -245,6 +254,9 @@ _T_co = TypeVar("_T_co", covariant=True)
245
254
  if TYPE_CHECKING:
246
255
  # This works because str.__contains__ does not accept object (either in typeshed or at runtime)
247
256
  # https://github.com/hauntsaninja/useful_types/blob/5e9710f3875107d068e7679fd7fec9cfab0eff3b/useful_types/__init__.py#L285
257
+ #
258
+ # Note: index() and count() methods are intentionally omitted to allow pyright to properly
259
+ # infer TypedDict types when dict literals are used in lists assigned to SequenceNotStr.
248
260
  class SequenceNotStr(Protocol[_T_co]):
249
261
  @overload
250
262
  def __getitem__(self, index: SupportsIndex, /) -> _T_co: ...
@@ -253,8 +265,6 @@ if TYPE_CHECKING:
253
265
  def __contains__(self, value: object, /) -> bool: ...
254
266
  def __len__(self) -> int: ...
255
267
  def __iter__(self) -> Iterator[_T_co]: ...
256
- def index(self, value: Any, start: int = 0, stop: int = ..., /) -> int: ...
257
- def count(self, value: Any, /) -> int: ...
258
268
  def __reversed__(self) -> Iterator[_T_co]: ...
259
269
  else:
260
270
  # just point this to a normal `Sequence` at runtime to avoid having to special case
@@ -0,0 +1,35 @@
1
+ import json
2
+ from typing import Any
3
+ from datetime import datetime
4
+ from typing_extensions import override
5
+
6
+ import pydantic
7
+
8
+ from .._compat import model_dump
9
+
10
+
11
+ def openapi_dumps(obj: Any) -> bytes:
12
+ """
13
+ Serialize an object to UTF-8 encoded JSON bytes.
14
+
15
+ Extends the standard json.dumps with support for additional types
16
+ commonly used in the SDK, such as `datetime`, `pydantic.BaseModel`, etc.
17
+ """
18
+ return json.dumps(
19
+ obj,
20
+ cls=_CustomEncoder,
21
+ # Uses the same defaults as httpx's JSON serialization
22
+ ensure_ascii=False,
23
+ separators=(",", ":"),
24
+ allow_nan=False,
25
+ ).encode()
26
+
27
+
28
+ class _CustomEncoder(json.JSONEncoder):
29
+ @override
30
+ def default(self, o: Any) -> Any:
31
+ if isinstance(o, datetime):
32
+ return o.isoformat()
33
+ if isinstance(o, pydantic.BaseModel):
34
+ return model_dump(o, exclude_unset=True, mode="json", by_alias=True)
35
+ return super().default(o)
anthropic/_version.py CHANGED
@@ -1,4 +1,4 @@
1
1
  # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
2
2
 
3
3
  __title__ = "anthropic"
4
- __version__ = "0.75.0" # x-release-please-version
4
+ __version__ = "0.77.0" # x-release-please-version