├── tests ├── __init__.py ├── unit │ ├── __init__.py │ ├── test_client.py │ └── test_utils.py └── integration │ ├── __init__.py │ └── test_api.py ├── surveymonty ├── VERSION ├── versions │ ├── __init__.py │ └── v3.json ├── __init__.py ├── constants.py ├── exceptions.py ├── utils.py └── client.py ├── .env ├── nose2.cfg ├── requirements.txt ├── MANIFEST.in ├── setup.cfg ├── Makefile ├── setup.py ├── .gitignore ├── LICENSE.md ├── CHANGELOG.md └── README.md /tests/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/unit/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /surveymonty/VERSION: -------------------------------------------------------------------------------- 1 | 0.2.5 2 | -------------------------------------------------------------------------------- /surveymonty/versions/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/integration/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.env: -------------------------------------------------------------------------------- 1 | source ./venv/bin/activate 2 | -------------------------------------------------------------------------------- /nose2.cfg: -------------------------------------------------------------------------------- 1 | [log-capture] 2 | always-on = True 3 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | nose2>=0.6.5,<1.0 2 | requests>=2.12.4,<3.0 3 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include surveymonty/VERSION 2 | include surveymonty/versions/*.json 3 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [metadata] 2 | description-file = README.md 3 | 4 | [wheel] 5 | universal = 1 6 | -------------------------------------------------------------------------------- /surveymonty/__init__.py: -------------------------------------------------------------------------------- 1 | import pkg_resources 2 | 3 | from .client import Client 4 | 5 | 6 | __version__ = pkg_resources.resource_string( 7 | 'surveymonty', 'VERSION' 8 | ).decode('utf-8').strip() 9 | -------------------------------------------------------------------------------- /surveymonty/constants.py: -------------------------------------------------------------------------------- 1 | """ 2 | surveymonty.constants 3 | --------------------- 4 | """ 5 | DEFAULT_HOST = 'https://api.surveymonkey.net' 6 | DEFAULT_VERSION = 'v3' 7 | VERSIONS_MODULE = 'surveymonty.versions' 8 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | venv: 2 | @which virtualenv || echo "Please install virtualenv https://virtualenv.pypa.io/en/stable" 3 | @virtualenv venv 4 | 5 | dependencies: venv 6 | @source venv/bin/activate; \ 7 | pip install -r requirements.txt 8 | 9 | integration-tests: 10 | @nose2 tests.integration 11 | 12 | unit-tests: 13 | @nose2 tests.unit 14 | 15 | deploy: 16 | @python setup.py sdist upload 17 | @python setup.py bdist_wheel upload 18 | -------------------------------------------------------------------------------- /surveymonty/exceptions.py: -------------------------------------------------------------------------------- 1 | """ 2 | surveymonty.exceptions 3 | ---------------------- 4 | """ 5 | 6 | 7 | class SurveyMontyError(Exception): 8 | """Base exception.""" 9 | pass 10 | 11 | 12 | class SurveyMontyAPIError(SurveyMontyError): 13 | """Error for non-2xx API responses.""" 14 | 15 | def __init__(self, resp, *args): 16 | super(SurveyMontyAPIError, self).__init__(resp.content, *args) 17 | self.response = resp 18 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup, find_packages 2 | 3 | 4 | with open('./surveymonty/VERSION', 'r') as version_file: 5 | version = version_file.read().strip() 6 | 7 | 8 | setup( 9 | name='surveymonty', 10 | version=version, 11 | 12 | install_requires=[ 13 | 'requests>=2.12.4,<3.0' 14 | ], 15 | 16 | packages=find_packages(), 17 | include_package_data=True, 18 | 19 | author='Andrew Shim', 20 | author_email='andrewkshim92@gmail.com', 21 | description='Python wrapper for SurveyMonkey API', 22 | license='MIT', 23 | keywords=['SurveyMonkey'], 24 | url='https://github.com/andrewkshim/SurveyMonty', 25 | ) 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Project-specific 2 | surveymonkey.config.json 3 | venv 4 | 5 | # Byte-compiled / optimized / DLL files 6 | __pycache__/ 7 | *.py[cod] 8 | 9 | # C extensions 10 | *.so 11 | 12 | # Distribution / packaging 13 | bin/ 14 | build/ 15 | develop-eggs/ 16 | dist/ 17 | eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | 27 | # Installer logs 28 | pip-log.txt 29 | pip-delete-this-directory.txt 30 | 31 | # Unit test / coverage reports 32 | .tox/ 33 | .coverage 34 | .cache 35 | nosetests.xml 36 | coverage.xml 37 | 38 | # Translations 39 | *.mo 40 | 41 | # Mr Developer 42 | .mr.developer.cfg 43 | .project 44 | .pydevproject 45 | 46 | # Rope 47 | .ropeproject 48 | 49 | # Django stuff: 50 | *.log 51 | *.pot 52 | 53 | # Sphinx documentation 54 | docs/_build/ 55 | 56 | # Vim temporary files 57 | *.swp 58 | *.swo 59 | 60 | # Mac directory file 61 | *DS_Store* 62 | 63 | # PyPI 64 | .pypirc 65 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Andrew Shim 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /tests/unit/test_client.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import surveymonty.client 3 | import surveymonty.utils as utils 4 | import unittest 5 | import unittest.mock 6 | 7 | 8 | class TestClient(unittest.TestCase): 9 | 10 | def setUp(self): 11 | self.access_token = 'stub_access_token' 12 | self.client = surveymonty.Client(self.access_token) 13 | 14 | def assert_request_mock_called(self, mock_request, method, endpoint, **kwargs): 15 | url = utils.make_url(self.client.version, endpoint) 16 | headers = utils.finalize_headers({}, self.access_token) 17 | mock_request.assert_called_once_with(method, url, headers=headers, **kwargs) 18 | 19 | def test_v3(self): 20 | config = utils.load_version_config(version='v3') 21 | for api_spec in config['endpoints']: 22 | name = api_spec['name'] 23 | endpoint = api_spec['endpoint'] 24 | url_param_names = utils.parse_url_params(endpoint) 25 | api_fn = getattr(self.client, name) 26 | 27 | with unittest.mock.patch('requests.request') as mock_request: 28 | api_fn(*url_param_names) 29 | 30 | full_endpoint = utils.make_full_endpoint( 31 | endpoint, 32 | url_param_names, 33 | url_param_names 34 | ) 35 | self.assert_request_mock_called(mock_request, api_spec['method'], full_endpoint) 36 | 37 | 38 | if __name__ == "__main__": 39 | unittest.main() 40 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # CHANGELOG 2 | 3 | 13 | 14 | ## 0.2.5 - 2016-12-22 15 | ### Added 16 | - Support for SurveyMonkey API V3. 17 | 18 | ### Deprecated 19 | - Old SurveyMonkey Client (included support for pagination). 20 | 21 | 22 | ## 0.1.19 - 2015-07-20 23 | Added version number for "requests". 24 | 25 | 26 | ## 0.1.18 - 2015-07-20 27 | - Synced version number with PyPI. 28 | - Added "requests" module to install\_requires in setup.py. 29 | 30 | 31 | ## 0.1.17 - Skipped 32 | 33 | 34 | ## 0.1.16 - 2014-03-09 35 | Bug fix. 36 | 37 | 38 | ## 0.1.15 - 2014-03-09 39 | Bug fix. 40 | 41 | 42 | ## 0.1.14 - 2014-03-09 43 | Bug fix. 44 | 45 | 46 | ## 0.1.13 - 2014-03-08 47 | Bug fix. 48 | 49 | 50 | ## 0.1.12 - 2014-03-08 51 | Changed order of arguments in `get_response`. 52 | 53 | 54 | ## 0.1.11 - 2014-02-26 55 | Updated `get_response` method to work with paged results. 56 | 57 | 58 | ## 0.1.10 - 2014-02-11 59 | Use wheel. 60 | 61 | 62 | ## 0.1.9 - 2014-02-08 63 | Bug fix. 64 | 65 | 66 | ## 0.1.8 - 2014-02-08 67 | Reattempt failed queries. 68 | 69 | 70 | ## 0.1.7 - 2014-02-06 71 | Remove print statement. 72 | 73 | 74 | ## 0.1.6 - 2014-02-06 75 | Bug fix. 76 | 77 | 78 | ## 0.1.5 - 2014-02-06 79 | Bug fix. 80 | 81 | 82 | ## 0.1.4 - 2014-02-06 83 | Input accepts numbers for IDs. 84 | 85 | 86 | ## 0.1.3 - 2014-02-06 87 | Made error handling more robust. 88 | 89 | 90 | ## 0.1.2 - 2014-02-06 91 | Bug fix. 92 | 93 | 94 | ## 0.1.1 - 2014-02-06 95 | Moved ACCESS\_TOKEN and API\_KEY access to environment variables. 96 | -------------------------------------------------------------------------------- /tests/integration/test_api.py: -------------------------------------------------------------------------------- 1 | import json 2 | import logging 3 | import os 4 | import surveymonty.client 5 | import sys 6 | import unittest 7 | 8 | 9 | def load_local_surveymonkey_config(): 10 | """ 11 | Loads your local SurveyMonkey config. This is a secret config that should 12 | contain, among other things, your access token. Do not place this config 13 | in version control. The config should be a JSON object that looks like: 14 | 15 | { 16 | "access_token": "your_access_token", 17 | "test_survey_id": "id_for_a_survey_you_created" 18 | } 19 | 20 | The file should be named "surveymonkey.config.json" and should live in the 21 | root of this repo. 22 | 23 | Returns: (dict) the config 24 | """ 25 | with open('./surveymonkey.config.json', 'r') as config: 26 | return json.load(config) 27 | 28 | 29 | class TestAPI(unittest.TestCase): 30 | """Some very basic tests against the actual SurveyMonkey API.""" 31 | 32 | def setUp(self): 33 | self.config = load_local_surveymonkey_config() 34 | self.client = surveymonty.Client(self.config['access_token']) 35 | 36 | def test_get_me(self): 37 | self.assertIsInstance(self.client.get_me(), dict) 38 | 39 | def test_get_groups(self): 40 | self.assertIsInstance(self.client.get_groups(), dict) 41 | 42 | def test_get_surveys(self): 43 | self.assertIsInstance(self.client.get_surveys(), dict) 44 | 45 | def test_get_survey(self): 46 | survey_id = self.config['test_survey_id'] 47 | survey = self.client.get_survey(survey_id) 48 | self.assertIsInstance(survey, dict) 49 | self.assertEqual(survey['id'], survey_id) 50 | 51 | 52 | if __name__ == "__main__": 53 | unittest.main() 54 | -------------------------------------------------------------------------------- /tests/unit/test_utils.py: -------------------------------------------------------------------------------- 1 | import surveymonty.utils as utils 2 | import unittest 3 | 4 | 5 | class TestClient(unittest.TestCase): 6 | 7 | def test_finalize_headers(self): 8 | stub_access_token = 'STUB_ACCESS_TOKEN' 9 | expected_headers = { 10 | 'Authorization': 'Bearer {}'.format(stub_access_token), 11 | 'Content-Type': 'application/json' 12 | } 13 | self.assertDictEqual( 14 | utils.finalize_headers({}, stub_access_token), 15 | expected_headers 16 | ) 17 | 18 | def test_clean_url_fragment(self): 19 | expected_str = 'hello' 20 | self.assertEqual(utils.clean_url_fragment('hello/'), expected_str) 21 | self.assertEqual(utils.clean_url_fragment('/hello/'), expected_str) 22 | 23 | def test_make_url(self): 24 | expected_url_a = 'https://api.surveymonkey.net/v3/endpoint' 25 | self.assertEqual(utils.make_url('v3', '/endpoint'), expected_url_a) 26 | 27 | expected_url_b = 'https://test.surveymonty.com/foo/bar' 28 | self.assertEqual( 29 | utils.make_url('foo', 'bar', host='https://test.surveymonty.com'), 30 | expected_url_b 31 | ) 32 | 33 | def test_parse_url_params(self): 34 | expected_params = ['hello', 'world'] 35 | self.assertEqual( 36 | utils.parse_url_params('/surveys/{hello}/details/{world}'), 37 | expected_params 38 | ) 39 | 40 | def test_make_full_endpoint(self): 41 | expected_endpoint = '/surveys/foo/details/bar' 42 | self.assertEqual( 43 | utils.make_full_endpoint( 44 | '/surveys/{hello}/details/{world}', 45 | ['hello', 'world'], 46 | ['foo', 'bar'] 47 | ), 48 | expected_endpoint 49 | ) 50 | 51 | def test_load_version_config(self): 52 | self.assertIsInstance(utils.load_version_config(), dict) 53 | 54 | 55 | if __name__ == "__main__": 56 | unittest.main() 57 | -------------------------------------------------------------------------------- /surveymonty/utils.py: -------------------------------------------------------------------------------- 1 | """ 2 | surveymonty.utils 3 | ----------------- 4 | """ 5 | import json 6 | import pkg_resources 7 | import re 8 | 9 | from . import constants 10 | 11 | 12 | def finalize_headers(headers, access_token): 13 | """ 14 | Args: 15 | - headers: (dict-like) HTTP headers 16 | - access_token: (str) SurveyMonkey access token 17 | 18 | Returns: (dict) headers updated with values that should be in all requests 19 | """ 20 | new_headers = dict(headers) 21 | new_headers.update({ 22 | 'Authorization': 'Bearer {}'.format(access_token), 23 | 'Content-Type': 'application/json' 24 | }) 25 | return new_headers 26 | 27 | 28 | def clean_url_fragment(f): 29 | """ 30 | Args: 31 | - f: (str) 32 | 33 | Returns: (str) 34 | """ 35 | return f.strip('/') 36 | 37 | 38 | def make_url(version, endpoint, host=constants.DEFAULT_HOST): 39 | """ 40 | Args: 41 | - version: (str) e.g. "v3" 42 | - endpoint: (str): e.g. "/surveys" 43 | 44 | Kwargs: 45 | - host: (str) e.g. "https://api.surveymonkey.net" 46 | 47 | Returns: (str) full URL to be queried 48 | """ 49 | return '{}/{}/{}'.format( 50 | clean_url_fragment(host), 51 | clean_url_fragment(version), 52 | clean_url_fragment(endpoint) 53 | ) 54 | 55 | 56 | def parse_url_params(endpoint): 57 | """ 58 | Args: 59 | - endpoint: (str) e.g. "/survey/{survey_id}" 60 | 61 | Returns: (list of str) e.g. ["survey_id"] 62 | """ 63 | return re.findall(r'{(\w+)}', endpoint) 64 | 65 | 66 | def make_full_endpoint(endpoint, url_param_names, fn_args): 67 | """ 68 | Args: 69 | - endpoint: (str) e.g. "/survey/{survey_id}" 70 | - url_param_names: (list of str) e.g. ["survey_id"] 71 | - fn_args: (list) e.g. ["id_1"] 72 | 73 | Returns: (str) the endpoint interpolated with the given args 74 | e.g. "/survey/id_1" 75 | """ 76 | url_params = { 77 | param_name: fn_args[index] 78 | for index, param_name in enumerate(url_param_names) 79 | } 80 | return endpoint.format(**url_params) 81 | 82 | 83 | def load_version_config(version=constants.DEFAULT_VERSION): 84 | """ 85 | Kwargs: 86 | - version: (str) e.g. "v3" 87 | 88 | Returns: (dict) endpoint config object for the given version 89 | """ 90 | version_filename = '{}.json'.format(version) 91 | config = pkg_resources.resource_string( 92 | constants.VERSIONS_MODULE, version_filename 93 | ).decode('utf-8') 94 | return json.loads(config) 95 | -------------------------------------------------------------------------------- /surveymonty/client.py: -------------------------------------------------------------------------------- 1 | """ 2 | surveymonty.client 3 | ------------------ 4 | """ 5 | import json 6 | import logging 7 | import requests 8 | 9 | from . import constants, utils 10 | from .exceptions import SurveyMontyAPIError 11 | 12 | 13 | _logger = logging.getLogger(__name__) 14 | 15 | 16 | class Client(object): 17 | """ 18 | Light wrapper for convenient access to the SurveyMonkey API. 19 | 20 | Args: 21 | - access_token: (str) your SurveyMonkey API access token 22 | 23 | Kwargs: 24 | - version: (str) the SurveyMonkey API version e.g. "v3" 25 | """ 26 | 27 | def __init__(self, access_token, version=constants.DEFAULT_VERSION): 28 | self.version = version 29 | 30 | config = utils.load_version_config(version) 31 | for api_spec in config['endpoints']: 32 | api_fn = self._make_api_fn(api_spec, access_token) 33 | setattr(self, api_spec['name'], api_fn) 34 | 35 | def _make_api_fn(self, api_spec, access_token): 36 | """ 37 | Args: 38 | - api_spec: (dict) the config spec for an API endpoint 39 | - access_token: (str) your SurveyMonkey API access token 40 | 41 | Returns: (function) a function that knows how to query an API endpoint 42 | """ 43 | endpoint = api_spec['endpoint'] 44 | name = api_spec['name'] 45 | url_param_names = utils.parse_url_params(endpoint) 46 | 47 | def api_fn(*args, **request_kwargs): 48 | if len(args) != len(url_param_names): 49 | msg = '{} expects {} arg(s) but received {}'.format( 50 | name, 51 | len(url_param_names), 52 | len(args) 53 | ) 54 | raise ValueError(msg) 55 | 56 | return self._request( 57 | api_spec['method'], 58 | utils.make_full_endpoint(endpoint, url_param_names, args), 59 | access_token, 60 | **request_kwargs 61 | ) 62 | 63 | api_fn.__name__ = str(name) 64 | return api_fn 65 | 66 | def _request(self, method, endpoint, access_token, **request_kwargs): 67 | """ 68 | Wrapper over requests.request. 69 | 70 | Args: 71 | - method: (str) e.g. "GET", "POST" 72 | - endpoint: (str) e.g. "/surveys" 73 | - access_token: (str) your SurveyMonkey API access token 74 | 75 | Kwargs: same as those of requests.request 76 | 77 | Returns: (dict) the JSON response for the given API endpoint 78 | """ 79 | request_kwargs['headers'] = utils.finalize_headers( 80 | request_kwargs.get('headers', {}), 81 | access_token 82 | ) 83 | url = utils.make_url(self.version, endpoint) 84 | resp = requests.request(method, url, **request_kwargs) 85 | 86 | if not resp.ok: 87 | raise SurveyMontyAPIError(resp) 88 | 89 | try: 90 | payload = resp.json() 91 | except ValueError: 92 | msg = 'unexpected SurveyMonkey API response, no JSON payload' 93 | raise SurveyMontyAPIError(resp, msg) 94 | 95 | _logger.debug('response for %s %s %r', method, endpoint, payload) 96 | return payload 97 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SurveyMonty 2 | 3 | **!!! NOTICE 2016-12-22 !!!** This project is no longer actively maintained. 4 | It will work with the latest SurveyMonkey API (v3), but there are no 5 | guarantees for later versions. This is a very light wrapper though, 6 | read through the rest of this doc and you'll have a good idea on 7 | how things work, so you'll be able to modify it yourself if you need to 😀. 8 | 9 | SurveyMonty is a Python wrapper for the SurveyMonkey API. Why the name? 10 | Because this is a wrapper in Python, and Python makes me think of 11 | [Monty Python](http://en.wikipedia.org/wiki/Monty_Python). 12 | Also, "monkey" and "Monty" both start with "mon". 13 | 14 | This content is released under the [MIT License](./LICENSE.md). 15 | 16 | 17 | # Installation 18 | ```bash 19 | $ pip install surveymonty 20 | ``` 21 | 22 | 23 | # Usage 24 | The SurveyMonty `Client` is a very lightweight wrapper over the 25 | SurveyMonkey API and only exists for minor convenience. 26 | 27 | The client requires your SurveyMonkey access token as its only argument: 28 | 29 | ```python 30 | import surveymonty 31 | 32 | client = surveymonty.Client("YOUR_ACCESS_TOKEN") 33 | ``` 34 | 35 | You should be able to find the access tokens in the Settings for 36 | your SurveyMonkey apps: https://developer.surveymonkey.com/apps 37 | 38 | The `client` has methods that correspond to the SurveyMonkey API 39 | endpoints: 40 | 41 | ```python 42 | # GET /surveys 43 | surveys = client.get_surveys() 44 | print(surveys) 45 | { 46 | 'page': 1, 47 | 'data': [ 48 | { 49 | 'id': 'FOO', 50 | 'href': 'https://api.surveymonkey.net/v3/surveys/FOO', 51 | 'nickname': '', 52 | 'title': 'FOO Survey' 53 | }, 54 | { 55 | 'id': 'BAR', 56 | 'href': 'https://api.surveymonkey.net/v3/surveys/BAR', 57 | 'nickname': '', 58 | 'title': 'BAR Survey' 59 | } 60 | ], 61 | 'total': 2, 62 | 'per_page': 50, 63 | 'links': { 64 | 'self': 'https://api.surveymonkey.net/v3/surveys?page=1&per_page=50' 65 | } 66 | } 67 | ``` 68 | 69 | You can find all of the supported API methods in the 70 | [V3 config file](./surveymonty/versions/v3.json) which drives the 71 | client. There's one entry for each endpoint e.g.: 72 | 73 | ```json 74 | { 75 | "name": "get_surveys", 76 | "method": "GET", 77 | "endpoint": "/surveys" 78 | } 79 | ``` 80 | 81 | The `name` corresponds to the method name on the `client` object, 82 | while the `method` and `endpoint` correspond to a SurveyMonkey 83 | API endpoint. 84 | 85 | For API endpoints that require URL params, you must supply the 86 | `client` method with corresponding arguments: 87 | 88 | ```python 89 | # GET /surveys/your_survey_id 90 | client.get_survey("your_survey_id") 91 | ``` 92 | 93 | To supply request body payloads or query params, you do the same 94 | as you would with the [Python requests library](http://docs.python-requests.org/en/master/user/quickstart/): 95 | 96 | ```python 97 | # GET /surveys?per_page=1 98 | client.get_surveys(params={"per_page": 1}) 99 | 100 | # POST /surveys 101 | client.create_survey(json={"title": "New Survey"}) 102 | ``` 103 | 104 | In fact, any `**kwargs` that you pass into the `client` methods 105 | will just get passed through to the `requests.request` method. 106 | 107 | 108 | # Resources 109 | - [SurveyMonkey API docs](https://developer.surveymonkey.com/api/v3/) 110 | -------------------------------------------------------------------------------- /surveymonty/versions/v3.json: -------------------------------------------------------------------------------- 1 | {"endpoints": [ 2 | { 3 | "name": "get_me", 4 | "method": "GET", 5 | "endpoint": "/users/me" 6 | }, 7 | { 8 | "name": "get_groups", 9 | "method": "GET", 10 | "endpoint": "/groups" 11 | }, 12 | { 13 | "name": "get_group", 14 | "method": "GET", 15 | "endpoint": "/groups/{group_id}" 16 | }, 17 | { 18 | "name": "get_group_members", 19 | "method": "GET", 20 | "endpoint": "/groups/{group_id}/members" 21 | }, 22 | { 23 | "name": "get_group_member", 24 | "method": "GET", 25 | "endpoint": "/groups/{group_id}/members/{member_id}" 26 | }, 27 | { 28 | "name": "get_surveys", 29 | "method": "GET", 30 | "endpoint": "/surveys" 31 | }, 32 | { 33 | "name": "create_survey", 34 | "method": "POST", 35 | "endpoint": "/surveys" 36 | }, 37 | { 38 | "name": "get_survey", 39 | "method": "GET", 40 | "endpoint": "/surveys/{survey_id}" 41 | }, 42 | { 43 | "name": "update_survey", 44 | "method": "PATCH", 45 | "endpoint": "/surveys/{survey_id}" 46 | }, 47 | { 48 | "name": "upsert_survey", 49 | "method": "PUT", 50 | "endpoint": "/surveys/{survey_id}" 51 | }, 52 | { 53 | "name": "delete_survey", 54 | "method": "DELETE", 55 | "endpoint": "/surveys/{survey_id}" 56 | }, 57 | { 58 | "name": "get_survey_details", 59 | "method": "GET", 60 | "endpoint": "/surveys/{survey_id}/details" 61 | }, 62 | { 63 | "name": "get_survey_categories", 64 | "method": "GET", 65 | "endpoint": "/survey_categories" 66 | }, 67 | { 68 | "name": "get_survey_templates", 69 | "method": "GET", 70 | "endpoint": "/survey_templates" 71 | }, 72 | { 73 | "name": "get_survey_pages", 74 | "method": "GET", 75 | "endpoint": "/surveys/{survey_id}/pages" 76 | }, 77 | { 78 | "name": "create_survey_page", 79 | "method": "POST", 80 | "endpoint": "/surveys/{survey_id}/pages" 81 | }, 82 | { 83 | "name": "get_survey_page", 84 | "method": "GET", 85 | "endpoint": "/surveys/{survey_id}/pages/{page_id}" 86 | }, 87 | { 88 | "name": "update_survey_page", 89 | "method": "PATCH", 90 | "endpoint": "/surveys/{survey_id}/pages/{page_id}" 91 | }, 92 | { 93 | "name": "upsert_survey_page", 94 | "method": "PUT", 95 | "endpoint": "/surveys/{survey_id}/pages/{page_id}" 96 | }, 97 | { 98 | "name": "delete_survey_page", 99 | "method": "DELETE", 100 | "endpoint": "/surveys/{survey_id}/pages/{page_id}" 101 | }, 102 | { 103 | "name": "get_survey_page_questions", 104 | "method": "GET", 105 | "endpoint": "/surveys/{survey_id}/pages/{page_id}/questions" 106 | }, 107 | { 108 | "name": "create_survey_page_question", 109 | "method": "POST", 110 | "endpoint": "/surveys/{survey_id}/pages/{page_id}/questions" 111 | }, 112 | { 113 | "name": "get_survey_page_question", 114 | "method": "GET", 115 | "endpoint": "/surveys/{survey_id}/pages/{page_id}/questions/{question_id}" 116 | }, 117 | { 118 | "name": "update_survey_page_question", 119 | "method": "PATCH", 120 | "endpoint": "/surveys/{survey_id}/pages/{page_id}/questions/{question_id}" 121 | }, 122 | { 123 | "name": "upsert_survey_page_question", 124 | "method": "PUT", 125 | "endpoint": "/surveys/{survey_id}/pages/{page_id}/questions/{question_id}" 126 | }, 127 | { 128 | "name": "delete_survey_page_question", 129 | "method": "DELETE", 130 | "endpoint": "/surveys/{survey_id}/pages/{page_id}/questions/{question_id}" 131 | }, 132 | { 133 | "name": "get_contact_lists", 134 | "method": "GET", 135 | "endpoint": "/contact_lists" 136 | }, 137 | { 138 | "name": "create_contact_list", 139 | "method": "POST", 140 | "endpoint": "/contact_lists" 141 | }, 142 | { 143 | "name": "get_contact_list", 144 | "method": "GET", 145 | "endpoint": "/contact_lists/{list_id}" 146 | }, 147 | { 148 | "name": "update_contact_list", 149 | "method": "PATCH", 150 | "endpoint": "/contact_lists/{list_id}" 151 | }, 152 | { 153 | "name": "upsert_contact_list", 154 | "method": "PUT", 155 | "endpoint": "/contact_lists/{list_id}" 156 | }, 157 | { 158 | "name": "delete_contact_list", 159 | "method": "DELETE", 160 | "endpoint": "/contact_lists/{list_id}" 161 | }, 162 | { 163 | "name": "copy_contact_list", 164 | "method": "POST", 165 | "endpoint": "/contact_lists/{list_id}/copy" 166 | }, 167 | { 168 | "name": "merge_contact_list", 169 | "method": "POST", 170 | "endpoint": "/contact_lists/{list_id}/merge" 171 | }, 172 | { 173 | "name": "get_contact_list_contacts", 174 | "method": "GET", 175 | "endpoint": "/contact_lists/{list_id}/contacts" 176 | }, 177 | { 178 | "name": "create_contact_list_contact", 179 | "method": "POST", 180 | "endpoint": "/contact_lists/{list_id}/contacts" 181 | }, 182 | { 183 | "name": "bulk_get_contact_list_contacts", 184 | "method": "GET", 185 | "endpoint": "/contact_lists/{list_id}/contacts/bulk" 186 | }, 187 | { 188 | "name": "bulk_create_contact_list_contacts", 189 | "method": "GET", 190 | "endpoint": "/contact_lists/{list_id}/contacts/bulk" 191 | }, 192 | { 193 | "name": "get_contacts", 194 | "method": "GET", 195 | "endpoint": "/contacts" 196 | }, 197 | { 198 | "name": "bulk_get_contacts", 199 | "method": "GET", 200 | "endpoint": "/contacts/bulk" 201 | }, 202 | { 203 | "name": "bulk_create_contacts", 204 | "method": "POST", 205 | "endpoint": "/contacts/bulk" 206 | }, 207 | { 208 | "name": "get_contact", 209 | "method": "GET", 210 | "endpoint": "/contacts/{contact_id}" 211 | }, 212 | { 213 | "name": "update_contact", 214 | "method": "PATCH", 215 | "endpoint": "/contacts/{contact_id}" 216 | }, 217 | { 218 | "name": "upsert_contact", 219 | "method": "PUT", 220 | "endpoint": "/contacts/{contact_id}" 221 | }, 222 | { 223 | "name": "delete_contact", 224 | "method": "DELETE", 225 | "endpoint": "/contacts/{contact_id}" 226 | }, 227 | { 228 | "name": "get_contact_fields", 229 | "method": "GET", 230 | "endpoint": "/contact_fields" 231 | }, 232 | { 233 | "name": "get_contact_field", 234 | "method": "GET", 235 | "endpoint": "/contact_fields/{field_id}" 236 | }, 237 | { 238 | "name": "update_contact_field", 239 | "method": "PATCH", 240 | "endpoint": "/contact_fields/{field_id}" 241 | }, 242 | { 243 | "name": "get_survey_collectors", 244 | "method": "GET", 245 | "endpoint": "/surveys/{survey_id}/collectors" 246 | }, 247 | { 248 | "name": "create_survey_collector", 249 | "method": "POST", 250 | "endpoint": "/surveys/{survey_id}/collectors" 251 | }, 252 | { 253 | "name": "get_collector", 254 | "method": "GET", 255 | "endpoint": "/collectors/{collector_id}" 256 | }, 257 | { 258 | "name": "update_collector", 259 | "method": "PATCH", 260 | "endpoint": "/collectors/{collector_id}" 261 | }, 262 | { 263 | "name": "upsert_collector", 264 | "method": "PUT", 265 | "endpoint": "/collectors/{collector_id}" 266 | }, 267 | { 268 | "name": "delete_collector", 269 | "method": "DELETE", 270 | "endpoint": "/collectors/{collector_id}" 271 | }, 272 | { 273 | "name": "get_collector_messages", 274 | "method": "GET", 275 | "endpoint": "/collectors/{collector_id}/messages" 276 | }, 277 | { 278 | "name": "create_collector_message", 279 | "method": "POST", 280 | "endpoint": "/collectors/{collector_id}/messages" 281 | }, 282 | { 283 | "name": "get_collector_message", 284 | "method": "GET", 285 | "endpoint": "/collectors/{collector_id}/messages/{message_id}" 286 | }, 287 | { 288 | "name": "update_collector_message", 289 | "method": "PATCH", 290 | "endpoint": "/collectors/{collector_id}/messages/{message_id}" 291 | }, 292 | { 293 | "name": "upsert_collector_message", 294 | "method": "PUT", 295 | "endpoint": "/collectors/{collector_id}/messages/{message_id}" 296 | }, 297 | { 298 | "name": "delete_collector_message", 299 | "method": "DELETE", 300 | "endpoint": "/collectors/{collector_id}/messages/{message_id}" 301 | }, 302 | { 303 | "name": "send_collector_message", 304 | "method": "POST", 305 | "endpoint": "/collectors/{collector_id}/messages/{message_id}/send" 306 | }, 307 | { 308 | "name": "get_collector_message_recipients", 309 | "method": "GET", 310 | "endpoint": "/collectors/{collector_id}/messages/{message_id}/recipients" 311 | }, 312 | { 313 | "name": "create_collector_message_recipient", 314 | "method": "POST", 315 | "endpoint": "/collectors/{collector_id}/messages/{message_id}/recipients" 316 | }, 317 | { 318 | "name": "bulk_create_collector_message_recipients", 319 | "method": "POST", 320 | "endpoint": "/collectors/{collector_id}/messages/{message_id}/recipients/bulk" 321 | }, 322 | { 323 | "name": "get_collector_recipients", 324 | "method": "GET", 325 | "endpoint": "/collectors/{collector_id}/recipients" 326 | }, 327 | { 328 | "name": "get_collector_recipient", 329 | "method": "GET", 330 | "endpoint": "/collectors/{collector_id}/recipients/{recipient_id}" 331 | }, 332 | { 333 | "name": "delete_collector_recipient", 334 | "method": "DELETE", 335 | "endpoint": "/collectors/{collector_id}/recipients/{recipient_id}" 336 | }, 337 | { 338 | "name": "get_survey_responses", 339 | "method": "GET", 340 | "endpoint": "/surveys/{survey_id}/responses" 341 | }, 342 | { 343 | "name": "get_collector_responses", 344 | "method": "GET", 345 | "endpoint": "/collectors/{collector_id}/responses" 346 | }, 347 | { 348 | "name": "create_collector_response", 349 | "method": "POST", 350 | "endpoint": "/collectors/{collector_id}/responses" 351 | }, 352 | { 353 | "name": "bulk_get_survey_responses", 354 | "method": "GET", 355 | "endpoint": "/surveys/{survey_id}/responses/bulk" 356 | }, 357 | { 358 | "name": "bulk_get_collector_responses", 359 | "method": "GET", 360 | "endpoint": "/collectors/{collector_id}/responses/bulk" 361 | }, 362 | { 363 | "name": "get_survey_response", 364 | "method": "GET", 365 | "endpoint": "/surveys/{survey_id}/responses/{responses_id}" 366 | }, 367 | { 368 | "name": "update_survey_response", 369 | "method": "PATCH", 370 | "endpoint": "/surveys/{survey_id}/responses/{responses_id}" 371 | }, 372 | { 373 | "name": "upsert_survey_response", 374 | "method": "PUT", 375 | "endpoint": "/surveys/{survey_id}/responses/{responses_id}" 376 | }, 377 | { 378 | "name": "delete_survey_response", 379 | "method": "DELETE", 380 | "endpoint": "/surveys/{survey_id}/responses/{responses_id}" 381 | }, 382 | { 383 | "name": "get_collector_response", 384 | "method": "GET", 385 | "endpoint": "/collectors/{collector_id}/responses/{responses_id}" 386 | }, 387 | { 388 | "name": "update_collector_response", 389 | "method": "PATCH", 390 | "endpoint": "/collectors/{collector_id}/responses/{responses_id}" 391 | }, 392 | { 393 | "name": "upsert_collector_response", 394 | "method": "PUT", 395 | "endpoint": "/collectors/{collector_id}/responses/{responses_id}" 396 | }, 397 | { 398 | "name": "delete_collector_response", 399 | "method": "DELETE", 400 | "endpoint": "/collectors/{collector_id}/responses/{responses_id}" 401 | }, 402 | { 403 | "name": "get_survey_response_details", 404 | "method": "GET", 405 | "endpoint": "/surveys/{survey_id}/responses/{responses_id}/details" 406 | }, 407 | { 408 | "name": "get_collector_response_details", 409 | "method": "GET", 410 | "endpoint": "/collectors/{collector_id}/responses/{responses_id}/details" 411 | }, 412 | { 413 | "name": "get_survey_rollups", 414 | "method": "GET", 415 | "endpoint": "/surveys/{survey_id}/rollups" 416 | }, 417 | { 418 | "name": "get_survey_page_rollups", 419 | "method": "get", 420 | "endpoint": "/surveys/{survey_id}/pages/{page_id}/rollups" 421 | }, 422 | { 423 | "name": "get_survey_page_question_rollups", 424 | "method": "GET", 425 | "endpoint": "/surveys/{survey_id}/pages/{page_id}/questions/{question_id}/rollups" 426 | }, 427 | { 428 | "name": "get_survey_trends", 429 | "method": "GET", 430 | "endpoint": "/surveys/{survey_id}/trends" 431 | }, 432 | { 433 | "name": "get_survey_page_trends", 434 | "method": "GET", 435 | "endpoint": "/surveys/{survey_id}/pages/{page_id}/trends" 436 | }, 437 | { 438 | "name": "get_survey_page_question_trends", 439 | "method": "GET", 440 | "endpoint": "/surveys/{survey_id}/pages/{page_id}/questions/{question_id}/trends" 441 | }, 442 | { 443 | "name": "get_webhooks", 444 | "method": "GET", 445 | "endpoint": "/webhooks" 446 | }, 447 | { 448 | "name": "create_webhook", 449 | "method": "POST", 450 | "endpoint": "/webhooks" 451 | }, 452 | { 453 | "name": "get_webhook", 454 | "method": "GET", 455 | "endpoint": "/webhooks/{webhook_id}" 456 | }, 457 | { 458 | "name": "update_webhook", 459 | "method": "PATCH", 460 | "endpoint": "/webhooks/{webhook_id}" 461 | }, 462 | { 463 | "name": "upsert_webhook", 464 | "method": "PUT", 465 | "endpoint": "/webhooks/{webhook_id}" 466 | }, 467 | { 468 | "name": "delete_webhook", 469 | "method": "DELETE", 470 | "endpoint": "/webhooks/{webhook_id}" 471 | }, 472 | { 473 | "name": "get_benchmark_bundles", 474 | "method": "GET", 475 | "endpoint": "/benchmark_bundles" 476 | }, 477 | { 478 | "name": "get_benchmark_bundle", 479 | "method": "GET", 480 | "endpoint": "/benchmark_bundles/{bundle_id}" 481 | }, 482 | { 483 | "name": "get_benchmark_bundle_analysis", 484 | "method": "GET", 485 | "endpoint": "/benchmark_bundles/{bundle_id}/analyze" 486 | }, 487 | { 488 | "name": "get_survey_page_question_benchmark", 489 | "method": "GET", 490 | "endpoint": "/surveys/{survey_id}/pages/{page_id}/questions/{question_id}/benchmark" 491 | }, 492 | { 493 | "name": "get_errors", 494 | "method": "GET", 495 | "endpoint": "/errors" 496 | }, 497 | { 498 | "name": "get_error", 499 | "method": "GET", 500 | "endpoint": "/errors/{error_id}" 501 | } 502 | ]} 503 | --------------------------------------------------------------------------------