corehttp 1.0.0b4__tar.gz → 1.0.0b6__tar.gz

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 (125) hide show
  1. corehttp-1.0.0b6/CHANGELOG.md +63 -0
  2. {corehttp-1.0.0b4/corehttp.egg-info → corehttp-1.0.0b6}/PKG-INFO +25 -1
  3. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/corehttp/_version.py +1 -1
  4. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/corehttp/credentials.py +54 -22
  5. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/corehttp/exceptions.py +7 -6
  6. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/corehttp/rest/_aiohttp.py +4 -4
  7. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/corehttp/rest/_http_response_impl.py +2 -8
  8. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/corehttp/rest/_httpx.py +1 -1
  9. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/corehttp/rest/_requests_basic.py +4 -5
  10. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/corehttp/rest/_rest_py3.py +4 -8
  11. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/corehttp/runtime/pipeline/__init__.py +3 -7
  12. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/corehttp/runtime/pipeline/_base.py +1 -1
  13. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/corehttp/runtime/pipeline/_base_async.py +4 -8
  14. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/corehttp/runtime/pipeline/_tools_async.py +2 -4
  15. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/corehttp/runtime/policies/_authentication.py +53 -24
  16. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/corehttp/runtime/policies/_authentication_async.py +45 -19
  17. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/corehttp/runtime/policies/_retry.py +1 -1
  18. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/corehttp/runtime/policies/_retry_async.py +1 -1
  19. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/corehttp/runtime/policies/_universal.py +4 -11
  20. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/corehttp/runtime/policies/_utils.py +1 -1
  21. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/corehttp/serialization.py +1 -1
  22. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/corehttp/transport/aiohttp/_aiohttp.py +2 -2
  23. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/corehttp/transport/requests/_bigger_block_size_http_adapters.py +1 -1
  24. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/corehttp/transport/requests/_requests_basic.py +2 -2
  25. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/corehttp/utils/_enum_meta.py +1 -1
  26. {corehttp-1.0.0b4 → corehttp-1.0.0b6/corehttp.egg-info}/PKG-INFO +25 -1
  27. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/corehttp.egg-info/SOURCES.txt +8 -0
  28. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/pyproject.toml +1 -1
  29. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/samples/sample_async_pipeline_client.py +0 -10
  30. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/tests/async_tests/test_authentication_async.py +71 -25
  31. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/tests/async_tests/test_rest_http_response_async.py +27 -27
  32. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/tests/async_tests/test_rest_stream_responses_async.py +1 -34
  33. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/tests/async_tests/test_retry_policy_async.py +1 -1
  34. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/tests/async_tests/test_streaming_async.py +34 -148
  35. corehttp-1.0.0b6/tests/perf_tests/__init__.py +0 -0
  36. corehttp-1.0.0b6/tests/perf_tests/_test_base.py +258 -0
  37. corehttp-1.0.0b6/tests/perf_tests/custom_iterator.py +80 -0
  38. corehttp-1.0.0b6/tests/perf_tests/download_binary.py +94 -0
  39. corehttp-1.0.0b6/tests/perf_tests/list_entities_json.py +135 -0
  40. corehttp-1.0.0b6/tests/perf_tests/query_entities_json.py +85 -0
  41. corehttp-1.0.0b6/tests/perf_tests/update_entity_json.py +92 -0
  42. corehttp-1.0.0b6/tests/perf_tests/upload_binary.py +91 -0
  43. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/tests/test_authentication.py +77 -32
  44. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/tests/test_exceptions.py +14 -0
  45. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/tests/test_rest_stream_responses.py +0 -53
  46. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/tests/test_retry_policy.py +3 -1
  47. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/tests/test_streaming.py +32 -131
  48. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/tests/test_utils.py +12 -0
  49. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/tests/testserver_tests/coretestserver/coretestserver/test_routes/helpers.py +2 -2
  50. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/tests/testserver_tests/coretestserver/coretestserver/test_routes/multipart.py +1 -7
  51. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/tests/testserver_tests/coretestserver/coretestserver/test_routes/streams.py +14 -0
  52. corehttp-1.0.0b4/CHANGELOG.md +0 -39
  53. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/LICENSE +0 -0
  54. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/MANIFEST.in +0 -0
  55. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/README.md +0 -0
  56. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/corehttp/__init__.py +0 -0
  57. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/corehttp/_match_conditions.py +0 -0
  58. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/corehttp/paging.py +0 -0
  59. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/corehttp/py.typed +0 -0
  60. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/corehttp/rest/__init__.py +0 -0
  61. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/corehttp/rest/_helpers.py +0 -0
  62. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/corehttp/rest/_http_response_impl_async.py +0 -0
  63. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/corehttp/runtime/__init__.py +0 -0
  64. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/corehttp/runtime/_base.py +0 -0
  65. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/corehttp/runtime/_pipeline_client.py +0 -0
  66. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/corehttp/runtime/_pipeline_client_async.py +0 -0
  67. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/corehttp/runtime/pipeline/_tools.py +0 -0
  68. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/corehttp/runtime/policies/__init__.py +0 -0
  69. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/corehttp/runtime/policies/_base.py +0 -0
  70. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/corehttp/runtime/policies/_base_async.py +0 -0
  71. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/corehttp/transport/__init__.py +0 -0
  72. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/corehttp/transport/_base.py +0 -0
  73. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/corehttp/transport/_base_async.py +0 -0
  74. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/corehttp/transport/aiohttp/__init__.py +0 -0
  75. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/corehttp/transport/httpx/__init__.py +0 -0
  76. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/corehttp/transport/httpx/_httpx.py +0 -0
  77. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/corehttp/transport/requests/__init__.py +0 -0
  78. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/corehttp/utils/__init__.py +0 -0
  79. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/corehttp/utils/_utils.py +0 -0
  80. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/corehttp.egg-info/dependency_links.txt +0 -0
  81. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/corehttp.egg-info/not-zip-safe +0 -0
  82. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/corehttp.egg-info/requires.txt +0 -0
  83. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/corehttp.egg-info/top_level.txt +0 -0
  84. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/samples/sample_pipeline_client.py +0 -0
  85. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/setup.cfg +0 -0
  86. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/setup.py +0 -0
  87. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/tests/async_tests/conftest.py +0 -0
  88. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/tests/async_tests/rest_client_async.py +0 -0
  89. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/tests/async_tests/test_content_length_checking_async.py +0 -0
  90. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/tests/async_tests/test_paging_async.py +0 -0
  91. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/tests/async_tests/test_pipeline_async.py +0 -0
  92. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/tests/async_tests/test_rest_context_manager_async.py +0 -0
  93. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/tests/async_tests/test_rest_headers_async.py +0 -0
  94. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/tests/async_tests/test_rest_http_request_async.py +0 -0
  95. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/tests/async_tests/test_testserver_async.py +0 -0
  96. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/tests/async_tests/test_universal_http_async.py +0 -0
  97. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/tests/conftest.py +0 -0
  98. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/tests/rest_client.py +0 -0
  99. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/tests/test_content_length_checking.py +0 -0
  100. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/tests/test_enums.py +0 -0
  101. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/tests/test_error_map.py +0 -0
  102. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/tests/test_paging.py +0 -0
  103. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/tests/test_pipeline.py +0 -0
  104. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/tests/test_requests_universal.py +0 -0
  105. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/tests/test_rest_context_manager.py +0 -0
  106. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/tests/test_rest_headers.py +0 -0
  107. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/tests/test_rest_http_request.py +0 -0
  108. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/tests/test_rest_http_response.py +0 -0
  109. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/tests/test_rest_query.py +0 -0
  110. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/tests/test_serialization.py +0 -0
  111. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/tests/test_stream_generator.py +0 -0
  112. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/tests/test_testserver.py +0 -0
  113. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/tests/test_universal_pipeline.py +0 -0
  114. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/tests/test_user_agent_policy.py +0 -0
  115. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/tests/testserver_tests/coretestserver/coretestserver/__init__.py +0 -0
  116. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/tests/testserver_tests/coretestserver/coretestserver/test_routes/__init__.py +0 -0
  117. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/tests/testserver_tests/coretestserver/coretestserver/test_routes/basic.py +0 -0
  118. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/tests/testserver_tests/coretestserver/coretestserver/test_routes/encoding.py +0 -0
  119. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/tests/testserver_tests/coretestserver/coretestserver/test_routes/errors.py +0 -0
  120. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/tests/testserver_tests/coretestserver/coretestserver/test_routes/headers.py +0 -0
  121. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/tests/testserver_tests/coretestserver/coretestserver/test_routes/structures.py +0 -0
  122. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/tests/testserver_tests/coretestserver/coretestserver/test_routes/urlencoded.py +0 -0
  123. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/tests/testserver_tests/coretestserver/coretestserver/test_routes/xml_route.py +0 -0
  124. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/tests/testserver_tests/coretestserver/setup.py +0 -0
  125. {corehttp-1.0.0b4 → corehttp-1.0.0b6}/tests/utils.py +0 -0
@@ -0,0 +1,63 @@
1
+ # Release History
2
+
3
+ ## 1.0.0b6 (2025-03-27)
4
+
5
+ ### Features Added
6
+
7
+ - The `TokenCredential` and `AsyncTokenCredential` protocols have been updated to include a new `get_token_info` method. This method should be used to acquire tokens and return an `AccessTokenInfo` object. [#38346](https://github.com/Azure/azure-sdk-for-python/pull/38346)
8
+ - Added a new `TokenRequestOptions` class, which is a `TypedDict` with optional parameters, that can be used to define options for token requests through the `get_token_info` method. [#38346](https://github.com/Azure/azure-sdk-for-python/pull/38346)
9
+ - Added a new `AccessTokenInfo` class, which is returned by `get_token_info` implementations. This class contains the token, its expiration time, and optional additional information like when a token should be refreshed. [#38346](https://github.com/Azure/azure-sdk-for-python/pull/38346)
10
+ - `BearerTokenCredentialPolicy` and `AsyncBearerTokenCredentialPolicy` now check if a credential has the `get_token_info` method defined. If so, the `get_token_info` method is used to acquire a token. [#38346](https://github.com/Azure/azure-sdk-for-python/pull/38346)
11
+ - These policies now also check the `refresh_on` attribute when determining if a new token request should be made.
12
+ - Added `model` attribute to `HttpResponseError` to allow accessing error attributes based on a known model. [#39636](https://github.com/Azure/azure-sdk-for-python/pull/39636)
13
+ - Added `auth_flows` support in `BearerTokenCredentialPolicy`. [#40084](https://github.com/Azure/azure-sdk-for-python/pull/40084)
14
+
15
+ ### Breaking Changes
16
+
17
+ - The `get_token` method has been removed from the `TokenCredential` and `AsyncTokenCredential` protocols. Implementations should now use the new `get_token_info` method to acquire tokens. [#38346](https://github.com/Azure/azure-sdk-for-python/pull/38346)
18
+ - The `AccessToken` class has been removed and replaced with a new `AccessTokenInfo` class. [#38346](https://github.com/Azure/azure-sdk-for-python/pull/38346)
19
+ - `BearerTokenCredentialPolicy` and `AsyncBearerTokenCredentialPolicy` now rely on credentials having the `get_token_info` method defined. [#38346](https://github.com/Azure/azure-sdk-for-python/pull/38346)
20
+
21
+ ## 1.0.0b5 (2024-02-29)
22
+
23
+ ### Other Changes
24
+
25
+ - Accept float for `retry_after` header.
26
+
27
+ ## 1.0.0b4 (2024-02-23)
28
+
29
+ ### Other Changes
30
+
31
+ - Relax type checking in `Pipeline` constructors to only check that each user-supplied policy object has either a `send` method or both an `on_request` and `on_response` method. This allows for more flexible policy implementations. [#34296](https://github.com/Azure/azure-sdk-for-python/pull/34296)
32
+
33
+ ## 1.0.0b3 (2024-02-01)
34
+
35
+ ### Features Added
36
+
37
+ - Support tuple input for `files` values to `corehttp.rest.HttpRequest` #34082
38
+ - Support simultaneous `files` and `data` field entry into `corehttp.rest.HttpRequest` #34082
39
+
40
+ ## 1.0.0b2 (2023-11-14)
41
+
42
+ ### Features Added
43
+
44
+ - Added the initial implementation of the HTTPX transport. [#32813](https://github.com/Azure/azure-sdk-for-python/pull/32813)
45
+
46
+ ### Breaking Changes
47
+
48
+ - Removed `requests` as a default dependency of `corehttp`. This is now an "extras" dependency and can be installed via `corehttp[requests]`. [#32813](https://github.com/Azure/azure-sdk-for-python/pull/32813)
49
+ - Renamed the `aio` extra to `aiohttp`. [#32813](https://github.com/Azure/azure-sdk-for-python/pull/32813)
50
+
51
+ ### Bugs Fixed
52
+
53
+ - Fixed an issue with `multipart/form-data` in the async transport where `data` was not getting encoded into the request body. [#32473](https://github.com/Azure/azure-sdk-for-python/pull/32473)
54
+ - Fixed an issue with `connection_verify`, `connection_cert`, and `connection_timeout` not being propagated to underlying transports. [#33057](https://github.com/Azure/azure-sdk-for-python/pull/33057)
55
+ - Fixed an issue with the `aiohttp` transport not using SSL by default. [#33057](https://github.com/Azure/azure-sdk-for-python/pull/33057)
56
+
57
+ ### Other Changes
58
+
59
+ - Added extras for `httpx`. [#32813](https://github.com/Azure/azure-sdk-for-python/pull/32813)
60
+
61
+ ## 1.0.0b1 (2023-10-18)
62
+
63
+ * Initial Release
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: corehttp
3
- Version: 1.0.0b4
3
+ Version: 1.0.0b6
4
4
  Summary: CoreHTTP Library for Python
5
5
  Home-page: https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/core/corehttp
6
6
  Author: Microsoft Corporation
@@ -87,6 +87,30 @@ additional questions or comments.
87
87
 
88
88
  # Release History
89
89
 
90
+ ## 1.0.0b6 (2025-03-27)
91
+
92
+ ### Features Added
93
+
94
+ - The `TokenCredential` and `AsyncTokenCredential` protocols have been updated to include a new `get_token_info` method. This method should be used to acquire tokens and return an `AccessTokenInfo` object. [#38346](https://github.com/Azure/azure-sdk-for-python/pull/38346)
95
+ - Added a new `TokenRequestOptions` class, which is a `TypedDict` with optional parameters, that can be used to define options for token requests through the `get_token_info` method. [#38346](https://github.com/Azure/azure-sdk-for-python/pull/38346)
96
+ - Added a new `AccessTokenInfo` class, which is returned by `get_token_info` implementations. This class contains the token, its expiration time, and optional additional information like when a token should be refreshed. [#38346](https://github.com/Azure/azure-sdk-for-python/pull/38346)
97
+ - `BearerTokenCredentialPolicy` and `AsyncBearerTokenCredentialPolicy` now check if a credential has the `get_token_info` method defined. If so, the `get_token_info` method is used to acquire a token. [#38346](https://github.com/Azure/azure-sdk-for-python/pull/38346)
98
+ - These policies now also check the `refresh_on` attribute when determining if a new token request should be made.
99
+ - Added `model` attribute to `HttpResponseError` to allow accessing error attributes based on a known model. [#39636](https://github.com/Azure/azure-sdk-for-python/pull/39636)
100
+ - Added `auth_flows` support in `BearerTokenCredentialPolicy`. [#40084](https://github.com/Azure/azure-sdk-for-python/pull/40084)
101
+
102
+ ### Breaking Changes
103
+
104
+ - The `get_token` method has been removed from the `TokenCredential` and `AsyncTokenCredential` protocols. Implementations should now use the new `get_token_info` method to acquire tokens. [#38346](https://github.com/Azure/azure-sdk-for-python/pull/38346)
105
+ - The `AccessToken` class has been removed and replaced with a new `AccessTokenInfo` class. [#38346](https://github.com/Azure/azure-sdk-for-python/pull/38346)
106
+ - `BearerTokenCredentialPolicy` and `AsyncBearerTokenCredentialPolicy` now rely on credentials having the `get_token_info` method defined. [#38346](https://github.com/Azure/azure-sdk-for-python/pull/38346)
107
+
108
+ ## 1.0.0b5 (2024-02-29)
109
+
110
+ ### Other Changes
111
+
112
+ - Accept float for `retry_after` header.
113
+
90
114
  ## 1.0.0b4 (2024-02-23)
91
115
 
92
116
  ### Other Changes
@@ -9,4 +9,4 @@
9
9
  # regenerated.
10
10
  # --------------------------------------------------------------------------
11
11
 
12
- VERSION = "1.0.0b4"
12
+ VERSION = "1.0.0b6"
@@ -5,39 +5,71 @@
5
5
  # -------------------------------------------------------------------------
6
6
  from __future__ import annotations
7
7
  from types import TracebackType
8
- from typing import Any, NamedTuple, Optional, AsyncContextManager, Type
8
+ from typing import NamedTuple, Optional, AsyncContextManager, Type, TypedDict, ContextManager
9
9
  from typing_extensions import Protocol, runtime_checkable
10
10
 
11
11
 
12
- class AccessToken(NamedTuple):
13
- """Represents an OAuth access token."""
12
+ class AccessTokenInfo:
13
+ """Information about an OAuth access token.
14
+
15
+ :param str token: The token string.
16
+ :param int expires_on: The token's expiration time in Unix time.
17
+ :keyword str token_type: The type of access token. Defaults to 'Bearer'.
18
+ :keyword int refresh_on: Specifies the time, in Unix time, when the cached token should be proactively
19
+ refreshed. Optional.
20
+ """
14
21
 
15
22
  token: str
23
+ """The token string."""
16
24
  expires_on: int
25
+ """The token's expiration time in Unix time."""
26
+ token_type: str
27
+ """The type of access token."""
28
+ refresh_on: Optional[int]
29
+ """Specifies the time, in Unix time, when the cached token should be proactively refreshed. Optional."""
30
+
31
+ def __init__(
32
+ self, token: str, expires_on: int, *, token_type: str = "Bearer", refresh_on: Optional[int] = None
33
+ ) -> None:
34
+ self.token = token
35
+ self.expires_on = expires_on
36
+ self.token_type = token_type
37
+ self.refresh_on = refresh_on
17
38
 
39
+ def __repr__(self) -> str:
40
+ return "AccessTokenInfo(token='{}', expires_on={}, token_type='{}', refresh_on={})".format(
41
+ self.token, self.expires_on, self.token_type, self.refresh_on
42
+ )
18
43
 
19
- AccessToken.token.__doc__ = """The token string."""
20
- AccessToken.expires_on.__doc__ = """The token's expiration time in Unix time."""
21
44
 
45
+ class TokenRequestOptions(TypedDict, total=False):
46
+ """Options to use for access token requests. All parameters are optional."""
22
47
 
23
- @runtime_checkable
24
- class TokenCredential(Protocol):
25
- """Protocol for classes able to provide OAuth tokens."""
48
+ claims: str
49
+ """Additional claims required in the token, such as those returned in a resource provider's claims
50
+ challenge following an authorization failure."""
51
+ tenant_id: str
52
+ """The tenant ID to include in the token request."""
26
53
 
27
- def get_token(self, *scopes: str, claims: Optional[str] = None, **kwargs: Any) -> AccessToken:
28
- """Request an access token for `scopes`.
29
54
 
30
- :param str scopes: The type of access needed.
55
+ class TokenCredential(Protocol, ContextManager["TokenCredential"]):
56
+ """Protocol for classes able to provide OAuth access tokens."""
31
57
 
32
- :keyword str claims: Additional claims required in the token, such as those returned in a resource
33
- provider's claims challenge following an authorization failure.
58
+ def get_token_info(self, *scopes: str, options: Optional[TokenRequestOptions] = None) -> AccessTokenInfo:
59
+ """Request an access token for `scopes`.
34
60
 
61
+ :param str scopes: The type of access needed.
62
+ :keyword options: A dictionary of options for the token request. Unknown options will be ignored. Optional.
63
+ :paramtype options: TokenRequestOptions
35
64
 
36
- :rtype: AccessToken
37
- :return: An AccessToken instance containing the token string and its expiration time in Unix time.
65
+ :rtype: AccessTokenInfo
66
+ :return: An AccessTokenInfo instance containing information about the token.
38
67
  """
39
68
  ...
40
69
 
70
+ def close(self) -> None:
71
+ pass
72
+
41
73
 
42
74
  class ServiceNamedKey(NamedTuple):
43
75
  """Represents a name and key pair."""
@@ -47,10 +79,11 @@ class ServiceNamedKey(NamedTuple):
47
79
 
48
80
 
49
81
  __all__ = [
50
- "AccessToken",
82
+ "AccessTokenInfo",
51
83
  "ServiceKeyCredential",
52
84
  "ServiceNamedKeyCredential",
53
85
  "TokenCredential",
86
+ "TokenRequestOptions",
54
87
  "AsyncTokenCredential",
55
88
  ]
56
89
 
@@ -134,16 +167,15 @@ class ServiceNamedKeyCredential:
134
167
  class AsyncTokenCredential(Protocol, AsyncContextManager["AsyncTokenCredential"]):
135
168
  """Protocol for classes able to provide OAuth tokens."""
136
169
 
137
- async def get_token(self, *scopes: str, claims: Optional[str] = None, **kwargs: Any) -> AccessToken:
170
+ async def get_token_info(self, *scopes: str, options: Optional[TokenRequestOptions] = None) -> AccessTokenInfo:
138
171
  """Request an access token for `scopes`.
139
172
 
140
173
  :param str scopes: The type of access needed.
174
+ :keyword options: A dictionary of options for the token request. Unknown options will be ignored. Optional.
175
+ :paramtype options: TokenRequestOptions
141
176
 
142
- :keyword str claims: Additional claims required in the token, such as those returned in a resource
143
- provider's claims challenge following an authorization failure.
144
-
145
- :rtype: AccessToken
146
- :return: An AccessToken instance containing the token string and its expiration time in Unix time.
177
+ :rtype: AccessTokenInfo
178
+ :return: An AccessTokenInfo instance containing the token string and its expiration time in Unix time.
147
179
  """
148
180
  ...
149
181
 
@@ -72,15 +72,12 @@ class _HttpResponseCommonAPI(Protocol):
72
72
  """
73
73
 
74
74
  @property
75
- def reason(self) -> Optional[str]:
76
- ...
75
+ def reason(self) -> Optional[str]: ...
77
76
 
78
77
  @property
79
- def status_code(self) -> Optional[int]:
80
- ...
78
+ def status_code(self) -> Optional[int]: ...
81
79
 
82
- def text(self) -> str:
83
- ...
80
+ def text(self) -> str: ...
84
81
 
85
82
  @property
86
83
  def request(self) -> object: # object as type, since all we need is str() on it
@@ -190,6 +187,8 @@ class HttpResponseError(BaseError):
190
187
  :vartype status_code: int
191
188
  :ivar response: The response that triggered the exception.
192
189
  :vartype response: ~corehttp.rest.HttpResponse or ~corehttp.rest.AsyncHttpResponse
190
+ :ivar model: The response body model
191
+ :vartype model: Any
193
192
  """
194
193
 
195
194
  def __init__(
@@ -203,6 +202,8 @@ class HttpResponseError(BaseError):
203
202
  self.reason = response.reason
204
203
  self.status_code = response.status_code
205
204
 
205
+ self.model: Optional[Any] = kwargs.pop("model", None)
206
+
206
207
  # By priority, message is:
207
208
  # - parameter "message", OR
208
209
  # - generic message using "reason"
@@ -30,7 +30,7 @@ import logging
30
30
  from itertools import groupby
31
31
  from typing import Iterator, cast, TYPE_CHECKING
32
32
  from multidict import CIMultiDict
33
- import aiohttp.client_exceptions # pylint: disable=all
33
+ import aiohttp.client_exceptions # pylint: disable=networking-import-outside-azure-core-transport
34
34
 
35
35
  from ._http_response_impl_async import AsyncHttpResponseImpl
36
36
  from ..exceptions import (
@@ -263,7 +263,7 @@ class AioHttpStreamDownloadGenerator(collections.abc.AsyncIterator):
263
263
  self.response = response
264
264
 
265
265
  # TODO: determine if block size should be public on RestAioHttpTransportResponse.
266
- self.block_size = response._block_size # pylint: disable=protected-access
266
+ self.block_size = response._block_size
267
267
  self._decompress = decompress
268
268
  self.content_length = int(response.headers.get("Content-Length", 0))
269
269
  self._decompressor = None
@@ -272,11 +272,11 @@ class AioHttpStreamDownloadGenerator(collections.abc.AsyncIterator):
272
272
  return self.content_length
273
273
 
274
274
  async def __anext__(self):
275
- internal_response = self.response._internal_response # pylint: disable=protected-access
275
+ internal_response = self.response._internal_response
276
276
  try:
277
277
  # TODO: Determine how chunks should be read.
278
278
  # chunk = await self.response.internal_response.content.read(self.block_size)
279
- chunk = await internal_response.content.read(self.block_size) # pylint: disable=protected-access
279
+ chunk = await internal_response.content.read(self.block_size)
280
280
  if not chunk:
281
281
  raise _ResponseStopIteration()
282
282
  if not self._decompress:
@@ -292,12 +292,7 @@ class HttpResponseImpl(_HttpResponseBaseImpl, _HttpResponse):
292
292
  yield self.content[i : i + chunk_size]
293
293
  else:
294
294
  self._stream_download_check()
295
- for part in self._stream_download_generator(
296
- response=self,
297
- pipeline=None,
298
- decompress=True,
299
- ):
300
- yield part
295
+ yield from self._stream_download_generator(response=self, pipeline=None, decompress=True)
301
296
  self.close()
302
297
 
303
298
  def iter_raw(self, **kwargs) -> Iterator[bytes]:
@@ -307,6 +302,5 @@ class HttpResponseImpl(_HttpResponseBaseImpl, _HttpResponse):
307
302
  :rtype: Iterator[str]
308
303
  """
309
304
  self._stream_download_check()
310
- for part in self._stream_download_generator(response=self, pipeline=None, decompress=False):
311
- yield part
305
+ yield from self._stream_download_generator(response=self, pipeline=None, decompress=False)
312
306
  self.close()
@@ -177,7 +177,7 @@ class AsyncHttpXStreamDownloadGenerator(AsyncIterator):
177
177
  return self
178
178
 
179
179
  async def __anext__(self):
180
- internal_response = self.response._internal_response # pylint: disable=protected-access
180
+ internal_response = self.response._internal_response
181
181
  try:
182
182
  return await self.iter_content_func.__anext__()
183
183
  except StopAsyncIteration:
@@ -27,8 +27,8 @@ from __future__ import annotations
27
27
  import logging
28
28
  import collections.abc as collections
29
29
  from typing import TYPE_CHECKING, Any
30
- import requests # pylint: disable=all
31
- from requests.structures import CaseInsensitiveDict # pylint: disable=all
30
+ import requests # pylint: disable=networking-import-outside-azure-core-transport
31
+ from requests.structures import CaseInsensitiveDict # pylint: disable=networking-import-outside-azure-core-transport
32
32
  from urllib3.exceptions import (
33
33
  DecodeError as CoreDecodeError,
34
34
  ReadTimeoutError,
@@ -122,7 +122,7 @@ class StreamDownloadGenerator:
122
122
  self.response = response
123
123
 
124
124
  # TODO: determine if block size should be public on RestTransportResponse.
125
- self.block_size = response._block_size # pylint: disable=protected-access
125
+ self.block_size = response._block_size
126
126
  decompress = kwargs.pop("decompress", True)
127
127
  if len(kwargs) > 0:
128
128
  raise TypeError("Got an unexpected keyword argument: {}".format(list(kwargs.keys())[0]))
@@ -172,8 +172,7 @@ def _read_raw_stream(response, chunk_size=1):
172
172
  # Special case for urllib3.
173
173
  if hasattr(response.raw, "stream"):
174
174
  try:
175
- for chunk in response.raw.stream(chunk_size, decode_content=False):
176
- yield chunk
175
+ yield from response.raw.stream(chunk_size, decode_content=False)
177
176
  except ProtocolError as e:
178
177
  raise ServiceResponseError(e, error=e) from e
179
178
  except CoreDecodeError as e:
@@ -329,16 +329,13 @@ class HttpResponse(_HttpResponseBase):
329
329
  """
330
330
 
331
331
  @abc.abstractmethod
332
- def __enter__(self) -> "HttpResponse":
333
- ...
332
+ def __enter__(self) -> "HttpResponse": ...
334
333
 
335
334
  @abc.abstractmethod
336
- def __exit__(self, *args: Any) -> None:
337
- ...
335
+ def __exit__(self, *args: Any) -> None: ...
338
336
 
339
337
  @abc.abstractmethod
340
- def close(self) -> None:
341
- ...
338
+ def close(self) -> None: ...
342
339
 
343
340
  @abc.abstractmethod
344
341
  def read(self) -> bytes:
@@ -415,5 +412,4 @@ class AsyncHttpResponse(_HttpResponseBase, AsyncContextManager["AsyncHttpRespons
415
412
  yield # pylint: disable=unreachable
416
413
 
417
414
  @abc.abstractmethod
418
- async def close(self) -> None:
419
- ...
415
+ async def close(self) -> None: ...
@@ -51,9 +51,7 @@ class PipelineContext(Dict[str, Any]):
51
51
 
52
52
  _PICKLE_CONTEXT = {"deserialized_data"}
53
53
 
54
- def __init__(
55
- self, transport: Optional["TransportType"], **kwargs: Any
56
- ) -> None: # pylint: disable=super-init-not-called
54
+ def __init__(self, transport: Optional["TransportType"], **kwargs: Any) -> None:
57
55
  self.transport: Optional["TransportType"] = transport
58
56
  self.options = kwargs
59
57
  self._protected = ["transport", "options"]
@@ -113,12 +111,10 @@ class PipelineContext(Dict[str, Any]):
113
111
  raise TypeError("Context objects cannot be updated.")
114
112
 
115
113
  @overload
116
- def pop(self, __key: str) -> Any:
117
- ...
114
+ def pop(self, __key: str) -> Any: ...
118
115
 
119
116
  @overload
120
- def pop(self, __key: str, __default: Optional[Any]) -> Any:
121
- ...
117
+ def pop(self, __key: str, __default: Optional[Any]) -> Any: ...
122
118
 
123
119
  def pop(self, *args: Any) -> Any:
124
120
  """Removes specified key and returns the value.
@@ -153,7 +153,7 @@ class Pipeline(ContextManager["Pipeline"], Generic[HTTPRequestType, HTTPResponse
153
153
  self._transport.__enter__()
154
154
  return self
155
155
 
156
- def __exit__(self, *exc_details: Any) -> None: # pylint: disable=arguments-differ
156
+ def __exit__(self, *exc_details: Any) -> None:
157
157
  self._transport.__exit__(*exc_details)
158
158
 
159
159
  def run(self, request: HTTPRequestType, **kwargs: Any) -> PipelineResponse[HTTPRequestType, HTTPResponseType]:
@@ -26,8 +26,8 @@
26
26
  from __future__ import annotations
27
27
  import inspect
28
28
  from types import TracebackType
29
- from typing import Any, Union, Generic, TypeVar, List, Optional, Iterable, Type
30
- from typing_extensions import AsyncContextManager, TypeGuard
29
+ from typing import Any, Union, Generic, TypeVar, List, Optional, Iterable, Type, AsyncContextManager
30
+ from typing_extensions import TypeGuard
31
31
 
32
32
  from . import PipelineRequest, PipelineResponse, PipelineContext
33
33
  from ..policies import AsyncHTTPPolicy, SansIOHTTPPolicy
@@ -45,9 +45,7 @@ def is_async_http_policy(policy: object) -> TypeGuard[AsyncHTTPPolicy]:
45
45
  return False
46
46
 
47
47
 
48
- class _SansIOAsyncHTTPPolicyRunner(
49
- AsyncHTTPPolicy[HTTPRequestType, AsyncHTTPResponseType]
50
- ): # pylint: disable=unsubscriptable-object
48
+ class _SansIOAsyncHTTPPolicyRunner(AsyncHTTPPolicy[HTTPRequestType, AsyncHTTPResponseType]):
51
49
  """Async implementation of the SansIO policy.
52
50
 
53
51
  Modifies the request and sends to the next policy in the chain.
@@ -76,9 +74,7 @@ class _SansIOAsyncHTTPPolicyRunner(
76
74
  return response
77
75
 
78
76
 
79
- class _AsyncTransportRunner(
80
- AsyncHTTPPolicy[HTTPRequestType, AsyncHTTPResponseType]
81
- ): # pylint: disable=unsubscriptable-object
77
+ class _AsyncTransportRunner(AsyncHTTPPolicy[HTTPRequestType, AsyncHTTPResponseType]):
82
78
  """Async Transport runner.
83
79
 
84
80
  Uses specified HTTP transport type to send request and returns response.
@@ -31,13 +31,11 @@ T = TypeVar("T")
31
31
 
32
32
 
33
33
  @overload
34
- async def await_result(func: Callable[P, Awaitable[T]], *args: P.args, **kwargs: P.kwargs) -> T:
35
- ...
34
+ async def await_result(func: Callable[P, Awaitable[T]], *args: P.args, **kwargs: P.kwargs) -> T: ...
36
35
 
37
36
 
38
37
  @overload
39
- async def await_result(func: Callable[P, T], *args: P.args, **kwargs: P.kwargs) -> T:
40
- ...
38
+ async def await_result(func: Callable[P, T], *args: P.args, **kwargs: P.kwargs) -> T: ...
41
39
 
42
40
 
43
41
  async def await_result(func: Callable[P, Union[T, Awaitable[T]]], *args: P.args, **kwargs: P.kwargs) -> T:
@@ -5,16 +5,17 @@
5
5
  # -------------------------------------------------------------------------
6
6
  from __future__ import annotations
7
7
  import time
8
- from typing import TYPE_CHECKING, Optional, TypeVar, MutableMapping, Any
8
+ from typing import TYPE_CHECKING, Optional, TypeVar, MutableMapping, Any, Union
9
9
 
10
+ from ...credentials import TokenRequestOptions
10
11
  from ...rest import HttpResponse, HttpRequest
11
12
  from . import HTTPPolicy, SansIOHTTPPolicy
12
13
  from ...exceptions import ServiceRequestError
13
14
 
14
15
  if TYPE_CHECKING:
15
- # pylint:disable=unused-import
16
+
16
17
  from ...credentials import (
17
- AccessToken,
18
+ AccessTokenInfo,
18
19
  TokenCredential,
19
20
  ServiceKeyCredential,
20
21
  )
@@ -31,15 +32,23 @@ class _BearerTokenCredentialPolicyBase:
31
32
  :param credential: The credential.
32
33
  :type credential: ~corehttp.credentials.TokenCredential
33
34
  :param str scopes: Lets you specify the type of access needed.
35
+ :keyword auth_flows: A list of authentication flows to use for the credential.
36
+ :paramtype auth_flows: list[dict[str, Union[str, list[dict[str, str]]]]]
34
37
  """
35
38
 
39
+ # pylint: disable=unused-argument
36
40
  def __init__(
37
- self, credential: "TokenCredential", *scopes: str, **kwargs: Any # pylint: disable=unused-argument
41
+ self,
42
+ credential: "TokenCredential",
43
+ *scopes: str,
44
+ auth_flows: Optional[list[dict[str, Union[str, list[dict[str, str]]]]]] = None,
45
+ **kwargs: Any,
38
46
  ) -> None:
39
47
  super(_BearerTokenCredentialPolicyBase, self).__init__()
40
48
  self._scopes = scopes
41
49
  self._credential = credential
42
- self._token: Optional["AccessToken"] = None
50
+ self._token: Optional["AccessTokenInfo"] = None
51
+ self._auth_flows = auth_flows
43
52
 
44
53
  @staticmethod
45
54
  def _enforce_https(request: PipelineRequest[HTTPRequestType]) -> None:
@@ -68,7 +77,12 @@ class _BearerTokenCredentialPolicyBase:
68
77
 
69
78
  @property
70
79
  def _need_new_token(self) -> bool:
71
- return not self._token or self._token.expires_on - time.time() < 300
80
+ now = time.time()
81
+ return (
82
+ not self._token
83
+ or (self._token.refresh_on is not None and self._token.refresh_on <= now)
84
+ or (self._token.expires_on - now < 300)
85
+ )
72
86
 
73
87
 
74
88
  class BearerTokenCredentialPolicy(_BearerTokenCredentialPolicyBase, HTTPPolicy[HTTPRequestType, HTTPResponseType]):
@@ -77,20 +91,30 @@ class BearerTokenCredentialPolicy(_BearerTokenCredentialPolicyBase, HTTPPolicy[H
77
91
  :param credential: The credential.
78
92
  :type credential: ~corehttp.TokenCredential
79
93
  :param str scopes: Lets you specify the type of access needed.
94
+ :keyword auth_flows: A list of authentication flows to use for the credential.
95
+ :paramtype auth_flows: list[dict[str, Union[str, list[dict[str, str]]]]]
80
96
  :raises: :class:`~corehttp.exceptions.ServiceRequestError`
81
97
  """
82
98
 
83
- def on_request(self, request: PipelineRequest[HTTPRequestType]) -> None:
99
+ def on_request(
100
+ self,
101
+ request: PipelineRequest[HTTPRequestType],
102
+ *,
103
+ auth_flows: Optional[list[dict[str, Union[str, list[dict[str, str]]]]]] = None,
104
+ ) -> None:
84
105
  """Called before the policy sends a request.
85
106
 
86
107
  The base implementation authorizes the request with a bearer token.
87
108
 
88
109
  :param ~corehttp.runtime.pipeline.PipelineRequest request: the request
110
+ :keyword auth_flows: A list of authentication flows to use for the credential.
111
+ :paramtype auth_flows: list[dict[str, Union[str, list[dict[str, str]]]]]
89
112
  """
90
113
  self._enforce_https(request)
91
114
 
92
115
  if self._token is None or self._need_new_token:
93
- self._token = self._credential.get_token(*self._scopes)
116
+ options: TokenRequestOptions = {"auth_flows": auth_flows} if auth_flows else {} # type: ignore
117
+ self._token = self._credential.get_token_info(*self._scopes, options=options)
94
118
  self._update_headers(request.http_request.headers, self._token.token)
95
119
 
96
120
  def authorize_request(self, request: PipelineRequest[HTTPRequestType], *scopes: str, **kwargs: Any) -> None:
@@ -102,7 +126,12 @@ class BearerTokenCredentialPolicy(_BearerTokenCredentialPolicyBase, HTTPPolicy[H
102
126
  :param ~corehttp.runtime.pipeline.PipelineRequest request: the request
103
127
  :param str scopes: required scopes of authentication
104
128
  """
105
- self._token = self._credential.get_token(*scopes, **kwargs)
129
+ options: TokenRequestOptions = {}
130
+ # Loop through all the keyword arguments and check if they are part of the TokenRequestOptions.
131
+ for key in list(kwargs.keys()):
132
+ if key in TokenRequestOptions.__annotations__: # pylint:disable=no-member
133
+ options[key] = kwargs.pop(key) # type: ignore[literal-required]
134
+ self._token = self._credential.get_token_info(*scopes, options=options)
106
135
  self._update_headers(request.http_request.headers, self._token.token)
107
136
 
108
137
  def send(self, request: PipelineRequest[HTTPRequestType]) -> PipelineResponse[HTTPRequestType, HTTPResponseType]:
@@ -113,25 +142,25 @@ class BearerTokenCredentialPolicy(_BearerTokenCredentialPolicyBase, HTTPPolicy[H
113
142
  :return: The pipeline response object
114
143
  :rtype: ~corehttp.runtime.pipeline.PipelineResponse
115
144
  """
116
- self.on_request(request)
145
+ self.on_request(request, auth_flows=self._auth_flows)
117
146
  try:
118
147
  response = self.next.send(request)
119
- self.on_response(request, response)
120
- except Exception: # pylint:disable=broad-except
148
+ except Exception:
121
149
  self.on_exception(request)
122
150
  raise
123
- else:
124
- if response.http_response.status_code == 401:
125
- self._token = None # any cached token is invalid
126
- if "WWW-Authenticate" in response.http_response.headers:
127
- request_authorized = self.on_challenge(request, response)
128
- if request_authorized:
129
- try:
130
- response = self.next.send(request)
131
- self.on_response(request, response)
132
- except Exception: # pylint:disable=broad-except
133
- self.on_exception(request)
134
- raise
151
+
152
+ self.on_response(request, response)
153
+ if response.http_response.status_code == 401:
154
+ self._token = None # any cached token is invalid
155
+ if "WWW-Authenticate" in response.http_response.headers:
156
+ request_authorized = self.on_challenge(request, response)
157
+ if request_authorized:
158
+ try:
159
+ response = self.next.send(request)
160
+ self.on_response(request, response)
161
+ except Exception:
162
+ self.on_exception(request)
163
+ raise
135
164
 
136
165
  return response
137
166