class MailChimpClient(object): """ MailChimp class to communicate with the v3 API """ def __init__(self, mc_api, mc_user='******', access_token=None, enabled=True, timeout=None, request_hooks=None, request_headers=None): """ Initialize the class with your optional user_id and required api_key. If `enabled` is not True, these methods become no-ops. This is particularly useful for testing or disabling with configuration. :param mc_api: Mailchimp API key :type mc_api: :py:class:`str` :param mc_user: Mailchimp user id :type mc_user: :py:class:`str` :param access_token: The OAuth access token :type access_token: :py:class:`str` :param enabled: Whether the API should execute any requests :type enabled: :py:class:`bool` :param timeout: (optional) How long to wait for the server to send data before giving up, as a float, or a :ref:`(connect timeout, read timeout) <timeouts>` tuple. :type timeout: float or tuple :param request_hooks: (optional) Hooks for :py:func:`requests.requests`. :type request_hooks: :py:class:`dict` :param request_headers: (optional) Headers for :py:func:`requests.requests`. :type request_headers: :py:class:`dict` """ super(MailChimpClient, self).__init__() self.enabled = enabled self.timeout = timeout if access_token: self.auth = MailChimpOAuth(access_token) self.base_url = self.auth.get_base_url() + '/3.0/' elif mc_api: if not re.match(r"^[0-9a-f]{32}$", mc_api.split('-')[0]): raise ValueError( 'The API key that you have entered is not valid, did you enter a username by mistake?\n' 'The order of arguments for API key and username has reversed in 2.1.0' ) self.auth = HTTPBasicAuth(mc_user, mc_api) datacenter = mc_api.split('-').pop() self.base_url = 'https://{0}.api.mailchimp.com/3.0/'.format( datacenter) else: raise Exception( 'You must provide an OAuth access token or API key') self.request_headers = request_headers or requests.utils.default_headers( ) self.request_hooks = request_hooks or requests.hooks.default_hooks() def _make_request(self, **kwargs): _logger.info(u'{method} Request: {url}'.format(**kwargs)) if kwargs.get('json'): _logger.info('PAYLOAD: {json}'.format(**kwargs)) response = requests.request(**kwargs) _logger.info(u'{method} Response: {status} {text}'\ .format(method=kwargs['method'], status=response.status_code, text=response.text)) return response @_enabled_or_noop def _post(self, url, data=None): """ Handle authenticated POST requests :param url: The url for the endpoint including path parameters :type url: :py:class:`str` :param data: The request body parameters :type data: :py:data:`none` or :py:class:`dict` :returns: The JSON output from the API or an error message """ url = urljoin(self.base_url, url) try: r = self._make_request(**dict(method='POST', url=url, json=data, auth=self.auth, timeout=self.timeout, hooks=self.request_hooks, headers=self.request_headers)) except requests.exceptions.RequestException as e: raise e else: if r.status_code >= 400: raise MailChimpError(r.json()) if r.status_code == 204: return None return r.json() @_enabled_or_noop def _get(self, url, **queryparams): """ Handle authenticated GET requests :param url: The url for the endpoint including path parameters :type url: :py:class:`str` :param queryparams: The query string parameters :returns: The JSON output from the API """ url = urljoin(self.base_url, url) if len(queryparams): url += '?' + urlencode(queryparams) try: r = self._make_request(**dict(method='GET', url=url, auth=self.auth, timeout=self.timeout, hooks=self.request_hooks, headers=self.request_headers)) except requests.exceptions.RequestException as e: raise e else: if r.status_code >= 400: raise MailChimpError(r.json()) return r.json() @_enabled_or_noop def _delete(self, url): """ Handle authenticated DELETE requests :param url: The url for the endpoint including path parameters :type url: :py:class:`str` :returns: The JSON output from the API """ url = urljoin(self.base_url, url) try: r = self._make_request(**dict(method='DELETE', url=url, auth=self.auth, timeout=self.timeout, hooks=self.request_hooks, headers=self.request_headers)) except requests.exceptions.RequestException as e: raise e else: if r.status_code >= 400: raise MailChimpError(r.json()) if r.status_code == 204: return return r.json() @_enabled_or_noop def _patch(self, url, data=None): """ Handle authenticated PATCH requests :param url: The url for the endpoint including path parameters :type url: :py:class:`str` :param data: The request body parameters :type data: :py:data:`none` or :py:class:`dict` :returns: The JSON output from the API """ url = urljoin(self.base_url, url) try: r = self._make_request(**dict(method='PATCH', url=url, json=data, auth=self.auth, timeout=self.timeout, hooks=self.request_hooks, headers=self.request_headers)) except requests.exceptions.RequestException as e: raise e else: if r.status_code >= 400: raise MailChimpError(r.json()) return r.json() @_enabled_or_noop def _put(self, url, data=None): """ Handle authenticated PUT requests :param url: The url for the endpoint including path parameters :type url: :py:class:`str` :param data: The request body parameters :type data: :py:data:`none` or :py:class:`dict` :returns: The JSON output from the API """ url = urljoin(self.base_url, url) try: r = self._make_request(**dict(method='PUT', url=url, json=data, auth=self.auth, timeout=self.timeout, hooks=self.request_hooks, headers=self.request_headers)) except requests.exceptions.RequestException as e: raise e else: if r.status_code >= 400: raise MailChimpError(r.json()) return r.json()
class MailChimpClient(object): """ MailChimp class to communicate with the v3 API """ def __init__(self, mc_user=None, mc_secret=None, enabled=True, timeout=None, request_hooks=None, request_headers=None, access_token=None): """ Initialize the class with you user_id and secret_key. If `enabled` is not True, these methods become no-ops. This is particularly useful for testing or disabling with configuration. :param mc_user: Mailchimp user id :type mc_user: :py:class:`str` :param mc_secret: Mailchimp secret key :type mc_secret: :py:class:`str` :param enabled: Whether the API should execute any requests :type enabled: :py:class:`bool` :param timeout: (optional) How long to wait for the server to send data before giving up, as a float, or a :ref:`(connect timeout, read timeout) <timeouts>` tuple. :type timeout: float or tuple :param request_hooks: (optional) Hooks for :py:func:`requests.requests`. :type request_hooks: :py:class:`dict` :param request_headers: (optional) Headers for :py:func:`requests.requests`. :type request_headers: :py:class:`dict` :param access_token: OAuth2 access token :type enabled: :py:class:`string` """ super(MailChimpClient, self).__init__() self.enabled = enabled self.timeout = timeout if access_token: self.auth = MailchimpOAuth(access_token) try: self.base_url = self.auth.get_base_url() + '/3.0/' except requests.exceptions.RequestException: raise Exception("Failed to successfully authenticate and obtain metadata") elif mc_user and mc_secret: self.auth = HTTPBasicAuth(mc_user, mc_secret) datacenter = mc_secret.split('-').pop() self.base_url = 'https://{}.api.mailchimp.com/3.0/'.format(datacenter) else: raise Exception("You must provide either access_token or a username and api_key") self.request_headers = request_headers or requests.utils.default_headers() self.request_hooks = request_hooks or requests.hooks.default_hooks() def _make_request(self, **kwargs): _logger.info(u'{method} Request: {url}'.format(**kwargs)) # if kwargs.get('json'): # _logger.info('PAYLOAD: {json}'.format(**kwargs)) response = requests.request(**kwargs) # _logger.info(u'{method} Response: {status} {text}'\ # .format(method=kwargs['method'], status=response.status_code, text=response.text)) return response @_enabled_or_noop def _post(self, url, data=None): """ Handle authenticated POST requests :param url: The url for the endpoint including path parameters :type url: :py:class:`str` :param data: The request body parameters :type data: :py:data:`none` or :py:class:`dict` :returns: The JSON output from the API or an error message """ url = urljoin(self.base_url, url) try: r = self._make_request(**dict( method='POST', url=url, json=data, auth=self.auth, timeout=self.timeout, hooks=self.request_hooks, headers=self.request_headers )) except requests.exceptions.RequestException as e: raise e else: try: r.raise_for_status() except HTTPError: raise HTTPError(r.content) if r.status_code == 204: return None return r.json() @_enabled_or_noop def _get(self, url, **queryparams): """ Handle authenticated GET requests :param url: The url for the endpoint including path parameters :type url: :py:class:`str` :param queryparams: The query string parameters :returns: The JSON output from the API """ url = urljoin(self.base_url, url) if len(queryparams): url += '?' + urlencode(queryparams) try: r = self._make_request(**dict( method='GET', url=url, auth=self.auth, timeout=self.timeout, hooks=self.request_hooks, headers=self.request_headers )) except requests.exceptions.RequestException as e: raise e else: r.raise_for_status() return r.json() @_enabled_or_noop def _delete(self, url): """ Handle authenticated DELETE requests :param url: The url for the endpoint including path parameters :type url: :py:class:`str` :returns: The JSON output from the API """ url = urljoin(self.base_url, url) try: r = self._make_request(**dict( method='DELETE', url=url, auth=self.auth, timeout=self.timeout, hooks=self.request_hooks, headers=self.request_headers )) except requests.exceptions.RequestException as e: raise e else: r.raise_for_status() if r.status_code == 204: return return r.json() @_enabled_or_noop def _patch(self, url, data=None): """ Handle authenticated PATCH requests :param url: The url for the endpoint including path parameters :type url: :py:class:`str` :param data: The request body parameters :type data: :py:data:`none` or :py:class:`dict` :returns: The JSON output from the API """ url = urljoin(self.base_url, url) try: r = self._make_request(**dict( method='PATCH', url=url, json=data, auth=self.auth, timeout=self.timeout, hooks=self.request_hooks, headers=self.request_headers )) except requests.exceptions.RequestException as e: raise e else: r.raise_for_status() return r.json() @_enabled_or_noop def _put(self, url, data=None): """ Handle authenticated PUT requests :param url: The url for the endpoint including path parameters :type url: :py:class:`str` :param data: The request body parameters :type data: :py:data:`none` or :py:class:`dict` :returns: The JSON output from the API """ url = urljoin(self.base_url, url) try: r = self._make_request(**dict( method='PUT', url=url, json=data, auth=self.auth, timeout=self.timeout, hooks=self.request_hooks, headers=self.request_headers )) except requests.exceptions.RequestException as e: raise e else: r.raise_for_status() return r.json()