Skip to content

Commit aeb2735

Browse files
authored
[rest] GA in docs! (Azure#21545)
1 parent a6991c8 commit aeb2735

File tree

11 files changed

+132
-129
lines changed

11 files changed

+132
-129
lines changed

sdk/core/azure-core/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@
44

55
### Features Added
66

7+
- GA `send_request` onto the `azure.core.PipelineClient` and `azure.core.AsyncPipelineClient`. This method takes in
8+
requests and sends them through our pipelines.
9+
- GA `azure.core.rest`. `azure.core.rest` is our new public simple HTTP library in `azure.core` that users will use to create requests, and consume responses.
10+
- GA errors `StreamConsumedError`, `StreamClosedError`, and `ResponseNotReadError` to `azure.core.exceptions`. These errors
11+
are thrown if you mishandle streamed responses from the `azure.core.rest` module
712
- add kwargs to the methods for `iter_raw` and `iter_bytes` #21529
813
- Added new error type `IncompleteReadError` which is raised if peer closes the connection before we have received the complete message body.
914

sdk/core/azure-core/CLIENT_LIBRARY_DEVELOPER.md

Lines changed: 108 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ When constructing an SDK, a developer may consume the pipeline like so:
1414

1515
```python
1616
from azure.core.pipeline import Pipeline
17-
from azure.core.transport import RequestsTransport, HttpRequest
17+
from azure.core.rest import HttpRequest
18+
from azure.core.transport import RequestsTransport
1819
from azure.core.pipeline.policies import (
1920
UserAgentPolicy,
2021
HeadersPolicy,
@@ -193,106 +194,126 @@ proxy_policy.proxies = {'https': 'http://user:[email protected]:1180/'}
193194

194195
### HttpRequest and HttpResponse
195196

196-
The HttpRequest and HttpResponse objects represent a generic concept of HTTP request and response constructs and are in no way tied to a particular transport or HTTP library.
197+
The `HttpRequest` and `HttpResponse` objects represent a generic concept of HTTP request and response constructs and are in no way tied to a particular transport or HTTP library.
197198

198-
The HttpRequest has the following API. It does not vary between transports:
199+
The `HttpRequest` has the following API. It does not vary between transports:
199200

200201
```python
201-
class HttpRequest(object):
202-
203-
def __init__(self, method, url, headers=None, files=None, data=None):
204-
self.method = method
202+
class HttpRequest:
203+
204+
def __init__(
205+
self,
206+
method: str,
207+
url: str,
208+
*,
209+
params: Optional[ParamsType] = None,
210+
headers: Optional[MutableMapping[str, str]] = None,
211+
json: Any = None,
212+
content: Optional[ContentType] = None,
213+
data: Optional[dict] = None,
214+
files: Optional[FilesType] = None,
215+
**kwargs
216+
):
205217
self.url = url
206-
self.headers = CaseInsensitiveDict(headers)
207-
self.files = files
208-
self.data = data
218+
self.method = method
219+
self.headers = CaseInsensitiveDict(default_headers)
209220

210221
@property
211-
def body(self):
212-
return self.data
213-
214-
@body.setter
215-
def body(self, value):
216-
self.data = value
217-
218-
def format_parameters(self, params):
219-
"""Format parameters into a valid query string.
220-
It's assumed all parameters have already been quoted as
221-
valid URL strings."""
222-
223-
def set_xml_body(self, data):
224-
"""Set an XML element tree as the body of the request."""
225-
226-
def set_json_body(self, data):
227-
"""Set a JSON-friendly object as the body of the request."""
228-
229-
def set_multipart_body(self, data=None):
230-
"""Set form-encoded data as the body of the request.
231-
Supported content-types are:
232-
- application/x-www-form-urlencoded
233-
- multipart/form-data
234-
"""
235-
236-
def set_bytes_body(self, data):
237-
"""Set generic bytes as the body of the request."""
238-
239-
def set_multipart_mixed(self, *requests, **kwargs):
240-
"""Set requests for a multipart/mixed body.
241-
Optionally apply "policies" in kwargs to each request.
242-
"""
222+
def content(self) -> Any:
223+
"""Get's the request's content"""
243224
```
244225

245-
The HttpResponse object on the other hand will generally have a transport-specific derivative.
246-
This is to accomodate how the data is extracted for the object returned by the HTTP library.
247-
There is also an async flavor: AsyncHttpResponse. This is to allow for the asynchronous streaming of
248-
data from the response.
249-
For example:
226+
`HttpResponse` on the other hand is an abstract base class that will have to be implemented
227+
for a transport-specific derivative to accommodate how data is extracted from the object
228+
returned by the HTTP library.
229+
230+
The API for each of these response types is identical, so the consumer of the `HttpResponse` need not know about these
231+
particular types.
232+
233+
The `HttpResponse` has the following API. It does not vary between transports, and has the following surface area:
250234

251235
```python
252-
from azure.core.pipeline.transport import (
253-
RequestsTransportResponse, # HttpResponse
254-
AioHttpTransportResponse, # AsyncHttpResponse
255-
TrioRequestsTransportResponse, # AsyncHttpResponse
256-
AsyncioRequestsTransportResponse, # AsyncHttpResponse
257-
)
258-
```
236+
class HttpResponse:
259237

260-
The API for each of these response types is identical, so the consumer of the Response need not know about these
261-
particular types.
238+
@property
239+
def request(self) -> HttpRequest:
240+
"""The request that resulted in this response."""
262241

263-
The HttpResponse has the following API. It does not vary between transports:
242+
@property
243+
def status_code(self) -> int:
244+
"""The status code of this response."""
245+
246+
@property
247+
def headers(self) -> MutableMapping[str, str]:
248+
"""The response headers. Must be case-insensitive."""
249+
250+
@property
251+
def reason(self) -> str:
252+
"""The reason phrase for this response."""
253+
254+
@property
255+
def content_type(self) -> Optional[str]:
256+
"""The content type of the response."""
257+
258+
@property
259+
def is_closed(self) -> bool:
260+
"""Whether the network connection has been closed yet."""
261+
262+
@property
263+
def is_stream_consumed(self) -> bool:
264+
"""Whether the stream has been consumed."""
265+
266+
@property
267+
def encoding(self) -> Optional[str]:
268+
"""Returns the response encoding."""
269+
270+
@encoding.setter
271+
def encoding(self, value: Optional[str]) -> None:
272+
"""Sets the response encoding."""
273+
274+
@property
275+
def url(self) -> str:
276+
"""The URL that resulted in this response."""
277+
278+
@property
279+
def content(self) -> bytes:
280+
"""Return the response's content in bytes."""
281+
282+
def text(self, encoding: Optional[str] = None) -> str:
283+
"""Returns the response body as a string."""
284+
285+
def json(self) -> Any:
286+
"""Returns the whole body as a json object."""
287+
288+
def raise_for_status(self) -> None:
289+
"""Raises an HttpResponseError if the response has an error status code."""
290+
291+
def read(self) -> bytes:
292+
"""Read the response's bytes."""
293+
294+
def iter_raw(self, **kwargs: Any) -> Iterator[bytes]:
295+
"""Iterates over the response's bytes. Will not decompress in the process."""
296+
297+
def iter_bytes(self, **kwargs: Any) -> Iterator[bytes]:
298+
"""Iterates over the response's bytes. Will decompress in the process."""
299+
300+
```
301+
302+
Async calls to networks will return an `AsyncHttpResponse` instead. It shares most of its properties with an `HttpResponse` with the following exceptions:
264303

265304
```python
266-
class HttpResponse(object):
267-
268-
def __init__(self, request, internal_response):
269-
self.request = request
270-
self.internal_response = internal_response # The object returned by the HTTP library
271-
self.status_code = None
272-
self.headers = CaseInsensitiveDict()
273-
self.reason = None
274-
self.content_type = None
275-
276-
def body(self):
277-
"""Return the whole body as bytes in memory."""
278-
279-
def text(self, encoding=None):
280-
"""Return the whole body as a string."""
281-
282-
def stream_download(self, pipeline, **kwargs):
283-
"""Generator for streaming request body data.
284-
Should be implemented by sub-classes if streaming download
285-
is supported.
286-
For the AsyncHttpResponse object this function will return
287-
and asynchronous generator.
288-
"""
289-
290-
def parts(self):
291-
"""An iterator of parts if content-type is multipart/mixed.
292-
For the AsyncHttpResponse object this function will return
293-
and asynchronous iterator.
294-
"""
305+
class AsyncHttpResponse:
306+
307+
...
308+
309+
async def read(self) -> bytes:
310+
"""Read the response's bytes into memory."""
311+
312+
async def iter_raw(self, **kwargs: Any) -> AsyncIterator[bytes]:
313+
"""Asynchronously iterates over the response's bytes. Will not decompress in the process."""
295314

315+
async def iter_bytes(self, **kwargs: Any) -> AsyncIterator[bytes]:
316+
"""Asynchronously iterates over the response's bytes. Will decompress in the process."""
296317
```
297318

298319
### PipelineRequest and PipelineResponse
@@ -467,7 +488,7 @@ A pipeline can either be synchronous or asynchronous.
467488
The pipeline does not expose the policy chain, so individual policies cannot/should not be further
468489
configured once the pipeline has been instantiated.
469490

470-
The pipeline has a single exposed operation: `run(request)` which will send a new HttpRequest object down
491+
The pipeline has a single exposed operation: `run(request)` which will send a new `HttpRequest` object down
471492
the pipeline. This operation returns a `PipelineResponse` object.
472493

473494
```python

sdk/core/azure-core/README.md

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -116,19 +116,16 @@ class TooManyRedirectsError(HttpResponseError):
116116

117117
*kwargs* are keyword arguments to include with the exception.
118118

119-
#### **Provisional** StreamConsumedError
120-
A **provisional** error thrown if you try to access the stream of the **provisional**
121-
responses `azure.core.rest.HttpResponse` or `azure.core.rest.AsyncHttpResponse` once
119+
#### StreamConsumedError
120+
An error thrown if you try to access the stream of `azure.core.rest.HttpResponse` or `azure.core.rest.AsyncHttpResponse` once
122121
the response stream has been consumed.
123122

124-
#### **Provisional** StreamClosedError
125-
A **provisional** error thrown if you try to access the stream of the **provisional**
126-
responses `azure.core.rest.HttpResponse` or `azure.core.rest.AsyncHttpResponse` once
123+
#### StreamClosedError
124+
An error thrown if you try to access the stream of the `azure.core.rest.HttpResponse` or `azure.core.rest.AsyncHttpResponse` once
127125
the response stream has been closed.
128126

129-
#### **Provisional** ResponseNotReadError
130-
A **provisional** error thrown if you try to access the `content` of the **provisional**
131-
responses `azure.core.rest.HttpResponse` or `azure.core.rest.AsyncHttpResponse` before
127+
#### ResponseNotReadError
128+
An error thrown if you try to access the `content` of `azure.core.rest.HttpResponse` or `azure.core.rest.AsyncHttpResponse` before
132129
reading in the response's bytes first.
133130

134131
### Configurations

sdk/core/azure-core/azure/core/_pipeline_client.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -176,9 +176,7 @@ def _build_pipeline(self, config, **kwargs): # pylint: disable=no-self-use
176176

177177
def send_request(self, request, **kwargs):
178178
# type: (HTTPRequestType, Any) -> HTTPResponseType
179-
"""**Provisional** method that runs the network request through the client's chained policies.
180-
181-
This method is marked as **provisional**, meaning it may be changed in a future release.
179+
"""Method that runs the network request through the client's chained policies.
182180
183181
>>> from azure.core.rest import HttpRequest
184182
>>> request = HttpRequest('GET', 'http://www.example.com')

sdk/core/azure-core/azure/core/_pipeline_client_async.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -208,9 +208,7 @@ def send_request(
208208
stream: bool = False,
209209
**kwargs: Any
210210
) -> Awaitable[AsyncHTTPResponseType]:
211-
"""**Provisional** method that runs the network request through the client's chained policies.
212-
213-
This method is marked as **provisional**, meaning it may be changed in a future release.
211+
"""Method that runs the network request through the client's chained policies.
214212
215213
>>> from azure.core.rest import HttpRequest
216214
>>> request = HttpRequest('GET', 'http://www.example.com')

sdk/core/azure-core/azure/core/exceptions.py

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -442,10 +442,9 @@ def __str__(self):
442442
return super(ODataV4Error, self).__str__()
443443

444444
class StreamConsumedError(AzureError):
445-
"""**Provisional** error thrown if you try to access the stream of a response once consumed.
445+
"""Error thrown if you try to access the stream of a response once consumed.
446446
447-
This error is marked as **provisional**, meaning it may be changed in a future release. It is
448-
thrown if you try to read / stream an ~azure.core.rest.HttpResponse or
447+
It is thrown if you try to read / stream an ~azure.core.rest.HttpResponse or
449448
~azure.core.rest.AsyncHttpResponse once the response's stream has been consumed.
450449
"""
451450
def __init__(self, response):
@@ -458,10 +457,9 @@ def __init__(self, response):
458457
super(StreamConsumedError, self).__init__(message)
459458

460459
class StreamClosedError(AzureError):
461-
"""**Provisional** error thrown if you try to access the stream of a response once closed.
460+
"""Error thrown if you try to access the stream of a response once closed.
462461
463-
This error is marked as **provisional**, meaning it may be changed in a future release. It is
464-
thrown if you try to read / stream an ~azure.core.rest.HttpResponse or
462+
It is thrown if you try to read / stream an ~azure.core.rest.HttpResponse or
465463
~azure.core.rest.AsyncHttpResponse once the response's stream has been closed.
466464
"""
467465
def __init__(self, response):
@@ -472,10 +470,9 @@ def __init__(self, response):
472470
super(StreamClosedError, self).__init__(message)
473471

474472
class ResponseNotReadError(AzureError):
475-
"""**Provisional** error thrown if you try to access a response's content without reading first.
473+
"""Error thrown if you try to access a response's content without reading first.
476474
477-
This error is marked as **provisional**, meaning it may be changed in a future release. It is
478-
thrown if you try to access an ~azure.core.rest.HttpResponse or
475+
It is thrown if you try to access an ~azure.core.rest.HttpResponse or
479476
~azure.core.rest.AsyncHttpResponse's content without first reading the response's bytes in first.
480477
"""
481478

sdk/core/azure-core/azure/core/polling/async_base_polling.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,6 @@ async def request_status(self, status_link): # pylint:disable=invalid-overridde
131131
# if I am a azure.core.pipeline.transport.HttpResponse
132132
request = self._client.get(status_link)
133133

134-
# can't use send_request in this case, because send_request is still provisional
135134
return await self._client._pipeline.run( # pylint: disable=protected-access
136135
request, stream=False, **self._operation_config
137136
)

sdk/core/azure-core/azure/core/polling/base_polling.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -588,8 +588,6 @@ def request_status(self, status_link):
588588
)
589589
# if I am a azure.core.pipeline.transport.HttpResponse
590590
request = self._client.get(status_link)
591-
592-
# can't use send_request in this case, because send_request is still provisional
593591
return self._client._pipeline.run( # pylint: disable=protected-access
594592
request, stream=False, **self._operation_config
595593
)

sdk/core/azure-core/azure/core/rest/_rest.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,7 @@
6060
################################## CLASSES ######################################
6161

6262
class HttpRequest(HttpRequestBackcompatMixin):
63-
"""Provisional object that represents an HTTP request.
64-
65-
**This object is provisional**, meaning it may be changed in a future release.
63+
"""HTTP request.
6664
6765
It should be passed to your client's `send_request` method.
6866
@@ -321,9 +319,8 @@ def content(self):
321319

322320

323321
class HttpResponse(_HttpResponseBase):
324-
"""**Provisional** abstract base class for HTTP responses.
322+
"""Abstract base class for HTTP responses.
325323
326-
**This object is provisional**, meaning it may be changed in a future release.
327324
Use this abstract base class to create your own transport responses.
328325
329326
Responses implementing this ABC are returned from your client's `send_request` method

0 commit comments

Comments
 (0)