# Path: canvas_sdk/client/request_context.py
# class RequestContext(object):
# 
#     """
#     A class that holds the default configuration values used to make Canvas API requests.  The requests
#     library is heavily leveraged in terms of the attributes that may be passed in.  Most of the attributes
#     are used to construct a requests.Session instance that by default will be reused across requests
#     made with a given :class:`RequestContext <RequestContext>`.  See below for a full list of parameters:
# 
#     :param str auth_token: OAuth2 token retrieved from a Canvas site
#     :param str base_api_url: The api endpoint of the Canvas site in the form "http(s)://[canvas.site.com]/api"
#     :param int per_page: (optional) For get requests that return a list of data, this will be used as the default per_page value
#     :param int max_retries: (optional) Number of times a request that generates a certain class of HTTP exception will be retried
#         before being raised back to the caller.  See :py:mod:`client.base` for a list of those error types.
#     :param dictionary headers: (optional) dictionary of headers to send for each request.  Will be merged with a default set of headers.
#     :param cookies: (optional) Cookies to attach to each requests.
#     :type cookies: dictionary or CookieJar
#     :param float timeout: (optional) The timeout of the request in seconds.
#     :param dictionary proxies: (optional) Mapping protocol to the URL of the proxy.
#     :param verify: (optional) if ``True``, the SSL cert will be verified.  A CA_BUNDLE path can also be provided.
#     :type verify: boolean or str
#     :param cert: (optional) if String, path to ssl client cert file (.pem).  If Tuple, ('cert', 'key') pair.
#     :type cert: str or Tuple
#     """
# 
#     @classmethod
#     def get_default_headers(cls):
#         """
#         These are headers that are sent with every API request.  Be careful of overriding these headers since the API
#         calls may not work if these are modified.
#         """
#         default_headers = {
#             'Accept': 'text/json'
#         }
#         return default_headers
# 
#     def __init__(self, auth_token, base_api_url, max_retries=0, per_page=None, headers=None, cookies=None, timeout=None, proxies=None, verify=True, cert=None):
#         self._session = None
#         self.auth_token = auth_token
#         self.per_page = per_page
#         parsed_url = urlparse(base_api_url)
#         if 'http' not in parsed_url.scheme:
#             raise AttributeError(
#                 "'%s' was provided, but base_url should be in the format http(s)://path/to/canvas/instance/api." % base_api_url)
#         self.base_api_url = base_api_url
#         self.headers = self.get_default_headers()
#         # Allow overriding of default values with values passed in by user
#         if headers:
#             self.headers.update(headers)
#         self.cookies = cookies
#         self.timeout = timeout
#         self.proxies = proxies
#         self.verify = verify
#         self.cert = cert
#         self.max_retries = max_retries
# 
#     @property
#     def auth(self):
#         """
#         A custom OAuth2 authentication handler for the instance's auth_token
#         """
#         return OAuth2Bearer(self.auth_token)
# 
#     @property
#     def session(self):
#         """
#         Get or set a requests.Session instance based on the session related values passed into the
#         class.  The setter should only be used if you need fine-grained control over your session.
#         You can refer to the requests library documentation for information on available options for
#         the session object: http://docs.python-requests.org/
#         NOTE: Refer to the setup.py file to match up the version of the Requests library the SDK uses
#         with the right doc version.
#         """
#         if not self._session:
#             self._session = requests.Session()
#             # Streaming is disabled by default when creating a requests.Session
#             # object, but let's be explicit here to prevent connections from staying
#             # open indefinitely
#             self._session.stream = False
#             self._session.auth = self.auth
#             self._session.headers.update(self.headers or {})
#             self._session.timeout = self.timeout
#             self._session.cert = self.cert
#             self._session.verify = self.verify
#             # We only need to set proxies and cookies if not None or empty since the
#             # defaults are empty dicts
#             if self.proxies:
#                 self._session.proxies = self.proxies
#             if self.cookies:
#                 self._session.cookies = self.cookies
#         return self._session
# 
#     @session.setter
#     def session(self, sess):
#         self._session = sess
# 
#     def expire_session(self):
#         """
#         To expire a session, it just needs to be set to None according to requests doc.
#         """
#         self.session = None


import unittest
from unittest import mock
from unittest.mock import patch
from canvas_sdk.client import RequestContext
    def test_session_creation_sets_timeout_to_instance_value(self, mock_auth, mock_requests_session):
        """
        Test that Session object is created with context timeout value.
        """
        context = RequestContext(self.auth_token, self.base_api_url, timeout=60)
        result = context.session
        self.assertEqual(
            60, result.timeout, "Timeout attribute on session should be equivalent to attribute passed in to context")

    @patch('canvas_sdk.client.request_context.requests.Session')
    @patch.object(RequestContext, 'auth', new_callable=mock.PropertyMock)
    def test_session_creation_does_not_explicitly_set_proxies_if_none(self, mock_auth, mock_requests_session):
        """
        Test that proxies attribute that Session object may be initialized with is not overriden by an empty/None context property
        """
        session_proxy = {'proxy': 'session'}
        mock_requests_session.return_value.proxies = session_proxy
        context = RequestContext(self.auth_token, self.base_api_url)
        context.proxies = None
        result = context.session
        self.assertEqual(session_proxy, result.proxies,
                         "Proxies attribute should not be overriden on session when no proxies set on context")

    @patch('canvas_sdk.client.request_context.requests.Session')
    @patch.object(RequestContext, 'auth', new_callable=mock.PropertyMock)
    def test_session_creation_sets_proxies_with_context_value(self, mock_auth, mock_requests_session):
        """
        Test that proxies attribute that Session object may be initialized with is overriden by corresponding context property
        """
        context_proxy = {'proxy': 'session'}

# Path: canvas_sdk/client/request_context.py
# class RequestContext(object):
# 
#     """
#     A class that holds the default configuration values used to make Canvas API requests.  The requests
#     library is heavily leveraged in terms of the attributes that may be passed in.  Most of the attributes
#     are used to construct a requests.Session instance that by default will be reused across requests
#     made with a given :class:`RequestContext <RequestContext>`.  See below for a full list of parameters:
# 
#     :param str auth_token: OAuth2 token retrieved from a Canvas site
#     :param str base_api_url: The api endpoint of the Canvas site in the form "http(s)://[canvas.site.com]/api"
#     :param int per_page: (optional) For get requests that return a list of data, this will be used as the default per_page value
#     :param int max_retries: (optional) Number of times a request that generates a certain class of HTTP exception will be retried
#         before being raised back to the caller.  See :py:mod:`client.base` for a list of those error types.
#     :param dictionary headers: (optional) dictionary of headers to send for each request.  Will be merged with a default set of headers.
#     :param cookies: (optional) Cookies to attach to each requests.
#     :type cookies: dictionary or CookieJar
#     :param float timeout: (optional) The timeout of the request in seconds.
#     :param dictionary proxies: (optional) Mapping protocol to the URL of the proxy.
#     :param verify: (optional) if ``True``, the SSL cert will be verified.  A CA_BUNDLE path can also be provided.
#     :type verify: boolean or str
#     :param cert: (optional) if String, path to ssl client cert file (.pem).  If Tuple, ('cert', 'key') pair.
#     :type cert: str or Tuple
#     """
# 
#     @classmethod
#     def get_default_headers(cls):
#         """
#         These are headers that are sent with every API request.  Be careful of overriding these headers since the API
#         calls may not work if these are modified.
#         """
#         default_headers = {
#             'Accept': 'text/json'
#         }
#         return default_headers
# 
#     def __init__(self, auth_token, base_api_url, max_retries=0, per_page=None, headers=None, cookies=None, timeout=None, proxies=None, verify=True, cert=None):
#         self._session = None
#         self.auth_token = auth_token
#         self.per_page = per_page
#         parsed_url = urlparse(base_api_url)
#         if 'http' not in parsed_url.scheme:
#             raise AttributeError(
#                 "'%s' was provided, but base_url should be in the format http(s)://path/to/canvas/instance/api." % base_api_url)
#         self.base_api_url = base_api_url
#         self.headers = self.get_default_headers()
#         # Allow overriding of default values with values passed in by user
#         if headers:
#             self.headers.update(headers)
#         self.cookies = cookies
#         self.timeout = timeout
#         self.proxies = proxies
#         self.verify = verify
#         self.cert = cert
#         self.max_retries = max_retries
# 
#     @property
#     def auth(self):
#         """
#         A custom OAuth2 authentication handler for the instance's auth_token
#         """
#         return OAuth2Bearer(self.auth_token)
# 
#     @property
#     def session(self):
#         """
#         Get or set a requests.Session instance based on the session related values passed into the
#         class.  The setter should only be used if you need fine-grained control over your session.
#         You can refer to the requests library documentation for information on available options for
#         the session object: http://docs.python-requests.org/
#         NOTE: Refer to the setup.py file to match up the version of the Requests library the SDK uses
#         with the right doc version.
#         """
#         if not self._session:
#             self._session = requests.Session()
#             # Streaming is disabled by default when creating a requests.Session
#             # object, but let's be explicit here to prevent connections from staying
#             # open indefinitely
#             self._session.stream = False
#             self._session.auth = self.auth
#             self._session.headers.update(self.headers or {})
#             self._session.timeout = self.timeout
#             self._session.cert = self.cert
#             self._session.verify = self.verify
#             # We only need to set proxies and cookies if not None or empty since the
#             # defaults are empty dicts
#             if self.proxies:
#                 self._session.proxies = self.proxies
#             if self.cookies:
#                 self._session.cookies = self.cookies
#         return self._session
# 
#     @session.setter
#     def session(self, sess):
#         self._session = sess
# 
#     def expire_session(self):
#         """
#         To expire a session, it just needs to be set to None according to requests doc.
#         """
#         self.session = None


# Path: tests/client/test_request_context.py
import unittest
from unittest import mock
from unittest.mock import patch
from canvas_sdk.client import RequestContext

    def test_session_creation_sets_timeout_to_instance_value(self, mock_auth, mock_requests_session):
        """
        Test that Session object is created with context timeout value.
        """
        context = RequestContext(self.auth_token, self.base_api_url, timeout=60)
        result = context.session
        self.assertEqual(
            60, result.timeout, "Timeout attribute on session should be equivalent to attribute passed in to context")

    @patch('canvas_sdk.client.request_context.requests.Session')
    @patch.object(RequestContext, 'auth', new_callable=mock.PropertyMock)
    def test_session_creation_does_not_explicitly_set_proxies_if_none(self, mock_auth, mock_requests_session):
        """
        Test that proxies attribute that Session object may be initialized with is not overriden by an empty/None context property
        """
        session_proxy = {'proxy': 'session'}
        mock_requests_session.return_value.proxies = session_proxy
        context = RequestContext(self.auth_token, self.base_api_url)
        context.proxies = None
        result = context.session
        self.assertEqual(session_proxy, result.proxies,
                         "Proxies attribute should not be overriden on session when no proxies set on context")

    @patch('canvas_sdk.client.request_context.requests.Session')
    @patch.object(RequestContext, 'auth', new_callable=mock.PropertyMock)
    def test_session_creation_sets_proxies_with_context_value(self, mock_auth, mock_requests_session):
        """
        Test that proxies attribute that Session object may be initialized with is overriden by corresponding context property
        """
        context_proxy = {'proxy': 'session'}

        context = RequestContext(self.auth_token, self.base_api_url, proxies=context_proxy)