def request(self, method, api_endpoint, **kwargs):
        """Wrapper for underlying :class:`requests.Session`

        Handles generating full API URL, session reuse and auth, request defaults, and invalid response status codes

        Used throughout library as the core underlying request/response method for all interactions with server

        Args:
            method (str): Request method (get, post, put, etc.)
            api_endpoint (str): Portion of URL matching API endpoint route as listed in platform /docs help page
            **kwargs (dict): Remaining arguments passed through to actual request call

        Notes:
            All other provided kwargs are passed to underlying :meth:`requests.Session.request()` call

        Raises:
            swimlane.exceptions.SwimlaneHTTP400Error: On 400 responses with additional context about the exception
            requests.HTTPError: Any other 4xx/5xx HTTP responses

        Returns:
            requests.Response: Successful response instances

        Examples:

            Request and parse server settings endpoint response

            >>> server_settings = swimlane.request('get', 'settings').json()
        """
        while api_endpoint.startswith('/'):
            api_endpoint = api_endpoint[1:]

        # Ensure a timeout is set
        kwargs.setdefault('timeout', self._default_timeout)

        # Manually grab and dump json data to have full control over serialization
        # Emulate default requests behavior
        json_data = kwargs.pop('json', None)
        if json_data is not None:
            headers = CaseInsensitiveDict(kwargs.get('headers', {}))
            headers.setdefault('Content-Type', 'application/json')
            kwargs['headers'] = headers

            kwargs['data'] = json.dumps(json_data,
                                        sort_keys=True,
                                        separators=(',', ':'))

        response = self._session.request(
            method, urljoin(str(self.host) + self._api_root, api_endpoint),
            **kwargs)

        # Roll 400 errors up into SwimlaneHTTP400Errors with specific Swimlane error code support
        try:
            response.raise_for_status()
        except requests.HTTPError as error:
            if error.response.status_code == 400:
                raise SwimlaneHTTP400Error(error)
            else:
                raise error

        return response
 def test_setdefault(self):
     cid = CaseInsensitiveDict({'Spam': 'blueval'})
     self.assertEqual(
         cid.setdefault('spam', 'notblueval'),
         'blueval'
     )
     self.assertEqual(
         cid.setdefault('notspam', 'notblueval'),
         'notblueval'
     )
Exemple #3
0
 def test_setdefault(self):
     cid = CaseInsensitiveDict({'Spam': 'blueval'})
     self.assertEqual(
         cid.setdefault('spam', 'notblueval'),
         'blueval'
     )
     self.assertEqual(
         cid.setdefault('notspam', 'notblueval'),
         'notblueval'
     )
Exemple #4
0
    def _prepare_request(self, command, json, opcode_name, fetch_list,
                         **kwargs):
        kwargs = CaseInsensitiveDict(kwargs)
        kwargs.update({
            'apiKey': self.key,
            opcode_name: command,
        })
        if json:
            kwargs['response'] = 'json'
        if 'page' in kwargs or fetch_list:
            kwargs.setdefault('pagesize', 500)

        kwarg = 'params' if self.method == 'get' else 'data'
        return kwarg, dict(kwargs._store.values())
Exemple #5
0
    def _prepare_request(self, command, json, opcode_name, fetch_list,
                         **kwargs):
        params = CaseInsensitiveDict(**kwargs)
        params.update({
            'apiKey': self.key,
            opcode_name: command,
        })
        if json:
            params['response'] = 'json'
        if 'page' in kwargs or fetch_list:
            params.setdefault('pagesize', PAGE_SIZE)

        kind = 'params' if self.method == 'get' else 'data'
        return kind, {k: v for k, v in params.items()}
Exemple #6
0
    def _prepare_request(self, command, json=True, opcode_name='command',
                         fetch_list=False, **kwargs):
        params = CaseInsensitiveDict(**kwargs)
        params.update({
            'apiKey': self.key,
            opcode_name: command,
        })
        if json:
            params['response'] = 'json'
        if 'page' in kwargs or fetch_list:
            params.setdefault('pagesize', PAGE_SIZE)
        if 'expires' not in params and self.expiration.total_seconds() >= 0:
            params['signatureVersion'] = '3'
            tz = pytz.utc
            expires = tz.localize(datetime.utcnow() + self.expiration)
            params['expires'] = expires.astimezone(tz).strftime(EXPIRES_FORMAT)

        kind = 'params' if self.method == 'get' else 'data'
        return kind, dict(params.items())
    def _get_email_headers_from_part(self, part):

        email_headers = list(part.items())
        if not email_headers:
            return {}

        # Convert the header tuple into a dictionary
        headers = CaseInsensitiveDict()

        # assume duplicate header names with unique values. ex: received
        for x in email_headers:
            try:
                headers.setdefault(x[0].lower().replace('-', '_').replace(' ', '_'), []).append(x[1])
            except Exception as e:
                error_msg = self._get_error_message_from_exception(e)
                err = "Error occurred while converting the header tuple into a dictionary"
                self.debug_print("{}. {}".format(err, error_msg))
        headers = {k.lower(): '\n'.join(v) for k, v in headers.items()}

        return dict(headers)
Exemple #8
0
    def _prepare_request(self,
                         command,
                         json=True,
                         opcode_name='command',
                         fetch_list=False,
                         **kwargs):
        params = CaseInsensitiveDict(**kwargs)
        params.update({
            'apiKey': self.key,
            opcode_name: command,
        })
        if json:
            params['response'] = 'json'
        if 'page' in kwargs or fetch_list:
            params.setdefault('pagesize', PAGE_SIZE)
        if 'expires' not in params and self.expiration.total_seconds() >= 0:
            params['signatureVersion'] = '3'
            tz = pytz.utc
            expires = tz.localize(datetime.utcnow() + self.expiration)
            params['expires'] = expires.astimezone(tz).strftime(EXPIRES_FORMAT)

        kind = 'params' if self.method == 'get' else 'data'
        return kind, dict(params.items())
Exemple #9
0
 def test_setdefault(self):
     cid = CaseInsensitiveDict({"Spam": "blueval"})
     assert cid.setdefault("spam", "notblueval") == "blueval"
     assert cid.setdefault("notspam", "notblueval") == "notblueval"
 def test_setdefault(self):
     cid = CaseInsensitiveDict({'Spam': 'blueval'})
     assert cid.setdefault('spam', 'notblueval') == 'blueval'
     assert cid.setdefault('notspam', 'notblueval') == 'notblueval'
Exemple #11
0
 def test_setdefault(self):
     cid = CaseInsensitiveDict({'Spam': 'blueval'})
     assert cid.setdefault('spam', 'notblueval') == 'blueval'
     assert cid.setdefault('notspam', 'notblueval') == 'notblueval'
Exemple #12
0
class NEB_enzyme_manager(object):
    def __init__(self, pickle_filepath=None):
        # requests.structures.CaseInsensitiveDict
        # <name>: {'product_table': ..., 'url': ..., ', 'cat_entry': ..., }
        self.Pickle_filepath = pickle_filepath
        self.Enzymes = CaseInsensitiveDict()
        if pickle_filepath:
            try:
                self.load_enzymes()
            except IOError as e:
                print("Could not load initial enzymes from %s:: %s: '%s'",
                      pickle_filepath, type(e), e)



    def get(self, name):
        """ Get enzyme by name. """
        if name in self.Enzymes:
            return self.Enzymes[name]
        url = self.search_product_url(name)
        if url:
            return self.Enzymes[name]

    def search_product_url(self, name):
        """ Search NEB website for product with name <name> and return product page url. """
        if self.Enzymes.get(name) and self.Enzymes[name].get('url'):
            return self.Enzymes[name]['url']
        url = neb_search_product_url(name)
        if url:
            self.Enzymes.setdefault(name, {})['url'] = url
        return url

    def get_product_table(self, name, entryid=None):
        """ Get product table for enzyma <name> """
        if self.Enzymes.get(name) and self.Enzymes[name].get('product_table'):
            return self.Enzymes[name]['product_table']
        if entryid:
            table = product_table(entryid)
        else:
            product_url = self.search_product_url(name)
            if not product_url:
                print("Could not find product name", name)
                return
            table = product_table(product_url)
        # Save and return
        self.Enzymes.setdefault(name, {})['product_table'] = table
        return table

    def get_price(self, name):
        """ Return price of <name> (using the first row in product table) """
        pt = self.get_product_table(name)
        return pt[0]['Price']

    def get_catno(self, name):
        """ Return price of <name> (using the first row in product table) """
        pt = self.get_product_table(name)
        return pt[0]['Catalog #']

    def get_size(self, name):
        """ Return price of <name> (using the first row in product table) """
        pt = self.get_product_table(name)
        return pt[0]['Size']

    def get_unit_price(self, name):
        """ Return unit price as $/unit """
        if self.Enzymes.get(name) and self.Enzymes[name].get('unit_price'):
            return self.Enzymes[name]['unit_price']
        table = self.get_product_table(name)
        up = unit_price(table)
        # Save and return
        self.Enzymes.setdefault(name, {})['unit_price'] = up
        return up

    def get_order_info_str(self, name):
        """ Return a standard price/order string for enzyme <name>. """
        return " {:7}: {:<6} ({}, {} for {}, {})"\
               .format(name, self.get_unit_price(name), self.get_catno(name),
                       self.get_price(name), self.get_size(name),
                       self.search_product_url(name))

    def load_enzymes(self, filepath=None):
        """ Load enzymes data from filepath or self.Pickle_filepath and merge with self.Enzymes. """
        if filepath is None:
            filepath = self.Pickle_filepath
        with open(filepath, 'rb') as fd:
            enzymes = pickle.load(fd)
        self.Enzymes.update(enzymes)
        print("%s enzymes loaded from file %s" % (len(enzymes), filepath))
        self.Pickle_filepath = filepath

    def save_enzymes(self, filepath=None):
        """ Save enzymes data to filepath or self.Pickle_filepath """
        if filepath is None:
            filepath = self.Pickle_filepath
        with open(filepath, 'wb') as fd:
            pickle.dump(self.Enzymes, fd)
        print("%s enzymes saved to file %s" % (len(self.Enzymes), filepath))
        self.Pickle_filepath = filepath
    def request(
        self,
        path: str,
        operation: str,
        method="GET",
        expected_status=200,
        request_kwargs: Optional[dict] = None,
        **kwargs,
    ) -> Union[List[Object], Object]:
        """
        Make the HTTP request using requests.

        The URL is created based on the path and base URL and any defaults
        from the OAS schema are injected.

        :return: a list or dict, the result of calling response.json()
        :raises: :class:`requests.HTTPException` for internal server errors
        :raises: :class:`ClientError` for HTTP 4xx status codes
        """
        url = urljoin(self.base_url, path)

        if request_kwargs:
            kwargs.update(request_kwargs)

        headers = CaseInsensitiveDict(kwargs.pop("headers", {}))
        headers.setdefault("Accept", "application/json")
        headers.setdefault("Content-Type", "application/json")
        schema_headers = get_headers(self.schema, operation)
        for header, value in schema_headers.items():
            headers.setdefault(header, value)
        if self.auth:
            headers.update(self.auth.credentials())

        kwargs["headers"] = headers

        pre_id = self.pre_request(method, url, **kwargs)

        response = requests.request(method, url, **kwargs)

        try:
            response_json = response.json()
        except Exception:
            response_json = None

        self.post_response(pre_id, response_json)

        self._log.add(
            self.service,
            url,
            method,
            dict(headers),
            copy.deepcopy(kwargs.get("data", kwargs.get("json", None))),
            response.status_code,
            dict(response.headers),
            response_json,
            params=kwargs.get("params"),
        )

        try:
            response.raise_for_status()
        except requests.HTTPError as exc:
            if response.status_code >= 500:
                raise
            raise ClientError(response_json) from exc

        assert response.status_code == expected_status, response_json
        return response_json
Exemple #14
0
class MockResponse(MagicMock):
    """Mock a response.

    This provides an object to mock a response given a real response and values
    that want to be changed. All attributes passed have priority over the real
    responses, which are used as a fallback, except when it comes to headers.
    With headers, any headers that are not set are taken from the real
    response if they exist. This is to ensure there won't be inconsistencies
    with the necessary headers.

    Recommended usage is as follows:

    1. Record the request(s) that need to be mocked via the betamax() factory
        decorator in helper.py

    2. Pass pass_recorder=True to betamax() and add a recorder argument to the
        test function

    3. The responses that you may wish to mock are available as the
        'recorded_response' attribute on the recorder's current cassette
        interaction. It's easiest to determine the interaction that you
        will need to mock via a debugger.

    The request content is determined from it's json, which is given as a
    dictionary/list. This is because all reddit api responses are valid json.
    If you must, you can set the text attribute as well, but this is only used
    if json is None.

    You can use the `as_context` method to use a context manager, or
    `as_decorator` to use this as a decorator and pass the mocked response as
    an extra argument.

    """
    def __init__(self,
                 real_response,
                 status_code=None,
                 json=None,
                 raise_for_status=None,
                 close=None,
                 reason=None,
                 cookies=None,
                 apparent_encoding=None,
                 encoding=None,
                 history=None,
                 headers=None,
                 elapsed=None,
                 _content_consumed=None,
                 parent=None,
                 text=None,
                 **kwargs):
        super(MockResponse, self).__init__(spec=real_response)
        self.real_response = real_response
        self.apparent_encoding = apparent_encoding or \
            real_response.apparent_encoding
        self.close = close or real_response.close
        self.json = (lambda: json) if json else real_response.json
        self.text = dumps(self.json()) if json else text
        self._content_consumed = _content_consumed or \
            real_response._content_consumed
        self.content = self.text.encode()
        self.parent = parent
        for k, v in kwargs.items():
            setattr(self, k, v)
        self._content = self.content
        self.history = history if history else \
            ([] or real_response.history)
        self.elapsed = elapsed if elapsed else \
            (type(real_response.elapsed)() or real_response.elapsed)
        self.cookies = cookies if cookies else \
            (type(real_response.cookies)() or real_response.cookies)
        self.encoding = encoding or real_response.encoding
        self.iter_content = iter(self.content)
        self.iter_lines = iter([self.content])
        self.raise_for_status = raise_for_status or \
            real_response.raise_for_status
        self.raw = real_response.raw
        self.status_code = status_code or real_response.status_code
        self.headers = CaseInsensitiveDict(headers) if headers else \
            CaseInsensitiveDict()
        for name, val in real_response.headers.items():
            self.headers.setdefault(name, val)
        self.reason = reason or real_response.reason
        self.is_permanent_redirect = \
            ('location' in self.headers and self.status_code in [301, 308])
        self.ok = 200 <= self.status_code < 300
        self.is_redirect = real_response.is_redirect

    @classmethod
    def in_place(cls, holder, attribute='recorded_response', *args, **kwargs):
        setattr(holder, attribute,
                cls(getattr(holder, attribute), *args, **kwargs))

    @classmethod
    def as_context(cls,
                   holder,
                   attribute='recorded_response',
                   *args,
                   **kwargs):
        class in_context(object):
            def __init__(self, holder, attribute, *args, **kwargs):
                self.holder, self.attribute, self.args, self.kwargs = \
                    holder, attribute, args, kwargs

            def __enter__(self):
                cls.in_place(self.holder, self.attribute, *self.args,
                             **self.kwargs)
                return getattr(self.holder, self.attribute)

            def __exit__(self, exc_type, exc_val, exc_trace):
                setattr(self.holder, self.attribute,
                        getattr(self.holder, self.attribute).real_response)

        return in_context(holder, attribute, *args, **kwargs)

    @classmethod
    def as_decorator(cls,
                     holder,
                     attribute='recorded_response',
                     *args,
                     **kwargs):
        def factory(func):
            @wraps(func)
            def wrapped(*a, **kw):
                with cls.as_context(holder, attribute, *args,
                                    **kwargs) as resp:
                    a = list(a)
                    a.append(resp)
                    a = tuple(a)
                    return func(*a, **kw)

            return wrapped

        return factory
Exemple #15
0
 def test_setdefault(self):
     cid = CaseInsensitiveDict({"Spam": "blueval"})
     self.assertEqual(cid.setdefault("spam", "notblueval"), "blueval")
     self.assertEqual(cid.setdefault("notspam", "notblueval"), "notblueval")