diff --git a/.gitignore b/.gitignore index 3d8e15f..8ca33f9 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,6 @@ dist/ *.egg-info *~ *.geany +secret_keys.py + +.env diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..930f55f --- /dev/null +++ b/.travis.yml @@ -0,0 +1,33 @@ +language: python +python: + - 2.6 + - 2.7 +env: + global: +# MAILCHIMP_API_KEY + - secure: |- + snHmkspOZFgByMfQh6C966JOtkqsT5spgb5Frhps9jLZTOJPzEi/UxPSPdxQ + b1iSNn30lYgBVarGao5OW5iOAFea2iQurBtHtuyhOiWl+zwm6fuuD8ZHmW4R + QzdPsB5TOG9RfDC5W5+km5vNsXvFV9GhWwUoTJ0gKxJkW+WQLjE= +# MAILCHIMP_LIST_ID + - secure: |- + GjWNYY0kSA5YQXdvymWcUQA8F0uNGLiwl06htyEbY/hG0DrdfJYzYNvos/CS + 8JgdIwvSopXmQaalOEjUxL6yAupZqRgeIzyR/VZY521/Wl9ZKaoTBnufJCH1 + wuGQdb49Cg/VkQ+LlO3+02S3qOq1x8Zf4572NVEriomKt8wP9nI= +# TEST_RECIPIENT_EMAIL + - secure: |- + e3dE5DwzjvpEhLu2nO7pOIBstBe0ahS+Ugy6tzPX8kIlSLjzNIPg3GWokdw3 + rwOuyWd/iqkHOIUWPX4XrVzU08S90tMStHfbfswCnWG46+XuW9FHq7B/MpPJ + v0ePdq/BNIO2vMX5O6Ku+F/d6LWRFJkLcft9d14nV1960iVkeVA= +# MANDRILL_API_KEY + - secure: |- + KSME137xMK3VLxEpBbKoEpdUUUFlwnQglRM7hoxLgGjksQh5V++HclpvAXoq + hQ9arqmgt62Tv8W5m2vpHxoH7az6ErSP2JqykNynkoNfr8elFithBb93i9PP + 4CrSvdCV05vcDm5BRUZ2OqA2/t//DPpOxdO4emxTXMfeOz2KDTs= +install: pip install -r requirements.txt +script: nosetests -v -w tests/ --logging-filter="mailsnake" --with-cov --cov mailsnake --cov-config .coveragerc --cov-report term-missing +notifications: + email: false +branches: + only: + - master diff --git a/AUTHORS.rst b/AUTHORS.rst new file mode 100644 index 0000000..7a76774 --- /dev/null +++ b/AUTHORS.rst @@ -0,0 +1,15 @@ +This project is forked from John-Kim Murphy's original MailSnake project (which he no longer actively maintains). + +Development Lead +```````````````` + +- Mike Helmick + + +Patches and Suggestions +```````````````````````` + +- `Brad Pitcher `_ +- `vlinhart `_ +- `starenka `_, +- `Ryan Tucker `_ diff --git a/LICENSE b/LICENSE index 06021bb..0fbe963 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License -Copyright (c) 2010-2012 John-Kim Murphy +Copyright (c) 2010-2013 John-Kim Murphy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md deleted file mode 100644 index 10b37e1..0000000 --- a/README.md +++ /dev/null @@ -1,139 +0,0 @@ -MailSnake -========= - -`MailSnake` is a Python wrapper for MailChimp's The API, STS API, Export API, and the -new Mandrill API. (Now with support for Python 3) - -Installation ------------- - pip install mailsnake - -Usage ------ - -```python -from mailsnake import MailSnake -from mailsnake.exceptions import * - -ms = MailSnake('YOUR MAILCHIMP API KEY') -try: - ms.ping() # returns "Everything's Chimpy!" -except MailSnakeException: - print 'An error occurred. :(' -``` - -You can also catch specific errors: - -```python -ms = MailSnake('my_wrong_mailchimp_api_key_that_does_not_exist') -try: - ms.ping() # returns "Everything's Chimpy!" -except InvalidApiKeyException: - print 'You have a bad API key, sorry.' -``` -The default API is MCAPI, but STS, Export, and Mandrill can be used by -supplying an api argument set to 'sts', 'export', or 'mandrill' -respectively. Here's an example: - -```python -mcsts = MailSnake('YOUR MAILCHIMP API KEY', api='sts') -mcsts.GetSendQuota() # returns something like {'Max24HourSend': '10000.0', 'SentLast24Hours': '0.0', 'MaxSendRate': '5.0'} -``` - -Since the Mandrill API is divided into sections, one must take that into -account when using it. Here's an example: - -```python -mapi = MailSnake('YOUR MANDRILL API KEY', api='mandrill') -mapi.users.ping() # returns 'PONG!' -``` - -or: - -```python -mapi_users = MailSnake('YOUR MANDRILL API KEY', api='mandrill', api_section='users') -mapi_users.ping() # returns 'PONG!' -``` - -Some Mandrill functions have a dash(-) in the name. Since Python -function names can't have dashes in them, use underscores(\_) instead: - -```python -mapi = MailSnake('YOUR MANDRILL API KEY', api='mandrill') -mapi.messages.send(message={'html':'email html', 'subject':'email subject', 'from_email':'from@example.com', 'from_name':'From Name', 'to':[{'email':'to@example.com', 'name':'To Name'}]}) # returns 'PONG!' -``` - -OAuth Tokens ------------- - -You can use a MailChimp OAuth token in place of an API key, but -because MailChimp's tokens don't include the datacenter as a suffix, -you must supply it yourself (substitute an actual number for X below): - -```python -ms = MailSnake('A MAILCHIMP OAUTH TOKEN', dc='usX') -ms.ping() # returns "Everything's Chimpy!" just like with an API key -``` - -If you completed the OAuth dance as described in the -[MailChimp OAuth2 documentation](http://apidocs.mailchimp.com/oauth2/), -you should have discovered the datacenter associated with the token -when making the metadata request. - -Additional Request Options --------------------------- - -MailSnake uses [Requests](http://docs.python-requests.org/en/v1.0.0/) for -HTTP. If you require more control over how your request is made, -you may supply a dictionary as the value of `requests_opts` when -constructing an instance of `MailSnake`. This will be passed through (as -kwargs) to `requests.post()`. See the next section for an example. - -Streamed Responses ------------------- - -Since responses from the MailChimp Export API can be quite large, it is -helpful to be able to consume them in a streamed fashion. If you supply -`requests_opts={'stream': True}` when calling MailSnake, a generator is -returned that deserializes and yields each line of the streamed response -as it arrives: - -```python -from mailsnake import MailSnake - -opts = {'stream': True} -export = MailSnake('YOURAPIKEY', api='export', requests_opts=opts) -resp = export.list(id='YOURLISTID') - -lines = 0 -for list_member in resp(): - if lines > 0: # skip header row - print list_member - lines += 1 -``` - -If you are using Requests < 1.0.0, supply `{'prefetch': False}` instead of -`{'stream': True}`. - -Note ----- - -API parameters must be passed by name. For example: - -```python -mcapi.listMemberInfo(id='YOUR LIST ID', email_address='name@example.com') -``` - -API Documentation ------------------ - -Note that in order to use the STS API or Mandrill you first need to -enable the Amazon Simple Email Service or the Mandrill -[integration](https://us4.admin.mailchimp.com/account/integrations/ "MailChimp Integrations") -in MailChimp. - -[MailChimp API v1.3 documentation](http://apidocs.mailchimp.com/api/1.3/ "MCAPI v1.3 Documentation") - -[MailChimp STS API v1.0 documentation](http://apidocs.mailchimp.com/sts/1.0/ "STS API v1.0 Documentation") - -[MailChimp Export API v1.0 documentation](http://apidocs.mailchimp.com/export/1.0/ "Export API v1.0") diff --git a/README.rst b/README.rst index c03ed27..b0c06d3 100644 --- a/README.rst +++ b/README.rst @@ -1,13 +1,21 @@ MailSnake ========= +.. image:: https://badge.fury.io/py/mailsnake.png + :target: http://badge.fury.io/py/mailsnake +.. image:: https://travis-ci.org/michaelhelmick/python-mailsnake.png?branch=master + :target: https://travis-ci.org/michaelhelmick/python-mailsnake +.. image:: https://pypip.in/d/mailsnake/badge.png + :target: https://crate.io/packages/mailsnake/ + ``MailSnake`` is a Python wrapper for `MailChimp API 1.3 `_ (as well as the `STS API `_, `Export API `_, and `Mandrill API `_) (Now with support for Python 3) Installation ------------ -:: - pip install mailsnake +.. code-block:: bash + + $ pip install mailsnake Usage ----- @@ -15,7 +23,7 @@ Usage Basic Ping ~~~~~~~~~~ -:: +.. code-block:: python from mailsnake import MailSnake from mailsnake.exceptions import * @@ -29,7 +37,7 @@ Basic Ping Mandrill Ping ~~~~~~~~~~~~~ -:: +.. code-block:: python mapi = MailSnake('YOUR MANDRILL API KEY', api='mandrill') mapi.users.ping() # returns "PONG!" @@ -38,7 +46,7 @@ Mandrill Ping STS Example ~~~~~~~~~~~ -:: +.. code-block:: python mcsts = MailSnake('YOUR MAILCHIMP API KEY', api='sts') mcsts.GetSendQuota() # returns something like {'Max24HourSend': '10000.0', 'SentLast24Hours': '0.0', 'MaxSendRate': '5.0'} @@ -47,7 +55,7 @@ STS Example Catching Errors ~~~~~~~~~~~~~~~ -:: +.. code-block:: python ms = MailSnake( 'my_wrong_mailchimp_api_key_that_does_not_exist') try: @@ -60,6 +68,6 @@ Note API parameters must be passed by name. For example: -:: +.. code-block:: python ms.listMemberInfo(id='YOUR LIST ID', email_address='name@email.com') diff --git a/mailsnake/.DS_Store b/mailsnake/.DS_Store new file mode 100644 index 0000000..5008ddf Binary files /dev/null and b/mailsnake/.DS_Store differ diff --git a/mailsnake/__init__.py b/mailsnake/__init__.py index 2419c69..bd857b7 100644 --- a/mailsnake/__init__.py +++ b/mailsnake/__init__.py @@ -1,14 +1,12 @@ -from .mailsnake import * +""" +MailSnake +--------- + +MailSnake is a Python wrapper for the MailSnake API v1.3 +""" __author__ = 'John-Kim Murphy' -__credits__ = [ - 'John-Kim Murphy', - 'Michael Helmick', - 'Brad Pitcher', - 'vlinhart', - 'starenka', - 'Ryan Tucker' -] -__version__ = '1.6.1' +__version__ = '2.0.0' -__all__ = ['MailSnake'] +from .api import MailSnake +from .exceptions import * diff --git a/mailsnake/mailsnake.py b/mailsnake/api.py similarity index 58% rename from mailsnake/mailsnake.py rename to mailsnake/api.py index 4bb99cf..2a79cbf 100644 --- a/mailsnake/mailsnake.py +++ b/mailsnake/api.py @@ -1,44 +1,40 @@ -""" MailSnake """ -import collections +# -*- coding: utf-8 -*- + +""" +mailsnake.api +~~~~~~~~~~~~~ + +This module contains functionality for access to core Twitter API calls, +Twitter Authentication, and miscellaneous methods that are useful when +dealing with the Twitter API +""" + + import requests -import types -from requests.compat import basestring - -try: - import simplejson as json -except ImportError: - try: - import json - except ImportError: - try: - from django.utils import simplejson as json - except ImportError: - raise ImportError('A json library is required to use ' + \ - 'this python library. Lol, yay for ' + \ - 'being verbose. ;)') +from .compat import json, basestring +from . import __version__ from .exceptions import * +import collections +import types + class MailSnake(object): - def __init__(self, - apikey='', - extra_params=None, - api='api', - api_section='', - requests_opts={}, - dc=None): + def __init__(self, apikey='', extra_params=None, api='api', api_section='', + requests_opts=None, dc=None): """Cache API key and address. For additional control over how requests are made, supply a dictionary for requests_opts. This will be passed through to requests.post() as kwargs. """ - self.apikey = apikey ACCEPTED_APIS = ('api', 'sts', 'export', 'mandrill') if not api in ACCEPTED_APIS: raise MailSnakeException('The API "%s" is not supported.') % api self.api = api + self.apikey = apikey + self.dc = self.apikey.split('-')[1] if '-' in self.apikey else dc self.default_params = {'apikey': apikey} extra_params = extra_params or {} @@ -51,13 +47,9 @@ def __init__(self, for x in ['users', 'messages', 'tags', 'rejects', 'senders', 'urls', 'templates', 'webhooks']: setattr(self, x, MailSnake(apikey, extra_params, - api, x)) + api, x)) self.default_params.update(extra_params) - if dc: - self.dc = dc - elif '-' in self.apikey: - self.dc = self.apikey.split('-')[1] api_info = { 'api': (self.dc, '.api.', 'mailchimp', '1.3/?method='), 'sts': (self.dc, '.sts.', 'mailchimp', '1.0/'), @@ -66,11 +58,29 @@ def __init__(self, } self.api_url = 'https://%s%s%s.com/%s' % api_info[api] - self.requests_opts = requests_opts - # Handle both prefetch=False (Requests < 1.0.0) - prefetch = requests_opts.get('prefetch', True) - # and stream=True (Requests >= 1.0.0) for response streaming - self.stream = requests_opts.get('stream', not prefetch) + self.requests_opts = requests_opts or {} + default_headers = {'User-Agent': 'MailSnake v' + __version__} + if not 'headers' in self.requests_opts: + # If they didn't set any headers, set our defaults for them + self.requests_opts['headers'] = default_headers + elif 'User-Agent' not in self.requests_opts['headers']: + # If they set headers, but didn't include User-Agent.. set it for them + self.requests_opts['headers'].update(default_headers) + + if self.api == 'api' or self.api == 'mandrill': + self.requests_opts['headers'].update({'content-type': 'application/json'}) + else: + self.requests_opts['headers'].update({'content-type': 'application/x-www-form-urlencoded'}) + + self.client = requests.Session() + # Make a copy of the client args and iterate over them + # Pop out all the acceptable args at this point because they will + # Never be used again. + requests_opts_copy = self.requests_opts.copy() + for k, v in requests_opts_copy.items(): + if k in ('cert', 'headers', 'hooks', 'max_redirects', 'proxies'): + setattr(self.client, k, v) + self.requests_opts.pop(k) # Pop, pop! def __repr__(self): if self.api == 'api': @@ -103,45 +113,40 @@ def call(self, method, params=None): data = json.dumps(params) if self.api == 'api': data = requests.utils.quote(data) - headers = {'content-type':'application/json'} + elif self.api == 'export': + data = flatten_data(params) else: data = params - headers = { - 'content-type': 'application/x-www-form-urlencoded' - } try: - if self.api == 'export': - req = requests.post(url, - params=flatten_data(data), - headers=headers, - **self.requests_opts) - else: - req = requests.post(url, - data=data, - headers=headers, - **self.requests_opts) + requests_args = {} + for k, v in self.requests_opts.items(): + # Maybe this should be set as a class variable and only done once? + if k in ('timeout', 'allow_redirects', 'stream', 'verify'): + requests_args[k] = v + + req = self.client.post(url, data=data, **requests_args) except requests.exceptions.RequestException as e: raise HTTPRequestException(e.message) if req.status_code != 200: raise HTTPRequestException(req.status_code) - try: - if self.stream: - def stream(): - for line in req.iter_lines(): - # Handle byte arrays in Python 3 - line = line.decode('utf-8') - if line: - yield json.loads(line) - rsp = stream - elif self.api == 'export' and req.text.find('\n') > -1: - rsp = [json.loads(i) for i in req.text.split('\n')[0:-1]] - else: - rsp = json.loads(req.text) - except ValueError as e: - raise ParseException(e.message) + try: + if 'stream' in requests_opts: + def stream(): + for line in req.iter_lines(): + # Handle byte arrays in Python 3 + line = line.decode('utf-8') + if line: + yield json.loads(line) + rsp = stream + elif self.api == 'export' and req.text.find('\n') > -1: + rsp = [json.loads(i) for i in req.text.split('\n')[0:-1]] + else: + rsp = json.loads(req.text) + except ValueError as e: + raise ParseException(e.message) types_ = int, bool, basestring, types.FunctionType if not isinstance(rsp, types_) and 'error' in rsp and 'code' in rsp: @@ -162,6 +167,7 @@ def get(self, *args, **kwargs): return get.__get__(self) + def flatten_data(data, parent_key=''): items = [] for k, v in data.items(): diff --git a/mailsnake/compat.py b/mailsnake/compat.py new file mode 100644 index 0000000..2ebc1f9 --- /dev/null +++ b/mailsnake/compat.py @@ -0,0 +1,35 @@ +# -*- coding: utf-8 -*- + +""" +mailsnake.compat +~~~~~~~~~~~~~~~~ + +This module contains imports and declarations for seamless Python 2 and +Python 3 compatibility. +""" + +import sys + +_ver = sys.version_info + +#: Python 2.x? +is_py2 = (_ver[0] == 2) + +#: Python 3.x? +is_py3 = (_ver[0] == 3) + +try: + import simplejson as json +except ImportError: + import json + +if is_py2: + str = unicode + basestring = basestring + numeric_types = (int, long, float) + + +elif is_py3: + str = str + basestring = (str, bytes) + numeric_types = (int, float) diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..6e65da1 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,3 @@ +coverage==3.6.0 +requests==1.2.3 +nose-cov==1.6 diff --git a/setup.py b/setup.py index 2cbb6ac..c75f20f 100644 --- a/setup.py +++ b/setup.py @@ -1,28 +1,26 @@ #!/usr/bin/env python -import sys -from setuptools import setup, find_packages +from setuptools import setup -# dep sugar. -_ver = sys.version_info +__author__ = 'John-Kim Murphy' +__version__ = '2.0.0' -if _ver[0] == 2: - dep = ['simplejson', 'requests'] -elif _ver[0] == 3: - dep = ['requests'] +packages = [ + 'mailsnake', +] setup( name='mailsnake', - version='1.6.2', - description='MailChimp API v1.3, STS, Export, Mandrill wrapper for Python.', - long_description=open('README.rst').read(), - author='John-Kim Murphy', + version=__version__, + install_requires=['requests==1.2.3'], + author=__author__, + license=open('LICENSE').read(), url='https://github.com/michaelhelmick/python-mailsnake', - packages=find_packages(), - download_url='http://pypi.python.org/pypi/mailsnake/', keywords='mailsnake mailchimp api wrapper export mandrill sts 1.3 p3k', - zip_safe=True, - install_requires=dep, + description='MailChimp API v1.3, STS, Export, Mandrill wrapper for Python.', + long_description=open('README.rst').read(), + include_package_data=True, + packages=packages, py_modules=['mailsnake'], classifiers=[ 'Development Status :: 5 - Production/Stable', diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/config.py b/tests/config.py new file mode 100644 index 0000000..a44f7c0 --- /dev/null +++ b/tests/config.py @@ -0,0 +1,6 @@ +import os + +MAILCHIMP_API_KEY = os.environ.get('MAILCHIMP_API_KEY') +MAILCHIMP_LIST_ID = os.environ.get('MAILCHIMP_LIST_ID') +TEST_RECIPIENT_EMAIL = os.environ.get('TEST_RECIPIENT_EMAIL') +MANDRILL_API_KEY = os.environ.get('MANDRILL_API_KEY') diff --git a/tests/template.html b/tests/template.html new file mode 100644 index 0000000..2be6383 --- /dev/null +++ b/tests/template.html @@ -0,0 +1,478 @@ + + + + + + + + + *|MC:SUBJECT|* + + + +
+ + + + +
+ + + + + +
+ + + + + + + +
+
+ Use one or two sentences in this area to offer a teaser of your email's content. Text here will show in a preview area in some email clients. +
+
+
+ Is this email not displaying correctly?
View it in your browser. +
+
+ + +
+ + + + + + + + + + + +
+ + + + + +
+ + + + + +
+ +
+ + + + + +
+ + + + + + +
+
default content
+
+ + +
+ +
+ + + + + +
+ + + + + + + + + + + + + +
+ +
+
+
+ *|IF:LIST|* + Copyright © *|CURRENT_YEAR|* *|LIST:COMPANY|*, All rights reserved. +
+ + *|LIST:DESCRIPTION|* +
+ Our mailing address is: +
+ *|HTML:LIST_ADDRESS_HTML|* +
+ + *|ELSE:|* + + Copyright © *|CURRENT_YEAR|* *|USER:COMPANY|*, All rights reserved. +
+ Our mailing address is: +
+ *|USER:ADDRESS_HTML|* + + *|END:IF|* +
+
+
+
+
+ *|IF:REWARDS|* *|HTML:REWARDS|* *|END:IF|* +
+
+
+ +
+ + +
+ +
+
+
+
+ + diff --git a/tests/test_core.py b/tests/test_core.py new file mode 100644 index 0000000..99dbd68 --- /dev/null +++ b/tests/test_core.py @@ -0,0 +1,128 @@ +import unittest + +from collections import MutableSequence +from mailsnake import MailSnake, exceptions +from random import random + +from .config import ( + MAILCHIMP_API_KEY, MAILCHIMP_LIST_ID, TEST_RECIPIENT_EMAIL, + MANDRILL_API_KEY +) + + +class MailSnakeTestCase(unittest.TestCase): + def setUp(self): + self.mcapi = MailSnake(MAILCHIMP_API_KEY) + + def test_ping(self): + """Testing ping to MailChimp succeeds""" + print self.mcapi.ping() + assert self.mcapi.ping() == "Everything's Chimpy!" + + def test_chimp_chatter(self): + chimp_chatter = self.mcapi.chimpChatter() + # Check that the result is a list + assert isinstance(chimp_chatter, MutableSequence) + # If the list is not empty, check a few keys + if len(chimp_chatter) > 0: + assert 'message' in chimp_chatter[0].keys() + assert chimp_chatter[0]['url'].find('mailchimp') > -1 + + # Campaign Related Methods + + def test_campaign_create_delete(self): + template_id = self._add_test_template() + from_email = self.mcapi.getAccountDetails()['contact']['email'] + options = { + 'list_id': MAILCHIMP_LIST_ID, + 'subject': 'testing', + 'from_email': from_email, + 'from_name': 'Test From', + 'to_name': 'Test To', + 'template_id': template_id, + 'inline_css': True, + 'generate_text': True, + 'title': 'testing' + } + test_content = '%f' % random() + content = {'html_std_content00': test_content} + campaign_id = self.mcapi.campaignCreate( + type='regular', options=options, content=content) + assert isinstance(campaign_id, unicode) + campaign_content = self.mcapi.campaignContent(cid=campaign_id) + assert 'html' in campaign_content + assert 'text' in campaign_content + assert test_content in campaign_content['html'] + assert test_content in campaign_content['text'] + default_content = 'default content' + assert not default_content in campaign_content['html'] + assert not default_content in campaign_content['text'] + + # Clean up + assert self.mcapi.campaignDelete(cid=campaign_id) + assert self.mcapi.templateDel(id=template_id) + + # List Related Methods + + def test_lists(self): + lists = self.mcapi.lists() + assert isinstance(lists, dict) + assert 'total' in lists + assert 'data' in lists + + def test_list_activity(self): + activity = self.mcapi.listActivity(id=MAILCHIMP_LIST_ID) + assert isinstance(activity, list) + + def test_list_subscribe_unsubscribe(self): + assert self.mcapi.listSubscribe(id=MAILCHIMP_LIST_ID, email_address=TEST_RECIPIENT_EMAIL, + double_optin=False, send_welcome=False) + assert self.mcapi.listUnsubscribe(id=MAILCHIMP_LIST_ID, email_address=TEST_RECIPIENT_EMAIL, + send_goodbye=False, send_notify=False) + + # Template Related Methods + + def test_templates(self): + types = {'user': False, 'gallery': False, 'base': False} + for t_type in types: + new_types = dict(types.items() + {t_type: True}.items()) + assert t_type in self.mcapi.templates(types=new_types) + + def test_templateAddDel(self): + template_id = self._add_test_template() + assert isinstance(template_id, int) + assert self.mcapi.templateDel(id=template_id) + + def _add_test_template(self): + html = open('./template.html', 'r').read() + templates = self.mcapi.templates(inactives={'include': True}) + template_names = [t['name'] for t in templates['user']] + index = 0 + base_name = 'mailsnake_test_template' + template_name = '%s%i' % (base_name, index) + while template_name in template_names: + index += 1 + template_name = '%s%i' % (base_name, index) + return self.mcapi.templateAdd(name=template_name, html=html) + +''' +class TestExportAPI(TestMailChimp): + def setUp(self): + super(TestExportAPI, self).setUp() + self.export = MailSnake(MAILCHIMP_API_KEY, api='export') + self.export_stream = MailSnake(MAILCHIMP_API_KEY, api='export', + requests_opts={'stream': True}) + + def test_list(self): + member_list = self.export.list(id=MAILCHIMP_LIST_ID) + assert len(member_list) == 1 + self._subscribe() + member_list = self.export.list(id=MAILCHIMP_LIST_ID) + assert len(member_list) == 2 + member_list = self.export_stream.list(id=MAILCHIMP_LIST_ID) + lines = 0 + for list_member in member_list(): + if lines > 0: + assert isinstance(list_member, list) + lines += 1 +''' diff --git a/tests/test_exceptions.py b/tests/test_exceptions.py new file mode 100644 index 0000000..fafb8db --- /dev/null +++ b/tests/test_exceptions.py @@ -0,0 +1,18 @@ +from mailsnake import MailSnake, exceptions + +from .config import ( + MAILCHIMP_API_KEY, MAILCHIMP_LIST_ID, TEST_RECIPIENT_EMAIL, + MANDRILL_API_KEY +) + +import unittest + + +class MailSnakeExceptionsTestCase(unittest.TestCase): + def setUp(self): + self.mcapi = MailSnake(MAILCHIMP_API_KEY) + self.bad_mcapi = MailSnake('WRONGKEY-us1') + + def test_invalid_apikey_exception(self): + """Test passing the wrong API Key will raise an InvalidApiKeyException""" + self.assertRaises(exceptions.InvalidApiKeyException, self.bad_mcapi.lists)