1# -------------------------------------------------------------------------- 
    2# 
    3# Copyright (c) Microsoft Corporation. All rights reserved. 
    4# 
    5# The MIT License (MIT) 
    6# 
    7# Permission is hereby granted, free of charge, to any person obtaining a copy 
    8# of this software and associated documentation files (the ""Software""), to 
    9# deal in the Software without restriction, including without limitation the 
    10# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 
    11# sell copies of the Software, and to permit persons to whom the Software is 
    12# furnished to do so, subject to the following conditions: 
    13# 
    14# The above copyright notice and this permission notice shall be included in 
    15# all copies or substantial portions of the Software. 
    16# 
    17# THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
    18# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
    19# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
    20# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
    21# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
    22# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 
    23# IN THE SOFTWARE. 
    24# 
    25# -------------------------------------------------------------------------- 
    26 
    27from typing import ( 
    28    TypeVar, 
    29    Generic, 
    30    Dict, 
    31    Any, 
    32    Tuple, 
    33    List, 
    34    Optional, 
    35    overload, 
    36    TYPE_CHECKING, 
    37    Union, 
    38) 
    39 
    40HTTPResponseType = TypeVar("HTTPResponseType", covariant=True)  # pylint: disable=typevar-name-incorrect-variance 
    41HTTPRequestType = TypeVar("HTTPRequestType", covariant=True)  # pylint: disable=typevar-name-incorrect-variance 
    42 
    43if TYPE_CHECKING: 
    44    from .transport import HttpTransport, AsyncHttpTransport 
    45 
    46    TransportType = Union[HttpTransport[Any, Any], AsyncHttpTransport[Any, Any]] 
    47 
    48 
    49class PipelineContext(Dict[str, Any]): 
    50    """A context object carried by the pipeline request and response containers. 
    51 
    52    This is transport specific and can contain data persisted between 
    53    pipeline requests (for example reusing an open connection pool or "session"), 
    54    as well as used by the SDK developer to carry arbitrary data through 
    55    the pipeline. 
    56 
    57    :param transport: The HTTP transport type. 
    58    :type transport: ~azure.core.pipeline.transport.HttpTransport or ~azure.core.pipeline.transport.AsyncHttpTransport 
    59    :param any kwargs: Developer-defined keyword arguments. 
    60    """ 
    61 
    62    _PICKLE_CONTEXT = {"deserialized_data"} 
    63 
    64    def __init__(self, transport: Optional["TransportType"], **kwargs: Any) -> None: 
    65        self.transport: Optional["TransportType"] = transport 
    66        self.options = kwargs 
    67        self._protected = ["transport", "options"] 
    68 
    69    def __getstate__(self) -> Dict[str, Any]: 
    70        state = self.__dict__.copy() 
    71        # Remove the unpicklable entries. 
    72        del state["transport"] 
    73        return state 
    74 
    75    def __reduce__(self) -> Tuple[Any, ...]: 
    76        reduced = super(PipelineContext, self).__reduce__() 
    77        saved_context = {} 
    78        for key, value in self.items(): 
    79            if key in self._PICKLE_CONTEXT: 
    80                saved_context[key] = value 
    81        # 1 is for from __reduce__ spec of pickle (generic args for recreation) 
    82        # 2 is how dict is implementing __reduce__ (dict specific) 
    83        # tuple are read-only, we use a list in the meantime 
    84        reduced_as_list: List[Any] = list(reduced) 
    85        dict_reduced_result = list(reduced_as_list[1]) 
    86        dict_reduced_result[2] = saved_context 
    87        reduced_as_list[1] = tuple(dict_reduced_result) 
    88        return tuple(reduced_as_list) 
    89 
    90    def __setstate__(self, state: Dict[str, Any]) -> None: 
    91        self.__dict__.update(state) 
    92        # Re-create the unpickable entries 
    93        self.transport = None 
    94 
    95    def __setitem__(self, key: str, item: Any) -> None: 
    96        # If reloaded from pickle, _protected might not be here until restored by pickle 
    97        # this explains the hasattr test 
    98        if hasattr(self, "_protected") and key in self._protected: 
    99            raise ValueError("Context value {} cannot be overwritten.".format(key)) 
    100        return super(PipelineContext, self).__setitem__(key, item) 
    101 
    102    def __delitem__(self, key: str) -> None: 
    103        if key in self._protected: 
    104            raise ValueError("Context value {} cannot be deleted.".format(key)) 
    105        return super(PipelineContext, self).__delitem__(key) 
    106 
    107    def clear(  # pylint: disable=docstring-missing-return, docstring-missing-rtype 
    108        self, 
    109    ) -> None: 
    110        """Clears the context objects. 
    111 
    112        :raises TypeError: If context objects cannot be cleared 
    113        """ 
    114        raise TypeError("Context objects cannot be cleared.") 
    115 
    116    def update(  # pylint: disable=docstring-missing-return, docstring-missing-rtype, docstring-missing-param 
    117        self, *args: Any, **kwargs: Any 
    118    ) -> None: 
    119        """Updates the context objects. 
    120 
    121        :raises TypeError: If context objects cannot be updated 
    122        """ 
    123        raise TypeError("Context objects cannot be updated.") 
    124 
    125    @overload 
    126    def pop(self, __key: str) -> Any: ... 
    127 
    128    @overload 
    129    def pop(self, __key: str, __default: Optional[Any]) -> Any: ... 
    130 
    131    def pop(self, *args: Any) -> Any: 
    132        """Removes specified key and returns the value. 
    133 
    134        :param args: The key to remove. 
    135        :type args: str 
    136        :return: The value for this key. 
    137        :rtype: any 
    138        :raises ValueError: If the key is in the protected list. 
    139        """ 
    140        if args and args[0] in self._protected: 
    141            raise ValueError("Context value {} cannot be popped.".format(args[0])) 
    142        return super(PipelineContext, self).pop(*args) 
    143 
    144 
    145class PipelineRequest(Generic[HTTPRequestType]): 
    146    """A pipeline request object. 
    147 
    148    Container for moving the HttpRequest through the pipeline. 
    149    Universal for all transports, both synchronous and asynchronous. 
    150 
    151    :param http_request: The request object. 
    152    :type http_request: ~azure.core.pipeline.transport.HttpRequest 
    153    :param context: Contains the context - data persisted between pipeline requests. 
    154    :type context: ~azure.core.pipeline.PipelineContext 
    155    """ 
    156 
    157    def __init__(self, http_request: HTTPRequestType, context: PipelineContext) -> None: 
    158        self.http_request = http_request 
    159        self.context = context 
    160 
    161 
    162class PipelineResponse(Generic[HTTPRequestType, HTTPResponseType]): 
    163    """A pipeline response object. 
    164 
    165    The PipelineResponse interface exposes an HTTP response object as it returns through the pipeline of Policy objects. 
    166    This ensures that Policy objects have access to the HTTP response. 
    167 
    168    This also has a "context" object where policy can put additional fields. 
    169    Policy SHOULD update the "context" with additional post-processed field if they create them. 
    170    However, nothing prevents a policy to actually sub-class this class a return it instead of the initial instance. 
    171 
    172    :param http_request: The request object. 
    173    :type http_request: ~azure.core.pipeline.transport.HttpRequest 
    174    :param http_response: The response object. 
    175    :type http_response: ~azure.core.pipeline.transport.HttpResponse 
    176    :param context: Contains the context - data persisted between pipeline requests. 
    177    :type context: ~azure.core.pipeline.PipelineContext 
    178    """ 
    179 
    180    def __init__( 
    181        self, 
    182        http_request: HTTPRequestType, 
    183        http_response: HTTPResponseType, 
    184        context: PipelineContext, 
    185    ) -> None: 
    186        self.http_request = http_request 
    187        self.http_response = http_response 
    188        self.context = context 
    189 
    190 
    191from ._base import Pipeline  # pylint: disable=wrong-import-position 
    192from ._base_async import AsyncPipeline  # pylint: disable=wrong-import-position 
    193 
    194__all__ = [ 
    195    "Pipeline", 
    196    "PipelineRequest", 
    197    "PipelineResponse", 
    198    "PipelineContext", 
    199    "AsyncPipeline", 
    200]