diff --git a/.gitignore b/.gitignore index 222296a..c8ea5d0 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ dist/ QualtricsAPI.egg-info setup.py pipfile.lock +build/ \ No newline at end of file diff --git a/QualtricsAPI/IDP/__init__.py b/QualtricsAPI/IDP/__init__.py new file mode 100644 index 0000000..033e6e1 --- /dev/null +++ b/QualtricsAPI/IDP/__init__.py @@ -0,0 +1,3 @@ +from .importedDataProject import * + +__all__ = ['importedDataProject'] diff --git a/QualtricsAPI/IDP/importedDataProject.py b/QualtricsAPI/IDP/importedDataProject.py new file mode 100644 index 0000000..c4b56cc --- /dev/null +++ b/QualtricsAPI/IDP/importedDataProject.py @@ -0,0 +1,494 @@ +import requests as r +import pandas as pd +from QualtricsAPI.Setup import Credentials +from QualtricsAPI.Exceptions import Qualtrics500Error, Qualtrics503Error, Qualtrics504Error, Qualtrics400Error, Qualtrics401Error, Qualtrics403Error +import zipfile +import io +import json + + +class ImportedDataProject(Credentials): + + def __init__(self, idp_source_id=None): + self.idp_source_id = idp_source_id + return + + def get_idp_schema(self, idp_id=None): + ''' This method returns a dictionary object containing the schema of the idp + ''' + assert idp_id != None or self.idp_source_id != None, 'Hey There! You need to set an ID when you instantiate the class, or pass one when you make this call.' + + # Reset the idp ID from whichever source is set - These are not standardized, so we can't check if they're good + if idp_id == None: + idp_id = self.idp_source_id + elif self.idp_source_id == None: + self.idp_source_id = idp_id + + headers, url = self.header_setup( + content_type=False, accept=True, xm=False, path=f'imported-data-projects/{self.idp_source_id}') + request = r.get(url, headers=headers) + response = request.json() + + try: + if response['meta']['httpStatus'] == '500 - Internal Server Error': + raise Qualtrics500Error('500 - Internal Server Error') + elif response['meta']['httpStatus'] == '503 - Temporary Internal Server Error': + raise Qualtrics503Error( + '503 - Temporary Internal Server Error') + elif response['meta']['httpStatus'] == '504 - Gateway Timeout': + raise Qualtrics504Error('504 - Gateway Timeout') + elif response['meta']['httpStatus'] == '400 - Bad Request': + raise Qualtrics400Error( + 'Qualtrics Error\n(Http Error: 400 - Bad Request): There was something invalid about the request.') + elif response['meta']['httpStatus'] == '401 - Unauthorized': + raise Qualtrics401Error( + 'Qualtrics Error\n(Http Error: 401 - Unauthorized): The Qualtrics API user could not be authenticated or does not have authorization to access the requested resource.') + elif response['meta']['httpStatus'] == '403 - Forbidden': + raise Qualtrics403Error( + 'Qualtrics Error\n(Http Error: 403 - Forbidden): The Qualtrics API user was authenticated and made a valid request, but is not authorized to access this requested resource.') + except (Qualtrics503Error, Qualtrics504Error) as e: + # Recursive call to handle Internal Server Errors + return self.get_idp_schema(idp_id=self.idp_source_id) + except (Qualtrics500Error, Qualtrics400Error, Qualtrics401Error, Qualtrics403Error) as e: + # Handle Authorization/Bad Request Errors + return print(e, response['meta']) + else: + + return response['meta'], response['result'] + + def add_columns_to_idp(self, idp_id=None, fields=None): + '''''' + assert idp_id != None or self.idp_source_id != None, 'Hey There! You need to set an ID when you instantiate the class, or pass one when you make this call.' + self._validate_fields(fields) + # Reset the idp ID from whichever source is set - These are not standardized, so we can't check if they're good + if idp_id == None: + idp_id = self.idp_source_id + elif self.idp_source_id == None: + self.idp_source_id = idp_id + + headers, url = self.header_setup( + content_type=True, accept=True, xm=False, path=f'imported-data-projects/{self.idp_source_id}') + payload = {"fields": fields} + request = r.post(url, json=payload, headers=headers) + response = request.json() + + try: + if response['meta']['httpStatus'] == '500 - Internal Server Error': + raise Qualtrics500Error('500 - Internal Server Error') + elif response['meta']['httpStatus'] == '503 - Temporary Internal Server Error': + raise Qualtrics503Error( + '503 - Temporary Internal Server Error') + elif response['meta']['httpStatus'] == '504 - Gateway Timeout': + raise Qualtrics504Error('504 - Gateway Timeout') + elif response['meta']['httpStatus'] == '400 - Bad Request': + raise Qualtrics400Error( + 'Qualtrics Error\n(Http Error: 400 - Bad Request): There was something invalid about the request.') + elif response['meta']['httpStatus'] == '401 - Unauthorized': + raise Qualtrics401Error( + 'Qualtrics Error\n(Http Error: 401 - Unauthorized): The Qualtrics API user could not be authenticated or does not have authorization to access the requested resource.') + elif response['meta']['httpStatus'] == '403 - Forbidden': + raise Qualtrics403Error( + 'Qualtrics Error\n(Http Error: 403 - Forbidden): The Qualtrics API user was authenticated and made a valid request, but is not authorized to access this requested resource.') + except (Qualtrics503Error, Qualtrics504Error) as e: + # Recursive call to handle Internal Server Errors + return self.add_columns_to_idp(idp_id=idp_id, fields=fields) + except (Qualtrics500Error, Qualtrics400Error, Qualtrics401Error, Qualtrics403Error) as e: + # Handle Authorization/Bad Request Errors + return print(e, response['meta']) + else: + print( + f"Successfully added columns to idp: {', '.join([field['name'] for field in fields])}") + return response['meta'] + + def add_single_record(self, idp_id=None, record=None): + ''' This method adds a single record to an IDP + + :param record: a dictionary containing key-value pairs for the data of the record to be created + :return: the result of the record creation HTTP request + ''' + assert idp_id != None or self.idp_source_id != None, 'Hey There! You need to set an ID when you instantiate the class, or pass one when you make this call.' + if record == None: + record = {} + self._validate_single_record(record) + + # Reset the idp ID from whichever source is set - These are not standardized, so we can't check if they're good + if idp_id == None: + idp_id = self.idp_source_id + elif self.idp_source_id == None: + self.idp_source_id = idp_id + + headers, url = self.header_setup( + content_type=True, accept=True, xm=False, path=f'imported-data-projects/{self.idp_source_id}/record') + request = r.post(url, json=record, headers=headers) + response = request.json() + + try: + if response['meta']['httpStatus'] == '500 - Internal Server Error': + raise Qualtrics500Error('500 - Internal Server Error') + elif response['meta']['httpStatus'] == '503 - Temporary Internal Server Error': + raise Qualtrics503Error( + '503 - Temporary Internal Server Error') + elif response['meta']['httpStatus'] == '504 - Gateway Timeout': + raise Qualtrics504Error('504 - Gateway Timeout') + elif response['meta']['httpStatus'] == '400 - Bad Request': + raise Qualtrics400Error( + 'Qualtrics Error\n(Http Error: 400 - Bad Request): There was something invalid about the request.') + elif response['meta']['httpStatus'] == '401 - Unauthorized': + raise Qualtrics401Error( + 'Qualtrics Error\n(Http Error: 401 - Unauthorized): The Qualtrics API user could not be authenticated or does not have authorization to access the requested resource.') + elif response['meta']['httpStatus'] == '403 - Forbidden': + raise Qualtrics403Error( + 'Qualtrics Error\n(Http Error: 403 - Forbidden): The Qualtrics API user was authenticated and made a valid request, but is not authorized to access this requested resource.') + except (Qualtrics503Error, Qualtrics504Error) as e: + # Recursive call to handle Internal Server Errors + return self.add_single_record(idp_id=idp_id, record=record) + except (Qualtrics500Error, Qualtrics400Error, Qualtrics401Error, Qualtrics403Error) as e: + # Handle Authorization/Bad Request Errors + return print(e, response['meta']) + else: + print( + f"Successfully added record to idp: {record}") + return response['meta'] + + def get_single_record_from_idp(self, idp_id=None, unique_field=None): + ''' Get a single record from an IDP + + ''' + assert idp_id != None or self.idp_source_id != None, 'Hey There! You need to set an ID when you instantiate the class, or pass one when you make this call.' + assert unique_field != None, "Hey there! Unique fields must not be none" + + if idp_id == None: + idp_id = self.idp_source_id + elif self.idp_source_id == None: + self.idp_source_id = idp_id + + headers, url = self.header_setup(content_type=False, accept=True, xm=False, + path=f'imported-data-projects/{self.idp_source_id}/records/{unique_field}') + request = r.get(url, headers=headers) + response = request.json() + + try: + if response['meta']['httpStatus'] == '500 - Internal Server Error': + raise Qualtrics500Error('500 - Internal Server Error') + elif response['meta']['httpStatus'] == '503 - Temporary Internal Server Error': + raise Qualtrics503Error( + '503 - Temporary Internal Server Error') + elif response['meta']['httpStatus'] == '504 - Gateway Timeout': + raise Qualtrics504Error('504 - Gateway Timeout') + elif response['meta']['httpStatus'] == '400 - Bad Request': + raise Qualtrics400Error( + 'Qualtrics Error\n(Http Error: 400 - Bad Request): There was something invalid about the request.') + elif response['meta']['httpStatus'] == '401 - Unauthorized': + raise Qualtrics401Error( + 'Qualtrics Error\n(Http Error: 401 - Unauthorized): The Qualtrics API user could not be authenticated or does not have authorization to access the requested resource.') + elif response['meta']['httpStatus'] == '403 - Forbidden': + raise Qualtrics403Error( + 'Qualtrics Error\n(Http Error: 403 - Forbidden): The Qualtrics API user was authenticated and made a valid request, but is not authorized to access this requested resource.') + except (Qualtrics503Error, Qualtrics504Error) as e: + # Recursive call to handle Internal Server Errors + return self.get_single_record_from_idp(idp_id=idp_id, unique_field=unique_field) + except (Qualtrics500Error, Qualtrics400Error, Qualtrics401Error, Qualtrics403Error) as e: + # Handle Authorization/Bad Request Errors + return print(e, response['meta']) + else: + print( + f"Successfully fetched record to idp: {unique_field}") + return response['result'] + + def delete_record_from_idp(self, idp_id=None, unique_field=None): + ''' This method takes in the key field of the IDP record to be deleted and calls the delete command + + :param unique_field: the key identifier of the record to be deleted + :return: HTTP status of response + ''' + assert idp_id != None or self.idp_source_id != None, 'Hey There! You need to set an ID when you instantiate the class, or pass one when you make this call.' + assert unique_field != None, "Hey there! Unique fields must not be none" + + if idp_id == None: + idp_id = self.idp_source_id + elif self.idp_source_id == None: + self.idp_source_id = idp_id + + headers, url = self.header_setup(content_type=False, accept=True, xm=False, + path=f'imported-data-projects/{self.idp_source_id}/records/{unique_field}') + request = r.delete(url, headers=headers) + response = request.json() + + try: + if response['meta']['httpStatus'] == '500 - Internal Server Error': + raise Qualtrics500Error('500 - Internal Server Error') + elif response['meta']['httpStatus'] == '503 - Temporary Internal Server Error': + raise Qualtrics503Error( + '503 - Temporary Internal Server Error') + elif response['meta']['httpStatus'] == '504 - Gateway Timeout': + raise Qualtrics504Error('504 - Gateway Timeout') + elif response['meta']['httpStatus'] == '400 - Bad Request': + raise Qualtrics400Error( + 'Qualtrics Error\n(Http Error: 400 - Bad Request): There was something invalid about the request.') + elif response['meta']['httpStatus'] == '401 - Unauthorized': + raise Qualtrics401Error( + 'Qualtrics Error\n(Http Error: 401 - Unauthorized): The Qualtrics API user could not be authenticated or does not have authorization to access the requested resource.') + elif response['meta']['httpStatus'] == '403 - Forbidden': + raise Qualtrics403Error( + 'Qualtrics Error\n(Http Error: 403 - Forbidden): The Qualtrics API user was authenticated and made a valid request, but is not authorized to access this requested resource.') + except (Qualtrics503Error, Qualtrics504Error) as e: + # Recursive call to handle Internal Server Errors + return self.delete_record_from_idp(idp_id=idp_id, unique_field=unique_field) + except (Qualtrics500Error, Qualtrics400Error, Qualtrics401Error, Qualtrics403Error) as e: + # Handle Authorization/Bad Request Errors + return print(e, response['meta']) + else: + print( + f"Successfully deleted record from idp: {unique_field}") + return response['meta'] + + def add_many_records(self, idp_id=None, records=None): + ''' + + ''' + assert idp_id != None or self.idp_source_id != None, 'Hey There! You need to set an ID when you instantiate the class, or pass one when you make this call.' + if records == None: + records = [{}] + for record in records: + self._validate_single_record(record) + + # Reset the idp ID from whichever source is set - These are not standardized, so we can't check if they're good + if idp_id == None: + idp_id = self.idp_source_id + elif self.idp_source_id == None: + self.idp_source_id = idp_id + + headers, url = self.header_setup( + content_type=True, accept=True, xm=False, path=f'imported-data-projects/{self.idp_source_id}/records') + payload = {"records": records} + request = r.post(url, json=payload, headers=headers) + response = request.json() + + try: + if response['meta']['httpStatus'] == '500 - Internal Server Error': + raise Qualtrics500Error('500 - Internal Server Error') + elif response['meta']['httpStatus'] == '503 - Temporary Internal Server Error': + raise Qualtrics503Error( + '503 - Temporary Internal Server Error') + elif response['meta']['httpStatus'] == '504 - Gateway Timeout': + raise Qualtrics504Error('504 - Gateway Timeout') + elif response['meta']['httpStatus'] == '400 - Bad Request': + raise Qualtrics400Error( + 'Qualtrics Error\n(Http Error: 400 - Bad Request): There was something invalid about the request.') + elif response['meta']['httpStatus'] == '401 - Unauthorized': + raise Qualtrics401Error( + 'Qualtrics Error\n(Http Error: 401 - Unauthorized): The Qualtrics API user could not be authenticated or does not have authorization to access the requested resource.') + elif response['meta']['httpStatus'] == '403 - Forbidden': + raise Qualtrics403Error( + 'Qualtrics Error\n(Http Error: 403 - Forbidden): The Qualtrics API user was authenticated and made a valid request, but is not authorized to access this requested resource.') + except (Qualtrics503Error, Qualtrics504Error) as e: + # Recursive call to handle Internal Server Errors + return self.add_many_records(idp_id=idp_id, records=records) + except (Qualtrics500Error, Qualtrics400Error, Qualtrics401Error, Qualtrics403Error) as e: + # Handle Authorization/Bad Request Errors + return print(e, response['meta']) + else: + print( + f"Successfully added records to idp: {len(records)}") + return response['meta'] + + def setup_get_file_request(self, idp_id=None, payload=None): + ''' This method makes the initial request and returns the progress id for the file download''' + assert idp_id != None or self.idp_source_id != None, 'Hey There! You need to set an ID when you instantiate the class, or pass one when you make this call.' + + if idp_id == None: + idp_id = self.idp_source_id + elif self.idp_source_id == None: + self.idp_source_id = idp_id + # make the reqest + headers, url = self.header_setup( + content_type=True, accept=True, xm=False, path=f'imported-data-projects/{idp_id}/exports') + request = r.post(url, data=json.dumps(payload), headers=headers) + response = request.json() + print('job start response:', response) + try: + if response['meta']['httpStatus'] == '500 - Internal Server Error': + raise Qualtrics500Error('500 - Internal Server Error') + elif response['meta']['httpStatus'] == '503 - Temporary Internal Server Error': + raise Qualtrics503Error( + '503 - Temporary Internal Server Error') + elif response['meta']['httpStatus'] == '504 - Gateway Timeout': + raise Qualtrics504Error('504 - Gateway Timeout') + elif response['meta']['httpStatus'] == '400 - Bad Request': + raise Qualtrics400Error( + 'Qualtrics Error\n(Http Error: 400 - Bad Request): There was something invalid about the request.') + elif response['meta']['httpStatus'] == '401 - Unauthorized': + raise Qualtrics401Error( + 'Qualtrics Error\n(Http Error: 401 - Unauthorized): The Qualtrics API user could not be authenticated or does not have authorization to access the requested resource.') + elif response['meta']['httpStatus'] == '403 - Forbidden': + raise Qualtrics403Error( + 'Qualtrics Error\n(Http Error: 403 - Forbidden): The Qualtrics API user was authenticated and made a valid request, but is not authorized to access this requested resource.') + except (Qualtrics500Error, Qualtrics503Error, Qualtrics504Error, Qualtrics400Error, Qualtrics401Error, Qualtrics403Error) as e: + return print(e) + else: + print("START RESPONSE", response) + job_id = response['result']['jobId'] + return job_id, url+"/"+job_id, headers + + def send_get_file_request(self, idp_id=None, payload=None): + '''This method starts the request to download the IDP data''' + is_file = None + job_id, url, headers = self.setup_get_file_request( + idp_id=idp_id, payload=payload) + progress_status = "in progress" + print("jobid:", job_id) + print("url chekin", url) + while progress_status != "complete" and progress_status != "failed" and is_file is None: + check_request = r.get(url, headers=headers) + check_response = check_request.json() + print("check_response", check_response) + try: + is_file = check_response['result']['fileId'] + except KeyError: + pass + progress_status = check_response['result']['status'] + try: + if check_response['meta']['httpStatus'] == '500 - Internal Server Error': + raise Qualtrics500Error('500 - Internal Server Error') + elif check_response['meta']['httpStatus'] == '503 - Temporary Internal Server Error': + raise Qualtrics503Error( + '503 - Temporary Internal Server Error') + elif check_response['meta']['httpStatus'] == '504 - Gateway Timeout': + raise Qualtrics504Error('504 - Gateway Timeout') + elif check_response['meta']['httpStatus'] == '400 - Bad Request': + raise Qualtrics400Error( + 'Qualtrics Error\n(Http Error: 400 - Bad Request): There was something invalid about the request.') + elif check_response['meta']['httpStatus'] == '401 - Unauthorized': + raise Qualtrics401Error( + 'Qualtrics Error\n(Http Error: 401 - Unauthorized): The Qualtrics API user could not be authenticated or does not have authorization to access the requested resource.') + elif check_response['meta']['httpStatus'] == '403 - Forbidden': + raise Qualtrics403Error( + 'Qualtrics Error\n(Http Error: 403 - Forbidden): The Qualtrics API user was authenticated and made a valid request, but is not authorized to access this requested resource.') + except (Qualtrics500Error, Qualtrics503Error, Qualtrics504Error, Qualtrics400Error, Qualtrics401Error, Qualtrics403Error) as e: + return print(e) + else: + download_headers, download_url = self.header_setup( + content_type=True, xm=False, accept=False, path=f"imported-data-projects/{idp_id}/exports/{is_file}/file") + download_headers['Accept'] = "application/octet-stream, application/json" + print("headers:", download_headers) + download_request = r.get( + download_url, headers=download_headers, stream=True) + print("download_request", download_request) + return download_request + + def get_idp_data(self, idp_id=None, **kwargs): + '''This function takes in the IDP ID and returns a CSV of all of the data within the IDP''' + assert idp_id != None or self.idp_source_id != None, 'Hey There! You need to set an ID when you instantiate the class, or pass one when you make this call.' + + if idp_id == None: + idp_id = self.idp_source_id + elif self.idp_source_id == None: + self.idp_source_id = idp_id + + dynamic_payload = {"format": 'csv'} + valid_keys = [ + 'formatDecimalAsComma', + 'limit', + 'newlineReplacement', + 'timeZone', + 'useLabels', + 'startDate', + 'endDate', + 'sortByLastModifiedDate', + 'fields' + ] + + for key in list(kwargs.keys()): + assert key in valid_keys, "Hey There! You can only send valid parameters: ['formatDecimalAsComma', 'limit', 'newlineReplacement', 'timeZone', 'useLabels', 'startDate', 'endDate', 'sortByLastModifiedDate', 'fields' ]" + if key == 'formatDecimalAsComma': + assert isinstance( + kwargs['formatDecimalAsComma'], bool), "Hey there! formatDecimalAsComma must be a boolean" + dynamic_payload.update({'formatDecimalAsComma': kwargs[(key)]}) + elif key == 'limit': + assert isinstance( + kwargs[key], int), "Hey there! limit must be an integer" + assert kwargs[key] > 0, "Hey there! limit must be greater than zero" + dynamic_payload.update({'limit': kwargs[key]}) + + elif key == 'newlineReplacement': + assert isinstance( + kwargs[key], str), "Hey there! newlineReplacement must be a string" + dynamic_payload.update({'newlineReplacement': kwargs[key]}) + + elif key == 'timeZone': + assert isinstance( + kwargs[key], str), "Hey there! timeZone must be a string" + dynamic_payload.update({'timeZone': kwargs[key]}) + + elif key == 'useLabels': + assert isinstance( + kwargs[key], bool), "Hey there! useLabels must be a boolean" + dynamic_payload.update({'useLabels': kwargs[key]}) + + elif key == 'startDate' or key == 'endDate': + import re + date_pattern = re.compile( + r'\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z') + assert isinstance( + kwargs[key], str), f"Hey there! {key} must be a string" + assert date_pattern.match( + kwargs[key]), f"Hey there! {key} must be a date-string formatted 'YYYY-MM-DDThh:mm:ssZ'" + dynamic_payload.update({key: kwargs[key]}) + + elif key == 'sortByLastModifiedDate': + assert isinstance( + kwargs[key], bool), "Hey there! sortByLastModifiedDate must be a boolean" + dynamic_payload.update({'sortByLastModifiedDate': kwargs[key]}) + + elif key == 'fields': + assert isinstance( + kwargs[key], list), "Hey there! fields must be a list of strings" + assert all(isinstance( + item, str) for item in kwargs[key]), "Hey there! all items in fields must be strings" + dynamic_payload.update({'fields': kwargs[key]}) + + download_request = self.send_get_file_request( + idp_id=idp_id, payload=dynamic_payload) + + with zipfile.ZipFile(io.BytesIO(download_request.content)) as survey_zip: + for s in survey_zip.infolist(): + df = pd.read_csv(survey_zip.open(s.filename)) + return df + +## private functions below here ## + + def _validate_fields(self, fields): + """ + Private method to validate the 'fields' parameter. + + :param fields: List of objects, each containing keys 'name' and 'type'. + :type fields: list + :raises AssertionError: If the fields are not valid. + """ + valid_types = {"number", "number-set", "string", + "string-set", "open-text", "date-time", "multi-answer"} + + assert isinstance(fields, list), "fields must be a list." + + for field in fields: + assert isinstance( + field, dict), "Each element in fields must be a dictionary." + assert set(field.keys()) == { + "name", "type"}, "Each dictionary must contain exactly the keys: 'name' and 'type'." + + name = field.get("name") + type_field = field.get("type") + + assert isinstance( + name, str) and name, "name must be a non-empty string." + assert isinstance( + type_field, str) and type_field in valid_types, f"type must be one of {valid_types}." + + def _validate_single_record(self, record): + assert isinstance(record, dict), "record must be a dictionary" + + for key, value in record.items(): + assert isinstance(key, str), "All keys must be strings" + assert isinstance(value, (str, int, float)), ( + "All values must be either strings, integers, or floats" + ) diff --git a/QualtricsAPI/Setup/credentials.py b/QualtricsAPI/Setup/credentials.py index e4ed653..37d6393 100644 --- a/QualtricsAPI/Setup/credentials.py +++ b/QualtricsAPI/Setup/credentials.py @@ -1,6 +1,7 @@ import numpy as np import os + class Credentials(object): ''' This class handles the setup of credentials needed to setup the Qualtrics API Authorization. Use the qualtrics_api_credentials method to create enviornment variables that will automatically populate the correct @@ -21,7 +22,7 @@ def qualtrics_api_credentials(self, token, data_center, directory_id=None): :return: Nothing explicitly, However you just create enviornment variables that will populate you HTTP Headers. ''' assert len(token) == 40, 'Hey there! It looks like your api token is a the incorrect length. It needs to be 40 characters long. Please try again.' - if directory_id: + if directory_id: assert len(directory_id) == 20, 'Hey there! It looks like your api directory ID is a the incorrect length. It needs to be 20 characters long. Please try again.' assert directory_id[:5] == 'POOL_', 'Hey there! It looks like your directory ID is incorrect. You can find the directory ID on the Qualtrics site under your account settings. Please try again.' os.environ['directory_id'] = directory_id @@ -30,21 +31,25 @@ def qualtrics_api_credentials(self, token, data_center, directory_id=None): os.environ['data_center'] = data_center return - def header_setup(self, content_type=False, xm=True, path=None): + def header_setup(self, content_type=False, xm=True, path=None, accept=False): '''This method accepts the argument content_type and returns the correct header, and base url. (Not a User-Facing Method) response => path = 'responseexports/' distributions => path = 'distributions' :param content_type: use to return json response. + :param accept: use to add accept param to header. (required for some GET requests) :return: a HTML header and base url. ''' if xm: assert os.environ['directory_id'], 'Hey there! This endpoint is only accessible for XM Directory Users . If you have access to the XM Directory, then be sure to include your directory_id when you use the qualtrics_api_credentials() method. ' - path = 'directories/{0}/'.format(os.environ['directory_id']) if xm else path + path = 'directories/{0}/'.format( + os.environ['directory_id'])+path if xm else path header = {"x-api-token": os.environ['token']} base_url = f"https://{os.environ['data_center']}.qualtrics.com/API/v3/{path}" if content_type is True: header["Content-Type"] = "application/json" + if accept is True: + header["Accept"] = "application/json" return header, base_url diff --git a/QualtricsAPI/Survey/distributions.py b/QualtricsAPI/Survey/distributions.py index c505523..725112f 100644 --- a/QualtricsAPI/Survey/distributions.py +++ b/QualtricsAPI/Survey/distributions.py @@ -1,8 +1,12 @@ import requests as r import pandas as pd from datetime import date, datetime, timedelta +from dateutil.relativedelta import relativedelta from QualtricsAPI.Setup import Credentials from QualtricsAPI.JSON import Parser +from QualtricsAPI.Exceptions import Qualtrics500Error, Qualtrics503Error, Qualtrics504Error, Qualtrics400Error, Qualtrics401Error, Qualtrics403Error +from time import sleep + class Distributions(Credentials): '''This is a child class to the credentials class and gathers information about Qualtric's Distributions.''' @@ -32,7 +36,8 @@ def set_send_date(self, weeks=0, days=0, hours=0, minutes=0, seconds=0): :type seconds: int :return: The formatted DateTime. (str) ''' - send_date = datetime.now() + timedelta(weeks=weeks, days=days, hours=hours, minutes=minutes, seconds=seconds) + send_date = datetime.now() + timedelta(weeks=weeks, days=days, + hours=hours, minutes=minutes, seconds=seconds) return date.strftime(send_date, '%Y-%m-%dT%H:%M:%SZ') def create_distribution(self, subject, reply_email, from_email, from_name, mailing_list, library, survey, message, send_date, link_type='Individual'): @@ -66,15 +71,19 @@ def create_distribution(self, subject, reply_email, from_email, from_name, maili ''' assert len(mailing_list) == 18, 'Hey, the parameter for "mailing_list" that was passed is the wrong length. It should have 18 characters.' - assert len(library) == 18, 'Hey, the parameter for "library" that was passed is the wrong length. It should have 18 characters.' - assert len(survey) == 18, 'Hey, the parameter for "survey" that was passed is the wrong length. It should have 18 characters.' - assert len(message) == 18, 'Hey, the parameter for "message" that was passed is the wrong length. It should have 18 characters.' + assert len( + library) == 18, 'Hey, the parameter for "library" that was passed is the wrong length. It should have 18 characters.' + assert len( + survey) == 18, 'Hey, the parameter for "survey" that was passed is the wrong length. It should have 18 characters.' + assert len( + message) == 18, 'Hey, the parameter for "message" that was passed is the wrong length. It should have 18 characters.' assert mailing_list[:3] == 'CG_', 'Hey there! It looks like your Mailing List ID is incorrect. You can find the Mailing List ID on the Qualtrics site under your account settings. It will begin with "CG_". Please try again.' assert survey[:3] == 'SV_', 'Hey there! It looks like your SurveyID is incorrect. You can find the SurveyID on the Qualtrics site under your account settings. It will begin with "SV_". Please try again.' assert message[:3] == 'MS_', 'Hey there! It looks like your MessageID is incorrect. You can find the MessageID by using the list messages method available in the Messages module of this Package. It will begin with "MS_". Please try again.' assert library[:3] == 'UR_' or library[:3] == 'GR_', 'Hey there! It looks like your Library ID is incorrect. You can find the Library ID on the Qualtrics site under your account settings. It will begin with "UR_" or "GR_". Please try again.' - headers, url = self.header_setup(content_type=True, xm=False, path='distributions') + headers, url = self.header_setup( + content_type=True, xm=False, path='distributions') data = { 'header': { 'fromEmail': from_email, @@ -91,8 +100,8 @@ def create_distribution(self, subject, reply_email, from_email, from_name, maili }, 'sendDate': send_date, 'message': { - 'libraryId': library, - 'messageId': message + 'libraryId': library, + 'messageId': message } } @@ -102,7 +111,8 @@ def create_distribution(self, subject, reply_email, from_email, from_name, maili distribution_id = response['result']['id'] return distribution_id except: - print(f"\nServerError: QualtricsAPI Error Code: {response['meta']['error']['errorCode']}\nQualtricsAPI Error Message: {response['meta']['error']['errorMessage']}") + print( + f"\nServerError: QualtricsAPI Error Code: {response['meta']['error']['errorCode']}\nQualtricsAPI Error Message: {response['meta']['error']['errorMessage']}") return def create_reminder(self, subject, reply_email, from_email, from_name, library, message, distribution, send_date): @@ -132,14 +142,16 @@ def create_reminder(self, subject, reply_email, from_email, from_name, library, ''' assert len(distribution) == 19, 'Hey, the parameter for "distribution" that was passed is the wrong length. It should have 19 characters.' - assert len(library) == 18, 'Hey, the parameter for "library" that was passed is the wrong length. It should have 18 characters.' - assert len(message) == 18, 'Hey, the parameter for "message" that was passed is the wrong length. It should have 18 characters.' + assert len( + library) == 18, 'Hey, the parameter for "library" that was passed is the wrong length. It should have 18 characters.' + assert len( + message) == 18, 'Hey, the parameter for "message" that was passed is the wrong length. It should have 18 characters.' assert distribution[:4] == 'EMD_', 'Hey there! It looks like your distributionID is incorrect. You can find the distributionID by using the list_distributions method in this module. It will begin with "UMD_". Please try again.' assert message[:3] == 'MS_', 'Hey there! It looks like your MessageID is incorrect. You can find the MessageID by using the list messages method available in the Messages module of this Package. It will begin with "MS_". Please try again.' assert library[:3] == 'UR_' or library[:3] == 'GR_', 'Hey there! It looks like your Library ID is incorrect. You can find the Library ID on the Qualtrics site under your account settings. It will begin with "UR_" or "GR_". Please try again.' - - headers, base_url = self.header_setup(content_type=True, xm=False, path='distributions') + headers, base_url = self.header_setup( + content_type=True, xm=False, path='distributions') url = f'{base_url}/{distribution}/reminders' data = { 'header': { @@ -150,8 +162,8 @@ def create_reminder(self, subject, reply_email, from_email, from_name, library, }, 'sendDate': send_date, 'message': { - 'libraryId': library, - 'messageId': message + 'libraryId': library, + 'messageId': message } } @@ -161,7 +173,8 @@ def create_reminder(self, subject, reply_email, from_email, from_name, library, reminder_id = response['result'] return reminder_id except: - print(f"\nServerError: QualtricsAPI Error Code: {response['meta']['error']['errorCode']}\nQualtricsAPI Error Message: {response['meta']['error']['errorMessage']}") + print( + f"\nServerError: QualtricsAPI Error Code: {response['meta']['error']['errorCode']}\nQualtricsAPI Error Message: {response['meta']['error']['errorMessage']}") return def create_thank_you(self, subject, reply_email, from_email, from_name, library, message, distribution, send_date): @@ -191,14 +204,16 @@ def create_thank_you(self, subject, reply_email, from_email, from_name, library, ''' assert len(distribution) == 19, 'Hey, the parameter for "distribution" that was passed is the wrong length. It should have 19 characters.' - assert len(library) == 18, 'Hey, the parameter for "library" that was passed is the wrong length. It should have 18 characters.' - assert len(message) == 18, 'Hey, the parameter for "message" that was passed is the wrong length. It should have 18 characters.' + assert len( + library) == 18, 'Hey, the parameter for "library" that was passed is the wrong length. It should have 18 characters.' + assert len( + message) == 18, 'Hey, the parameter for "message" that was passed is the wrong length. It should have 18 characters.' assert distribution[:4] == 'EMD_', 'Hey there! It looks like your distributionID is incorrect. You can find the distributionID by using the list_distributions method in this module. It will begin with "UMD_". Please try again.' assert message[:3] == 'MS_', 'Hey there! It looks like your MessageID is incorrect. You can find the MessageID by using the list messages method available in the Messages module of this Package. It will begin with "MS_". Please try again.' assert library[:3] == 'UR_' or library[:3] == 'GR_', 'Hey there! It looks like your Library ID is incorrect. You can find the Library ID on the Qualtrics site under your account settings. It will begin with "UR_" or "GR_". Please try again.' - - headers, base_url = self.header_setup(content_type=True, xm=False, path='distributions') + headers, base_url = self.header_setup( + content_type=True, xm=False, path='distributions') url = f'{base_url}/{distribution}/thankyous' data = { 'header': { @@ -209,8 +224,8 @@ def create_thank_you(self, subject, reply_email, from_email, from_name, library, }, 'sendDate': send_date, 'message': { - 'libraryId': library, - 'messageId': message + 'libraryId': library, + 'messageId': message } } request = r.post(url, json=data, headers=headers) @@ -219,7 +234,8 @@ def create_thank_you(self, subject, reply_email, from_email, from_name, library, thanks_id = response['result'] return thanks_id except: - print(f"\nServerError: QualtricsAPI Error Code: {response['meta']['error']['errorCode']}\nQualtricsAPI Error Message: {response['meta']['error']['errorMessage']}") + print( + f"\nServerError: QualtricsAPI Error Code: {response['meta']['error']['errorCode']}\nQualtricsAPI Error Message: {response['meta']['error']['errorMessage']}") return def list_distributions(self, survey): @@ -234,16 +250,18 @@ def list_distributions(self, survey): ''' assert survey[:3] == 'SV_', 'Hey there! It looks like your SurveyID is incorrect. You can find the SurveyID on the Qualtrics site under your account settings. It will begin with "SV_". Please try again.' - assert len(survey) == 18, 'Hey, the parameter for "survey" that was passed is the wrong length. It should have 18 characters.' + assert len( + survey) == 18, 'Hey, the parameter for "survey" that was passed is the wrong length. It should have 18 characters.' headers, base_url = self.header_setup(xm=False, path='distributions') url = f'{base_url}?surveyId={survey}' columns = ['id', 'parentDistributionId', 'ownerId', 'organizationId', 'requestStatus', 'requestType', - 'sendDate', 'createdDate', 'modifiedDate', 'headers', 'fromEmail', 'replyToEmail', 'fromName', - 'subject', 'recipients', 'mailingListId', 'contactId', 'sampleId', 'message', 'messageId', - 'messageText', 'surveyLink', 'surveyId', 'expirationDate', 'linkType', 'stats', 'sent', 'failed', - 'started', 'bounced', 'opened', 'skipped', 'finished', 'complaints', 'blocked', 'mailing_list_library_id', 'message_library_id'] + 'sendDate', 'createdDate', 'modifiedDate', 'headers', 'fromEmail', 'replyToEmail', 'fromName', + 'subject', 'recipients', 'mailingListId', 'contactId', 'sampleId', 'message', 'messageId', + 'messageText', 'surveyLink', 'surveyId', 'expirationDate', 'linkType', 'stats', 'sent', 'failed', + 'started', 'bounced', 'opened', 'skipped', 'finished', 'complaints', 'blocked', 'mailing_list_library_id', 'message_library_id'] master = pd.DataFrame(columns=columns) + def extract_distributions(url=url, master=master): request = r.get(url, headers=headers) response = request.json() @@ -252,24 +270,28 @@ def extract_distributions(url=url, master=master): dists = Parser().json_parser(response=response, keys=keys, arr=False) dist_df = pd.DataFrame(dists).transpose() dist_df.columns = keys - library_ids = Parser().json_parser(response=response, keys=['libraryId'], arr=False) - dist_df['mailing_list_library_id'] = library_ids[0][:len(dist_df)] + library_ids = Parser().json_parser( + response=response, keys=['libraryId'], arr=False) + dist_df['mailing_list_library_id'] = library_ids[0][:len( + dist_df)] dist_df['message_library_id'] = library_ids[0][len(dist_df):] - master = pd.concat([master, dist_df], sort=False).reset_index(drop=True) + master = pd.concat([master, dist_df], + sort=False).reset_index(drop=True) next_page = response['result']['nextPage'] return master, next_page else: print(response['meta']) - master, next_page = extract_distributions(url=url, master=master) + master, next_page = extract_distributions( + url=url, master=master) master, next_page = extract_distributions() if next_page == None: return master else: while next_page != None: - master, next_page = extract_distributions(url=next_page, master=master) + master, next_page = extract_distributions( + url=next_page, master=master) return master - def get_distribution(self, survey, distribution): ''' This method gives users the ability to get a specific distribution corresponding with a given survey. Given that @@ -285,7 +307,8 @@ def get_distribution(self, survey, distribution): ''' assert survey[:3] == 'SV_', 'Hey there! It looks like your SurveyID is incorrect. You can find the SurveyID on the Qualtrics site under your account settings. It will begin with "SV_". Please try again.' - assert len(survey) == 18, 'Hey, the parameter for "survey" that was passed is the wrong length. It should have 18 characters.' + assert len( + survey) == 18, 'Hey, the parameter for "survey" that was passed is the wrong length. It should have 18 characters.' assert len(distribution) == 19, 'Hey, the parameter for "distribution" that was passed is the wrong length. It should have 19 characters.' assert distribution[:4] == 'EMD_', 'Hey there! It looks like your distributionID is incorrect. You can find the distributionID by using the list_distributions method in this module. It will begin with "UMD_". Please try again.' @@ -296,19 +319,21 @@ def get_distribution(self, survey, distribution): response = request.json() keys = ['id', 'parentDistributionId', 'ownerId', 'organizationId', 'requestStatus', 'requestType', 'sendDate', 'createdDate', 'modifiedDate', 'headers', 'fromEmail', 'replyToEmail', 'fromName', - 'subject', 'recipients', 'mailingListId', 'contactId', 'sampleId', 'message', 'messageId', - 'messageText', 'surveyLink', 'surveyId', 'expirationDate', 'linkType', 'stats', 'sent', 'failed', - 'started', 'bounced', 'opened', 'skipped', 'finished', 'complaints', 'blocked'] + 'subject', 'recipients', 'mailingListId', 'contactId', 'sampleId', 'message', 'messageId', + 'messageText', 'surveyLink', 'surveyId', 'expirationDate', 'linkType', 'stats', 'sent', 'failed', + 'started', 'bounced', 'opened', 'skipped', 'finished', 'complaints', 'blocked'] dists = Parser().json_parser(response=response, keys=keys, arr=False) dist_df = pd.DataFrame(dists) dist_df.index = keys - library_ids = Parser().json_parser(response=response, keys=['libraryId'], arr=False) - lib = pd.DataFrame(library_ids[0], index=['mailing_list_library_id', 'message_library_id']) + library_ids = Parser().json_parser( + response=response, keys=['libraryId'], arr=False) + lib = pd.DataFrame(library_ids[0], index=[ + 'mailing_list_library_id', 'message_library_id']) dist_df = dist_df.append(lib) return dist_df except: - print(f"\nServerError: QualtricsAPI Error Code: {response['meta']['error']['errorCode']}\nQualtricsAPI Error Message: {response['meta']['error']['errorMessage']}") - + print( + f"\nServerError: QualtricsAPI Error Code: {response['meta']['error']['errorCode']}\nQualtricsAPI Error Message: {response['meta']['error']['errorMessage']}") def create_sms_distribution(self, dist_name, mailing_list, library, survey, message, send_date, parentDistributionId=None, method='Invite'): '''This method gives users the ability to create a SMS distribution for a given mailing list and survey. In order to use this method you @@ -334,15 +359,19 @@ def create_sms_distribution(self, dist_name, mailing_list, library, survey, mess ''' assert len(mailing_list) == 18, 'Hey, the parameter for "mailing_list" that was passed is the wrong length. It should have 18 characters.' - assert len(library) == 18, 'Hey, the parameter for "library" that was passed is the wrong length. It should have 18 characters.' - assert len(survey) == 18, 'Hey, the parameter for "survey" that was passed is the wrong length. It should have 18 characters.' - assert len(message) == 18, 'Hey, the parameter for "message" that was passed is the wrong length. It should have 18 characters.' + assert len( + library) == 18, 'Hey, the parameter for "library" that was passed is the wrong length. It should have 18 characters.' + assert len( + survey) == 18, 'Hey, the parameter for "survey" that was passed is the wrong length. It should have 18 characters.' + assert len( + message) == 18, 'Hey, the parameter for "message" that was passed is the wrong length. It should have 18 characters.' assert mailing_list[:3] == 'CG_', 'Hey there! It looks like your Mailing List ID is incorrect. You can find the Mailing List ID on the Qualtrics site under your account settings. It will begin with "CG_". Please try again.' assert survey[:3] == 'SV_', 'Hey there! It looks like your SurveyID is incorrect. You can find the SurveyID on the Qualtrics site under your account settings. It will begin with "SV_". Please try again.' assert message[:3] == 'MS_', 'Hey there! It looks like your MessageID is incorrect. You can find the MessageID by using the list messages method available in the Messages module of this Package. It will begin with "MS_". Please try again.' assert library[:3] == 'UR_' or library[:3] == 'GR_', 'Hey there! It looks like your Library ID is incorrect. You can find the Library ID on the Qualtrics site under your account settings. It will begin with "UR_" or "GR_". Please try again.' - headers, url = self.header_setup(content_type=True, xm=False, path='distributions/sms') + headers, url = self.header_setup( + content_type=True, xm=False, path='distributions/sms') data = { 'sendDate': send_date, 'surveyId': survey, @@ -352,13 +381,13 @@ def create_sms_distribution(self, dist_name, mailing_list, library, survey, mess }, 'name': dist_name, 'message': { - 'libraryId': library, - 'messageId': message + 'libraryId': library, + 'messageId': message } } - if parentDistributionId != None: - data['parentDistributionId'] = parentDistributionId + if parentDistributionId != None: + data['parentDistributionId'] = parentDistributionId request = r.post(url, json=data, headers=headers) response = request.json() @@ -366,5 +395,366 @@ def create_sms_distribution(self, dist_name, mailing_list, library, survey, mess distribution_id = response['result']['id'] return distribution_id except: - print(f"\nServerError: QualtricsAPI Error Code: {response['meta']['error']['errorCode']}\nQualtricsAPI Error Message: {response['meta']['error']['errorMessage']}") - return \ No newline at end of file + print( + f"\nServerError: QualtricsAPI Error Code: {response['meta']['error']['errorCode']}\nQualtricsAPI Error Message: {response['meta']['error']['errorMessage']}") + return + + def create_transaction_batch(self, transaction_ids=None): + '''Creates a transaction batch + + :param transaction_ids: List of transaction ids to be added to the batch (can be empty) + ''' + assert transaction_ids is None or (isinstance(transaction_ids, list) and all(isinstance( + id, str) for id in transaction_ids)), "transaction_ids must be a list of strings or None" + + # Create Transaction Batch + if transaction_ids == None: + transaction_ids = [] + create_tx_batch_headers, create_tx_batch_url = self.header_setup( + content_type=True, xm=True, path=f'transactionbatches') + create_tx_batch_payload = { + "transactionIds": transaction_ids, + "creationDate": datetime.now().strftime('%Y-%m-%dT%I:%M:%SZ') + } + create_tx_batch_request = r.post( + create_tx_batch_url, json=create_tx_batch_payload, headers=create_tx_batch_headers) + create_tx_batch_response = create_tx_batch_request.json() + create_tx_batch_data = self._handle_response(create_tx_batch_response) + tx_batch_id = create_tx_batch_data['id'] + return tx_batch_id + + def generate_individual_survey_link(self, survey=None, mailing_list=None, contact=None, embedded_data=None, transactional_data=None, expiration=1): + '''This function takes in a single contact and a survey and returns a unique link for that contact to take that survey. + + :param survey: Survey ID + :type survey: str (18 characters long, starts with "SV_") + :param mailing_list: Mailing list ID + :type mailing_list: str (18 characters long, starts with "CG_") + :param contact: Contact ID + :type contact: str (19 characters long, starts with "CID_") + :param embedded_data: Dictionary containing embedded data + :type embedded_data: dict (keys and values must be strings) + :param transactional_data: Dictionary containing transactional data + :type transactional_data: dict (keys and values must be strings) + :param expiration: Expiration time in months + :type expiration: int (must be greater or equal to 1) + ''' + + # Validate inputs + assert isinstance(survey, str) and len(survey) == 18 and survey.startswith( + "SV_"), "Survey must be a string of 18 characters starting with 'SV_'" + assert isinstance(mailing_list, str) and len(mailing_list) == 18 and mailing_list.startswith( + "CG_"), "Mailing list must be a string of 18 characters starting with 'CG_'" + assert isinstance(contact, str) and len(contact) == 19 and contact.startswith( + "CID_"), "Contact must be a string of 19 characters starting with 'CID_'" + assert embedded_data is None or (isinstance(embedded_data, dict) and all(isinstance(k, str) and isinstance( + v, str) for k, v in embedded_data.items())), "Embedded data must be a dictionary with string keys and values" + assert transactional_data is None or (isinstance(transactional_data, dict) and all(isinstance(k, str) and isinstance( + v, str) for k, v in transactional_data.items())), "Transactional data must be a dictionary with string keys and values" + assert isinstance( + expiration, int) and expiration >= 1, "Expiration must be an integer greater or equal to 1" + + if embedded_data == None: + embedded_data = {} + if transactional_data == None: + transactional_data = {} + + assert len( + survey) == 18, 'Hey, the parameter for "survey" that was passed is the wrong length. It should have 18 characters.' + assert survey[:3] == 'SV_', 'Hey there! It looks like your SurveyID is incorrect. You can find the SurveyID on the Qualtrics site under your account settings. It will begin with "SV_". Please try again.' + assert len(mailing_list) == 18, 'Hey, the parameter for "mailing_list" that was passed is the wrong length. It should have 18 characters.' + assert mailing_list[:3] == 'CG_', 'Hey there! It looks like your Mailing List ID is incorrect. You can find the Mailing List ID on the Qualtrics site under your account settings. It will begin with "CG_". Please try again.' + self._validate_contact_data(contact) + self._validate_embedded_data(embedded_data) + self._validate_embedded_data(transactional_data) + assert isinstance(expiration, int), "Expiration must be an integer." + assert expiration > 0, "Expiration must be greater than 0." + + # Create contact in mailing list + create_contact_headers, create_contact_url = self.header_setup( + content_type=True, xm=True, path=f"mailinglists/{mailing_list}/contacts") + if embedded_data != None: + contact['embeddedData'] = embedded_data + create_contact_request = r.post( + create_contact_url, json=contact, headers=create_contact_headers) + create_contact_response = create_contact_request.json() + cc_result = self._handle_response(create_contact_response) + contact_id = cc_result['id'] + print("Contact Created in mailing list.", contact_id) + # Create Transaction + create_tx_headers, create_tx_url = self.header_setup( + content_type=True, xm=True, path=f'transactions') + date_time_now = datetime.now().strftime('%Y-%m-%d %I:%M:%S') + tx_payload = { + "single_link_transaction": { + "contactId": contact_id, + "mailingListId": mailing_list, + "transactionDate": date_time_now, + "data": transactional_data + } + } + create_tx_request = r.post( + create_tx_url, headers=create_tx_headers, json=tx_payload) + create_tx_response = create_tx_request.json() + create_tx_data = self._handle_response(create_tx_response) + transaction_id = create_tx_data['createdTransactions']['single_link_transaction']['id'] + print("Created Transaction.", transaction_id) + # Create Transaction Batch + tx_batch_id = self.create_transaction_batch([transaction_id]) + print("Created Transaction Batch:", tx_batch_id) + link_elements = self.generate_links_from_tx_batch( + survey, mailing_list, tx_batch_id, expiration) + return link_elements[0]['link'] + + def generate_links_from_dataframe(self, survey=None, mailing_list=None, df=None, embedded_fields=[], transactional_fields=[], expiration=1): + '''This method takes in a pandas dataframe and generates links for the contacts in the dataframe. + + :param survey: Survey ID + :type survey: str (18 characters long, starts with "SV_") + :param mailing_list: Mailing list ID + :type mailing_list: str (18 characters long, starts with "CG_") + :param df: DataFrame containing contact information with at least 1 row of data. + Must contain at least one of the following columns: 'firstName', 'lastName', 'email', 'extRef', or 'language'. + :type df: pd.DataFrame + :param embedded_fields: List of strings where each string is a column name in df that should be embedded. + :type embedded_fields: list of str + :param transactional_fields: List of strings where each string is a column name in df that should be included as transactional fields. + :type transactional_fields: list of str + :param expiration: Expiration time in days. + :type expiration: int (must be greater or equal to 1) + ''' + + # Validate inputs + assert isinstance(survey, str) and len(survey) == 18 and survey.startswith( + "SV_"), "Survey must be a string of 18 characters starting with 'SV_'" + assert isinstance(mailing_list, str) and len(mailing_list) == 18 and mailing_list.startswith( + "CG_"), "Mailing list must be a string of 18 characters starting with 'CG_'" + assert isinstance(df, pd.DataFrame) and len( + df) > 0, "df must be a pandas DataFrame with at least 1 row" + assert {'firstName', 'lastName', 'email', 'extRef', 'language'}.intersection( + df.columns), "df must contain at least one of the following columns: 'firstName', 'lastName', 'email', 'extRef', or 'language'" + assert isinstance(embedded_fields, list) and all(isinstance(field, str) + for field in embedded_fields), "Embedded fields must be a list of strings" + assert all( + field in df.columns for field in embedded_fields), f"All embedded fields must match columns in df. Provided: {embedded_fields}" + assert isinstance(transactional_fields, list) and all(isinstance(field, str) + for field in transactional_fields), "Transactional fields must be a list of strings" + assert all( + field in df.columns for field in transactional_fields), f"All transactional fields must match columns in df. Provided: {transactional_fields}" + assert isinstance( + expiration, int) and expiration >= 1, "Expiration must be an integer greater or equal to 1" + + # Create TX Batch (empty) + tx_batch_id = self.create_transaction_batch([]) + # Loop through the dataframe and accumulate the contacts in a list + contacts = [] + for idx, row in df.iterrows(): + contact = self._series_to_contact_object( + row, embedded_fields, transactional_fields) + # print(contact) + contacts.append(contact) + print("number of contacts:", len(contacts)) + contact_import_payload = { + "transactionMeta": { + "batchId": tx_batch_id + }, + "contacts": contacts + } + if len(transactional_fields) > 0: + contact_import_payload['transactionMeta']['fields'] = transactional_fields + contact_headers, contact_url = self.header_setup( + content_type=True, accept=True, xm=True, path=f'mailinglists/{mailing_list}/transactioncontacts') + contact_request = r.post( + contact_url, headers=contact_headers, json=contact_import_payload) + contact_response = contact_request.json() + contact_result = self._handle_response(contact_response) + tracking_url = contact_result['tracking']['url'] + import_id = contact_result['id'] + # print("Tracking URL:", tracking_url) + print("import ID:", import_id) + processing_contacts = True + last_console_update = "" + while processing_contacts: + processing_request = r.get(tracking_url, headers=contact_headers) + processing_response = processing_request.json() + processing_result = self._handle_response(processing_response) + msg = "Processing contacts: "+str( + processing_result['percentComplete'])+"% complete" + if last_console_update != msg: + print(msg) + last_console_update = msg + if processing_result['percentComplete'] >= 100: + print("added", processing_result['contacts']['count']['added']) + print( + "updated", processing_result['contacts']['count']['updated']) + print( + "failed", processing_result['contacts']['count']['failed']) + processing_contacts = False + sleep(1.5) + # Generate links + links = self.generate_links_from_tx_batch( + survey=survey, mailing_list=mailing_list, tx_batch_id=tx_batch_id, expiration=expiration) + links_df = pd.DataFrame(links) + links_df.set_index('contactId', inplace=True) + return links_df + + def generate_links_from_tx_batch(self, survey=None, mailing_list=None, tx_batch_id=None, expiration=2): + '''This method takes in a survey and transaction batch and generates links for all contacts in that batch. + + :param survey: Survey ID + :type survey: str (18 characters long, starts with "SV_") + :param mailing_list: Mailing list ID + :type mailing_list: str (18 characters long, starts with "CG_") + :param tx_batch_id: Transaction batch ID + :type tx_batch_id: str (18 characters long, starts with "BT_") + :param expiration: Expiration time in months + :type expiration: int (must be greater or equal to 1) + ''' + + # Validate inputs + assert isinstance(survey, str) and len(survey) == 18 and survey.startswith( + "SV_"), "Survey must be a string of 18 characters starting with 'SV_'" + assert isinstance(mailing_list, str) and len(mailing_list) == 18 and mailing_list.startswith( + "CG_"), "Mailing list must be a string of 18 characters starting with 'CG_'" + assert isinstance(tx_batch_id, str) and len(tx_batch_id) == 18 and tx_batch_id.startswith( + "BT_"), "Transaction batch ID must be a string of 18 characters starting with 'BT_'" + assert isinstance( + expiration, int) and expiration >= 1, "Expiration must be an integer greater or equal to 1" + # Generate Distribution Links for TX batch + gen_dist_headers, gen_dist_url = self.header_setup( + content_type=True, xm=False, accept=False, path=f'distributions') + gen_dist_payload = { + "surveyId": survey, + "linkType": "Individual", + "description": "distribution "+datetime.now().strftime('%Y-%m-%d %I:%M:%S'), + "action": "CreateTransactionBatchdistribution", + "transactionBatchId": tx_batch_id, + "expirationDate": (datetime.now() + relativedelta(months=+expiration)).strftime('%Y-%m-%d %I:%M:%S'), + "mailingListId": mailing_list + } + gen_dist_request = r.post( + gen_dist_url, json=gen_dist_payload, headers=gen_dist_headers) + gen_dist_response = gen_dist_request.json() + gen_dist_data = self._handle_response(gen_dist_response) + distribution_id = gen_dist_data['id'] + print("Created distribution:", distribution_id) + # Fetch Distribution links + fetch_link_headers, fetch_link_url = self.header_setup( + content_type=True, xm=False, accept=False, path=f'distributions/{distribution_id}/links?surveyId={survey}') + fetch_link_request = r.get(fetch_link_url, headers=fetch_link_headers) + fetch_link_response = fetch_link_request.json() + fetch_link_data = self._handle_response(fetch_link_response) + # print(fetch_link_data['elements'][0]) + elements = fetch_link_data['elements'] + # print("Links Created.", elements) + return elements + + ## Private utility methods below here ## + + def _handle_response(self, response: dict): + try: + http_status = response['meta']['httpStatus'] + + if http_status == '500 - Internal Server Error': + raise Qualtrics500Error('500 - Internal Server Error') + elif http_status == '503 - Temporary Internal Server Error': + raise Qualtrics503Error( + '503 - Temporary Internal Server Error') + elif http_status == '504 - Gateway Timeout': + raise Qualtrics504Error('504 - Gateway Timeout') + elif http_status == '400 - Bad Request': + raise Qualtrics400Error( + 'Qualtrics Error\n(Http Error: 400 - Bad Request): There was something invalid about the request.') + elif http_status == '401 - Unauthorized': + raise Qualtrics401Error( + 'Qualtrics Error\n(Http Error: 401 - Unauthorized): The Qualtrics API user could not be authenticated or does not have authorization to access the requested resource.') + elif http_status == '403 - Forbidden': + raise Qualtrics403Error( + 'Qualtrics Error\n(Http Error: 403 - Forbidden): The Qualtrics API user was authenticated and made a valid request, but is not authorized to access this requested resource.') + + except (Qualtrics503Error, Qualtrics504Error): + # Recursive call to handle Internal Server Errors can be placed here + # Example: return self.get_survey_response(response=response) + pass # Placeholder for recursive call logic + except (Qualtrics500Error, Qualtrics400Error, Qualtrics401Error, Qualtrics403Error) as e: + # Handle Authorization/Bad Request Errors + print(e) + else: + # Return the successful response result + if 'result' in response: + return response['result'] + else: + return response['meta'] + + def _validate_contact_data(self, contact_data): + # Ensure payload is a dictionary + assert isinstance(contact_data, dict), "Payload must be a dictionary." + + # Ensure payload is not empty + assert contact_data, "Payload must have at least one field." + + valid_fields = {"firstName", "lastName", + "email", "phone", "extRef", "unsubscribed"} + for key, value in contact_data.items(): + # Ensure each field is a valid field + assert key in valid_fields, f"Invalid field '{key}' in payload." + + # Ensure 'unsubscribed' is a boolean if it exists + if key == "unsubscribed": + assert isinstance( + value, bool) or value is None, "Field 'unsubscribed' must be a boolean." + else: + # Ensure all other fields are strings or null + assert isinstance( + value, str) or value is None, f"Field '{key}' must be a string or null." + + # Ensure there is at least one non-null field + assert any(value is not None for value in contact_data.values() + ), "Payload must have at least one non-null field." + + return True + + def _validate_embedded_data(self, embedded_data): + # Ensure payload is a dictionary + assert isinstance(embedded_data, dict), "Payload must be a dictionary." + + if embedded_data: + for key, value in embedded_data.items(): + # Ensure all keys are strings + assert isinstance(key, str), f"Key '{key}' must be a string." + + # Ensure all values are either strings or numbers + assert isinstance( + value, (str, int, float)), f"Value '{value}' for key '{key}' must be a string or a number." + + return True + + def _series_to_contact_object(self, row, embedded_data_columns, transaction_data_columns): + # Initialize the contact object with requisite keys. + contact = {} + + # Root fields for the contact object + root_fields = ['firstName', 'lastName', 'email', 'extRef', 'language'] + + # Update the contact object with values from the row for root fields + for field in root_fields: + if field in row: + contact[field] = row[field] + + # Add 'embeddedData' field + embedded_data = {} + for field in embedded_data_columns: + if field in row: + if row[field] != '': + embedded_data[field] = row[field] + contact["embeddedData"] = embedded_data + + # Add 'transactionData' field + transaction_data = {} + for field in transaction_data_columns: + if field in row: + transaction_data[field] = row[field] + contact["transactionData"] = transaction_data + contact['unsubscribed'] = False + + return contact diff --git a/QualtricsAPI/Survey/responses.py b/QualtricsAPI/Survey/responses.py index 57ee02f..d9400ec 100644 --- a/QualtricsAPI/Survey/responses.py +++ b/QualtricsAPI/Survey/responses.py @@ -366,7 +366,7 @@ def get_survey_response(self, survey=None, response=None, verbose=False, verify= 'Qualtrics Error\n(Http Error: 403 - Forbidden): The Qualtrics API user was authenticated and made a valid request, but is not authorized to access this requested resource.') except (Qualtrics503Error, Qualtrics504Error) as e: # Recursive call to handle Internal Server Errors - return self.get_survey_response(self, survey=survey, response=response, verbose=verbose) + return self.get_survey_response(survey=survey, response=response, verbose=verbose) except (Qualtrics500Error, Qualtrics400Error, Qualtrics401Error, Qualtrics403Error) as e: # Handle Authorization/Bad Request Errors return print(e) @@ -409,7 +409,7 @@ def create_survey_response(self, survey=None, dynamic_payload={}, verbose=False, 'Qualtrics Error\n(Http Error: 403 - Forbidden): The Qualtrics API user was authenticated and made a valid request, but is not authorized to access this requested resource.') except (Qualtrics503Error, Qualtrics504Error) as e: # Recursive call to handle Internal Server Errors - return self.create_survey_response(self, survey=survey, dynamic_payload=dynamic_payload, verify=verify) + return self.create_survey_response(survey=survey, dynamic_payload=dynamic_payload, verify=verify) except (Qualtrics500Error, Qualtrics400Error, Qualtrics401Error, Qualtrics403Error) as e: # Handle Authorization/Bad Request Errors return print(e, response['meta']) diff --git a/QualtricsAPI/XM/mailinglists.py b/QualtricsAPI/XM/mailinglists.py index 95c8440..87b2dab 100644 --- a/QualtricsAPI/XM/mailinglists.py +++ b/QualtricsAPI/XM/mailinglists.py @@ -5,6 +5,7 @@ from QualtricsAPI.JSON import Parser from QualtricsAPI.Exceptions import Qualtrics500Error + class MailingList(Credentials): ''' This class contains methods that give users the ability to work with their users Mailing list's and their users Mailing Lists contact data within the XMDirectory.''' @@ -22,7 +23,8 @@ def create_list(self, name=None): :return: tuple containing the Mailing List's and the Mailing List's new id. ''' assert name != None, 'Hey there! The name parameter cannot be None. You need to pass in a new Mailing List name as a string into the name parameter.' - assert isinstance(name, str) == True, 'Hey there! The name parameter must be of type string.' + assert isinstance( + name, str) == True, 'Hey there! The name parameter must be of type string.' headers, base_url = self.header_setup(content_type=True, xm=True) url = f"{base_url}/mailinglists" @@ -30,10 +32,12 @@ def create_list(self, name=None): request = r.post(url, json=data, headers=headers) response = request.json() try: - list_id = Parser().json_parser(response=response, keys=['id'], arr=False)[0][0] + list_id = Parser().json_parser( + response=response, keys=['id'], arr=False)[0][0] return name, list_id except: - print(f"ServerError: {response['meta']['httpStatus']}\nError Code: {response['meta']['error']['errorCode']}\nError Message: {response['meta']['error']['errorMessage']}") + print( + f"ServerError: {response['meta']['httpStatus']}\nError Code: {response['meta']['error']['errorCode']}\nError Message: {response['meta']['error']['errorMessage']}") def list_lists(self, page_size=100): '''This method lists all the mailing lists in the directory for the specified user token. You won't typically need to adjust @@ -49,25 +53,32 @@ def list_lists(self, page_size=100): headers, base_url = self.header_setup(xm=True) url = base_url + f"/mailinglists/?pageSize={page_size}" try: - def get_page(mailing_lists=mailing_lists, url=url): - ''' This method is a nested method that extracts a single page of mailing lists. ''' - request = r.get(url, headers=headers) - response = request.json() - keys = ['mailingListId', 'name', 'ownerId', 'lastModifiedDate', 'creationDate','contactCount', 'nextPage'] - lists = Parser().json_parser(response=response, keys=keys, arr=False) - single_page = pd.DataFrame(lists).transpose() - single_page.columns = keys - single_page['creationDate'] = pd.to_datetime(single_page['creationDate'], unit='ms') - single_page['lastModifiedDate'] = pd.to_datetime(single_page['lastModifiedDate'], unit='ms') - mailing_lists = pd.concat([mailing_lists, single_page]).reset_index(drop=True) - next_page = str(response['result']['nextPage']) - return mailing_lists, next_page, response - mailing_lists, next_page, response = get_page(mailing_lists=mailing_lists, url=url) - while next_page != 'None': - mailing_lists, next_page, response = get_page(mailing_lists=mailing_lists, url=next_page) - return mailing_lists + def get_page(mailing_lists=mailing_lists, url=url): + ''' This method is a nested method that extracts a single page of mailing lists. ''' + request = r.get(url, headers=headers) + response = request.json() + keys = ['mailingListId', 'name', 'ownerId', 'lastModifiedDate', + 'creationDate', 'contactCount', 'nextPage'] + lists = Parser().json_parser(response=response, keys=keys, arr=False) + single_page = pd.DataFrame(lists).transpose() + single_page.columns = keys + single_page['creationDate'] = pd.to_datetime( + single_page['creationDate'], unit='ms') + single_page['lastModifiedDate'] = pd.to_datetime( + single_page['lastModifiedDate'], unit='ms') + mailing_lists = pd.concat( + [mailing_lists, single_page]).reset_index(drop=True) + next_page = str(response['result']['nextPage']) + return mailing_lists, next_page, response + mailing_lists, next_page, response = get_page( + mailing_lists=mailing_lists, url=url) + while next_page != 'None': + mailing_lists, next_page, response = get_page( + mailing_lists=mailing_lists, url=next_page) + return mailing_lists except: - print(f"ServerError: {response['meta']['httpStatus']}\nError Code: {response['meta']['error']['errorCode']}\nError Message: {response['meta']['error']['errorMessage']}") + print( + f"ServerError: {response['meta']['httpStatus']}\nError Code: {response['meta']['error']['errorCode']}\nError Message: {response['meta']['error']['errorMessage']}") def get_list(self, mailing_list=None): '''This function gets the list specfied by the mailing list param and returns the list members. @@ -77,7 +88,8 @@ def get_list(self, mailing_list=None): :return: A Pandas DataFrame ''' assert mailing_list != None, 'Hey there! The mailing_list parameter cannot be None. You need to pass in a Mailing List ID as a string into the mailing_list parameter.' - assert isinstance(mailing_list, str) == True, 'Hey there! The mailing_list parameter must be of type string.' + assert isinstance( + mailing_list, str) == True, 'Hey there! The mailing_list parameter must be of type string.' assert len(mailing_list) == 18, 'Hey, the parameter for "mailing_list" that was passed is the wrong length. It should have 18 characters.' assert mailing_list[:3] == 'CG_', 'Hey there! It looks like your Mailing List ID is incorrect. You can find the Mailing List ID on the Qualtrics site under your account settings. It will begin with "CG_". Please try again.' @@ -87,19 +99,21 @@ def get_list(self, mailing_list=None): response = request.json() try: list_info = { - "mailingListId": response['result']['mailingListId'], - "name": response['result']['name'], - "ownerId": response['result']['ownerId'], - "lastModifiedDate": response['result']['lastModifiedDate'], - "creationDate": response['result']['creationDate'], - "contactCount": response['result']['contactCount'] + "mailingListId": response['result']['mailingListId'], + "name": response['result']['name'], + "ownerId": response['result']['ownerId'], + "lastModifiedDate": response['result']['lastModifiedDate'], + "creationDate": response['result']['creationDate'], + "contactCount": response['result']['contactCount'] } df = pd.DataFrame.from_dict(list_info, orient='index').transpose() df['creationDate'] = pd.to_datetime(df['creationDate'], unit='ms') - df['lastModifiedDate'] = pd.to_datetime(df['lastModifiedDate'], unit='ms') + df['lastModifiedDate'] = pd.to_datetime( + df['lastModifiedDate'], unit='ms') return df except: - print(f"ServerError: {response['meta']['httpStatus']}\nError Code: {response['meta']['error']['errorCode']}\nError Message: {response['meta']['error']['errorMessage']}") + print( + f"ServerError: {response['meta']['httpStatus']}\nError Code: {response['meta']['error']['errorCode']}\nError Message: {response['meta']['error']['errorMessage']}") def rename_list(self, mailing_list=None, name=None): '''This method takes an existing mailing list name and updates it to reflect the name defined in the name parameter. @@ -111,9 +125,11 @@ def rename_list(self, mailing_list=None, name=None): :return: A string indicating the success or failure of the method call. ''' assert mailing_list != None, 'Hey there! The mailing_list parameter cannot be None. You need to pass in a Mailing List ID as a string into the mailing_list parameter.' - assert isinstance(mailing_list, str) == True, 'Hey there! The mailing_list parameter must be of type string.' + assert isinstance( + mailing_list, str) == True, 'Hey there! The mailing_list parameter must be of type string.' assert name != None, 'Hey there! The name parameter cannot be None. You need to pass in a new Mailing List name as a string into the name parameter.' - assert isinstance(name, str) == True, 'Hey there! The name parameter must be of type string.' + assert isinstance( + name, str) == True, 'Hey there! The name parameter must be of type string.' assert len(mailing_list) == 18, 'Hey there! The parameter for "mailing_list" that was passed is the wrong length. It should have 18 characters.' assert mailing_list[:3] == 'CG_', 'Hey there! It looks like your Mailing List ID is incorrect. You can find the Mailing List ID on the Qualtrics site under your account settings. Please try again.' @@ -124,9 +140,11 @@ def rename_list(self, mailing_list=None, name=None): response = request.json() try: if response['meta']['httpStatus'] == '200 - OK': - print(f'Your mailing list "{mailing_list}" has been renamed to {name} in the XM Directory.') + print( + f'Your mailing list "{mailing_list}" has been renamed to {name} in the XM Directory.') except: - print(f"ServerError: {response['meta']['httpStatus']}\nError Code: {response['meta']['error']['errorCode']}\nError Message: {response['meta']['error']['errorMessage']}") + print( + f"ServerError: {response['meta']['httpStatus']}\nError Code: {response['meta']['error']['errorCode']}\nError Message: {response['meta']['error']['errorMessage']}") return def delete_list(self, mailing_list=None): @@ -138,7 +156,8 @@ def delete_list(self, mailing_list=None): ''' assert mailing_list != None, 'Hey, the mailing_list parameter cannot be None. You need to pass in a Mailing List ID as a string into the mailing_list parameter.' - assert isinstance(mailing_list, str) == True, 'Hey there, the mailing_list parameter must be of type string.' + assert isinstance( + mailing_list, str) == True, 'Hey there, the mailing_list parameter must be of type string.' assert len(mailing_list) == 18, 'Hey there! The parameter for "mailing_list" that was passed is the wrong length. It should have 18 characters.' assert mailing_list[:3] == 'CG_', 'Hey there! It looks like your Mailing List ID is incorrect. You can find the Mailing List ID on the Qualtrics site under your account settings. Please try again.' @@ -149,9 +168,11 @@ def delete_list(self, mailing_list=None): response = request.json() try: if response['meta']['httpStatus'] == '200 - OK': - print(f'Your mailing list "{mailing_list}" has been deleted from the XM Directory.') + print( + f'Your mailing list "{mailing_list}" has been deleted from the XM Directory.') except: - print(f"ServerError: {response['meta']['httpStatus']}\nError Code: {response['meta']['error']['errorCode']}\nError Message: {response['meta']['error']['errorMessage']}") + print( + f"ServerError: {response['meta']['httpStatus']}\nError Code: {response['meta']['error']['errorCode']}\nError Message: {response['meta']['error']['errorMessage']}") return def list_contacts(self, mailing_list=None, page_size=100): @@ -166,28 +187,34 @@ def list_contacts(self, mailing_list=None, page_size=100): assert len(mailing_list) == 18, 'Hey, the parameter for "mailing_list" that was passed is the wrong length. It should have 18 characters.' assert mailing_list[:3] == 'CG_', 'Hey there! It looks like your Mailing List ID is incorrect. You can find the Mailing List ID on the Qualtrics site under your account settings. Please try again.' assert page_size != 0, 'Hey there! You need to have a page size greater than 1' - + contact_list = pd.DataFrame() headers, base_url = self.header_setup(xm=True) - url = base_url + f"/mailinglists/{mailing_list}/contacts?pageSize={page_size}" + url = base_url + \ + f"/mailinglists/{mailing_list}/contacts?pageSize={page_size}" try: - def get_page(mailing_list=mailing_list, contact_list=contact_list, url=url): - request = r.get(url, headers=headers) - response = request.json() - keys = ['contactId','firstName','lastName','email','phone','extRef','language','unsubscribed'] - contact_lists = Parser().json_parser(response=response, keys=keys, arr=False) - single_page = pd.DataFrame(contact_lists).transpose() - single_page.columns = keys - single_page['mailing_list'] = mailing_list - contact_list = pd.concat([contact_list, single_page]).reset_index(drop=True) - next_page = str(response['result']['nextPage']) - return contact_list, next_page, response - contact_list, next_page, response = get_page(mailing_list=mailing_list, contact_list=contact_list, url=url) - while next_page != 'None': - contact_list, next_page, response = get_page(mailing_list=mailing_list, contact_list=contact_list, url=next_page) - return contact_list + def get_page(mailing_list=mailing_list, contact_list=contact_list, url=url): + request = r.get(url, headers=headers) + response = request.json() + keys = ['contactId', 'firstName', 'lastName', 'email', + 'phone', 'extRef', 'language', 'unsubscribed'] + contact_lists = Parser().json_parser(response=response, keys=keys, arr=False) + single_page = pd.DataFrame(contact_lists).transpose() + single_page.columns = keys + single_page['mailing_list'] = mailing_list + contact_list = pd.concat( + [contact_list, single_page]).reset_index(drop=True) + next_page = str(response['result']['nextPage']) + return contact_list, next_page, response + contact_list, next_page, response = get_page( + mailing_list=mailing_list, contact_list=contact_list, url=url) + while next_page != 'None': + contact_list, next_page, response = get_page( + mailing_list=mailing_list, contact_list=contact_list, url=next_page) + return contact_list except: - print(f"ServerError: {response['meta']['httpStatus']}\nError Code: {response['meta']['error']['errorCode']}\nError Message: {response['meta']['error']['errorMessage']}") + print( + f"ServerError: {response['meta']['httpStatus']}\nError Code: {response['meta']['error']['errorCode']}\nError Message: {response['meta']['error']['errorMessage']}") def create_contact_in_list(self, mailing_list=None, **kwargs): '''This method creates contacts in the specified mailing list. It is important to remember here that whenever you create a contact in @@ -203,7 +230,7 @@ def create_contact_in_list(self, mailing_list=None, **kwargs): :param email: The new contact's email. :type email: str :param phone: The new contact's phone number. - :tyoe phone: str + :type phone: str :param external_ref: The new contact's external reference. :type external_ref: str :param unsubscribed: This parameter denotes whether the new contact is unsubscribed from surveys (Default: False). @@ -219,7 +246,8 @@ def create_contact_in_list(self, mailing_list=None, **kwargs): dynamic_payload = {} for key in list(kwargs.keys()): - assert key in ['first_name', 'last_name', 'email', 'unsubscribed', 'language', 'external_ref', 'metadata', 'phone'], "Hey there! You can only pass in parameters with names in the list, ['first_name', 'last_name', 'email', 'unsubscribed', 'language', 'external_ref', 'metadata']" + assert key in ['first_name', 'last_name', 'email', 'unsubscribed', 'language', 'external_ref', 'metadata', + 'phone'], "Hey there! You can only pass in parameters with names in the list, ['first_name', 'last_name', 'email', 'unsubscribed', 'language', 'external_ref', 'metadata']" if key == 'first_name': dynamic_payload.update({'firstName': kwargs[str(key)]}) elif key == 'last_name': @@ -237,7 +265,8 @@ def create_contact_in_list(self, mailing_list=None, **kwargs): elif key == 'phone': dynamic_payload.update({'phone': kwargs[str(key)]}) elif key == 'metadata': - assert isinstance(kwargs['metadata'], dict), 'Hey there, your metadata parameter needs to be of type "dict"!' + assert isinstance( + kwargs['metadata'], dict), 'Hey there, your metadata parameter needs to be of type "dict"!' dynamic_payload.update({'embeddedData': kwargs[str(key)]}) headers, base_url = self.header_setup(content_type=True, xm=True) @@ -254,14 +283,15 @@ def create_contact_in_list(self, mailing_list=None, **kwargs): request = r.post(url, json=dynamic_payload, headers=headers) response = request.json() if response['meta']['httpStatus'] == '500 - Internal Server Error': - attempt+=1 + attempt += 1 t.sleep(0.25) continue elif response['meta']['httpStatus'] == '200 - OK': return response['result']['id'], response['result']['contactLookupId'] return print(f"ServerError: {response['meta']['httpStatus']}\nError Code: {response['meta']['error']['errorCode']}\nError Message: {response['meta']['error']['errorMessage']}") except Exception: - print(f"ServerError: {response['meta']['httpStatus']}\nError Code: {response['meta']['error']['errorCode']}\nError Message: {response['meta']['error']['errorMessage']}") + print( + f"ServerError: {response['meta']['httpStatus']}\nError Code: {response['meta']['error']['errorCode']}\nError Message: {response['meta']['error']['errorMessage']}") else: contact_list_id = response['result']['contactLookupId'] - return contact_id, contact_list_id \ No newline at end of file + return contact_id, contact_list_id diff --git a/README.md b/README.md index 32ac7f2..307cf89 100644 --- a/README.md +++ b/README.md @@ -91,9 +91,69 @@ m.list_contacts() #Creates contacts in a Mailing List m.create_contact_in_list() ``` + +## Distributions Module + +The `Distributions()` module has methods for creating distributions, reminders, thank you's, SMS distributions, and generating links. + +### Distributions +Distributions can be created and fetched with the following methods. +```python +from Qualtrics.Survey import Distributions + +# Create a distribution client +distribution_client = Distributions() + +# List Distributions for Survey +distribution_list = distribution_client.list_distributions(survey="") + +# Create Distribution for Survey +distribution_id = distribution_client.create_distribution(subject="", reply_email="", from_email="",from_name="", mailing_list="", library="", survey="", message="", send_date="", link_type="") + +# Create Reminder for Distribution +reminder_distribution_id = distribution_client.create_reminder(subject="", reply_email="", from_email="",from_name="", mailing_list="", library="", message="", distribution="", send_date="") + +# Create Thank-You for Distribution +thank_you_distribution_id = distribution_client.create_thank_you(subject="", reply_email="", from_email="",from_name="", mailing_list="", library="", message="", distribution="", send_date="") +``` + +### Link Generation + +Some users do not wish to send the surveys from Qualtrics, but rather want to generate individual links tied to contacts which will open the survey for that user. The `Distributions()` module contains a method for doing this for a single contact, and for doing it from a dataframe for many contacts (max 10,000 at a time). +```python +import pandas as pd + +# Generate Survey Link for single contact +contact_data = { # Sample contact dictionary + "firstName": 'firstName', + "lastName": 'lastName', + "email": 'email@mail.com', + "phone": '999-555-9999', + "extRef": 'myexref', + "unsubscribed": False +} +embedded_data = {"my_key":"my_value"} # Sample Embedded Data object +transactional_data = {"my_key":"my_value"} # Sample Transactional Data object + +# The request will return the single link as a string +my_link = distribution_client.generate_individual_survey_link(survey="", mailing_list="", contact=contact_data, embedded_data=embeddedData, transactional_data=transactionalData, expiration=2) # Where expiration is number of months before link expires (must be >= 1) +print("individual link:",my_link) + +# Generate dataframe of links from input dataframe +df = pd.read_csv("path/to/my.csv",na_filter=False) # empty fields being nan will cause error +embedded_data_cols = ['headers','of','embedded fields'] +transactional_data_cols ['headers','of','transactional fields'] + +# The request will return a pandas dataframe containing all contacts and links generated by the API +links_df = distribution_client.generate_links_from_dataframe(survey="", mailing_list="", df=df, embedded_fields=embedded_data_cols, transactional_fields=transactional_data_cols, expiration=3) +links_df.to_csv("links_table.csv") # Save the DF to file if desired +``` + ## Survey Module -The `Responses()` module has two methods. Each of those methods can be called using the following methodology. +### Fetch Response Data + +The `Responses()` module has two methods for retrieval of response data. Each of those methods can be called using the following methodology. ```python from QualtricsAPI.Survey import Responses @@ -105,6 +165,63 @@ Responses().get_survey_responses(survey="") Responses().get_survey_questions(survey="") ``` +### Update Response Embedded Data + +The `Responses()` module has two methods for updating embedded data on survey responses. `update_survey_response_embedded_data` will update a single response from a dictonary of strings. `bulk_update_many_responses_from_dataframe` will update many responses at once from a pandas dataframe. + +```python +from QualtricsAPI.Survey import Responses +import pandas as pd + +r = Responses() + +# Update a single response from dictionary of strings +new_data = {"my":"new","data":"dictionary"} +r.update_survey_response_embedded_data(survey="", response_id="", embedded_data=new_data) + +# Update many responses from dataframe +my_df = pd.read_csv("path/to/my/file.csv") +r.bulk_update_many_responses_from_dataframe(survey="", df=my_df,rid_col="
", update_cols=['headers','of','columns','to be','updated'], chunk_size=100) +``` +## Imported Data Project Module + +### Get IDP Data + +The `ImportedDataProject()` module can be used to retrieve data from imported data projects with the following usage. +```python +from QualtricsAPI.IDP import ImportedDataProject + +# Create an instance of our IDP project +idp = ImportedDataProject(idp_source_id="") + +meta, schema = idp.get_idp_schema() + +record = idp.get_single_record_from_idp(unique_field=) +``` + +### Create/Update/Delete IDP data + +The IDP module includes methods for creating/updating (it will upsert on the unique value) rows into an IDP as both single rows or up to 50 in bulk, as well as a method to delete individual records. +```python +# Add Columns to IDP +new_columns = [{"name":"","type":""}] +column_add_result = idp.add_columns_to_idp(fields=new_cols) + +# Create a record from a dictionary +new_record = {"":""} +# keys must match IDP names, values must match type - fetch the schema to see valid inputs +result = idp.add_single_record(record=new_record) + +# Create many records from list +new_records = [{"":""},{"":""}] +many_result = idp.add_many_records(records=new_records) + +# Delete row from IDP +delete_result = idp.delete_record_from_idp(unique_field='') +# Value must match type as well +``` +the `ImportedDataProject()` module can be imported without a project ID, and IDs can be passed at the time any method is called (`idp_id` is the parameter to set this from a function call). Passing a new id will update the class to this new id. + # Wrap-up Again this is currently under development so there may be reduced functionality, but I hope this helps fellow Qualtrics users to expedite their current workflow! diff --git a/build/lib/QualtricsAPI/Exceptions/__init__.py b/build/lib/QualtricsAPI/Exceptions/__init__.py deleted file mode 100644 index bb747a9..0000000 --- a/build/lib/QualtricsAPI/Exceptions/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -# __init__.py -from .exceptions import * - -__all__ = ['exceptions'] diff --git a/build/lib/QualtricsAPI/Exceptions/exceptions.py b/build/lib/QualtricsAPI/Exceptions/exceptions.py deleted file mode 100644 index 0aebbea..0000000 --- a/build/lib/QualtricsAPI/Exceptions/exceptions.py +++ /dev/null @@ -1,40 +0,0 @@ -''' -These HTTP Errors are defined by Qualtrics. Documentation can be found -(https://api.qualtrics.com/instructions/docs/Instructions/responses.md) - -''' - -class Qualtrics400Error(Exception): - '''This Exception handles errors associated with the HTTP 400 (Bad Request) responses.''' - def __init__(self, msg): - super().__init__(msg) - -class Qualtrics401Error(Exception): - '''This Exception handles errors associated with the HTTP 401 (Unauthorized) responses.''' - def __init__(self, msg): - super().__init__(msg) - -class Qualtrics403Error(Exception): - '''This Exception handles errors associated with the HTTP 403 (Forbidden) responses.''' - def __init__(self, msg): - super().__init__(msg) - -class Qualtrics429Error(Exception): - '''This Exception handles errors associated with the HTTP 429 (Too Many Requests) responses.''' - def __init__(self, msg): - super().__init__(msg) - -class Qualtrics500Error(Exception): - '''This Exception handles errors associated with the HTTP 500 (Internal Server Error) responses.''' - def __init__(self, msg): - super().__init__(msg) - -class Qualtrics503Error(Exception): - '''This Exception handles errors associated with the HTTP 503 (Temporary Internal Server Error) responses.''' - def __init__(self, msg): - super().__init__(msg) - -class Qualtrics504Error(Exception): - '''This Exception handles errors associated with the HTTP 504 (Gateway Timeout) responses.''' - def __init__(self, msg): - super().__init__(msg) \ No newline at end of file diff --git a/build/lib/QualtricsAPI/JSON/__init__.py b/build/lib/QualtricsAPI/JSON/__init__.py deleted file mode 100644 index e315bd8..0000000 --- a/build/lib/QualtricsAPI/JSON/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -# __init__.py -from .parser import * - -__all__ = ['parser'] diff --git a/build/lib/QualtricsAPI/JSON/parser.py b/build/lib/QualtricsAPI/JSON/parser.py deleted file mode 100644 index df803a1..0000000 --- a/build/lib/QualtricsAPI/JSON/parser.py +++ /dev/null @@ -1,74 +0,0 @@ -import numpy as np - -class Parser(object): - - def __init__(self): - return - - def extract_values(self, obj=None, key=None): - ''' This outer method a specific value from a nested dictionary. - - :param obj: a dictionary object. - :param key: The Specific Key that the value is associated with. - :return: the value associated with the given key - ''' - values = [] - def extract(obj, values, key): - '''This inner method recursively searches for the given key in a nested dictionary. (Not a User-Facing Method) - - :param obj: a dictionary object. - :param values: a list that will house the values of the given key. - :param key: The Specific Key that the value is associated with. - :return: the value associated with the given key - ''' - if isinstance(obj, dict): - for k, v in obj.items(): - if isinstance(v, (dict, list)): - extract(v, values, key) - elif k == key: - values.append(v) - elif isinstance(obj, list): - for j in obj: - extract(j, values, key) - return values - results = extract(obj, values, key) - return results - - def extract_keys(self, obj): - '''This outer method extracts all of the keys from a nested dictionary. - - :param obj: a dictionary object. - :return: a list of keys within a given dictonary. - ''' - keys = [] - - def extract(obj, keys): - '''This inner method recursively locates each of the keys within a nested dictionary. - - :param obj: a dictionary object. - :param keys: a list of previously identified keys - :return: a list of keys within a given recursion of the inner method. - ''' - if isinstance(obj, dict): - for k,v in obj.items(): - if isinstance(v, (dict, list)): - keys.append(k) - extract(v, keys) - else: - keys.append(k) - elif isinstance(obj, list): - for element in obj: - extract(element, keys) - return keys - obj_keys = extract(obj, keys) - return obj_keys - - def json_parser(self, response=None, keys=[], arr=True): - '''This method itterates over the all of the keys within a keys list.''' - - #Improvement: Include the Extract keys method in this method. - elements = [self.extract_values(response, item) for item in keys] - if arr == True: - return np.array(elements).T - else: - return elements diff --git a/build/lib/QualtricsAPI/Library/__init__.py b/build/lib/QualtricsAPI/Library/__init__.py deleted file mode 100644 index 72a4505..0000000 --- a/build/lib/QualtricsAPI/Library/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -# __init__.py -from .messages import * - -__all__ = ['messages'] diff --git a/build/lib/QualtricsAPI/Library/messages.py b/build/lib/QualtricsAPI/Library/messages.py deleted file mode 100644 index 19f8834..0000000 --- a/build/lib/QualtricsAPI/Library/messages.py +++ /dev/null @@ -1,78 +0,0 @@ -import requests as r -import zipfile -import json -import io -import pandas as pd -from QualtricsAPI.Setup import Credentials -from QualtricsAPI.JSON import Parser - -class Messages(Credentials): - '''This is a child class to the Credentials class and it gathers information about Qualtric's Messages.''' - - def __init__(self, token=None, directory_id=None, data_center=None): - self.token = token - self.data_center = data_center - self.directory_id = directory_id - return - - def list_messages(self, library=None): - '''This method gets the all of the messages available to a user in a given library. Messages are defined based on - the library (User-Deifined or Global) that they exist within. Thus, in order to list the messages availble to your - user account, you need to specify the library that the api must look within. There can exist several different - categories of messages. These include, 'invite', 'inactiveSurvey', 'reminder', 'thankYou', 'smsInvite', 'validation', - 'emailSubject', 'general', 'lookAndFeel', and 'endOfSurvey'. This method returns all the types of these, if they exist. - - :param library: The (Global or User) Library ID which the messages are located within. - :type library: str - :return: A Pandas DataFrame - ''' - - assert len(library) == 18, 'Hey, the parameter for the Libary ID that was passed is the wrong length. It should have 18 characters.' - assert library[:3] == 'UR_' or library[:3] == 'GR_', 'Hey there! It looks like your Library ID is incorrect. You can find the Library ID on the Qualtrics site under your account settings. It will begin with "UR_" or "GR_". Please try again.' - - - # Need Recursion to handle nextPage Errors - headers, base_url = self.header_setup(xm=False, path='libraries') - url = base_url + f"/{library}/messages/" - request = r.get(url, headers=headers) - response = request.json() - try: - keys = ['id', 'description', 'category'] - messages = Parser().json_parser(response=response['result'], keys=keys, arr=False) - msg_df = pd.DataFrame(messages).transpose() - msg_df.columns = ['MessageID', 'MessageDescription', 'MessageCategory'] - msg_df['LibraryID'] = library - except: - print(f"\nServerError: QualtricsAPI Error Code: {response['meta']['error']['errorCode']}\nQualtricsAPI Error Message: {response['meta']['error']['errorMessage']}") - return msg_df - - def get_message(self, library=None, message=None): - '''This method gets the messages available to a user in a given library. Messages are defined based on the library - (User-Deifined or Global) that they exist within. Thus, in order to query the correct message we must pass the - associated libraryID into the library parameter, along with the MessageID into the message parameter. There can exist - several different categories of messages. These include, 'invite', 'inactiveSurvey', 'reminder', 'thankYou', 'smsInvite', - 'validation', 'emailSubject', 'general', 'lookAndFeel', and 'endOfSurvey'. This method returns any type of these, if they - exist. - - :param library: The (Global or User) Library ID which the messages are located within. - :type library: str - :param message: The Message ID corresponding specific message. - :type message: str - :return: A tuple containing the MessageID, MessageCategory, and MessageDescription - ''' - - assert len(library) == 18, 'Hey, the parameter for "library" that was passed is the wrong length. It should have 18 characters.' - assert len(message) == 18, 'Hey, the parameter for "message" that was passed is the wrong length. It should have 18 characters.' - assert message[:3] == 'MS_', 'Hey there! It looks like your MessageID is incorrect. You can find the MessageID by using the list messages method available in the Messages module of this Package. It will begin with "MS_". Please try again.' - assert library[:3] == 'UR_' or library[:3] == 'GR_', 'Hey there! It looks like your Library ID is incorrect. You can find the Library ID on the Qualtrics site under your account settings. It will begin with "UR_" or "GR_". Please try again.' - - - headers, base_url = self.header_setup(xm=False, path='libraries') - url = base_url + f"/{library}/messages/{message}" - request = r.get(url, headers=headers) - response = request.json() - try: - msg_html = response['result']['messages']['en'] - except: - print(f"\nServerError: QualtricsAPI Error Code: {response['meta']['error']['errorCode']}\nQualtricsAPI Error Message: {response['meta']['error']['errorMessage']}") - return message, response['result']['category'], response['result']['description'] diff --git a/build/lib/QualtricsAPI/Setup/__init__.py b/build/lib/QualtricsAPI/Setup/__init__.py deleted file mode 100644 index 1b97ad5..0000000 --- a/build/lib/QualtricsAPI/Setup/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -# __init__.py -from .credentials import * - -__all__ = ['credentials'] diff --git a/build/lib/QualtricsAPI/Setup/credentials.py b/build/lib/QualtricsAPI/Setup/credentials.py deleted file mode 100644 index e4ed653..0000000 --- a/build/lib/QualtricsAPI/Setup/credentials.py +++ /dev/null @@ -1,50 +0,0 @@ -import numpy as np -import os - -class Credentials(object): - ''' This class handles the setup of credentials needed to setup the Qualtrics API Authorization. Use the - qualtrics_api_credentials method to create enviornment variables that will automatically populate the correct - HTTP headers for the request that you are making. ''' - - def __init__(self): - return - - def qualtrics_api_credentials(self, token, data_center, directory_id=None): - '''This method creates enviornment variables for the users Qualtrics API token, data center, and their directory id. - - :param token: Your Qualtrics API Token - :type token: str - :param data_center: Your Qualtrics data center - :type data_center: str - :param directory_id: Your Qualtrics directory id (XM Directory Users-Only) - :type directory_id: str - :return: Nothing explicitly, However you just create enviornment variables that will populate you HTTP Headers. - ''' - assert len(token) == 40, 'Hey there! It looks like your api token is a the incorrect length. It needs to be 40 characters long. Please try again.' - if directory_id: - assert len(directory_id) == 20, 'Hey there! It looks like your api directory ID is a the incorrect length. It needs to be 20 characters long. Please try again.' - assert directory_id[:5] == 'POOL_', 'Hey there! It looks like your directory ID is incorrect. You can find the directory ID on the Qualtrics site under your account settings. Please try again.' - os.environ['directory_id'] = directory_id - - os.environ['token'] = token - os.environ['data_center'] = data_center - return - - def header_setup(self, content_type=False, xm=True, path=None): - '''This method accepts the argument content_type and returns the correct header, and base url. (Not a User-Facing Method) - - response => path = 'responseexports/' - distributions => path = 'distributions' - - :param content_type: use to return json response. - :return: a HTML header and base url. - ''' - if xm: - assert os.environ['directory_id'], 'Hey there! This endpoint is only accessible for XM Directory Users . If you have access to the XM Directory, then be sure to include your directory_id when you use the qualtrics_api_credentials() method. ' - path = 'directories/{0}/'.format(os.environ['directory_id']) if xm else path - - header = {"x-api-token": os.environ['token']} - base_url = f"https://{os.environ['data_center']}.qualtrics.com/API/v3/{path}" - if content_type is True: - header["Content-Type"] = "application/json" - return header, base_url diff --git a/build/lib/QualtricsAPI/Survey/__init__.py b/build/lib/QualtricsAPI/Survey/__init__.py deleted file mode 100644 index 78c4cf9..0000000 --- a/build/lib/QualtricsAPI/Survey/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -# __init__.py -from .responses import * -from .distributions import * - -__all__ = ['responses', 'distributions'] diff --git a/build/lib/QualtricsAPI/Survey/distributions.py b/build/lib/QualtricsAPI/Survey/distributions.py deleted file mode 100644 index c505523..0000000 --- a/build/lib/QualtricsAPI/Survey/distributions.py +++ /dev/null @@ -1,370 +0,0 @@ -import requests as r -import pandas as pd -from datetime import date, datetime, timedelta -from QualtricsAPI.Setup import Credentials -from QualtricsAPI.JSON import Parser - -class Distributions(Credentials): - '''This is a child class to the credentials class and gathers information about Qualtric's Distributions.''' - - def __init__(self, token=None, directory_id=None, data_center=None): - self.token = token - self.data_center = data_center - self.directory_id = directory_id - return - - def set_send_date(self, weeks=0, days=0, hours=0, minutes=0, seconds=0): - '''This method is a helper function to format the send date arguments for several methods in the Distribution Module. - The send_date parameter must be in the format ""%Y-%m-%dT%H:%M:%SZ" in order for the API to properly parse the send date. - Thus, this method defines the offset for the send_date, and formats it properly. An example would be if you wanted to send - a reminder one week from now, simply pass "1" as an argument in to the "weeks" parameter. The default behaviour is for the - send_date to be now, thus all params are set to zero offset. - - :param weeks: The week offset for the send_date. [Default = 0] - :type weeks: int - :param days: The day offset for the send_date. [Default = 0] - :type days: int - :param hours: The hour offset for the send_date. [Default = 0] - :type hours: int - :param minutes: The minute offset for the send_date. [Default = 0] - :type minutes: int - :param seconds: The second offset for the send_date. [Default = 0] - :type seconds: int - :return: The formatted DateTime. (str) - ''' - send_date = datetime.now() + timedelta(weeks=weeks, days=days, hours=hours, minutes=minutes, seconds=seconds) - return date.strftime(send_date, '%Y-%m-%dT%H:%M:%SZ') - - def create_distribution(self, subject, reply_email, from_email, from_name, mailing_list, library, survey, message, send_date, link_type='Individual'): - '''This method gives users the ability to create a distribution for a given mailing list and survey. In order to use this method you - must already have access to pre-defined Messages and their MessageID's existing within a User-Defined (starts with UR) - or Global (starts with GR) Library. You can list the messages and their MessageID's(starts with MS) that are available to your user - account by using the "QualtricsAPI.Library.Messages.list_messages()" method. As a final note, this method gives users the ability to - define the different types of messages. - - :param subject: The subject for the reminder email. - :type subject: str - :param reply_email: The reply email address. - :type reply_email: str - :param from_email: The email address that the distribution is sent from. - :type from_email: str - :param from_name: The name that shows up on the distribution. - :type from_name: str - :param library: The (Global or User) Library ID which the messages are located within. - :type library: str - :param message: The Message ID corresponding with the message that is to be sent. - :type message: str - :param mailing_list: The Mailing List ID corresponding with the Mailing List that the distribution is to be sent to. - :type mailing_list: str - :param survey: The Survey ID corresponding with the Survey that the distribution is to be sent to. - :type survey: str - :param send_date: The date that the distribution is supposed to be sent on. Pass gmtime() for immediate distribution or use the set_send_date() method to format properly. - :type send_date: str - :param link_type: This parameter refers to the type of link that is to be sent within the distribution. - :type link_type: str - :return: The Distribution ID. (str) - ''' - - assert len(mailing_list) == 18, 'Hey, the parameter for "mailing_list" that was passed is the wrong length. It should have 18 characters.' - assert len(library) == 18, 'Hey, the parameter for "library" that was passed is the wrong length. It should have 18 characters.' - assert len(survey) == 18, 'Hey, the parameter for "survey" that was passed is the wrong length. It should have 18 characters.' - assert len(message) == 18, 'Hey, the parameter for "message" that was passed is the wrong length. It should have 18 characters.' - assert mailing_list[:3] == 'CG_', 'Hey there! It looks like your Mailing List ID is incorrect. You can find the Mailing List ID on the Qualtrics site under your account settings. It will begin with "CG_". Please try again.' - assert survey[:3] == 'SV_', 'Hey there! It looks like your SurveyID is incorrect. You can find the SurveyID on the Qualtrics site under your account settings. It will begin with "SV_". Please try again.' - assert message[:3] == 'MS_', 'Hey there! It looks like your MessageID is incorrect. You can find the MessageID by using the list messages method available in the Messages module of this Package. It will begin with "MS_". Please try again.' - assert library[:3] == 'UR_' or library[:3] == 'GR_', 'Hey there! It looks like your Library ID is incorrect. You can find the Library ID on the Qualtrics site under your account settings. It will begin with "UR_" or "GR_". Please try again.' - - headers, url = self.header_setup(content_type=True, xm=False, path='distributions') - data = { - 'header': { - 'fromEmail': from_email, - 'fromName': from_name, - 'replyToEmail': reply_email, - 'subject': subject - }, - 'surveyLink': { - 'surveyId': survey, - 'type': link_type - }, - 'recipients': { - 'mailingListId': mailing_list - }, - 'sendDate': send_date, - 'message': { - 'libraryId': library, - 'messageId': message - } - } - - request = r.post(url, json=data, headers=headers) - response = request.json() - try: - distribution_id = response['result']['id'] - return distribution_id - except: - print(f"\nServerError: QualtricsAPI Error Code: {response['meta']['error']['errorCode']}\nQualtricsAPI Error Message: {response['meta']['error']['errorMessage']}") - return - - def create_reminder(self, subject, reply_email, from_email, from_name, library, message, distribution, send_date): - '''This method gives users the ability to create a reminder for a given distribution. In order to create a reminders you must have - already created a distribution for a given mailing list and survey. Once created, you will pass the Distribution ID corresponding to - the correct distribution to the distribution parameter and the reminder will be set to that specific distribution. Unlike the - QualtricsAPI.Survey.Distribution.create_distribution() method, this method does not require you to specify the mailing list or survey - because it will use the parameters defined when the associated distribution was set up. - - :param subject: The subject for the reminder email. - :type subject: str - :param reply_email: The reply email address. - :type reply_email: str - :param from_email: The email address that the reminder is sent from. - :type from_email: str - :param from_name: The name that shows up on the reminder. - :type from_name: str - :param library: The (Global or User) Library ID which the messages are located within. - :type library: str - :param message: The Message ID corresponding with the message that is to be sent. - :type message: str - :param distribution: The Distribution ID corresponding with the distribution that the reminder is to be attached to. - :type distribution: str - :param send_date: The date that the reminder is supposed to be sent on. Pass gmtime() for immediate distribution or use the set_send_date() method to format properly. - :type send_date: str - :return: The "Reminder" Distribution ID. (str) - ''' - - assert len(distribution) == 19, 'Hey, the parameter for "distribution" that was passed is the wrong length. It should have 19 characters.' - assert len(library) == 18, 'Hey, the parameter for "library" that was passed is the wrong length. It should have 18 characters.' - assert len(message) == 18, 'Hey, the parameter for "message" that was passed is the wrong length. It should have 18 characters.' - assert distribution[:4] == 'EMD_', 'Hey there! It looks like your distributionID is incorrect. You can find the distributionID by using the list_distributions method in this module. It will begin with "UMD_". Please try again.' - assert message[:3] == 'MS_', 'Hey there! It looks like your MessageID is incorrect. You can find the MessageID by using the list messages method available in the Messages module of this Package. It will begin with "MS_". Please try again.' - assert library[:3] == 'UR_' or library[:3] == 'GR_', 'Hey there! It looks like your Library ID is incorrect. You can find the Library ID on the Qualtrics site under your account settings. It will begin with "UR_" or "GR_". Please try again.' - - - headers, base_url = self.header_setup(content_type=True, xm=False, path='distributions') - url = f'{base_url}/{distribution}/reminders' - data = { - 'header': { - 'fromEmail': from_email, - 'fromName': from_name, - 'replyToEmail': reply_email, - 'subject': subject - }, - 'sendDate': send_date, - 'message': { - 'libraryId': library, - 'messageId': message - } - } - - request = r.post(url, json=data, headers=headers) - response = request.json() - try: - reminder_id = response['result'] - return reminder_id - except: - print(f"\nServerError: QualtricsAPI Error Code: {response['meta']['error']['errorCode']}\nQualtricsAPI Error Message: {response['meta']['error']['errorMessage']}") - return - - def create_thank_you(self, subject, reply_email, from_email, from_name, library, message, distribution, send_date): - '''This method gives users the ability to create a thank you for a given distribution. In order to create thank you distributions you - must have already created a distribution for a given mailing list and survey. Once created, you will pass the Distribution ID - corresponding to the correct distribution to the distribution parameter and the reminder will be set to that specific distribution. - Unlike the QualtricsAPI.Survey.Distribution.create_distribution() method, this method does not require you to specify the mailing - list or survey because it will use the parameters defined when the associated distribution was set up. - - :param subject: The subject for the reminder email. - :type subject: str - :param reply_email: The reply email address. - :type reply_email: str - :param from_email: The email address that the reminder is sent from. - :type from_email: str - :param from_name: The name that shows up on the reminder. - :type from_name: str - :param library: The (Global or User) Library ID which the messages are located within. - :type library: str - :param message: The Message ID corresponding with the message that is to be sent. - :type message: str - :param distribution: The Distribution ID corresponding with the distribution that the reminder is to be attached to. - :type distribution: str - :param send_date: The date that the reminder is supposed to be sent on. Pass gmtime() for immediate distribution or use the set_send_date() method to format properly. - :type send_date: str - :return: The "Thank You" Distribution ID. (str) - ''' - - assert len(distribution) == 19, 'Hey, the parameter for "distribution" that was passed is the wrong length. It should have 19 characters.' - assert len(library) == 18, 'Hey, the parameter for "library" that was passed is the wrong length. It should have 18 characters.' - assert len(message) == 18, 'Hey, the parameter for "message" that was passed is the wrong length. It should have 18 characters.' - assert distribution[:4] == 'EMD_', 'Hey there! It looks like your distributionID is incorrect. You can find the distributionID by using the list_distributions method in this module. It will begin with "UMD_". Please try again.' - assert message[:3] == 'MS_', 'Hey there! It looks like your MessageID is incorrect. You can find the MessageID by using the list messages method available in the Messages module of this Package. It will begin with "MS_". Please try again.' - assert library[:3] == 'UR_' or library[:3] == 'GR_', 'Hey there! It looks like your Library ID is incorrect. You can find the Library ID on the Qualtrics site under your account settings. It will begin with "UR_" or "GR_". Please try again.' - - - headers, base_url = self.header_setup(content_type=True, xm=False, path='distributions') - url = f'{base_url}/{distribution}/thankyous' - data = { - 'header': { - 'fromEmail': from_email, - 'fromName': from_name, - 'replyToEmail': reply_email, - 'subject': subject - }, - 'sendDate': send_date, - 'message': { - 'libraryId': library, - 'messageId': message - } - } - request = r.post(url, json=data, headers=headers) - response = request.json() - try: - thanks_id = response['result'] - return thanks_id - except: - print(f"\nServerError: QualtricsAPI Error Code: {response['meta']['error']['errorCode']}\nQualtricsAPI Error Message: {response['meta']['error']['errorMessage']}") - return - - def list_distributions(self, survey): - ''' This method will list all of the distributions corresponding with a given survey. Given that distributions are - specific to individual surveys, we must pass the SurveyID as an arguement into the survey parameter for this method - to work appropriately. This method will return a Pandas DataFrame filled with a list of the distributions associated - with the specific SurveyID passed to the survey parameter. - - :param survey: The Survey ID corresponding with the Survey that the distribution is to be sent to. - :type survey: str - :return: A Pandas DataFrame - ''' - - assert survey[:3] == 'SV_', 'Hey there! It looks like your SurveyID is incorrect. You can find the SurveyID on the Qualtrics site under your account settings. It will begin with "SV_". Please try again.' - assert len(survey) == 18, 'Hey, the parameter for "survey" that was passed is the wrong length. It should have 18 characters.' - - headers, base_url = self.header_setup(xm=False, path='distributions') - url = f'{base_url}?surveyId={survey}' - columns = ['id', 'parentDistributionId', 'ownerId', 'organizationId', 'requestStatus', 'requestType', - 'sendDate', 'createdDate', 'modifiedDate', 'headers', 'fromEmail', 'replyToEmail', 'fromName', - 'subject', 'recipients', 'mailingListId', 'contactId', 'sampleId', 'message', 'messageId', - 'messageText', 'surveyLink', 'surveyId', 'expirationDate', 'linkType', 'stats', 'sent', 'failed', - 'started', 'bounced', 'opened', 'skipped', 'finished', 'complaints', 'blocked', 'mailing_list_library_id', 'message_library_id'] - master = pd.DataFrame(columns=columns) - def extract_distributions(url=url, master=master): - request = r.get(url, headers=headers) - response = request.json() - if response['meta']['httpStatus'] == '200 - OK': - keys = columns[:-2] - dists = Parser().json_parser(response=response, keys=keys, arr=False) - dist_df = pd.DataFrame(dists).transpose() - dist_df.columns = keys - library_ids = Parser().json_parser(response=response, keys=['libraryId'], arr=False) - dist_df['mailing_list_library_id'] = library_ids[0][:len(dist_df)] - dist_df['message_library_id'] = library_ids[0][len(dist_df):] - master = pd.concat([master, dist_df], sort=False).reset_index(drop=True) - next_page = response['result']['nextPage'] - return master, next_page - else: - print(response['meta']) - master, next_page = extract_distributions(url=url, master=master) - - master, next_page = extract_distributions() - if next_page == None: - return master - else: - while next_page != None: - master, next_page = extract_distributions(url=next_page, master=master) - return master - - - def get_distribution(self, survey, distribution): - ''' This method gives users the ability to get a specific distribution corresponding with a given survey. Given that - distributions are specific to individual surveys, we must pass the SurveyID as an arguement into the survey parameter for - this method to work appropriately. This method will return a Pandas DataFrame consisting of multiple variables associated - with the specified distirbution. - - :param survey: The Survey ID corresponding with the Survey that the distribution is to be sent to. - :type survey: str - :param distribution: A specific Distribution ID associated with the given survey. - :type distribution: str - :return: A Pandas DataFrame - ''' - - assert survey[:3] == 'SV_', 'Hey there! It looks like your SurveyID is incorrect. You can find the SurveyID on the Qualtrics site under your account settings. It will begin with "SV_". Please try again.' - assert len(survey) == 18, 'Hey, the parameter for "survey" that was passed is the wrong length. It should have 18 characters.' - assert len(distribution) == 19, 'Hey, the parameter for "distribution" that was passed is the wrong length. It should have 19 characters.' - assert distribution[:4] == 'EMD_', 'Hey there! It looks like your distributionID is incorrect. You can find the distributionID by using the list_distributions method in this module. It will begin with "UMD_". Please try again.' - - headers, base_url = self.header_setup(xm=False, path='distributions') - url = f'{base_url}/{distribution}?surveyId={survey}' - request = r.get(url, headers=headers) - try: - response = request.json() - keys = ['id', 'parentDistributionId', 'ownerId', 'organizationId', 'requestStatus', 'requestType', - 'sendDate', 'createdDate', 'modifiedDate', 'headers', 'fromEmail', 'replyToEmail', 'fromName', - 'subject', 'recipients', 'mailingListId', 'contactId', 'sampleId', 'message', 'messageId', - 'messageText', 'surveyLink', 'surveyId', 'expirationDate', 'linkType', 'stats', 'sent', 'failed', - 'started', 'bounced', 'opened', 'skipped', 'finished', 'complaints', 'blocked'] - dists = Parser().json_parser(response=response, keys=keys, arr=False) - dist_df = pd.DataFrame(dists) - dist_df.index = keys - library_ids = Parser().json_parser(response=response, keys=['libraryId'], arr=False) - lib = pd.DataFrame(library_ids[0], index=['mailing_list_library_id', 'message_library_id']) - dist_df = dist_df.append(lib) - return dist_df - except: - print(f"\nServerError: QualtricsAPI Error Code: {response['meta']['error']['errorCode']}\nQualtricsAPI Error Message: {response['meta']['error']['errorMessage']}") - - - def create_sms_distribution(self, dist_name, mailing_list, library, survey, message, send_date, parentDistributionId=None, method='Invite'): - '''This method gives users the ability to create a SMS distribution for a given mailing list and survey. In order to use this method you - must already have access to pre-defined Messages and their MessageID's existing within a User-Defined (starts with UR) - or Global (starts with GR) Library. You can list the messages and their MessageID's(starts with MS) that are available to your user - account by using the "QualtricsAPI.Library.Messages.list_messages()" method. - - :param dist_name: The name that shows up for the distribution. - :type dist_name: str - :param library: The (Global or User) Library ID which the messages are located within. - :type library: str - :param message: The Message ID corresponding with the message that is to be sent. - :type message: str - :param mailing_list: The Mailing List ID corresponding with the Mailing List that the distribution is to be sent to. - :type mailing_list: str - :param survey: The Survey ID corresponding with the Survey that the distribution is to be sent to. - :type survey: str - :param send_date: The date that the distribution is supposed to be sent on. Pass gmtime() for immediate distribution or use the set_send_date() method to format properly. - :type send_date: str - :param method: This parameter refers to the type of distribution that is to be sent out to the mailing list. - :type method: str - :return: The Distribution ID. (str) - ''' - - assert len(mailing_list) == 18, 'Hey, the parameter for "mailing_list" that was passed is the wrong length. It should have 18 characters.' - assert len(library) == 18, 'Hey, the parameter for "library" that was passed is the wrong length. It should have 18 characters.' - assert len(survey) == 18, 'Hey, the parameter for "survey" that was passed is the wrong length. It should have 18 characters.' - assert len(message) == 18, 'Hey, the parameter for "message" that was passed is the wrong length. It should have 18 characters.' - assert mailing_list[:3] == 'CG_', 'Hey there! It looks like your Mailing List ID is incorrect. You can find the Mailing List ID on the Qualtrics site under your account settings. It will begin with "CG_". Please try again.' - assert survey[:3] == 'SV_', 'Hey there! It looks like your SurveyID is incorrect. You can find the SurveyID on the Qualtrics site under your account settings. It will begin with "SV_". Please try again.' - assert message[:3] == 'MS_', 'Hey there! It looks like your MessageID is incorrect. You can find the MessageID by using the list messages method available in the Messages module of this Package. It will begin with "MS_". Please try again.' - assert library[:3] == 'UR_' or library[:3] == 'GR_', 'Hey there! It looks like your Library ID is incorrect. You can find the Library ID on the Qualtrics site under your account settings. It will begin with "UR_" or "GR_". Please try again.' - - headers, url = self.header_setup(content_type=True, xm=False, path='distributions/sms') - data = { - 'sendDate': send_date, - 'surveyId': survey, - 'method': method, - 'recipients': { - 'mailingListId': mailing_list - }, - 'name': dist_name, - 'message': { - 'libraryId': library, - 'messageId': message - } - } - - if parentDistributionId != None: - data['parentDistributionId'] = parentDistributionId - - request = r.post(url, json=data, headers=headers) - response = request.json() - try: - distribution_id = response['result']['id'] - return distribution_id - except: - print(f"\nServerError: QualtricsAPI Error Code: {response['meta']['error']['errorCode']}\nQualtricsAPI Error Message: {response['meta']['error']['errorMessage']}") - return \ No newline at end of file diff --git a/build/lib/QualtricsAPI/Survey/responses.py b/build/lib/QualtricsAPI/Survey/responses.py deleted file mode 100644 index d8f6ef0..0000000 --- a/build/lib/QualtricsAPI/Survey/responses.py +++ /dev/null @@ -1,300 +0,0 @@ -import requests as r -import zipfile -import io -import json -import pandas as pd -from datetime import date, datetime, timedelta -from dateutil.parser import parse -from QualtricsAPI.Setup import Credentials -from QualtricsAPI.JSON import Parser -from QualtricsAPI.Exceptions import Qualtrics500Error, Qualtrics503Error, Qualtrics504Error, Qualtrics400Error, Qualtrics401Error, Qualtrics403Error -import warnings - -class Responses(Credentials): - '''This is a child class to the credentials class that gathers the survey responses from Qualtrics surveys''' - - def __init__(self): - return - - def setup_request(self, file_format='csv', survey=None): - ''' This method sets up the request and handles the setup of the request for the survey.''' - - assert survey != None, 'Hey There! The survey parameter cannot be None. You need to pass in a survey ID as a string into the survey parameter.' - assert isinstance(survey, str) == True, 'Hey There! The survey parameter must be of type string.' - assert len(survey) == 18, 'Hey there! It looks like your survey ID is a the incorrect length. It needs to be 18 characters long. Please try again.' - assert survey[:3] == 'SV_', 'Hey there! It looks like your survey ID is incorrect. You can find the survey ID on the Qualtrics site under your account settings. Please try again.' - - headers, url = self.header_setup(content_type=True, xm=False, path='responseexports/') - payload = {"format": file_format, "surveyId": survey} - request = r.request("POST", url, data=json.dumps(payload), headers=headers) - response = request.json() - try: - progress_id = response['result']['id'] - return progress_id, url, headers - except: - print(f"ServerError:\nError Code: {response['meta']['error']['errorCode']}\nError Message: {response['meta']['error']['errorMessage']}") - - def send_request(self, file_format='csv', survey=None): - '''This method sends the request, and sets up the download request.''' - file = None - progress_id, url, headers = self.setup_request(file_format=file_format, survey=survey) - check_progress = 0 - progress_status = "in progress" - while check_progress < 100 and (progress_status != "complete") and (file is None): - check_url = url + progress_id - check_response = r.request("GET", check_url, headers=headers) - file = check_response.json()["result"]["file"] - check_progress = check_response.json()["result"]["percentComplete"] - download_url = url + progress_id + '/file' - download_request = r.get(download_url, headers=headers, stream=True) - return download_request - - def get_responses(self, survey=None): - '''This function accepts the survey id, and returns the survey responses associated with that survey. - - :param survey: This is the id associated with a given survey. - :return: a Pandas DataFrame - ''' - warnings.warn('This method is being actively depricated. Please migrate your code over to the new V3 method "Responses().get_survey_responses".', DeprecationWarning, stacklevel=2) - download_request = self.send_request(file_format='csv', survey=survey) - with zipfile.ZipFile(io.BytesIO(download_request.content)) as survey_zip: - for s in survey_zip.infolist(): - df = pd.read_csv(survey_zip.open(s.filename)) - return df - - def get_questions(self, survey=None): - '''This method returns a DataFrame containing the survey questions and the Question IDs. - - :param survey: This is the id associated with a given survey. - :return: a Pandas DataFrame - ''' - warnings.warn('This method is being actively depricated. Please migrate your code over to the new V3 method "Responses().get_survey_questions".', DeprecationWarning, stacklevel=2) - df = self.get_responses(survey=survey) - questions = pd.DataFrame(df[:1].T) - questions.columns = ['Questions'] - return questions - - # Version 3 Code - def setup_request_v3(self, survey=None, payload=None): - ''' This method sets up the request and handles the setup of the request for the survey.''' - - assert survey != None, 'Hey There! The survey parameter cannot be None. You need to pass in a survey ID as a string into the survey parameter.' - assert isinstance(survey, str) == True, 'Hey There! The survey parameter must be of type string.' - assert len(survey) == 18, 'Hey there! It looks like your survey ID is a the incorrect length. It needs to be 18 characters long. Please try again.' - assert survey[:3] == 'SV_', 'Hey there! It looks like your survey ID is incorrect. You can find the survey ID on the Qualtrics site under your account settings. Please try again.' - - headers, url = self.header_setup(content_type=True, xm=False, path=f'surveys/{survey}/export-responses/') - request = r.request("POST", url, data=json.dumps(payload), headers=headers) - response = request.json() - try: - if response['meta']['httpStatus'] == '500 - Internal Server Error': - raise Qualtrics500Error('500 - Internal Server Error') - elif response['meta']['httpStatus'] == '503 - Temporary Internal Server Error': - raise Qualtrics503Error('503 - Temporary Internal Server Error') - elif response['meta']['httpStatus'] == '504 - Gateway Timeout': - raise Qualtrics504Error('504 - Gateway Timeout') - elif response['meta']['httpStatus'] == '400 - Bad Request': - raise Qualtrics400Error('Qualtrics Error\n(Http Error: 400 - Bad Request): There was something invalid about the request.') - elif response['meta']['httpStatus'] == '401 - Unauthorized': - raise Qualtrics401Error('Qualtrics Error\n(Http Error: 401 - Unauthorized): The Qualtrics API user could not be authenticated or does not have authorization to access the requested resource.') - elif response['meta']['httpStatus'] == '403 - Forbidden': - raise Qualtrics403Error('Qualtrics Error\n(Http Error: 403 - Forbidden): The Qualtrics API user was authenticated and made a valid request, but is not authorized to access this requested resource.') - except (Qualtrics500Error, Qualtrics503Error, Qualtrics504Error, Qualtrics400Error, Qualtrics401Error, Qualtrics403Error) as e: - return print(e) - else: - progress_id = response['result']['progressId'] - return progress_id, url, headers - - # Version 3 Code - def send_request_v3(self, survey=None, payload=None): - '''This method sends the request, and sets up the download request.''' - is_file = None - progress_id, url, headers = self.setup_request_v3(survey=survey, payload=payload) - progress_status = "in progress" - while progress_status != "complete" and progress_status != "failed" and is_file is None: - check_url = url + progress_id - check_request = r.request("GET", check_url, headers=headers) - check_response = check_request.json() - try: - is_file = check_response["result"]["fileId"] - except KeyError: - pass - progress_status = check_response["result"]["status"] - try: - if check_response['meta']['httpStatus'] == '500 - Internal Server Error': - raise Qualtrics500Error('500 - Internal Server Error') - elif check_response['meta']['httpStatus'] == '503 - Temporary Internal Server Error': - raise Qualtrics503Error('503 - Temporary Internal Server Error') - elif check_response['meta']['httpStatus'] == '504 - Gateway Timeout': - raise Qualtrics504Error('504 - Gateway Timeout') - elif check_response['meta']['httpStatus'] == '400 - Bad Request': - raise Qualtrics400Error('Qualtrics Error\n(Http Error: 400 - Bad Request): There was something invalid about the request.') - elif check_response['meta']['httpStatus'] == '401 - Unauthorized': - raise Qualtrics401Error('Qualtrics Error\n(Http Error: 401 - Unauthorized): The Qualtrics API user could not be authenticated or does not have authorization to access the requested resource.') - elif check_response['meta']['httpStatus'] == '403 - Forbidden': - raise Qualtrics403Error('Qualtrics Error\n(Http Error: 403 - Forbidden): The Qualtrics API user was authenticated and made a valid request, but is not authorized to access this requested resource.') - except (Qualtrics500Error, Qualtrics503Error, Qualtrics504Error, Qualtrics400Error, Qualtrics401Error, Qualtrics403Error) as e: - return print(e) - else: - download_url = url + is_file + '/file' - download_request = r.get(download_url, headers=headers, stream=True) - return download_request - - # Version 3 Code - def get_survey_responses(self, survey=None, **kwargs): - '''This function accepts the survey id, and returns the survey responses associated with that survey. - :param useLabels: Instead of exporting the recode value for the answer choice, export the text of the answer choice. For more information on recode values, see Recode Values on the Qualtrics Support Page. - :type useLabels: bool - :param includeLabelColumns: For columns that have answer labels, export two columns: one that uses recode values and one that uses labels. The label column will has a IsLabelsColumn field in the 3rd header row. Note that this cannot be used with useLabels. - :type includeLabelColumns: bool - :param exportResponsesInProgress: Export only responses-in-progress. - :type exportResponsesInProgress: bool - :param limit: Maximum number of responses exported. This begins with the first survey responses recieved. So a Limit = 10, would be the surveys first 10 responses. - :type limit: int - :param seenUnansweredRecode: Recode seen-but-unanswered questions with this value. - :type seenUnansweredRecode: int - :param multiselectSeenUnansweredRecode: Recode seen-but-unanswered choices for multi-select questions with this value. If not set, this will be the seenUnansweredRecode value. - :type multiselectSeenUnansweredRecode: int - :param includeDisplayOrder: If true, include display order information in your export. This is useful for surveys with randomization. - :type includeDisplayOrder: bool - :param endDate: Only export responses recorded after the specified UTC date. Example Format: ('%Y-%m-%dT%H:%M:%SZ' => 2020-01-13T12:30:00Z) - :type endDate: str - :param startDate: Only export responses recorded after the specified UTC date. Example Format: ('%Y-%m-%dT%H:%M:%SZ'=> 2020-01-13T12:30:00Z) - :type startDate: str - :param timeZone: Timezone used to determine response date values. If this parameter is not provided, dates will be exported in UTC/GMT. See (https://api.qualtrics.com/instructions/docs/Instructions/dates-and-times.md) for the available timeZones. :type timeZone: str - :param survey: This is the id associated with a given survey. - :return: a Pandas DataFrame - ''' - dynamic_payload = {"format": 'csv'} - for key in list(kwargs.keys()): - assert key in ['useLabels', 'includeLabelColumns', 'exportResponsesInProgress', 'limit', 'seenUnansweredRecode', 'multiselectSeenUnansweredRecode', 'includeDisplayOrder', 'startDate', 'endDate', 'timeZone'], "Hey there! You can only pass in parameters with names in the list, ['useLabels', 'includeLabelColumns', 'exportResponsesInProgress', 'limit', 'seenUnansweredRecode', 'multiselectSeenUnansweredRecode', 'includeDisplayOrder', 'startDate', 'endDate', 'timeZone']" - if key == 'useLabels': - assert 'includeLabelColumns' not in list(kwargs.keys()), 'Hey there, you cannot pass both the "includeLabelColumns" and the "useLabels" parameters at the same time. Please pass just one and try again.' - assert isinstance(kwargs['useLabels'], bool), 'Hey there, your "useLabels" parameter needs to be of type "bool"!' - dynamic_payload.update({'useLabels': kwargs[(key)]}) - elif key == 'exportResponsesInProgress': - assert isinstance(kwargs['exportResponsesInProgress'], bool), 'Hey there, your "exportResponsesInProgress" parameter needs to be of type "bool"!' - dynamic_payload.update({'exportResponsesInProgress': kwargs[(key)]}) - elif key == 'limit': - assert isinstance(kwargs['limit'], int), 'Hey there, your "limit" parameter needs to be of type "int"!' - dynamic_payload.update({'limit': kwargs[(key)]}) - elif key == 'seenUnansweredRecode': - assert isinstance(kwargs['seenUnansweredRecode'], int), 'Hey there, your "seenUnansweredRecode" parameter needs to be of type "int"!' - dynamic_payload.update({'seenUnansweredRecode': kwargs[(key)]}) - elif key == 'multiselectSeenUnansweredRecode': - assert isinstance(kwargs['multiselectSeenUnansweredRecode'], int), 'Hey there, your "multiselectSeenUnansweredRecode" parameter needs to be of type "int"!' - dynamic_payload.update({'multiselectSeenUnansweredRecode': kwargs[(key)]}) - elif key == 'includeLabelColumns': - assert isinstance(kwargs['includeLabelColumns'], bool), 'Hey there, your "includeLabelColumns" parameter needs to be of type "bool"!' - assert 'useLabels' not in list(kwargs.keys()), 'Hey there, you cannot pass both the "includeLabelColumns" and the "useLabels" parameters at the same time. Please pass just one and try again.' - dynamic_payload.update({'includeLabelColumns': kwargs[(key)]}) - elif key == 'includeDisplayOrder': - assert isinstance(kwargs['includeDisplayOrder'], bool), 'Hey there, your "includeDisplayOrder" parameter needs to be of type "bool"!' - dynamic_payload.update({'includeDisplayOrder': kwargs[(key)]}) - elif key == 'startDate': - assert isinstance(kwargs['startDate'], str), 'Hey there, your "startDate" parameter needs to be of type "str"!' - start_date = parse(timestr=kwargs[(key)]) - dynamic_payload.update({'startDate': start_date.strftime('%Y-%m-%dT%H:%M:%SZ')}) - elif key == 'endDate': - assert isinstance(kwargs['endDate'], str), 'Hey there, your "endDate" parameter needs to be of type "str"!' - end_date = parse(timestr=kwargs[(key)]) - dynamic_payload.update({'endDate': end_date.strftime('%Y-%m-%dT%H:%M:%SZ')}) - elif key == 'timeZone': - assert isinstance(kwargs['timeZone'], str), 'Hey there, your "timeZone" parameter needs to be of type "str"!' - dynamic_payload.update({'timeZone': kwargs[(key)]}) - download_request = self.send_request_v3(survey=survey, payload=dynamic_payload) - with zipfile.ZipFile(io.BytesIO(download_request.content)) as survey_zip: - for s in survey_zip.infolist(): - df = pd.read_csv(survey_zip.open(s.filename)) - return df - - # Version 3 Code - def get_survey_questions(self, survey=None): - '''This method returns a DataFrame containing the survey questions and the Question IDs. - - :param survey: This is the id associated with a given survey. - :return: a Pandas DataFrame - ''' - df = self.get_survey_responses(survey=survey, limit=2) - questions = pd.DataFrame(df[:1].T) - questions.columns = ['Questions'] - return questions - - def get_survey_response(self, survey=None, response=None, verbose=False): - ''' This method retrieves a single response from a given survey. ''' - - assert survey != None, 'Hey There! The survey parameter cannot be None. You need to pass in a survey ID as a string into the survey parameter.' - assert response != None, 'Hey There! The response parameter cannot be None. You need to pass in a response ID as a string into the response parameter.' - assert isinstance(survey, str) == True, 'Hey There! The survey parameter must be of type string.' - assert isinstance(response, str) == True, 'Hey There! The response parameter must be of type string.' - assert len(survey) == 18, 'Hey there! It looks like your survey ID is a the incorrect length. It needs to be 18 characters long. Please try again.' - assert len(response) == 17, 'Hey there! It looks like your response ID is a the incorrect length. It needs to be 17 characters long. Please try again.' - assert survey[:3] == 'SV_', 'Hey there! It looks like your survey ID is incorrect. You can find the survey ID on the Qualtrics site under your account settings. Please try again.' - assert response[:2] == 'R_', 'Hey there! It looks like your response ID is incorrect. You can find the response ID on the Qualtrics site under your account settings. Please try again.' - - headers, url = self.header_setup(content_type=True, xm=False, path=f'/surveys/{survey}/responses/{response}') - request = r.request("GET", url, headers=headers) - response = request.json() - try: - if response['meta']['httpStatus'] == '500 - Internal Server Error': - raise Qualtrics500Error('500 - Internal Server Error') - elif response['meta']['httpStatus'] == '503 - Temporary Internal Server Error': - raise Qualtrics503Error('503 - Temporary Internal Server Error') - elif response['meta']['httpStatus'] == '504 - Gateway Timeout': - raise Qualtrics504Error('504 - Gateway Timeout') - elif response['meta']['httpStatus'] == '400 - Bad Request': - raise Qualtrics400Error('Qualtrics Error\n(Http Error: 400 - Bad Request): There was something invalid about the request.') - elif response['meta']['httpStatus'] == '401 - Unauthorized': - raise Qualtrics401Error('Qualtrics Error\n(Http Error: 401 - Unauthorized): The Qualtrics API user could not be authenticated or does not have authorization to access the requested resource.') - elif response['meta']['httpStatus'] == '403 - Forbidden': - raise Qualtrics403Error('Qualtrics Error\n(Http Error: 403 - Forbidden): The Qualtrics API user was authenticated and made a valid request, but is not authorized to access this requested resource.') - except (Qualtrics503Error, Qualtrics504Error) as e: - # Recursive call to handle Internal Server Errors - return self.get_survey_response(self, survey=survey, response=response, verbose=verbose) - except (Qualtrics500Error, Qualtrics400Error, Qualtrics401Error, Qualtrics403Error) as e: - # Handle Authorization/Bad Request Errors - return print(e) - else: - if verbose == True: - return response['meta']['httpStatus'], response['result'] - else: - return response['result'] - return - - - def create_survey_response(self, survey=None, dynamic_payload={}, verbose=False): - ''' This method creates a single response for a given survey. ''' - - assert survey != None, 'Hey There! The survey parameter cannot be None. You need to pass in a survey ID as a string into the survey parameter.' - assert isinstance(survey, str) == True, 'Hey There! The survey parameter must be of type string.' - assert len(survey) == 18, 'Hey there! It looks like your survey ID is a the incorrect length. It needs to be 18 characters long. Please try again.' - assert survey[:3] == 'SV_', 'Hey there! It looks like your survey ID is incorrect. You can find the survey ID on the Qualtrics site under your account settings. Please try again.' - - headers, url = self.header_setup(content_type=True, xm=False, path=f'/surveys/{survey}/responses') - request = r.post(url, json=dynamic_payload, headers=headers) - response = request.json() - try: - if response['meta']['httpStatus'] == '500 - Internal Server Error': - raise Qualtrics500Error('500 - Internal Server Error') - elif response['meta']['httpStatus'] == '503 - Temporary Internal Server Error': - raise Qualtrics503Error('503 - Temporary Internal Server Error') - elif response['meta']['httpStatus'] == '504 - Gateway Timeout': - raise Qualtrics504Error('504 - Gateway Timeout') - elif response['meta']['httpStatus'] == '400 - Bad Request': - raise Qualtrics400Error('Qualtrics Error\n(Http Error: 400 - Bad Request): There was something invalid about the request.') - elif response['meta']['httpStatus'] == '401 - Unauthorized': - raise Qualtrics401Error('Qualtrics Error\n(Http Error: 401 - Unauthorized): The Qualtrics API user could not be authenticated or does not have authorization to access the requested resource.') - elif response['meta']['httpStatus'] == '403 - Forbidden': - raise Qualtrics403Error('Qualtrics Error\n(Http Error: 403 - Forbidden): The Qualtrics API user was authenticated and made a valid request, but is not authorized to access this requested resource.') - except (Qualtrics503Error, Qualtrics504Error) as e: - # Recursive call to handle Internal Server Errors - return self.create_survey_response(self, survey=survey, dynamic_payload=dynamic_payload) - except (Qualtrics500Error, Qualtrics400Error, Qualtrics401Error, Qualtrics403Error) as e: - # Handle Authorization/Bad Request Errors - return print(e, response['meta']) - else: - if verbose == True: - return response['meta'], response['result'] - else: - return response['result'] - return \ No newline at end of file diff --git a/build/lib/QualtricsAPI/Users/__init__.py b/build/lib/QualtricsAPI/Users/__init__.py deleted file mode 100644 index 34d550d..0000000 --- a/build/lib/QualtricsAPI/Users/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -# __init__.py -from .surveys import * - -__all__ = ['surveys'] diff --git a/build/lib/QualtricsAPI/Users/surveys.py b/build/lib/QualtricsAPI/Users/surveys.py deleted file mode 100644 index cffcc28..0000000 --- a/build/lib/QualtricsAPI/Users/surveys.py +++ /dev/null @@ -1,111 +0,0 @@ -import requests as r -import json -import pandas as pd -from QualtricsAPI.Setup import Credentials -from QualtricsAPI.JSON import Parser -from QualtricsAPI.Exceptions import Qualtrics500Error, Qualtrics503Error, Qualtrics504Error, Qualtrics400Error, Qualtrics401Error, Qualtrics403Error - -class Surveys(Credentials): - '''This is a child class to the credentials class that handles survey functionality for the authenticated user.''' - - def __init__(self): - return - - def list_user_surveys(self): - '''This method provides functionality to share a survey within a given brand/organization. - - :return: a Pandas DataFrame with the user's available surveys. - ''' - surveys = pd.DataFrame(columns=['id', 'name', 'ownerId', 'lastModified', 'creationDate', 'isActive', 'nextPage']) - headers, url = self.header_setup(content_type=False, xm=False, path='surveys') - - def extract_page(surveys=surveys, url=url): - ''' This method is a nested method that extracts a single page of surveys. ''' - try: - request = r.get(url, headers=headers) - response = request.json() - if response['meta']['httpStatus'] == '500 - Internal Server Error': - raise Qualtrics500Error('500 - Internal Server Error') - elif response['meta']['httpStatus'] == '503 - Temporary Internal Server Error': - raise Qualtrics503Error('503 - Temporary Internal Server Error') - elif response['meta']['httpStatus'] == '504 - Gateway Timeout': - raise Qualtrics504Error('504 - Gateway Timeout') - elif response['meta']['httpStatus'] == '400 - Bad Request': - raise Qualtrics400Error('Qualtrics Error\n(Http Error: 400 - Bad Request): There was something invalid about the request.') - elif response['meta']['httpStatus'] == '401 - Unauthorized': - raise Qualtrics401Error('Qualtrics Error\n(Http Error: 401 - Unauthorized): The Qualtrics API user could not be authenticated or does not have authorization to access the requested resource.') - elif response['meta']['httpStatus'] == '403 - Forbidden': - raise Qualtrics403Error('Qualtrics Error\n(Http Error: 403 - Forbidden): The Qualtrics API user was authenticated and made a valid request, but is not authorized to access this requested resource.') - except (Qualtrics500Error, Qualtrics503Error): - t.sleep(0.25) - extract_page(surveys=surveys, url=url) - except Qualtrics504Error: - t.sleep(5) - extract_page(surveys=surveys, url=url) - except (Qualtrics400Error, Qualtrics401Error, Qualtrics403Error) as e: - print(e) - except: - t.sleep(10) - extract_page(surveys=surveys, url=url) - else: - keys = ['id', 'name', 'ownerId', 'lastModified', 'creationDate', 'isActive'] - lists = Parser().json_parser(response=response, keys=keys, arr=False) - single_page = pd.DataFrame(lists).transpose() - single_page.columns = keys - surveys = pd.concat([surveys, single_page]).reset_index(drop=True) - next_page = response['result']['nextPage'] - return surveys, next_page - - surveys, next_page = extract_page(surveys=surveys, url=url) - - if next_page is None: - return surveys - else: - while next_page is not None: - surveys, next_page = extract_page(surveys=surveys, url=next_page) - return surveys - - def share_user_surveys(self, survey=None, recipient_id=None, permissions={}): - '''This method provides functionality to share a survey within a given brand/organization. - - :param survey: the name of the list to be created. - :param recipient_id: the group/user qualtrics id - :param permissions: an object of permission properties. - :return: A message on HTTP-200 Success - ''' - - assert survey != None, 'Hey there! The survey parameter cannot be None.' - assert isinstance(survey, str) == True, 'Hey there! The survey parameter must be of type string.' - assert recipient_id != None, 'Hey there! The recipient parameter cannot be None.' - assert isinstance(recipient_id, str) == True, 'Hey there! The recipient parameter must be of type string.' - assert permissions != None, 'Hey there! The permissions parameter cannot be None.' - assert isinstance(permissions, dict) == True, 'Hey there! The permissions parameter must be of type dict.' - - headers, url = self.header_setup(content_type=False, xm=False, path=f'surveys/{survey}/permissions/collaborations') - data = { - 'recipientId': recipient_id, - 'permissions': permissions - } - try: - request = r.post(url, json=data, headers=headers) - response = request.json() - if response['meta']['httpStatus'] == '500 - Internal Server Error': - raise Qualtrics500Error('500 - Internal Server Error') - elif response['meta']['httpStatus'] == '503 - Temporary Internal Server Error': - raise Qualtrics503Error('503 - Temporary Internal Server Error') - elif response['meta']['httpStatus'] == '504 - Gateway Timeout': - raise Qualtrics504Error('504 - Gateway Timeout') - elif response['meta']['httpStatus'] == '400 - Bad Request': - raise Qualtrics400Error('Qualtrics Error\n(Http Error: 400 - Bad Request): There was something invalid about the request.') - elif response['meta']['httpStatus'] == '401 - Unauthorized': - raise Qualtrics401Error('Qualtrics Error\n(Http Error: 401 - Unauthorized): The Qualtrics API user could not be authenticated or does not have authorization to access the requested resource.') - elif response['meta']['httpStatus'] == '403 - Forbidden': - raise Qualtrics403Error('Qualtrics Error\n(Http Error: 403 - Forbidden): The Qualtrics API user was authenticated and made a valid request, but is not authorized to access this requested resource.') - except (Qualtrics500Error, Qualtrics503Error, Qualtrics504Error) as e: - # Recursive call to handle Internal Server Errors - return self.share_user_surveys(survey=survey, recipient_id=recipient_id, permissions=permissions) - except (Qualtrics400Error, Qualtrics401Error, Qualtrics403Error) as e: - # Handle Authorization/Bad Request Errors - return print(e) - else: - return f'The survey "{survey}" was shared with the user/group "{recipient_id}"' \ No newline at end of file diff --git a/build/lib/QualtricsAPI/XM/__init__.py b/build/lib/QualtricsAPI/XM/__init__.py deleted file mode 100644 index 165d284..0000000 --- a/build/lib/QualtricsAPI/XM/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -# __init__.py -from .mailinglists import * -from .xmdirectory import * - -__all__ = ['mailinglists', 'xmdirectory'] diff --git a/build/lib/QualtricsAPI/XM/mailinglists.py b/build/lib/QualtricsAPI/XM/mailinglists.py deleted file mode 100644 index 95c8440..0000000 --- a/build/lib/QualtricsAPI/XM/mailinglists.py +++ /dev/null @@ -1,267 +0,0 @@ -import time as t -import requests as r -import pandas as pd -from QualtricsAPI.Setup import Credentials -from QualtricsAPI.JSON import Parser -from QualtricsAPI.Exceptions import Qualtrics500Error - -class MailingList(Credentials): - ''' This class contains methods that give users the ability to work with their users Mailing list's and - their users Mailing Lists contact data within the XMDirectory.''' - - def __init__(self, token=None, directory_id=None, data_center=None): - self.token = token - self.data_center = data_center - self.directory_id = directory_id - return - - def create_list(self, name=None): - '''This method will create a mailing list in the XM Directory for the your specified user's account. - - :param list_name: the name of the list to be created. - :return: tuple containing the Mailing List's and the Mailing List's new id. - ''' - assert name != None, 'Hey there! The name parameter cannot be None. You need to pass in a new Mailing List name as a string into the name parameter.' - assert isinstance(name, str) == True, 'Hey there! The name parameter must be of type string.' - - headers, base_url = self.header_setup(content_type=True, xm=True) - url = f"{base_url}/mailinglists" - data = {"name": "{0}".format(name)} - request = r.post(url, json=data, headers=headers) - response = request.json() - try: - list_id = Parser().json_parser(response=response, keys=['id'], arr=False)[0][0] - return name, list_id - except: - print(f"ServerError: {response['meta']['httpStatus']}\nError Code: {response['meta']['error']['errorCode']}\nError Message: {response['meta']['error']['errorMessage']}") - - def list_lists(self, page_size=100): - '''This method lists all the mailing lists in the directory for the specified user token. You won't typically need to adjust - the pre-defined parameters. - - :param page_size: The number of mailing lists to return per call. - :type page_size: int - :return: A Pandas DataFrame - ''' - assert page_size != 0, 'Hey there! You need to have a page size greater than 1' - - mailing_lists = pd.DataFrame() - headers, base_url = self.header_setup(xm=True) - url = base_url + f"/mailinglists/?pageSize={page_size}" - try: - def get_page(mailing_lists=mailing_lists, url=url): - ''' This method is a nested method that extracts a single page of mailing lists. ''' - request = r.get(url, headers=headers) - response = request.json() - keys = ['mailingListId', 'name', 'ownerId', 'lastModifiedDate', 'creationDate','contactCount', 'nextPage'] - lists = Parser().json_parser(response=response, keys=keys, arr=False) - single_page = pd.DataFrame(lists).transpose() - single_page.columns = keys - single_page['creationDate'] = pd.to_datetime(single_page['creationDate'], unit='ms') - single_page['lastModifiedDate'] = pd.to_datetime(single_page['lastModifiedDate'], unit='ms') - mailing_lists = pd.concat([mailing_lists, single_page]).reset_index(drop=True) - next_page = str(response['result']['nextPage']) - return mailing_lists, next_page, response - mailing_lists, next_page, response = get_page(mailing_lists=mailing_lists, url=url) - while next_page != 'None': - mailing_lists, next_page, response = get_page(mailing_lists=mailing_lists, url=next_page) - return mailing_lists - except: - print(f"ServerError: {response['meta']['httpStatus']}\nError Code: {response['meta']['error']['errorCode']}\nError Message: {response['meta']['error']['errorMessage']}") - - def get_list(self, mailing_list=None): - '''This function gets the list specfied by the mailing list param and returns the list members. - - :param mailing_list: Your mailing list id that you are interested in getting information on. - :type mailing_list: str - :return: A Pandas DataFrame - ''' - assert mailing_list != None, 'Hey there! The mailing_list parameter cannot be None. You need to pass in a Mailing List ID as a string into the mailing_list parameter.' - assert isinstance(mailing_list, str) == True, 'Hey there! The mailing_list parameter must be of type string.' - assert len(mailing_list) == 18, 'Hey, the parameter for "mailing_list" that was passed is the wrong length. It should have 18 characters.' - assert mailing_list[:3] == 'CG_', 'Hey there! It looks like your Mailing List ID is incorrect. You can find the Mailing List ID on the Qualtrics site under your account settings. It will begin with "CG_". Please try again.' - - headers, base_url = self.header_setup(xm=True) - url = f"{base_url}/mailinglists/{mailing_list}" - request = r.get(url, headers=headers) - response = request.json() - try: - list_info = { - "mailingListId": response['result']['mailingListId'], - "name": response['result']['name'], - "ownerId": response['result']['ownerId'], - "lastModifiedDate": response['result']['lastModifiedDate'], - "creationDate": response['result']['creationDate'], - "contactCount": response['result']['contactCount'] - } - df = pd.DataFrame.from_dict(list_info, orient='index').transpose() - df['creationDate'] = pd.to_datetime(df['creationDate'], unit='ms') - df['lastModifiedDate'] = pd.to_datetime(df['lastModifiedDate'], unit='ms') - return df - except: - print(f"ServerError: {response['meta']['httpStatus']}\nError Code: {response['meta']['error']['errorCode']}\nError Message: {response['meta']['error']['errorMessage']}") - - def rename_list(self, mailing_list=None, name=None): - '''This method takes an existing mailing list name and updates it to reflect the name defined in the name parameter. - - :param mailing_list: the mailing list that you want to rename. - :type mailing_list: str - :param name: The new name for the mailing list. - :type name: str - :return: A string indicating the success or failure of the method call. - ''' - assert mailing_list != None, 'Hey there! The mailing_list parameter cannot be None. You need to pass in a Mailing List ID as a string into the mailing_list parameter.' - assert isinstance(mailing_list, str) == True, 'Hey there! The mailing_list parameter must be of type string.' - assert name != None, 'Hey there! The name parameter cannot be None. You need to pass in a new Mailing List name as a string into the name parameter.' - assert isinstance(name, str) == True, 'Hey there! The name parameter must be of type string.' - assert len(mailing_list) == 18, 'Hey there! The parameter for "mailing_list" that was passed is the wrong length. It should have 18 characters.' - assert mailing_list[:3] == 'CG_', 'Hey there! It looks like your Mailing List ID is incorrect. You can find the Mailing List ID on the Qualtrics site under your account settings. Please try again.' - - data = {"name": f"{name}"} - headers, base_url = self.header_setup(content_type=True, xm=True) - url = f"{base_url}/mailinglists/{mailing_list}" - request = r.put(url, json=data, headers=headers) - response = request.json() - try: - if response['meta']['httpStatus'] == '200 - OK': - print(f'Your mailing list "{mailing_list}" has been renamed to {name} in the XM Directory.') - except: - print(f"ServerError: {response['meta']['httpStatus']}\nError Code: {response['meta']['error']['errorCode']}\nError Message: {response['meta']['error']['errorMessage']}") - return - - def delete_list(self, mailing_list=None): - '''This method will delete the specified mailing list from the given users XM Directory. - - :param mailing_list: Your mailing list id that you are interested in deleting. - :type mailing_list: str - :return: A string indicating the success or failure of the method call. - ''' - - assert mailing_list != None, 'Hey, the mailing_list parameter cannot be None. You need to pass in a Mailing List ID as a string into the mailing_list parameter.' - assert isinstance(mailing_list, str) == True, 'Hey there, the mailing_list parameter must be of type string.' - assert len(mailing_list) == 18, 'Hey there! The parameter for "mailing_list" that was passed is the wrong length. It should have 18 characters.' - assert mailing_list[:3] == 'CG_', 'Hey there! It looks like your Mailing List ID is incorrect. You can find the Mailing List ID on the Qualtrics site under your account settings. Please try again.' - - data = {"name": f"{mailing_list}"} - headers, base_url = self.header_setup(xm=True) - url = f"{base_url}/mailinglists/{mailing_list}" - request = r.delete(url, json=data, headers=headers) - response = request.json() - try: - if response['meta']['httpStatus'] == '200 - OK': - print(f'Your mailing list "{mailing_list}" has been deleted from the XM Directory.') - except: - print(f"ServerError: {response['meta']['httpStatus']}\nError Code: {response['meta']['error']['errorCode']}\nError Message: {response['meta']['error']['errorMessage']}") - return - - def list_contacts(self, mailing_list=None, page_size=100): - '''This method creates a pandas DataFrame of all the contacts information within the defined mailing list. - - :param mailing_list: the mailing list id - :type mailing_list: str - :param page_size: The number of contacts in the mailing list to return per call. (typically this doesn't not need to be changed.) - :type page_size: int - :return: A Pandas DataFrame - ''' - assert len(mailing_list) == 18, 'Hey, the parameter for "mailing_list" that was passed is the wrong length. It should have 18 characters.' - assert mailing_list[:3] == 'CG_', 'Hey there! It looks like your Mailing List ID is incorrect. You can find the Mailing List ID on the Qualtrics site under your account settings. Please try again.' - assert page_size != 0, 'Hey there! You need to have a page size greater than 1' - - contact_list = pd.DataFrame() - headers, base_url = self.header_setup(xm=True) - url = base_url + f"/mailinglists/{mailing_list}/contacts?pageSize={page_size}" - try: - def get_page(mailing_list=mailing_list, contact_list=contact_list, url=url): - request = r.get(url, headers=headers) - response = request.json() - keys = ['contactId','firstName','lastName','email','phone','extRef','language','unsubscribed'] - contact_lists = Parser().json_parser(response=response, keys=keys, arr=False) - single_page = pd.DataFrame(contact_lists).transpose() - single_page.columns = keys - single_page['mailing_list'] = mailing_list - contact_list = pd.concat([contact_list, single_page]).reset_index(drop=True) - next_page = str(response['result']['nextPage']) - return contact_list, next_page, response - contact_list, next_page, response = get_page(mailing_list=mailing_list, contact_list=contact_list, url=url) - while next_page != 'None': - contact_list, next_page, response = get_page(mailing_list=mailing_list, contact_list=contact_list, url=next_page) - return contact_list - except: - print(f"ServerError: {response['meta']['httpStatus']}\nError Code: {response['meta']['error']['errorCode']}\nError Message: {response['meta']['error']['errorMessage']}") - - def create_contact_in_list(self, mailing_list=None, **kwargs): - '''This method creates contacts in the specified mailing list. It is important to remember here that whenever you create a contact in - a mailing list, you are also creating that contact in the XMDirectory. Once created 2 seperate IDs are created for the contact. The ContactID - is the reference for the contact in the XMDirectory, and the Contact Lookup ID is the reference of the contact in the Mailing List. - - :param mailing_list: The mailing list id for the list that you want to add the contact too. - :type mailing_list: str - :param first_name: The new contact's first name. - :type first_name: str - :param last_name: The new contact's last name. - :type last_name: str - :param email: The new contact's email. - :type email: str - :param phone: The new contact's phone number. - :tyoe phone: str - :param external_ref: The new contact's external reference. - :type external_ref: str - :param unsubscribed: This parameter denotes whether the new contact is unsubscribed from surveys (Default: False). - :type unsbscribed: str - :param language: The language prefered by the new contact (Default: English) - :type language: str - :param metadata: Any relevant contact metadata. - :type metadata: dict - :return: the contact id (contact_id) in XMDirectory, and the contact id (contact_list_id) in the mailing list. - ''' - assert len(mailing_list) == 18, 'Hey there! The parameter for "mailing_list" that was passed is the wrong length. It should have 18 characters.' - assert mailing_list[:3] == 'CG_', 'Hey there! It looks like your Mailing List ID is incorrect. You can find the Mailing List ID on the Qualtrics site under your account settings. Please try again.' - - dynamic_payload = {} - for key in list(kwargs.keys()): - assert key in ['first_name', 'last_name', 'email', 'unsubscribed', 'language', 'external_ref', 'metadata', 'phone'], "Hey there! You can only pass in parameters with names in the list, ['first_name', 'last_name', 'email', 'unsubscribed', 'language', 'external_ref', 'metadata']" - if key == 'first_name': - dynamic_payload.update({'firstName': kwargs[str(key)]}) - elif key == 'last_name': - dynamic_payload.update({'lastName': kwargs[str(key)]}) - elif key == 'email': - dynamic_payload.update({'email': kwargs[str(key)]}) - elif key == 'phone': - dynamic_payload.update({'phone': kwargs[str(key)]}) - elif key == 'language': - dynamic_payload.update({'language': kwargs[str(key)]}) - elif key == 'external_ref': - dynamic_payload.update({'extRef': kwargs[str(key)]}) - elif key == 'unsubscribed': - dynamic_payload.update({'unsubscribed': kwargs[str(key)]}) - elif key == 'phone': - dynamic_payload.update({'phone': kwargs[str(key)]}) - elif key == 'metadata': - assert isinstance(kwargs['metadata'], dict), 'Hey there, your metadata parameter needs to be of type "dict"!' - dynamic_payload.update({'embeddedData': kwargs[str(key)]}) - - headers, base_url = self.header_setup(content_type=True, xm=True) - url = base_url + f"/mailinglists/{mailing_list}/contacts" - request = r.post(url, json=dynamic_payload, headers=headers) - response = request.json() - try: - if response['meta']['httpStatus'] == '500 - Internal Server Error': - raise Qualtrics500Error('500 - Internal Server Error') - contact_id = response['result']['id'] - except Qualtrics500Error: - attempt = 0 - while attempt < 20: - request = r.post(url, json=dynamic_payload, headers=headers) - response = request.json() - if response['meta']['httpStatus'] == '500 - Internal Server Error': - attempt+=1 - t.sleep(0.25) - continue - elif response['meta']['httpStatus'] == '200 - OK': - return response['result']['id'], response['result']['contactLookupId'] - return print(f"ServerError: {response['meta']['httpStatus']}\nError Code: {response['meta']['error']['errorCode']}\nError Message: {response['meta']['error']['errorMessage']}") - except Exception: - print(f"ServerError: {response['meta']['httpStatus']}\nError Code: {response['meta']['error']['errorCode']}\nError Message: {response['meta']['error']['errorMessage']}") - else: - contact_list_id = response['result']['contactLookupId'] - return contact_id, contact_list_id \ No newline at end of file diff --git a/build/lib/QualtricsAPI/XM/xmdirectory.py b/build/lib/QualtricsAPI/XM/xmdirectory.py deleted file mode 100644 index 420eec8..0000000 --- a/build/lib/QualtricsAPI/XM/xmdirectory.py +++ /dev/null @@ -1,302 +0,0 @@ -import time as t -import io -import json -import requests as r -import pandas as pd -from QualtricsAPI.Setup import Credentials -from QualtricsAPI.JSON import Parser -from QualtricsAPI.Exceptions import Qualtrics500Error, Qualtrics503Error, Qualtrics504Error, Qualtrics400Error, Qualtrics401Error, Qualtrics403Error - -class XMDirectory(Credentials): - ''' This class contains methods that give users the ability to work with their contact data within the - XMDirectory.''' - - def __init__(self, token=None, directory_id=None, data_center=None): - self.token = token - self.data_center = data_center - self.directory_id = directory_id - - def create_contact_in_XM(self, **kwargs): - '''This function gives you the ability to create a contact in your XM Directory. This method does re-list not each - element that you just created. It returns the XMDirectory "Contact ID" associated with the newly created XM directory - contact. - - :param dynamic_payload: A dictionary containing the correct key-value pairs. - :type dynamic_payload: dict - :param first_name: The contacts first name. - :type first_name: str - :param last_name: The contacts last name. - :type last_name: str - :param email: the contacts email. - :type email: str - :param phone: the contacts phone number. - :type phone: str - :param language: the native language of the contact. (Default: English) - :type language: str - :param metadata: any relevant contact metadata. - :type metadata: dict - :return: The newly created contact id (CID) in XMDirectory. - :type return: str - ''' - - dynamic_payload={} - verbose = False - for key in list(kwargs.keys()): - assert key in ['first_name', 'last_name', 'email', 'unsubscribed', 'language', 'external_ref', 'metadata', 'phone', 'verbose', 'dynamic_payload'], "Hey there! You can only pass in parameters with names in the list, ['first_name', 'last_name', 'email', 'unsubscribed', 'language', 'external_ref', 'metadata']" - if key == 'first_name': - dynamic_payload.update({'firstName': kwargs[str(key)]}) - elif key == 'last_name': - dynamic_payload.update({'lastName': kwargs[str(key)]}) - elif key == 'email': - dynamic_payload.update({'email': kwargs[str(key)]}) - elif key == 'phone': - dynamic_payload.update({'phone': kwargs[str(key)]}) - elif key == 'language': - dynamic_payload.update({'language': kwargs[str(key)]}) - elif key == 'external_ref': - dynamic_payload.update({'extRef': kwargs[str(key)]}) - elif key == 'unsubscribed': - dynamic_payload.update({'unsubscribed': kwargs[str(key)]}) - elif key == 'phone': - dynamic_payload.update({'phone': kwargs[str(key)]}) - elif key == 'metadata': - assert isinstance(kwargs['metadata'], dict), 'Hey there, your metadata parameter needs to be of type "dict"!' - dynamic_payload.update({'embeddedData': kwargs[str(key)]}) - elif key == 'dynamic_payload': - dynamic_payload = dict(kwargs[str(key)]) - elif key == 'verbose': - verbose = True - - headers, base_url = self.header_setup(content_type=True, xm=True) - url = f"{base_url}/contacts" - request = r.post(url, json=dynamic_payload, headers=headers) - response = request.json() - try: - if response['meta']['httpStatus'] == '500 - Internal Server Error': - raise Qualtrics500Error('500 - Internal Server Error') - elif response['meta']['httpStatus'] == '503 - Temporary Internal Server Error': - raise Qualtrics503Error('503 - Temporary Internal Server Error') - elif response['meta']['httpStatus'] == '504 - Gateway Timeout': - raise Qualtrics504Error('504 - Gateway Timeout') - elif response['meta']['httpStatus'] == '400 - Bad Request': - raise Qualtrics400Error('Qualtrics Error\n(Http Error: 400 - Bad Request): There was something invalid about the request.') - elif response['meta']['httpStatus'] == '401 - Unauthorized': - raise Qualtrics401Error('Qualtrics Error\n(Http Error: 401 - Unauthorized): The Qualtrics API user could not be authenticated or does not have authorization to access the requested resource.') - elif response['meta']['httpStatus'] == '403 - Forbidden': - raise Qualtrics403Error('Qualtrics Error\n(Http Error: 403 - Forbidden): The Qualtrics API user was authenticated and made a valid request, but is not authorized to access this requested resource.') - except (Qualtrics500Error, Qualtrics503Error, Qualtrics504Error) as e: - # Recursive call to handle Internal Server Errors - return self.create_contact_in_XM(dynamic_payload=dynamic_payload) - except (Qualtrics400Error, Qualtrics401Error, Qualtrics403Error) as e: - # Handle Authorization/Bad Request Errors - return print(e) - else: - if verbose == True: - return response['meta']['httpStatus'], response['result']['id'] - else: - return response['result']['id'] - - def delete_contact(self, contact_id=None): - '''This method will delete a contact from your XMDirectory. (Caution this cannot be reversed once deleted!) - - :param contact_id: The unique id associated with each contact in the XM Directory. - :type contact_id: str - :return: A string indicating the success or failure of the method call. - ''' - assert contact_id != None, 'Hey, the contact_id parameter cannot be None. You need to pass in a XM Directory Contact ID as a string into the contact_id parameter.' - assert isinstance(contact_id, str) == True, 'Hey there, the contact_id parameter must be of type string.' - assert len(contact_id) == 19, 'Hey, the parameter for "contact_id" that was passed is the wrong length. It should have 19 characters.' - assert contact_id[:4] == 'CID_', 'Hey there! It looks like the Contact ID that was entered is incorrect. It should begin with "CID_". Please try again.' - - headers, base_url = self.header_setup(xm=True) - url = f"{base_url}/contacts/{contact_id}" - request = r.delete(url, headers=headers) - response = request.json() - try: - if response['meta']['httpStatus'] == '200 - OK': - return f'Your XM Contact"{contact_id}" has been deleted from the XM Directory.' - except: - print(f"ServerError:\nError Code: {response['meta']['error']['errorCode']}\nError Message: {response['meta']['error']['errorMessage']}") - - def update_contact(self, contact_id=None, **kwargs): - '''This method will update a contact from your XMDirectory. - - :param contact_id: The unique id associated with each contact in the XM Directory. - :type contact_id: str - :param first_name: The new contact's first name. - :type first_name: str - :param last_name: The new contact's last name. - :type last_name: str - :param email: The new contact's email. - :type email: str - :param phone: The new contact's phone number. - :tyoe phone: str - :param external_ref: The new contact's external reference. - :type external_ref: str - :param unsubscribed: This parameter denotes whether the new contact is unsubscribed from surveys (Default: False). - :type unsbscribed: str - :param language: The language prefered by the new contact (Default: English) - :type language: str - :param metadata: Any relevant contact metadata. - :type metadata: dict - :return: A string indicating the success or failure of the method call. - ''' - assert contact_id != None, 'Hey, the contact_id parameter cannot be None. You need to pass in a XM Directory Contact ID as a string into the contact_id parameter.' - assert isinstance(contact_id, str) == True, 'Hey there, the contact_id parameter must be of type string.' - assert len(contact_id) == 19, 'Hey, the parameter for "contact_id" that was passed is the wrong length. It should have 19 characters.' - assert contact_id[:4] == 'CID_', 'Hey there! It looks like the Contact ID that was entered is incorrect. It should begin with "CID_". Please try again.' - - dynamic_payload = {} - for key in list(kwargs.keys()): - assert key in ['first_name', 'last_name', 'email', 'unsubscribed', 'language', 'external_ref', 'metadata', 'phone'], "Hey there! You can only pass in parameters with names in the list, ['first_name', 'last_name', 'email', 'unsubscribed', 'language', 'external_ref', 'metadata']" - if key == 'first_name': - dynamic_payload.update({'firstName': kwargs[str(key)]}) - elif key == 'last_name': - dynamic_payload.update({'lastName': kwargs[str(key)]}) - elif key == 'email': - dynamic_payload.update({'email': kwargs[str(key)]}) - elif key == 'phone': - dynamic_payload.update({'phone': kwargs[str(key)]}) - elif key == 'language': - dynamic_payload.update({'language': kwargs[str(key)]}) - elif key == 'external_ref': - dynamic_payload.update({'extRef': kwargs[str(key)]}) - elif key == 'unsubscribed': - dynamic_payload.update({'unsubscribed': kwargs[str(key)]}) - elif key == 'phone': - dynamic_payload.update({'phone': kwargs[str(key)]}) - elif key == 'metadata': - assert isinstance(kwargs['metadata'], dict), 'Hey there, your metadata parameter needs to be of type "dict"!' - dynamic_payload.update({'embeddedData': kwargs[str(key)]}) - - headers, base_url = self.header_setup(xm=True) - url = f"{base_url}/contacts/{contact_id}" - request = r.put(url, json=dynamic_payload, headers=headers) - response = request.json() - try: - if response['meta']['httpStatus'] == '500 - Internal Server Error': - raise Qualtrics500Error('500 - Internal Server Error') - except Qualtrics500Error: - attempt = 0 - while attempt < 20: - request = r.put(url, json=dynamic_payload, headers=headers) - response = request.json() - if response['meta']['httpStatus'] == '500 - Internal Server Error': - attempt+=1 - t.sleep(0.25) - continue - elif response['meta']['httpStatus'] == '200 - OK': - return f'The contact ({contact_id}) was updated in the XM Directory.' - return print(f"ServerError: {response['meta']['httpStatus']}\nError Code: {response['meta']['error']['errorCode']}\nError Message: {response['meta']['error']['errorMessage']}") - except Exception: - print(f"ServerError: {response['meta']['httpStatus']}\nError Code: {response['meta']['error']['errorCode']}\nError Message: {response['meta']['error']['errorMessage']}") - else: - return f'The contact ({contact_id}) was updated in the XM Directory.' - - def list_contacts_in_directory(self): - '''This method will list the top-level information about the contacts in your XM Directory. As a word of caution, - this method may take a while to complete depending on the size of your XM Directory. There exists some latency - with between - - :return: A Pandas DataFrame - ''' - - page_size=1000 - i=1000 - master = pd.DataFrame(columns=['contactId','firstName', 'lastName', 'email', 'phone','unsubscribed', 'language', 'extRef']) - headers, base_url = self.header_setup(xm=True) - url = base_url + f"/contacts?pageSize={page_size}&useNewPaginationScheme=true" - - def extract_page(url=url, master=master, page_size=page_size): - ''' This is a method that extracts a single page of contacts in a mailing list.''' - try: - request = r.get(url, headers=headers) - response = request.json() - if response['meta']['httpStatus'] == '500 - Internal Server Error': - raise Qualtrics500Error('500 - Internal Server Error') - elif response['meta']['httpStatus'] == '503 - Temporary Internal Server Error': - raise Qualtrics503Error('503 - Temporary Internal Server Error') - elif response['meta']['httpStatus'] == '504 - Gateway Timeout': - raise Qualtrics504Error('504 - Gateway Timeout') - except (Qualtrics500Error, Qualtrics503Error): - t.sleep(0.25) - extract_page(url=url, master=master) - except Qualtrics504Error: - t.sleep(5) - extract_page(url=url, master=master) - except: - t.sleep(10) - extract_page(url=url, master=master) - else: - keys = ['contactId','firstName', 'lastName', 'email', 'phone','unsubscribed', 'language', 'extRef'] - contact_lists = Parser().json_parser(response=response, keys=keys, arr=False) - next_page = response['result']['nextPage'] - single_contact_list = pd.DataFrame(contact_lists).transpose() - single_contact_list.columns = keys - master = pd.concat([master, single_contact_list]).reset_index(drop=True) - return master, next_page - - master, next_page = extract_page() - - print(i) - if next_page is None: - return master - else: - while next_page is not None: - master, next_page = extract_page(url=next_page, master=master) - i+=1000 - print(i) - return master - - def get_contact(self, contact_id=None): - ''' This method is similar to the 'list_contacts_in_directory' method. Except it will just return a single contact's - information. - - :param contact_id: The unique id associated with each contact in the XM Directory. - :type contact_id: str - :return: A Pandas DataFrame - ''' - assert contact_id != None, 'Hey, the contact_id parameter cannot be None. You need to pass in a XM Directory Contact ID as a string into the contact_id parameter.' - assert isinstance(contact_id, str) == True, 'Hey there, the contact_id parameter must be of type string.' - assert len(contact_id) == 19, 'Hey, the parameter for "contact_id" that was passed is the wrong length. It should have 19 characters.' - assert contact_id[:4] == 'CID_', 'Hey there! It looks like the Contact ID that was entered is incorrect. It should begin with "CID_". Please try again.' - - headers, base_url = self.header_setup(xm=True) - url = base_url + f'/contacts/{str(contact_id)}' - request = r.get(url, headers=headers) - response = request.json() - try: - primary = pd.DataFrame.from_dict(response['result'], orient='index').transpose() - primary['creationDate'] = pd.to_datetime(primary['creationDate'],unit='ms') - primary['lastModified'] = pd.to_datetime(primary['lastModified'],unit='ms') - return primary - except: - print(f"ServerError:\nError Code: {response['meta']['error']['errorCode']}\nError Message: {response['meta']['error']['errorMessage']}") - - def get_contact_additional_info(self, contact_id=None, content=None): - ''' This method will return the additional "nested" information associated with a contact in the XMDirectory. - To get these different nested pieces of infomation you can pass one of three arguements to the 'content' parameter. If you - pass 'mailinglistmembership', you will return the different Mailing Lists that the contact is associated with in the form of a - pandas DataFrame. If you pass 'stats', you will return the response statistics associated with the contact, again in the form - of a Pandas DataFrame. Finally, if you pass the 'embeddedData' argument, you will return any emmbedded data associated with - the given contact, and as you guessed it, in the form of a Pandas DataFrame. - - :param contact_id: The unique id associated with each contact in the XM Directory. - :type contact_id: str - :param content: A string representing either 'mailingListMembership', 'stats', 'embeddedData' - :type content: str - :return: A Pandas DataFrame - ''' - assert contact_id != None, 'Hey, the contact_id parameter cannot be None. You need to pass in a XM Directory Contact ID as a string into the contact_id parameter.' - assert isinstance(contact_id, str) == True, 'Hey there, the contact_id parameter must be of type string.' - assert len(contact_id) == 19, 'Hey, the parameter for "contact_id" that was passed is the wrong length. It should have 19 characters.' - assert contact_id[:4] == 'CID_', 'Hey there! It looks like the Contact ID that was entered is incorrect. It should begin with "CID_". Please try again.' - assert content != None, 'Hey there, you need to pass an argument ("embeddedData", or "mailingListMembership") to the "content" parameter.' - - try: - primary = self.get_contact(contact_id=contact_id) - keys = Parser().extract_keys(primary[content][0]) - data = pd.DataFrame.from_dict(primary[content][0], orient='index').transpose() - return data - except: - print('Hey there! Something went wrong please try again.') diff --git a/build/lib/QualtricsAPI/__init__.py b/build/lib/QualtricsAPI/__init__.py deleted file mode 100644 index dfce8d4..0000000 --- a/build/lib/QualtricsAPI/__init__.py +++ /dev/null @@ -1,9 +0,0 @@ -# __init__.py -from QualtricsAPI.Setup import Credentials -from QualtricsAPI.Survey import Responses -from QualtricsAPI.JSON import Parser -from QualtricsAPI.XM import MailingList -from QualtricsAPI.XM import XMDirectory -from QualtricsAPI.Library import Messages - -__all__ = ["Setup", "JSON", "Contacts", "Survey", "Library"] diff --git a/build/lib/QualtricsAPI/tests/__init__.py b/build/lib/QualtricsAPI/tests/__init__.py deleted file mode 100644 index 6697191..0000000 --- a/build/lib/QualtricsAPI/tests/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from .test import * - -__all__ = ['test'] diff --git a/build/lib/QualtricsAPI/tests/test.py b/build/lib/QualtricsAPI/tests/test.py deleted file mode 100644 index aa02e39..0000000 --- a/build/lib/QualtricsAPI/tests/test.py +++ /dev/null @@ -1,1482 +0,0 @@ -# Run in the Root Directory to run tests -## python3 -m unittest QualtricsAPI/tests/test.py - -import unittest -import pandas as pd -from QualtricsAPI.Setup import Credentials -from QualtricsAPI.Survey import Responses -from QualtricsAPI.JSON import Parser -from QualtricsAPI.XM import MailingList -from QualtricsAPI.XM import XMDirectory -from QualtricsAPI.Library import Messages -from QualtricsAPI.Survey import Distributions -from datetime import date, datetime, timedelta -from time import gmtime - -# Setup Tests Class -class setup_tests(object): - - def __init__(self): - return - - def setup_test_token(self, short=False): - '''Setup for Test Case 1: qualtrics_api_credentials token parameter lengths.(40)''' - - token = 'ThisIsaFakeAPITokenAndIsTooShortToWork!' if short else 'ThisIsaFakeAPITokenAndIsTooShortToWork!!!' - return token - - def setup_test_directory_id(self, short=False, false_id=False): - '''Setup for Test Case 2: qualtrics_api_credentials directory id parameter lengths (20), and the incorrect id (POOL_). ''' - - directory_id = 'POOL_ThisIsaFakeID!' if short else 'POOL_ThisIsaFakeDirectoryID!' - bad_id = 'ThisIsaFakeIDwo/POOL' if false_id else 'POOL_ThisIsaFakeID!' - return directory_id, bad_id - - def setup_test_mailing_list_id(self, short=False, false_id=False): - '''Setup for Test Case 3: Mailing List Sub-Module method's exception handling of the mailing list's length (18), and - the incorrect id (CG_).''' - - mailing_list_id = 'CG_ThisIsaFakeID!' if short else 'CG_ThisIsaFakeMailingID!' - bad_id = 'ThisIsaFakeIDwo/CG' if false_id else None - return mailing_list_id, bad_id - - def setup_test_contact_id(self, short=False, false_id=False): - '''Setup for Test Case 4: XMDirectory Sub-Module method's exception handling of the contact_id's length (18), and - the incorrect id (CG_).''' - - contact_id = 'CID_ThisIsaFakeID!' if short else 'CID_ThisIsaFakeMailingID!' - bad_id = 'ThisIsaFakeIDwo/CID' if false_id else None - return contact_id, bad_id - - def setup_test_survey_id(self, short=False, false_id=False): - '''Setup for Test Case 5: Responses Sub-Module method's exception handling of the survey_id's length (18), and - the incorrect id (SV_).''' - - survey_id = 'SV_ThisIsaFakeID!' if short else 'SV_ThisIsaFakeMailingID!' - bad_id = 'ThisIsaFakeIDwo/SV' if false_id else None - return survey_id, bad_id - - def setup_test_library_id_ur(self, short=False, false_id=False): - '''Setup for Test Case 6: Responses Sub-Module method's exception handling of the library_id's length (18), and - the incorrect id (UR_).''' - - lib_id = 'UR_ThisIsaFakeID!' if short else 'UR_ThisIsaFakeMailingID!' - bad_id = 'ThisIsaFakeIDwo/UR' if false_id else None - return lib_id, bad_id - - def setup_test_library_id_gr(self, short=False, false_id=False): - '''Setup for Test Case 7: Responses Sub-Module method's exception handling of the library_id's length (18), and - the incorrect id (GR_).''' - - lib_id = 'GR_ThisIsaFakeID!' if short else 'GR_ThisIsaFakeMailingID!' - bad_id = 'ThisIsaFakeIDwo/GR' if false_id else None - return lib_id, bad_id - - def setup_test_dist_id(self, short=False, false_id=False): - '''Setup for Test Case 8: Responses Sub-Module method's exception handling of the distribution_id's length (19), and - the incorrect id (UMD_).''' - - dist_id = 'EMD_ThisIsaFakeID!' if short else 'EMD_ThisIsaFakeMailingID!' - bad_id = 'ThisIsaFakeIDwo/EMD' if false_id else None - return dist_id, bad_id - - def setup_test_message_id(self, short=False, false_id=False): - '''Setup for Test Case 9: Responses Sub-Module method's exception handling of the message_id's length (18), and - the incorrect id (MS_).''' - - msg_id = 'MS_ThisIsaFakeID!' if short else 'MS_ThisIsaFakeMailingID!' - bad_id = 'ThisIsaFakeIDwo/MS' if false_id else None - return msg_id, bad_id - -#UnitTest Class -class TestQualtricsAPI(unittest.TestCase): - - correct_token = 'ThisIsaFakeAPITokenAndIsTooShortToWork!!' - - def test_credentials_long_token(self): - '''This method tests that an assertion is raised in the Credentials Module when the user enters an api token that is too long.''' - token = setup_tests().setup_test_token(short=False) - directory_id, bad_id = setup_tests().setup_test_directory_id(short=False, false_id=False) - with self.assertRaises(AssertionError): - Credentials().qualtrics_api_credentials(token=token, data_center='FAKE', directory_id=directory_id) - - #Test Assertion Error is handled: Short Token - def test_credentials_short_token(self): - '''This method tests that an assertion is raised in the Credentials Module when the user enters an api token that is too short.''' - token = setup_tests().setup_test_token(short=True) - directory_id, bad_id = setup_tests().setup_test_directory_id(short=False, false_id=False) - with self.assertRaises(AssertionError): - Credentials().qualtrics_api_credentials(token=token, data_center='FAKE', directory_id=directory_id) - - ## API Credentials: Directory ID - #Test Assertion Error is handled: Short Directory id - def test_credentials_short_directory_id(self): - '''This method tests that an assertion is raised in the Credentials Module when the user enters a directory id that is too short.''' - token = setup_tests().setup_test_token(short=True) - directory_id, bad_id = setup_tests().setup_test_directory_id(short=True, false_id=False) - with self.assertRaises(AssertionError): - Credentials().qualtrics_api_credentials(token=TestQualtricsAPI.correct_token, data_center='FAKE', directory_id=directory_id) - - #Test Assertion Error is handled: Long Directory id - def test_credentials_long_directory_id(self): - '''This method tests that an assertion is raised in the Credentials Module when the user enters a directory id that is too long.''' - token = setup_tests().setup_test_token(short=True) - directory_id, bad_id = setup_tests().setup_test_directory_id(short=False, false_id=False) - with self.assertRaises(AssertionError): - Credentials().qualtrics_api_credentials(token=TestQualtricsAPI.correct_token, data_center='FAKE', directory_id=directory_id) - - #Test Assertion Error is handled: Incorrect Dictonary ID - def test_credentials_bad_directory_id(self): - '''This method tests that an assertion is raised in the Credentials Module when the user enters a directory id that is incorrect.''' - token = setup_tests().setup_test_token(short=True) - directory_id, bad_id = setup_tests().setup_test_directory_id(short=False, false_id=True) - with self.assertRaises(AssertionError): - Credentials().qualtrics_api_credentials(token=TestQualtricsAPI.correct_token, data_center='FAKE', directory_id=bad_id) - - - ## MailingList: Mailing List IDs (rename_list) - #Test Assertion Error is handled: Long Mailing List ID - def test_ml_short_ml_id_rename(self): - '''This method tests that an assertion is raised in the MailingList Module when the user enters a mailing_list_id that is too long.''' - mailing_list_id, bad_id = setup_tests().setup_test_mailing_list_id(short=False, false_id=False) - with self.assertRaises(AssertionError): - MailingList().rename_list(mailing_list=mailing_list_id, name='Fake') - - #Test Assertion Error is handled: Short Mailing List ID - def test_ml_long_ml_id_rename(self): - '''This method tests that an assertion is raised in the MailingList Module when the user enters a mailing_list_id that is too short.''' - mailing_list_id, bad_id = setup_tests().setup_test_mailing_list_id(short=True, false_id=False) - with self.assertRaises(AssertionError): - MailingList().rename_list(mailing_list=mailing_list_id, name='Fake') - - #Test Assertion Error is handled: Incorrect Mailing List ID - def test_ml_bad_ml_id_rename(self): - '''This method tests that an assertion is raised in the MailingList Module when the user enters a mailing_list_id that is incorrect. ''' - mailing_list_id, bad_id = setup_tests().setup_test_mailing_list_id(short=False, false_id=True) - with self.assertRaises(AssertionError): - MailingList().rename_list(mailing_list=bad_id, name='Fake') - - #Test Assertion Error is handled: (None) Mailing List ID - def test_ml_none_ml_id_rename(self): - '''This method tests that an assertion is raised in the MailingList Module when the user enters a mailing_list_id that is incorrect. ''' - mailing_list_id, bad_id = setup_tests().setup_test_mailing_list_id(short=False, false_id=False) - with self.assertRaises(AssertionError): - MailingList().rename_list(mailing_list=bad_id, name='Fake') - - #Test Assertion Error is handled: bool Mailing List ID - def test_ml_bool_ml_id_rename(self): - '''This method tests that an assertion is raised in the MailingList Module when the user enters a mailing_list_id that is incorrect. ''' - NonString = bool() - with self.assertRaises(AssertionError): - MailingList().rename_list(mailing_list=NonString, name='Fake') - - #Test Assertion Error is handled: bool Mailing List ID - def test_ml_list_ml_id_rename(self): - '''This method tests that an assertion is raised in the MailingList Module when the user enters a mailing_list_id that is incorrect. ''' - NonString = list() - with self.assertRaises(AssertionError): - MailingList().rename_list(mailing_list=NonString, name='Fake') - - #Test Assertion Error is handled: float Mailing List ID - def test_ml_float_ml_id_rename(self): - '''This method tests that an assertion is raised in the MailingList Module when the user enters a mailing_list_id that is incorrect. ''' - NonString = float() - with self.assertRaises(AssertionError): - MailingList().rename_list(mailing_list=NonString, name='Fake') - - #Test Assertion Error is handled: int Mailing List ID - def test_ml_int_ml_id_rename(self): - '''This method tests that an assertion is raised in the MailingList Module when the user enters a mailing_list_id that is incorrect. ''' - NonString = int() - with self.assertRaises(AssertionError): - MailingList().rename_list(mailing_list=NonString, name='Fake') - - #Test Assertion Error is handled: dict Mailing List ID - def test_ml_dict_ml_id_rename(self): - '''This method tests that an assertion is raised in the MailingList Module when the user enters a mailing_list_id that is incorrect. ''' - NonString = dict() - with self.assertRaises(AssertionError): - MailingList().rename_list(mailing_list=NonString, name='Fake') - - #Test Assertion Error is handled: tuple Mailing List ID - def test_ml_tuple_ml_id_rename(self): - '''This method tests that an assertion is raised in the MailingList Module when the user enters a mailing_list_id that is incorrect. ''' - NonString = tuple() - with self.assertRaises(AssertionError): - MailingList().rename_list(mailing_list=NonString, name='Fake') - - ## MailingList: Mailing List IDs (delete_list) - #Test Assertion Error is handled: Long Mailing List ID - def test_ml_short_ml_id_delete(self): - '''This method tests that an assertion is raised in the MailingList Module when the user enters a mailing_list_id that is too long.''' - mailing_list_id, bad_id = setup_tests().setup_test_mailing_list_id(short=False, false_id=False) - with self.assertRaises(AssertionError): - MailingList().delete_list(mailing_list=mailing_list_id) - - #Test Assertion Error is handled: Short Mailing List ID - def test_ml_long_ml_id_delete(self): - '''This method tests that an assertion is raised in the MailingList Module when the user enters a mailing_list_id that is too short.''' - mailing_list_id, bad_id = setup_tests().setup_test_mailing_list_id(short=True, false_id=False) - with self.assertRaises(AssertionError): - MailingList().delete_list(mailing_list=mailing_list_id) - - #Test Assertion Error is handled: None Mailing List ID - def test_ml_none_ml_id_delete(self): - '''This method tests that an assertion is raised in the MailingList Module when the user enters a mailing_list_id that is too short.''' - mailing_list_id, bad_id = setup_tests().setup_test_mailing_list_id(short=True, false_id=True) - with self.assertRaises(AssertionError): - MailingList().delete_list(mailing_list=mailing_list_id) - - #Test Assertion Error is handled: bool Mailing List ID - def test_ml_bool_ml_id_delete(self): - '''This method tests that an assertion is raised in the MailingList Module when the user enters a mailing_list_id that is too short.''' - NonString = bool() - with self.assertRaises(AssertionError): - MailingList().delete_list(mailing_list=NonString) - - #Test Assertion Error is handled: Incorrect Mailing List ID - def test_ml_bad_ml_id_delete(self): - '''This method tests that an assertion is raised in the MailingList Module when the user enters a mailing_list_id is that is incorrect.''' - mailing_list_id, bad_id = setup_tests().setup_test_mailing_list_id(short=False, false_id=True) - with self.assertRaises(AssertionError): - MailingList().delete_list(mailing_list=bad_id) - - ## MailingList: Mailing List IDs (list_contacts) - #Test Assertion Error is handled: Long Mailing List ID - def test_ml_short_ml_id_list_contacts(self): - '''This method tests that an assertion is raised in the MailingList Module when the user enters a mailing_list_id that is too long.''' - mailing_list_id, bad_id = setup_tests().setup_test_mailing_list_id(short=False, false_id=False) - with self.assertRaises(AssertionError): - MailingList().list_contacts(mailing_list=mailing_list_id) - - #Test Assertion Error is handled: Short Mailing List ID - def test_ml_long_ml_id_list_contacts(self): - '''This method tests that an assertion is raised in the MailingList Module when the user enters a mailing_list_id that is too short. ''' - mailing_list_id, bad_id = setup_tests().setup_test_mailing_list_id(short=True, false_id=False) - with self.assertRaises(AssertionError): - MailingList().list_contacts(mailing_list=mailing_list_id) - - #Test Assertion Error is handled: Incorrect Mailing List ID - def test_ml_bad_ml_id_list_contacts(self): - '''This method tests that an assertion is raised in the MailingList Module when the user enters a mailing_list_id that is incorrect. ''' - mailing_list_id, bad_id = setup_tests().setup_test_mailing_list_id(short=False, false_id=True) - with self.assertRaises(AssertionError): - MailingList().list_contacts(mailing_list=bad_id) - - ## MailingList: Mailing List IDs (create_contact_in_list) - #Test Assertion Error is handled: Long Mailing List ID - def test_ml_short_ml_id_create(self): - '''This method tests that an assertion is raised in the MailingList Module when the user enters a mailing_list_id that is too long.''' - mailing_list_id, bad_id = setup_tests().setup_test_mailing_list_id(short=False, false_id=False) - with self.assertRaises(AssertionError): - MailingList().create_contact_in_list(mailing_list=mailing_list_id) - - #Test Assertion Error is handled: Short Mailing List ID - def test_ml_long_ml_id_create(self): - '''This method tests that an assertion is raised in the MailingList Module when the user enters a mailing_list_id that is too short.''' - mailing_list_id, bad_id = setup_tests().setup_test_mailing_list_id(short=True, false_id=False) - with self.assertRaises(AssertionError): - MailingList().create_contact_in_list(mailing_list=mailing_list_id) - - #Test Assertion Error is handled: Incorrect Mailing List ID - def test_ml_bad_ml_id_create(self): - '''This method tests that an assertion is raised in the MailingList Module when the user enters a mailing_list_id is that is incorrect.''' - mailing_list_id, bad_id = setup_tests().setup_test_mailing_list_id(short=False, false_id=True) - with self.assertRaises(AssertionError): - MailingList().create_contact_in_list(mailing_list=bad_id) - - ## XMDirectory: Contact IDs (delete_contact) - #Test Assertion Error is handled: Long Contact id - def test_xm_short_contact_id_delete(self): - '''This method tests that an assertion is raised in the XMDirectory Module when the user enters a contact_id that is too long. ''' - contact_id, bad_id = setup_tests().setup_test_contact_id(short=False, false_id=False) - with self.assertRaises(AssertionError): - XMDirectory().delete_contact(contact_id=contact_id) - - #Test Assertion Error is handled: Short Contact id - def test_xm_long_contact_id_delete(self): - '''This method tests that an assertion is raised in the XMDirectory Module when the user enters a contact_id that is too short. ''' - contact_id, bad_id = setup_tests().setup_test_contact_id(short=True, false_id=False) - with self.assertRaises(AssertionError): - XMDirectory().delete_contact(contact_id=contact_id) - - #Test Assertion Error is handled: Incorrect Contact id - def test_xm_bad_contact_id_delete(self): - '''This method tests that an assertion is raised in the XMDirectory Module when the user enters a contact_id that is incorrect. ''' - contact_id, bad_id = setup_tests().setup_test_contact_id(short=False, false_id=True) - with self.assertRaises(AssertionError): - XMDirectory().delete_contact(contact_id=bad_id) - - #Test Assertion Error is handled: (None) Contact id - def test_xm_none_contact_id_delete(self): - '''This method tests that an assertion is raised in the XMDirectory Module when the user enters a contact_id that is incorrect. ''' - contact_id, bad_id = setup_tests().setup_test_contact_id(short=False, false_id=False) - with self.assertRaises(AssertionError): - XMDirectory().delete_contact(contact_id=bad_id) - - #Test Assertion Error is handled: bool Contact id - def test_xm_bool_contact_id_delete(self): - '''This method tests that an assertion is raised in the XMDirectory Module when the user enters a contact_id that is incorrect. ''' - NonString = bool() - with self.assertRaises(AssertionError): - XMDirectory().delete_contact(contact_id=NonString) - - #Test Assertion Error is handled: list Contact id - def test_xm_list_contact_id_delete(self): - '''This method tests that an assertion is raised in the XMDirectory Module when the user enters a contact_id that is incorrect. ''' - NonString = list() - with self.assertRaises(AssertionError): - XMDirectory().delete_contact(contact_id=NonString) - - #Test Assertion Error is handled: int Contact id - def test_xm_int_contact_id_delete(self): - '''This method tests that an assertion is raised in the XMDirectory Module when the user enters a contact_id that is incorrect. ''' - NonString = int() - with self.assertRaises(AssertionError): - XMDirectory().delete_contact(contact_id=NonString) - - #Test Assertion Error is handled: float Contact id - def test_xm_float_contact_id_delete(self): - '''This method tests that an assertion is raised in the XMDirectory Module when the user enters a contact_id that is incorrect. ''' - NonString = float() - with self.assertRaises(AssertionError): - XMDirectory().delete_contact(contact_id=NonString) - - #Test Assertion Error is handled: dict Contact id - def test_xm_dict_contact_id_delete(self): - '''This method tests that an assertion is raised in the XMDirectory Module when the user enters a contact_id that is incorrect. ''' - NonString = dict() - with self.assertRaises(AssertionError): - XMDirectory().delete_contact(contact_id=NonString) - - #Test Assertion Error is handled: tuple Contact id - def test_xm_tuple_contact_id_delete(self): - '''This method tests that an assertion is raised in the XMDirectory Module when the user enters a contact_id that is incorrect. ''' - NonString = tuple() - with self.assertRaises(AssertionError): - XMDirectory().delete_contact(contact_id=NonString) - - ## XMDirectory: Contact IDs (update_contact) - #Test Assertion Error is handled: Long Contact id - def test_xm_short_contact_id_update(self): - '''This method tests that an assertion is raised in the XMDirectory Module when the user enters a contact_id that is too long. ''' - contact_id, bad_id = setup_tests().setup_test_contact_id(short=False, false_id=False) - with self.assertRaises(AssertionError): - XMDirectory().update_contact(contact_id=contact_id) - - #Test Assertion Error is handled: Short Contact id - def test_xm_long_contact_id_update(self): - '''This method tests that an assertion is raised in the XMDirectory Module when the user enters a contact_id that is too short. ''' - contact_id, bad_id = setup_tests().setup_test_contact_id(short=True, false_id=False) - with self.assertRaises(AssertionError): - XMDirectory().update_contact(contact_id=contact_id) - - #Test Assertion Error is handled: Incorrect Contact id - def test_xm_bad_contact_id_update(self): - '''This method tests that an assertion is raised in the XMDirectory Module when the user enters a contact_id that is incorrect. ''' - contact_id, bad_id = setup_tests().setup_test_contact_id(short=False, false_id=True) - with self.assertRaises(AssertionError): - XMDirectory().update_contact(contact_id=bad_id) - - #Test Assertion Error is handled: (None) Contact id - def test_xm_bad_contact_id_update(self): - '''This method tests that an assertion is raised in the XMDirectory Module when the user enters a contact_id that is incorrect. ''' - contact_id, bad_id = setup_tests().setup_test_contact_id(short=False, false_id=False) - with self.assertRaises(AssertionError): - XMDirectory().update_contact(contact_id=bad_id) - - #Test Assertion Error is handled: (None) Contact id - def test_xm_bad_contact_id_update(self): - '''This method tests that an assertion is raised in the XMDirectory Module when the user enters a contact_id that is incorrect. ''' - contact_id, bad_id = setup_tests().setup_test_contact_id(short=False, false_id=False) - with self.assertRaises(AssertionError): - XMDirectory().update_contact(contact_id=bad_id) - - #Test Assertion Error is handled: (None) Contact id - def test_xm_none_contact_id_update(self): - '''This method tests that an assertion is raised in the XMDirectory Module when the user enters a contact_id that is incorrect. ''' - contact_id, bad_id = setup_tests().setup_test_contact_id(short=False, false_id=False) - with self.assertRaises(AssertionError): - XMDirectory().update_contact(contact_id=bad_id) - - #Test Assertion Error is handled: bool Contact id - def test_xm_bool_contact_id_update(self): - '''This method tests that an assertion is raised in the XMDirectory Module when the user enters a contact_id that is incorrect. ''' - NonString = bool() - with self.assertRaises(AssertionError): - XMDirectory().update_contact(contact_id=NonString) - - #Test Assertion Error is handled: list Contact id - def test_xm_list_contact_id_update(self): - '''This method tests that an assertion is raised in the XMDirectory Module when the user enters a contact_id that is incorrect. ''' - NonString = list() - with self.assertRaises(AssertionError): - XMDirectory().update_contact(contact_id=NonString) - - #Test Assertion Error is handled: int Contact id - def test_xm_int_contact_id_update(self): - '''This method tests that an assertion is raised in the XMDirectory Module when the user enters a contact_id that is incorrect. ''' - NonString = int() - with self.assertRaises(AssertionError): - XMDirectory().update_contact(contact_id=NonString) - - #Test Assertion Error is handled: float Contact id - def test_xm_float_contact_id_update(self): - '''This method tests that an assertion is raised in the XMDirectory Module when the user enters a contact_id that is incorrect. ''' - NonString = float() - with self.assertRaises(AssertionError): - XMDirectory().update_contact(contact_id=NonString) - - #Test Assertion Error is handled: dict Contact id - def test_xm_dict_contact_id_update(self): - '''This method tests that an assertion is raised in the XMDirectory Module when the user enters a contact_id that is incorrect. ''' - NonString = dict() - with self.assertRaises(AssertionError): - XMDirectory().update_contact(contact_id=NonString) - - #Test Assertion Error is handled: tuple Contact id - def test_xm_tuple_contact_id_update(self): - '''This method tests that an assertion is raised in the XMDirectory Module when the user enters a contact_id that is incorrect. ''' - NonString = tuple() - with self.assertRaises(AssertionError): - XMDirectory().update_contact(contact_id=NonString) - - #Test Assertion Error is handled: (None) Contact id - def test_xm_bad_contact_id_update(self): - '''This method tests that an assertion is raised in the XMDirectory Module when the user enters a contact_id that is incorrect. ''' - contact_id, bad_id = setup_tests().setup_test_contact_id(short=False, false_id=False) - with self.assertRaises(AssertionError): - XMDirectory().update_contact(contact_id=bad_id) - - ## XMDirectory: Contact IDs (get_contact) - #Test Assertion Error is handled: Long Contact id - def test_xm_short_contact_id_get(self): - '''This method tests that an assertion is raised in the XMDirectory Module when the user enters a contact_id that is too long. ''' - contact_id, bad_id = setup_tests().setup_test_contact_id(short=False, false_id=False) - with self.assertRaises(AssertionError): - XMDirectory().get_contact(contact_id=contact_id) - - #Test Assertion Error is handled: Short Contact id - def test_xm_long_contact_id_get(self): - '''This method tests that an assertion is raised in the XMDirectory Module when the user enters a contact_id that is too short. ''' - contact_id, bad_id = setup_tests().setup_test_contact_id(short=True, false_id=False) - with self.assertRaises(AssertionError): - XMDirectory().get_contact(contact_id=contact_id) - - #Test Assertion Error is handled: Incorrect Contact id - def test_xm_bad_contact_id_get(self): - '''This method tests that an assertion is raised in the XMDirectory Module when the user enters a contact_id that is incorrect. ''' - contact_id, bad_id = setup_tests().setup_test_contact_id(short=False, false_id=True) - with self.assertRaises(AssertionError): - XMDirectory().get_contact(contact_id=bad_id) - - #Test Assertion Error is handled: (None) Contact id - def test_xm_none_contact_id_get(self): - '''This method tests that an assertion is raised in the XMDirectory Module when the user enters a contact_id that is incorrect. ''' - contact_id, bad_id = setup_tests().setup_test_contact_id(short=False, false_id=False) - with self.assertRaises(AssertionError): - XMDirectory().get_contact(contact_id=bad_id) - - #Test Assertion Error is handled: bool Contact id - def test_xm_bool_contact_id_get(self): - '''This method tests that an assertion is raised in the XMDirectory Module when the user enters a contact_id that is incorrect. ''' - bad_id = bool() - with self.assertRaises(AssertionError): - XMDirectory().get_contact(contact_id=bad_id) - - #Test Assertion Error is handled: list Contact id - def test_xm_list_contact_id_get(self): - '''This method tests that an assertion is raised in the XMDirectory Module when the user enters a contact_id that is incorrect. ''' - bad_id = list() - with self.assertRaises(AssertionError): - XMDirectory().get_contact(contact_id=bad_id) - - #Test Assertion Error is handled: float Contact id - def test_xm_float_contact_id_get(self): - '''This method tests that an assertion is raised in the XMDirectory Module when the user enters a contact_id that is incorrect. ''' - bad_id = float() - with self.assertRaises(AssertionError): - XMDirectory().get_contact(contact_id=bad_id) - - #Test Assertion Error is handled: dict Contact id - def test_xm_dict_contact_id_get(self): - '''This method tests that an assertion is raised in the XMDirectory Module when the user enters a contact_id that is incorrect. ''' - bad_id = dict() - with self.assertRaises(AssertionError): - XMDirectory().get_contact(contact_id=bad_id) - - #Test Assertion Error is handled: tuple Contact id - def test_xm_tuple_contact_id_get(self): - '''This method tests that an assertion is raised in the XMDirectory Module when the user enters a contact_id that is incorrect. ''' - bad_id = tuple() - with self.assertRaises(AssertionError): - XMDirectory().get_contact(contact_id=bad_id) - - #Test Assertion Error is handled: int Contact id - def test_xm_int_contact_id_get(self): - '''This method tests that an assertion is raised in the XMDirectory Module when the user enters a contact_id that is incorrect. ''' - bad_id = int() - with self.assertRaises(AssertionError): - XMDirectory().get_contact(contact_id=bad_id) - - ## XMDirectory: Contact IDs (get_contact_additional_info) - #Test Assertion Error is handled: Long Contact id - def test_xm_short_contact_id_get_add(self): - '''This method tests that an assertion is raised in the XMDirectory Module when the user enters a contact_id that is too long. ''' - contact_id, bad_id = setup_tests().setup_test_contact_id(short=False, false_id=False) - with self.assertRaises(AssertionError): - XMDirectory().get_contact_additional_info(contact_id=contact_id) - - #Test Assertion Error is handled: Short Contact id - def test_xm_long_contact_id_get_add(self): - '''This method tests that an assertion is raised in the XMDirectory Module when the user enters a contact_id that is too short. ''' - contact_id, bad_id = setup_tests().setup_test_contact_id(short=True, false_id=False) - with self.assertRaises(AssertionError): - XMDirectory().get_contact_additional_info(contact_id=contact_id) - - #Test Assertion Error is handled: Incorrect Contact id - def test_xm_bad_contact_id_get_add(self): - '''This method tests that an assertion is raised in the XMDirectory Module when the user enters a contact_id that is incorrect. ''' - contact_id, bad_id = setup_tests().setup_test_contact_id(short=False, false_id=True) - with self.assertRaises(AssertionError): - XMDirectory().get_contact_additional_info(contact_id=bad_id) - - #Test Assertion Error is handled: (None) Contact id - def test_xm_none_contact_id_get_add(self): - '''This method tests that an assertion is raised in the XMDirectory Module when the user enters a contact_id that is incorrect. ''' - contact_id, bad_id = setup_tests().setup_test_contact_id(short=False, false_id=False) - with self.assertRaises(AssertionError): - XMDirectory().get_contact_additional_info(contact_id=bad_id) - - #Test Assertion Error is handled: (None) Content - def test_xm_none_content_get_add(self): - '''This method tests that an assertion is raised in the XMDirectory Module when the user enters a contact_id that is incorrect. ''' - with self.assertRaises(AssertionError): - XMDirectory().get_contact_additional_info(contact_id='ThisisaFakeContact', content=None) - - #Test Assertion Error is handled: bool Contact id - def test_xm_bool_contact_id_get_add(self): - '''This method tests that an assertion is raised in the XMDirectory Module when the user enters a contact_id that is incorrect. ''' - NonString = bool() - with self.assertRaises(AssertionError): - XMDirectory().get_contact_additional_info(contact_id=NonString) - - #Test Assertion Error is handled: int Contact id - def test_xm_int_contact_id_get_add(self): - '''This method tests that an assertion is raised in the XMDirectory Module when the user enters a contact_id that is incorrect. ''' - NonString = int() - with self.assertRaises(AssertionError): - XMDirectory().get_contact_additional_info(contact_id=NonString) - - #Test Assertion Error is handled: list Contact id - def test_xm_list_contact_id_get_add(self): - '''This method tests that an assertion is raised in the XMDirectory Module when the user enters a contact_id that is incorrect. ''' - NonString = list() - with self.assertRaises(AssertionError): - XMDirectory().get_contact_additional_info(contact_id=NonString) - - #Test Assertion Error is handled: float Contact id - def test_xm_float_contact_id_get_add(self): - '''This method tests that an assertion is raised in the XMDirectory Module when the user enters a contact_id that is incorrect. ''' - NonString = float() - with self.assertRaises(AssertionError): - XMDirectory().get_contact_additional_info(contact_id=NonString) - - #Test Assertion Error is handled: dict Contact id - def test_xm_dict_contact_id_get_add(self): - '''This method tests that an assertion is raised in the XMDirectory Module when the user enters a contact_id that is incorrect. ''' - NonString = dict() - with self.assertRaises(AssertionError): - XMDirectory().get_contact_additional_info(contact_id=NonString) - - #Test Assertion Error is handled: tuple Contact id - def test_xm_tuple_contact_id_get_add(self): - '''This method tests that an assertion is raised in the XMDirectory Module when the user enters a contact_id that is incorrect. ''' - NonString = tuple() - with self.assertRaises(AssertionError): - XMDirectory().get_contact_additional_info(contact_id=NonString) - - ## Responses: Survey IDs ## - #Test Assertion Error is handled: Long Survey id - def test_responses_short_survey_id(self): - '''This method tests that an assertion is raised in the Responses Module when the user enters a survey_id that is too long. ''' - survey_id, bad_id = setup_tests().setup_test_survey_id(short=False, false_id=False) - with self.assertRaises(AssertionError): - Responses().setup_request(file_format='csv', survey=survey_id) - - #Test Assertion Error is handled: Short Survey id - def test_responses_long_survey_id(self): - '''This method tests that an assertion is raised in the Responses Module when the user enters a survey_id that is too short. ''' - survey_id, bad_id = setup_tests().setup_test_survey_id(short=True, false_id=False) - with self.assertRaises(AssertionError): - Responses().setup_request(file_format='csv', survey=survey_id) - - #Test Assertion Error is handled: Incorrect Survey id - def test_responses_bad_survey_id(self): - '''This method tests that an assertion is raised in the Responses Module when the user enters a survey_id that is incorrect. ''' - survey_id, bad_id = setup_tests().setup_test_survey_id(short=False, false_id=True) - with self.assertRaises(AssertionError): - Responses().setup_request(file_format='csv', survey=bad_id) - - #Test Assertion Error is handled: (None) Survey id - def test_responses_none_survey_id(self): - '''This method tests that an assertion is raised in the Responses Module when the user enters a survey_id that is incorrect. ''' - survey_id, bad_id = setup_tests().setup_test_survey_id(short=False, false_id=False) - with self.assertRaises(AssertionError): - Responses().setup_request(file_format='csv', survey=bad_id) - - #Test Assertion Error is handled: bool Survey id - def test_responses_bool_survey_id(self): - '''This method tests that an assertion is raised in the Responses Module when the user enters a survey_id that is incorrect. ''' - NonString = bool() - with self.assertRaises(AssertionError): - Responses().setup_request(file_format='csv', survey=NonString) - - #Test Assertion Error is handled: list Survey id - def test_responses_list_survey_id(self): - '''This method tests that an assertion is raised in the Responses Module when the user enters a survey_id that is incorrect. ''' - NonString = list() - with self.assertRaises(AssertionError): - Responses().setup_request(file_format='csv', survey=NonString) - - #Test Assertion Error is handled: int Survey id - def test_responses_int_survey_id(self): - '''This method tests that an assertion is raised in the Responses Module when the user enters a survey_id that is incorrect. ''' - NonString = int() - with self.assertRaises(AssertionError): - Responses().setup_request(file_format='csv', survey=NonString) - - #Test Assertion Error is handled: float Survey id - def test_responses_float_survey_id(self): - '''This method tests that an assertion is raised in the Responses Module when the user enters a survey_id that is incorrect. ''' - NonString = float() - with self.assertRaises(AssertionError): - Responses().setup_request(file_format='csv', survey=NonString) - - #Test Assertion Error is handled: dict Survey id - def test_responses_dict_survey_id(self): - '''This method tests that an assertion is raised in the Responses Module when the user enters a survey_id that is incorrect. ''' - NonString = dict() - with self.assertRaises(AssertionError): - Responses().setup_request(file_format='csv', survey=NonString) - - #Test Assertion Error is handled: tuple Survey id - def test_responses_tuple_survey_id(self): - '''This method tests that an assertion is raised in the Responses Module when the user enters a survey_id that is incorrect. ''' - NonString = tuple() - with self.assertRaises(AssertionError): - Responses().setup_request(file_format='csv', survey=NonString) - - ## Messages: Library IDs ## - #Test Assertion Error is handled: Long Library id (list_messages: UR) - def test_responses_short_library_id_list_msgs_ur(self): - '''This method tests that an assertion is raised in the Messages Module's list_messages method when the user enters a - library_id (UR: User-Defined Resource) that is too long. ''' - lib_id, bad_id = setup_tests().setup_test_library_id_ur(short=False, false_id=False) - with self.assertRaises(AssertionError): - Messages().list_messages(library=lib_id) - - #Test Assertion Error is handled: Short Library id (list_messages: UR) - def test_responses_long_library_id_lst_msgs_ur(self): - '''This method tests that an assertion is raised in the Messages Module's list_messages method when the user enters a - library_id (UR: User-Defined Resource) that is too short. ''' - lib_id, bad_id = setup_tests().setup_test_library_id_ur(short=True, false_id=False) - with self.assertRaises(AssertionError): - Messages().list_messages(library=lib_id) - - #Test Assertion Error is handled: Incorrect Library id (list_messages: UR) - def test_responses_bad_libary_id_lst_msgs_ur(self): - '''This method tests that an assertion is raised in the Messages Module's list_messages method when the user enters - a library_id (UR: User-Defined Resource) that is incorrect. ''' - lib_id, bad_id = setup_tests().setup_test_library_id_ur(short=False, false_id=True) - with self.assertRaises(AssertionError): - Messages().list_messages(library=bad_id) - - #Test Assertion Error is handled: Long Library id (list_messages: GR) - def test_responses_short_library_id_list_msgs_gr(self): - '''This method tests that an assertion is raised in the Messages Module's list_messages method when the user enters - a library_id (GR: Global Resource) that is too long. ''' - lib_id, bad_id = setup_tests().setup_test_library_id_gr(short=False, false_id=False) - with self.assertRaises(AssertionError): - Messages().list_messages(library=lib_id) - - #Test Assertion Error is handled: Short Library id (list_messages: GR) - def test_responses_long_library_id_lst_msgs_gr(self): - '''This method tests that an assertion is raised in the Messages Module's list_messages method when the user enters - a library_id (GR: Global Resource) that is too short. ''' - lib_id, bad_id = setup_tests().setup_test_library_id_gr(short=True, false_id=False) - with self.assertRaises(AssertionError): - Messages().list_messages(library=lib_id) - - #Test Assertion Error is handled: Incorrect Library id (list_messages: GR) - def test_responses_bad_libary_id_lst_msgs_gr(self): - '''This method tests that an assertion is raised in the Messages Module's list_messages method when the user enters - a library_id (GR: Global Resource) that is incorrect. ''' - lib_id, bad_id = setup_tests().setup_test_library_id_gr(short=False, false_id=True) - with self.assertRaises(AssertionError): - Messages().list_messages(library=bad_id) - - ## Messages: Library IDs ## - #Test Assertion Error is handled: Long Library id (get_message: UR) - def test_responses_short_library_id_get_msg_ur(self): - '''This method tests that an assertion is raised in the Messages Module's get_message method when the user enters a - library_id (UR: User-Defined Resource) that is too long. ''' - lib_id, bad_id = setup_tests().setup_test_library_id_ur(short=False, false_id=False) - with self.assertRaises(AssertionError): - Messages().get_message(library=lib_id, message="MS_ThisIsaFakeMsg!") - - #Test Assertion Error is handled: Short Library id (get_message: UR) - def test_responses_long_library_id_get_msg_ur(self): - '''This method tests that an assertion is raised in the Messages Module's get_message method when the user enters a - library_id (UR: User-Defined Resource) that is too short. ''' - lib_id, bad_id = setup_tests().setup_test_library_id_ur(short=True, false_id=False) - with self.assertRaises(AssertionError): - Messages().get_message(library=lib_id, message="MS_ThisIsaFakeMsg!") - - #Test Assertion Error is handled: Incorrect Library id (get_message: UR) - def test_responses_bad_libary_id_get_msg_ur(self): - '''This method tests that an assertion is raised in the Messages Module's get_message method when the user enters - a library_id (UR: User-Defined Resource) that is incorrect. ''' - lib_id, bad_id = setup_tests().setup_test_library_id_ur(short=False, false_id=True) - with self.assertRaises(AssertionError): - Messages().get_message(library=bad_id, message="MS_ThisIsaFakeMsg!") - - #Test Assertion Error is handled: Long Library id (get_message: GR) - def test_responses_short_library_id_get_msg_gr(self): - '''This method tests that an assertion is raised in the Messages Module's get_message method when the user enters - a library_id (GR: Global Resource) that is too long. ''' - lib_id, bad_id = setup_tests().setup_test_library_id_gr(short=False, false_id=False) - with self.assertRaises(AssertionError): - Messages().get_message(library=lib_id, message="MS_ThisIsaFakeMsg!") - - #Test Assertion Error is handled: Short Library id (get_message: GR) - def test_responses_long_library_id_get_msg_gr(self): - '''This method tests that an assertion is raised in the Messages Module's get_message method when the user enters - a library_id (GR: Global Resource) that is too short. ''' - lib_id, bad_id = setup_tests().setup_test_library_id_gr(short=True, false_id=False) - with self.assertRaises(AssertionError): - Messages().get_message(library=lib_id, message="MS_ThisIsaFakeMsg!") - - #Test Assertion Error is handled: Incorrect Library id (get_message: GR) - def test_responses_bad_libary_id_get_msg_gr(self): - '''This method tests that an assertion is raised in the Messages Module's get_message method when the user enters - a library_id (GR: Global Resource) that is incorrect. ''' - lib_id, bad_id = setup_tests().setup_test_library_id_gr(short=False, false_id=True) - with self.assertRaises(AssertionError): - Messages().get_message(library=bad_id, message="MS_ThisIsaFakeMsg!") - - ## Messages: Message IDs ## - #Test Assertion Error is handled: Long Message ID (get_message) - def test_responses_short_msg_id_get_msgs(self): - '''This method tests that an assertion is raised in the Messages Module's get_message method when the user enters a - message_id that is too long. ''' - msg_id, bad_id = setup_tests().setup_test_message_id(short=False, false_id=False) - with self.assertRaises(AssertionError): - Messages().get_message(library="GR_ThisIsaFakeLib!", message=msg_id) - - #Test Assertion Error is handled: Short Message ID (get_message) - def test_responses_long_msg_id_get_msgs(self): - '''This method tests that an assertion is raised in the Messages Module's get_message method when the user enters a - message_id that is too short. ''' - msg_id, bad_id = setup_tests().setup_test_message_id(short=True, false_id=False) - with self.assertRaises(AssertionError): - Messages().get_message(library="GR_ThisIsaFakeLib!", message=msg_id) - - #Test Assertion Error is handled: Incorrect Message ID (get_message) - def test_responses_bad_msg_id_get_msgs(self): - '''This method tests that an assertion is raised in the Messages Module's get_message method when the user enters - a message_id that is incorrect. ''' - msg_id, bad_id = setup_tests().setup_test_message_id(short=False, false_id=True) - with self.assertRaises(AssertionError): - Messages().get_message(library="GR_ThisIsaFakeLib!", message=msg_id) - - ## Distribution: MailiingList IDs ## - #Test Assertion Error is handled: Long MailiingListID (create_distribution) - def test_responses_short_ml_id_create_dist(self): - '''This method tests that an assertion is raised in the Distribution Module's create_distribution method when the user enters a - mailing_list_id that is too long. ''' - mailing_list_id, bad_id = setup_tests().setup_test_mailing_list_id(short=False, false_id=False) - with self.assertRaises(AssertionError): - Distributions().create_distribution(mailing_list=mailing_list_id, library="GR_ThisIsaFakeLib!", message="MS_ThisIsaFakeMsg!", subject="Fake", send_date=gmtime(), reply_email="Fake@Fake.com", from_email="Fake@Fake.com", from_name="Fake", survey="SV_ThisIsaFakeID!!") - - #Test Assertion Error is handled: Short MailiingList ID (create_distribution) - def test_responses_long_ml_id_create_dist(self): - '''This method tests that an assertion is raised in the Distribution Module's create_distribution method when the user enters a - mailing_list_id that is too short.''' - mailing_list_id, bad_id = setup_tests().setup_test_mailing_list_id(short=True, false_id=False) - with self.assertRaises(AssertionError): - Distributions().create_distribution(mailing_list=mailing_list_id, library="GR_ThisIsaFakeLib!", message="MS_ThisIsaFakeMsg!", subject="Fake", send_date=gmtime(), reply_email="Fake@Fake.com", from_email="Fake@Fake.com", from_name="Fake", survey="SV_ThisIsaFakeID!!") - - #Test Assertion Error is handled: Incorrect MailiingList ID (create_distribution) - def test_responses_bad_ml_id_create_dist(self): - '''This method tests that an assertion is raised in the Distribution Module's create_distribution method when the user enters - a mailing_list_id that is incorrect. ''' - mailing_list_id, bad_id = setup_tests().setup_test_mailing_list_id(short=False, false_id=True) - with self.assertRaises(AssertionError): - Distributions().create_distribution(mailing_list=bad_id, library="GR_ThisIsaFakeLib!", message="MS_ThisIsaFakeMsg!", subject="Fake", send_date=gmtime(), reply_email="Fake@Fake.com", from_email="Fake@Fake.com", from_name="Fake", survey="SV_ThisIsaFakeID!!") - - ## Distribution: Survey IDs ## - #Test Assertion Error is handled: Long Survey ID (create_distribution) - def test_responses_short_sv_id_create_dist(self): - '''This method tests that an assertion is raised in the Distribution Module's create_distribution method when the user enters a - survey_id that is too long. ''' - survey_id, bad_id = setup_tests().setup_test_survey_id(short=False, false_id=False) - with self.assertRaises(AssertionError): - Distributions().create_distribution(survey=survey_id, mailing_list="CG_ThisIsaFakeMail", library="GR_ThisIsaFakeLib!", message="MS_ThisIsaFakeMsg!", send_date=gmtime(), subject="Fake", reply_email="Fake@Fake.com", from_email="Fake@Fake.com", from_name="Fake") - - #Test Assertion Error is handled: Short Survey ID (create_distribution) - def test_responses_long_sv_id_create_dist(self): - '''This method tests that an assertion is raised in the Distribution Module's create_distribution method when the user enters a - survey_id that is too short.''' - survey_id, bad_id = setup_tests().setup_test_survey_id(short=True, false_id=False) - with self.assertRaises(AssertionError): - Distributions().create_distribution(survey=survey_id, mailing_list="CG_ThisIsaFakeMail", library="GR_ThisIsaFakeLib!", message="MS_ThisIsaFakeMsg!", send_date=gmtime(), subject="Fake", reply_email="Fake@Fake.com", from_email="Fake@Fake.com", from_name="Fake") - - #Test Assertion Error is handled: Incorrect Survey ID (create_distribution) - def test_responses_bad_sv_id_create_dist(self): - '''This method tests that an assertion is raised in the Distribution Module's create_distribution method when the user enters - a survey_id that is incorrect. ''' - survey_id, bad_id = setup_tests().setup_test_survey_id(short=False, false_id=True) - with self.assertRaises(AssertionError): - Distributions().create_distribution(survey=bad_id, mailing_list="CG_ThisIsaFakeMail", library="GR_ThisIsaFakeLib!", message="MS_ThisIsaFakeMsg!", send_date=gmtime(), subject="Fake", reply_email="Fake@Fake.com", from_email="Fake@Fake.com", from_name="Fake") - - ## Distribution: Survey IDs ## - #Test Assertion Error is handled: Long Survey ID (list_distributions) - def test_responses_short_sv_id_list_dist(self): - '''This method tests that an assertion is raised in the Distribution Module's list_distributions method when the user enters a - survey_id that is too long. ''' - survey_id, bad_id = setup_tests().setup_test_survey_id(short=False, false_id=False) - with self.assertRaises(AssertionError): - Distributions().list_distributions(survey=survey_id) - - #Test Assertion Error is handled: Short Survey ID (list_distributions) - def test_responses_long_sv_id_list_dist(self): - '''This method tests that an assertion is raised in the Distribution Module's list_distributions method when the user enters a - survey_id that is too short.''' - survey_id, bad_id = setup_tests().setup_test_survey_id(short=True, false_id=False) - with self.assertRaises(AssertionError): - Distributions().list_distributions(survey=survey_id) - - #Test Assertion Error is handled: Incorrect Survey ID (list_distributions) - def test_responses_bad_sv_id_list_dist(self): - '''This method tests that an assertion is raised in the Distribution Module's list_distributions method when the user enters - a survey_id that is incorrect. ''' - survey_id, bad_id = setup_tests().setup_test_survey_id(short=False, false_id=True) - with self.assertRaises(AssertionError): - Distributions().list_distributions(survey=bad_id) - - ## Distribution: Survey IDs ## - #Test Assertion Error is handled: Long Survey ID (get_distribution) - def test_responses_short_sv_id_get_dist(self): - '''This method tests that an assertion is raised in the Distribution Module's get_distributionmethod when the user enters a - survey_id that is too long. ''' - survey_id, bad_id = setup_tests().setup_test_survey_id(short=False, false_id=False) - with self.assertRaises(AssertionError): - Distributions().get_distribution(survey=survey_id, distribution="EMD_ThisIsaFakeID!") - - #Test Assertion Error is handled: Short Survey ID (get_distribution) - def test_responses_long_sv_id_get_dist(self): - '''This method tests that an assertion is raised in the Distribution Module's get_distribution method when the user enters a - survey_id that is too short.''' - survey_id, bad_id = setup_tests().setup_test_survey_id(short=True, false_id=False) - with self.assertRaises(AssertionError): - Distributions().get_distribution(survey=survey_id, distribution="EMD_ThisIsaFakeID!") - - #Test Assertion Error is handled: Incorrect Survey ID (get_distribution) - def test_responses_bad_sv_id_get_dist(self): - '''This method tests that an assertion is raised in the Distribution Module's get_distribution method when the user enters - a survey_id that is incorrect. ''' - survey_id, bad_id = setup_tests().setup_test_survey_id(short=False, false_id=True) - with self.assertRaises(AssertionError): - Distributions().get_distribution(survey=bad_id, distribution="EMD_ThisIsaFakeID!") - - ## Distribution: Library IDs (UR) ## - #Test Assertion Error is handled: Long Library ID (create_distribution: UR) - def test_responses_short_lib_id_create_dist_ur(self): - '''This method tests that an assertion is raised in the Distribution Module's create_distribution method when the user enters a - library_id (UR: User-Defined Resource) that is too long. ''' - library_id, bad_id = setup_tests().setup_test_library_id_ur(short=False, false_id=False) - with self.assertRaises(AssertionError): - Distributions().create_distribution(library=library_id, survey="SV_ThisIsaFakeID!!", mailing_list="CG_ThisIsaFakeMail", message="MS_ThisIsaFakeMsg!", send_date=gmtime(), subject="Fake", reply_email="Fake@Fake.com", from_email="Fake@Fake.com", from_name="Fake") - - #Test Assertion Error is handled: Short Library ID (create_distribution: UR) - def test_responses_long_lib_id_create_dist_ur(self): - '''This method tests that an assertion is raised in the Distribution Module's create_distribution method when the user enters a - library_id (UR: User-Defined Resource) that is too short.''' - library_id, bad_id = setup_tests().setup_test_library_id_ur(short=True, false_id=False) - with self.assertRaises(AssertionError): - Distributions().create_distribution(library=library_id, survey="SV_ThisIsaFakeID!!", mailing_list="CG_ThisIsaFakeMail", message="MS_ThisIsaFakeMsg!", send_date=gmtime(), subject="Fake", reply_email="Fake@Fake.com", from_email="Fake@Fake.com", from_name="Fake") - - #Test Assertion Error is handled: Incorrect Library ID (create_distribution: UR) - def test_responses_bad_lib_id_create_dist_ur(self): - '''This method tests that an assertion is raised in the Distribution Module's create_distribution method when the user enters - a library_id (UR: User-Defined Resource) that is incorrect. ''' - library_id, bad_id = setup_tests().setup_test_library_id_ur(short=False, false_id=True) - with self.assertRaises(AssertionError): - Distributions().create_distribution(library=bad_id, survey="SV_ThisIsaFakeID!!", mailing_list="CG_ThisIsaFakeMail", message="MS_ThisIsaFakeMsg!", send_date=gmtime(), subject="Fake", reply_email="Fake@Fake.com", from_email="Fake@Fake.com", from_name="Fake") - - ## Distribution: Library IDs (GR) ## - #Test Assertion Error is handled: Long Library ID (create_distribution: GR) - def test_responses_short_lib_id_create_dist_gr(self): - '''This method tests that an assertion is raised in the Distribution Module's create_distribution method when the user enters a - library_id (GR: Global Resource) that is too long. ''' - library_id, bad_id = setup_tests().setup_test_library_id_gr(short=False, false_id=False) - with self.assertRaises(AssertionError): - Distributions().create_distribution(library=library_id, survey="SV_ThisIsaFakeID!!", mailing_list="CG_ThisIsaFakeMail", message="MS_ThisIsaFakeMsg!", send_date=gmtime(), subject="Fake", reply_email="Fake@Fake.com", from_email="Fake@Fake.com", from_name="Fake") - - #Test Assertion Error is handled: Short Library ID (create_distribution: GR) - def test_responses_long_lib_id_create_dist_gr(self): - '''This method tests that an assertion is raised in the Distribution Module's create_distribution method when the user enters a - library_id (GR: Global Resource) that is too short.''' - library_id, bad_id = setup_tests().setup_test_library_id_gr(short=True, false_id=False) - with self.assertRaises(AssertionError): - Distributions().create_distribution(library=library_id, survey="SV_ThisIsaFakeID!!", mailing_list="CG_ThisIsaFakeMail", message="MS_ThisIsaFakeMsg!", send_date=gmtime(), subject="Fake", reply_email="Fake@Fake.com", from_email="Fake@Fake.com", from_name="Fake") - - #Test Assertion Error is handled: Incorrect Library ID (create_distribution: GR) - def test_responses_bad_lib_id_create_dist_gr(self): - '''This method tests that an assertion is raised in the Distribution Module's create_distribution method when the user enters - a library_id (GR: Global Resource) that is incorrect. ''' - library_id, bad_id = setup_tests().setup_test_library_id_gr(short=False, false_id=True) - with self.assertRaises(AssertionError): - Distributions().create_distribution(library=bad_id, survey="SV_ThisIsaFakeID!!", mailing_list="CG_ThisIsaFakeMail", message="MS_ThisIsaFakeMsg!", send_date=gmtime(), subject="Fake", reply_email="Fake@Fake.com", from_email="Fake@Fake.com", from_name="Fake") - - ## Distribution: Library IDs (UR) ## - #Test Assertion Error is handled: Long Library ID (create_reminder: UR) - def test_responses_short_lib_id_create_remind_ur(self): - '''This method tests that an assertion is raised in the Distribution Module's create_reminder method when the user enters a - library_id (UR: User-Defined Resource) that is too long. ''' - library_id, bad_id = setup_tests().setup_test_library_id_ur(short=False, false_id=False) - with self.assertRaises(AssertionError): - Distributions().create_reminder(library=library_id, distribution="EMD_ThisIsaFakeID!", message="MS_ThisIsaFakeMsg!", subject="Fake", reply_email="Fake@Fake.com", send_date=gmtime(), from_email="Fake@Fake.com", from_name="Fake") - - #Test Assertion Error is handled: Short Library ID (create_reminder: UR) - def test_responses_long_lib_id_create_remind_ur(self): - '''This method tests that an assertion is raised in the Distribution Module's create_reminder method when the user enters a - library_id (UR: User-Defined Resource) that is too short.''' - library_id, bad_id = setup_tests().setup_test_library_id_ur(short=True, false_id=False) - with self.assertRaises(AssertionError): - Distributions().create_reminder(library=library_id, distribution="EMD_ThisIsaFakeID!", message="MS_ThisIsaFakeMsg!", subject="Fake", reply_email="Fake@Fake.com", send_date=gmtime(), from_email="Fake@Fake.com", from_name="Fake") - - #Test Assertion Error is handled: Incorrect Library ID (create_reminder: UR) - def test_responses_bad_lib_id_create_remind_ur(self): - '''This method tests that an assertion is raised in the Distribution Module's create_reminder method when the user enters - a library_id (UR: User-Defined Resource) that is incorrect. ''' - library_id, bad_id = setup_tests().setup_test_library_id_ur(short=False, false_id=True) - with self.assertRaises(AssertionError): - Distributions().create_reminder(library=bad_id, distribution="EMD_ThisIsaFakeID!", message="MS_ThisIsaFakeMsg!", subject="Fake", reply_email="Fake@Fake.com", send_date=gmtime(), from_email="Fake@Fake.com", from_name="Fake") - - ## Distribution: Library IDs (GR) ## - #Test Assertion Error is handled: Long Library ID (create_reminder: GR) - def test_responses_short_lib_id_create_remind_gr(self): - '''This method tests that an assertion is raised in the Distribution Module's create_reminder method when the user enters a - library_id (GR: Global Resource) that is too long. ''' - library_id, bad_id = setup_tests().setup_test_library_id_gr(short=False, false_id=False) - with self.assertRaises(AssertionError): - Distributions().create_reminder(library=library_id, distribution="EMD_ThisIsaFakeID!", message="MS_ThisIsaFakeMsg!", subject="Fake", reply_email="Fake@Fake.com", send_date=gmtime(), from_email="Fake@Fake.com", from_name="Fake") - - #Test Assertion Error is handled: Short Library ID (create_reminder: GR) - def test_responses_long_lib_id_create_remind_gr(self): - '''This method tests that an assertion is raised in the Distribution Module's create_reminder method when the user enters a - library_id (GR: Global Resource) that is too short.''' - library_id, bad_id = setup_tests().setup_test_library_id_gr(short=True, false_id=False) - with self.assertRaises(AssertionError): - Distributions().create_reminder(library=library_id, distribution="EMD_ThisIsaFakeID!", message="MS_ThisIsaFakeMsg!", subject="Fake", reply_email="Fake@Fake.com", send_date=gmtime(), from_email="Fake@Fake.com", from_name="Fake") - - #Test Assertion Error is handled: Incorrect Library ID (create_reminder: GR) - def test_responses_bad_lib_id_create_remind_gr(self): - '''This method tests that an assertion is raised in the Distribution Module's create_reminder method when the user enters - a library_id (GR: Global Resource) that is incorrect. ''' - library_id, bad_id = setup_tests().setup_test_library_id_gr(short=False, false_id=True) - with self.assertRaises(AssertionError): - Distributions().create_reminder(library=bad_id, distribution="EMD_ThisIsaFakeID!", message="MS_ThisIsaFakeMsg!", subject="Fake", reply_email="Fake@Fake.com", send_date=gmtime(), from_email="Fake@Fake.com", from_name="Fake") - - ## Distribution: Library IDs ## - #Test Assertion Error is handled: Long Library ID (create_thank_you: UR) - def test_responses_short_lib_id_create_ty_ur(self): - '''This method tests that an assertion is raised in the Distribution Module's create_thank_you method when the user enters a - library_id (UR: User-Defined Resource) that is too long. ''' - library_id, bad_id = setup_tests().setup_test_library_id_ur(short=False, false_id=False) - with self.assertRaises(AssertionError): - Distributions().create_thank_you(library=library_id, distribution="EMD_ThisIsaFakeID!", message="MS_ThisIsaFakeMsg!", subject="Fake", reply_email="Fake@Fake.com", send_date=gmtime(), from_email="Fake@Fake.com", from_name="Fake") - - #Test Assertion Error is handled: Short Library ID (create_thank_you: UR) - def test_responses_long_lib_id_create_ty_ur(self): - '''This method tests that an assertion is raised in the Distribution Module's create_thank_you method when the user enters a - library_id (UR: User-Defined Resource) that is too short.''' - library_id, bad_id = setup_tests().setup_test_library_id_ur(short=True, false_id=False) - with self.assertRaises(AssertionError): - Distributions().create_thank_you(library=library_id, distribution="EMD_ThisIsaFakeID!", message="MS_ThisIsaFakeMsg!", subject="Fake", reply_email="Fake@Fake.com", send_date=gmtime(), from_email="Fake@Fake.com", from_name="Fake") - - #Test Assertion Error is handled: Incorrect Library ID (create_thank_you: UR) - def test_responses_bad_lib_id_create_ty_ur(self): - '''This method tests that an assertion is raised in the Distribution Module's create_thank_you method when the user enters - a library_id (UR: User-Defined Resource) that is incorrect. ''' - library_id, bad_id = setup_tests().setup_test_library_id_ur(short=False, false_id=True) - with self.assertRaises(AssertionError): - Distributions().create_thank_you(library=bad_id, distribution="EMD_ThisIsaFakeID!", message="MS_ThisIsaFakeMsg!", subject="Fake", reply_email="Fake@Fake.com", send_date=gmtime(), from_email="Fake@Fake.com", from_name="Fake") - - ## Distribution: Library IDs (GR) ## - #Test Assertion Error is handled: Long Library ID (create_reminder: GR) - def test_responses_short_lib_id_create_ty_gr(self): - '''This method tests that an assertion is raised in the Distribution Module's create_thank_you method when the user enters a - library_id (GR: Global Resource) that is too long. ''' - library_id, bad_id = setup_tests().setup_test_library_id_gr(short=False, false_id=False) - with self.assertRaises(AssertionError): - Distributions().create_thank_you(library=library_id, distribution="EMD_ThisIsaFakeID!", message="MS_ThisIsaFakeMsg!", subject="Fake", reply_email="Fake@Fake.com", send_date=gmtime(), from_email="Fake@Fake.com", from_name="Fake") - - #Test Assertion Error is handled: Short Library ID (create_reminder: GR) - def test_responses_long_lib_id_create_ty_gr(self): - '''This method tests that an assertion is raised in the Distribution Module's create_thank_you method when the user enters a - library_id (GR: Global Resource) that is too short.''' - library_id, bad_id = setup_tests().setup_test_library_id_gr(short=True, false_id=False) - with self.assertRaises(AssertionError): - Distributions().create_thank_you(library=library_id, distribution="EMD_ThisIsaFakeID!", message="MS_ThisIsaFakeMsg!", subject="Fake", reply_email="Fake@Fake.com", send_date=gmtime(), from_email="Fake@Fake.com", from_name="Fake") - - #Test Assertion Error is handled: Incorrect Library ID (create_reminder: GR) - def test_responses_bad_lib_id_create_ty_gr(self): - '''This method tests that an assertion is raised in the Distribution Module's create_thank_you method when the user enters - a library_id (GR: Global Resource) that is incorrect. ''' - library_id, bad_id = setup_tests().setup_test_library_id_gr(short=False, false_id=True) - with self.assertRaises(AssertionError): - Distributions().create_thank_you(library=bad_id, distribution="EMD_ThisIsaFakeID!", message="MS_ThisIsaFakeMsg!", subject="Fake", reply_email="Fake@Fake.com", send_date=gmtime(), from_email="Fake@Fake.com", from_name="Fake") - - ## Distribution: Distribution IDs ## - #Test Assertion Error is handled: Long Distribution ID (get_distribution) - def test_responses_short_dist_id_get_dist(self): - '''This method tests that an assertion is raised in the Distribution Module's get_distribution method when the user enters a - distribution_id that is too long. ''' - dist_id, bad_id = setup_tests().setup_test_dist_id(short=False, false_id=False) - with self.assertRaises(AssertionError): - Distributions().get_distribution(survey="SV_ThisIsaFakeID!!", distribution=dist_id) - - #Test Assertion Error is handled: Short Distribution ID (get_distribution) - def test_responses_long_dist_id_get_dist(self): - '''This method tests that an assertion is raised in the Distribution Module's get_distribution method when the user enters a - distribution_id that is too short.''' - dist_id, bad_id = setup_tests().setup_test_dist_id(short=True, false_id=False) - with self.assertRaises(AssertionError): - Distributions().get_distribution(survey="SV_ThisIsaFakeID!!", distribution=dist_id) - - #Test Assertion Error is handled: Incorrect Distribution ID (get_distribution) - def test_responses_bad_dist_id_get_dist(self): - '''This method tests that an assertion is raised in the Distribution Module's get_distribution method when the user enters - a distribution_id that is incorrect. ''' - dist_id, bad_id = setup_tests().setup_test_dist_id(short=False, false_id=True) - with self.assertRaises(AssertionError): - Distributions().get_distribution(survey="SV_ThisIsaFakeID!!", distribution=bad_id) - - ## Distribution. Distribution IDs ## - #Test Assertion Error is handled: Long Distribution ID (create_reminder) - def test_responses_short_dist_id_create_remind(self): - '''This method tests that an assertion is raised in the Distribution Module's create_reminder method when the user enters a - distrubution_id that is too long. ''' - distribution_id, bad_id = setup_tests().setup_test_dist_id(short=False, false_id=False) - with self.assertRaises(AssertionError): - Distributions().create_reminder(distribution=distribution_id, library="GR_ThisIsaFakeLib!", message="MS_ThisIsaFakeMsg!", subject="Fake", reply_email="Fake@Fake.com", send_date=gmtime(), from_email="Fake@Fake.com", from_name="Fake") - - #Test Assertion Error is handled: Short Distribution ID (create_reminder) - def test_responses_long_dist_id_create_remind(self): - '''This method tests that an assertion is raised in the Distribution Module's create_reminder method when the user enters a - distrubution_id that is too short.''' - distribution_id, bad_id = setup_tests().setup_test_dist_id(short=True, false_id=False) - with self.assertRaises(AssertionError): - Distributions().create_reminder(distribution=distribution_id, library="GR_ThisIsaFakeLib!", message="MS_ThisIsaFakeMsg!", subject="Fake", reply_email="Fake@Fake.com", send_date=gmtime(), from_email="Fake@Fake.com", from_name="Fake") - - #Test Assertion Error is handled: Incorrect Distribution ID (create_reminder) - def test_responses_bad_dist_id_create_remind(self): - '''This method tests that an assertion is raised in the Distribution Module's create_reminder method when the user enters - a distrubution_id that is incorrect. ''' - distribution_id, bad_id = setup_tests().setup_test_dist_id(short=False, false_id=True) - with self.assertRaises(AssertionError): - Distributions().create_reminder(distribution=bad_id, library="GR_ThisIsaFakeLib!", message="MS_ThisIsaFakeMsg!", subject="Fake", reply_email="Fake@Fake.com", send_date=gmtime(), from_email="Fake@Fake.com", from_name="Fake") - - ## Distribution: Distribution IDs ## - #Test Assertion Error is handled: Long Distribution ID (create_thank_you) - def test_responses_short_dist_id_create_ty(self): - '''This method tests that an assertion is raised in the Distribution Module's create_thank_you method when the user enters a - distrubution_id that is too long. ''' - distribution_id, bad_id = setup_tests().setup_test_dist_id(short=False, false_id=False) - with self.assertRaises(AssertionError): - Distributions().create_thank_you(distribution=distribution_id, library="GR_ThisIsaFakeLib!", message="MS_ThisIsaFakeMsg!", subject="Fake", reply_email="Fake@Fake.com", send_date=gmtime(), from_email="Fake@Fake.com", from_name="Fake") - - #Test Assertion Error is handled: Short Distribution ID (create_thank_you) - def test_responses_long_dist_id_create_ty(self): - '''This method tests that an assertion is raised in the Distribution Module's create_thank_you method when the user enters a - distrubution_id that is too short.''' - distribution_id, bad_id = setup_tests().setup_test_dist_id(short=True, false_id=False) - with self.assertRaises(AssertionError): - Distributions().create_thank_you(distribution=distribution_id, library="GR_ThisIsaFakeLib!", message="MS_ThisIsaFakeMsg!", subject="Fake", reply_email="Fake@Fake.com", send_date=gmtime(), from_email="Fake@Fake.com", from_name="Fake") - - #Test Assertion Error is handled: Incorrect Distribution ID (create_thank_you) - def test_responses_bad_dist_id_create_ty(self): - '''This method tests that an assertion is raised in the Distribution Module's create_thank_you method when the user enters - a distrubution_id that is incorrect. ''' - distribution_id, bad_id = setup_tests().setup_test_dist_id(short=False, false_id=True) - with self.assertRaises(AssertionError): - Distributions().create_thank_you(distribution=bad_id, library="GR_ThisIsaFakeLib!", message="MS_ThisIsaFakeMsg!", subject="Fake", reply_email="Fake@Fake.com", send_date=gmtime(), from_email="Fake@Fake.com", from_name="Fake") - - ## Distribution: Message IDs ## - #Test Assertion Error is handled: Long Message ID (create_distribution) - def test_responses_short_msg_id_create_dist(self): - '''This method tests that an assertion is raised in the Distribution Module's create_distribution method when the user enters a - message_id that is too long. ''' - msg_id, bad_id = setup_tests().setup_test_message_id(short=False, false_id=False) - with self.assertRaises(AssertionError): - Distributions().create_distribution(message=msg_id, library="GR_ThisIsaFakeLib!", survey="SV_ThisIsaFakeID!!", mailing_list="CG_ThisIsaFakeMail", subject="Fake", send_date=gmtime(), reply_email="Fake@Fake.com", from_email="Fake@Fake.com", from_name="Fake") - - #Test Assertion Error is handled: Short Message ID (create_distribution) - def test_responses_long_msg_id_create_dist(self): - '''This method tests that an assertion is raised in the Distribution Module's create_distribution method when the user enters a - message_id that is too short.''' - msg_id, bad_id = setup_tests().setup_test_message_id(short=True, false_id=False) - with self.assertRaises(AssertionError): - Distributions().create_distribution(message=msg_id ,library="GR_ThisIsaFakeLib!", survey="SV_ThisIsaFakeID!!", mailing_list="CG_ThisIsaFakeMail", subject="Fake", send_date=gmtime(), reply_email="Fake@Fake.com", from_email="Fake@Fake.com", from_name="Fake") - - #Test Assertion Error is handled: Incorrect Message ID (create_distribution) - def test_responses_bad_msg_id_create_dist(self): - '''This method tests that an assertion is raised in the Distribution Module's create_distribution method when the user enters - a message_id that is incorrect. ''' - msg_id, bad_id = setup_tests().setup_test_message_id(short=False, false_id=True) - with self.assertRaises(AssertionError): - Distributions().create_distribution(message=bad_id, library="GR_ThisIsaFakeLib!", survey="SV_ThisIsaFakeID!!", mailing_list="CG_ThisIsaFakeMail", subject="Fake", send_date=gmtime(), reply_email="Fake@Fake.com", from_email="Fake@Fake.com", from_name="Fake") - - ## Distribution: Message IDs ## - #Test Assertion Error is handled: Long Message ID (create_reminder) - def test_responses_short_msg_id_create_remind(self): - '''This method tests that an assertion is raised in the Distribution Module's create_reminder method when the user enters a - message_id that is too long. ''' - msg_id, bad_id = setup_tests().setup_test_message_id(short=False, false_id=False) - with self.assertRaises(AssertionError): - Distributions().create_reminder(distribution="EMD_ThisIsaFakeID!", library="GR_ThisIsaFakeLib!", message=msg_id, subject="Fake", reply_email="Fake@Fake.com", send_date=gmtime(), from_email="Fake@Fake.com", from_name="Fake") - - #Test Assertion Error is handled: Short Message ID (create_reminder) - def test_responses_long_msg_id_create_remind(self): - '''This method tests that an assertion is raised in the Distribution Module's create_reminder method when the user enters a - message_id that is too short.''' - msg_id, bad_id = setup_tests().setup_test_message_id(short=True, false_id=False) - with self.assertRaises(AssertionError): - Distributions().create_reminder(distribution="EMD_ThisIsaFakeID!", library="GR_ThisIsaFakeLib!", message=msg_id, subject="Fake", reply_email="Fake@Fake.com", send_date=gmtime(), from_email="Fake@Fake.com", from_name="Fake") - - #Test Assertion Error is handled: Incorrect Message ID (create_reminder) - def test_responses_bad_msg_id_create_remind(self): - '''This method tests that an assertion is raised in the Distribution Module's create_reminder method when the user enters - a message_id that is incorrect. ''' - msg_id, bad_id = setup_tests().setup_test_message_id(short=False, false_id=True) - with self.assertRaises(AssertionError): - Distributions().create_reminder(distribution="EMD_ThisIsaFakeID!", library="GR_ThisIsaFakeLib!", message=bad_id, subject="Fake", reply_email="Fake@Fake.com", send_date=gmtime(), from_email="Fake@Fake.com", from_name="Fake") - - ## Distribution Message IDs ## - #Test Assertion Error is handled: Long Message ID (create_thank_you) - def test_responses_short_msg_id_create_ty(self): - '''This method tests that an assertion is raised in the Distribution Module's create_thank_you method when the user enters a - message_id that is too long. ''' - msg_id, bad_id = setup_tests().setup_test_message_id(short=False, false_id=False) - with self.assertRaises(AssertionError): - Distributions().create_thank_you(distribution="EMD_ThisIsaFakeID!", library="GR_ThisIsaFakeLib!", message=msg_id, subject="Fake", reply_email="Fake@Fake.com", send_date=gmtime(), from_email="Fake@Fake.com", from_name="Fake") - - #Test Assertion Error is handled: Short Message ID (create_thank_you) - def test_responses_long_msg_id_create_ty(self): - '''This method tests that an assertion is raised in the Distribution Module's create_thank_you method when the user enters a - message_id that is too short.''' - msg_id, bad_id = setup_tests().setup_test_message_id(short=True, false_id=False) - with self.assertRaises(AssertionError): - Distributions().create_thank_you(distribution="EMD_ThisIsaFakeID!", library="GR_ThisIsaFakeLib!", message=msg_id, subject="Fake", reply_email="Fake@Fake.com", send_date=gmtime(), from_email="Fake@Fake.com", from_name="Fake") - - #Test Assertion Error is handled: Incorrect Message ID (create_thank_you) - def test_responses_bad_msg_id_create_ty(self): - '''This method tests that an assertion is raised in the Distribution Module's create_thank_you method when the user enters - a message_id that is incorrect. ''' - msg_id, bad_id = setup_tests().setup_test_message_id(short=False, false_id=True) - with self.assertRaises(AssertionError): - Distributions().create_thank_you(distribution="EMD_ThisIsaFakeID!", library="GR_ThisIsaFakeLib!", message=bad_id, subject="Fake", reply_email="Fake@Fake.com", send_date=gmtime(), from_email="Fake@Fake.com", from_name="Fake") - - # #Test Assertion Error is handled: bool first name (Create Contact in XM) - # def test_bad_first_name_bool_create_contact_xm(self): - # '''This method tests that an assertion is raised in the XMDirectory Module's create_contact_in_XM method when the user enters - # a first_name that is a type bool.''' - # boolFirstName = bool() - # with self.assertRaises(AssertionError): - # XMDirectory().create_contact_in_XM(first_name=boolFirstName) - - # #Test Assertion Error is handled: list first name (Create Contact in XM) - # def test_bad_first_name_list_create_contact_xm(self): - # '''This method tests that an assertion is raised in the XMDirectory Module's create_contact_in_XM method when the user enters - # a first_name that is a type list.''' - # listFirstName = list() - # with self.assertRaises(AssertionError): - # XMDirectory().create_contact_in_XM(first_name=listFirstName) - - # #Test Assertion Error is handled: float first name (Create Contact in XM) - # def test_bad_first_name_float_create_contact_xm(self): - # '''This method tests that an assertion is raised in the XMDirectory Module's create_contact_in_XM method when the user enters - # a first_name that is a type float.''' - # floatFirstName = float() - # with self.assertRaises(AssertionError): - # XMDirectory().create_contact_in_XM(first_name=floatFirstName) - - # #Test Assertion Error is handled: int first name (Create Contact in XM) - # def test_bad_first_name_int_create_contact_xm(self): - # '''This method tests that an assertion is raised in the XMDirectory Module's create_contact_in_XM method when the user enters - # a first_name that is a type int.''' - # intFirstName = int() - # with self.assertRaises(AssertionError): - # XMDirectory().create_contact_in_XM(first_name=intFirstName) - - # #Test Assertion Error is handled: dict first name (Create Contact in XM) - # def test_bad_first_name_dict_create_contact_xm(self): - # '''This method tests that an assertion is raised in the XMDirectory Module's create_contact_in_XM method when the user enters - # a first_name that is a type dict.''' - # dictFirstName = dict() - # with self.assertRaises(AssertionError): - # XMDirectory().create_contact_in_XM(first_name=dictFirstName) - - # #Test Assertion Error is handled: tuple first name (Create Contact in XM) - # def test_bad_first_name_tuple_create_contact_xm(self): - # '''This method tests that an assertion is raised in the XMDirectory Module's create_contact_in_XM method when the user enters - # a first_name that is a type tuple.''' - # tupleFirstName = tuple() - # with self.assertRaises(AssertionError): - # XMDirectory().create_contact_in_XM(first_name=tupleFirstName) - - # #Test Assertion Error is handled: bool last name (Create Contact in XM) - # def test_bad_last_name_bool_create_contact_xm(self): - # '''This method tests that an assertion is raised in the XMDirectory Module's create_contact_in_XM method when the user enters - # a last_name that is a type bool.''' - # boolLastName = bool() - # with self.assertRaises(AssertionError): - # XMDirectory().create_contact_in_XM(last_name=boolLastName) - - # #Test Assertion Error is handled: list last name (Create Contact in XM) - # def test_bad_last_name_list_create_contact_xm(self): - # '''This method tests that an assertion is raised in the XMDirectory Module's create_contact_in_XM method when the user enters - # a last_name that is a type list.''' - # listLastName = list() - # with self.assertRaises(AssertionError): - # XMDirectory().create_contact_in_XM(last_name=listLastName) - - # #Test Assertion Error is handled: float last name (Create Contact in XM) - # def test_bad_last_name_float_create_contact_xm(self): - # '''This method tests that an assertion is raised in the XMDirectory Module's create_contact_in_XM method when the user enters - # a last_name that is a type float.''' - # floatLastName = float() - # with self.assertRaises(AssertionError): - # XMDirectory().create_contact_in_XM(last_name=floatLastName) - - # #Test Assertion Error is handled: int last name (Create Contact in XM) - # def test_bad_last_name_int_create_contact_xm(self): - # '''This method tests that an assertion is raised in the XMDirectory Module's create_contact_in_XM method when the user enters - # a last_name that is a type int.''' - # intLastName = int() - # with self.assertRaises(AssertionError): - # XMDirectory().create_contact_in_XM(last_name=intLastName) - - # #Test Assertion Error is handled: dict last name (Create Contact in XM) - # def test_bad_last_name_dict_create_contact_xm(self): - # '''This method tests that an assertion is raised in the XMDirectory Module's create_contact_in_XM method when the user enters - # a last_name that is a type dict.''' - # dictLastName = dict() - # with self.assertRaises(AssertionError): - # XMDirectory().create_contact_in_XM(last_name=dictLastName) - - # #Test Assertion Error is handled: tuple last name (Create Contact in XM) - # def test_bad_last_name_tuple_create_contact_xm(self): - # '''This method tests that an assertion is raised in the XMDirectory Module's create_contact_in_XM method when the user enters - # a last_name that is a type tuple.''' - # tupleLastName = tuple() - # with self.assertRaises(AssertionError): - # XMDirectory().create_contact_in_XM(last_name=tupleLastName) - - # #Test Assertion Error is handled: bool email (Create Contact in XM) - # def test_bad_email_bool_create_contact_xm(self): - # '''This method tests that an assertion is raised in the XMDirectory Module's create_contact_in_XM method when the user enters - # a email that is a type bool.''' - # boolEmail = bool() - # with self.assertRaises(AssertionError): - # XMDirectory().create_contact_in_XM(email=boolEmail) - - # #Test Assertion Error is handled: list email (Create Contact in XM) - # def test_bad_email_list_create_contact_xm(self): - # '''This method tests that an assertion is raised in the XMDirectory Module's create_contact_in_XM method when the user enters - # a email that is a type list.''' - # listEmail = list() - # with self.assertRaises(AssertionError): - # XMDirectory().create_contact_in_XM(email=listEmail) - - # #Test Assertion Error is handled: float email (Create Contact in XM) - # def test_bad_email_float_create_contact_xm(self): - # '''This method tests that an assertion is raised in the XMDirectory Module's create_contact_in_XM method when the user enters - # a email that is a type float.''' - # floatEmail = float() - # with self.assertRaises(AssertionError): - # XMDirectory().create_contact_in_XM(email=floatEmail) - - # #Test Assertion Error is handled: int email (Create Contact in XM) - # def test_bad_email_int_create_contact_xm(self): - # '''This method tests that an assertion is raised in the XMDirectory Module's create_contact_in_XM method when the user enters - # a email that is a type int.''' - # intEmail = int() - # with self.assertRaises(AssertionError): - # XMDirectory().create_contact_in_XM(email=intEmail) - - # #Test Assertion Error is handled: dict email (Create Contact in XM) - # def test_bad_email_dict_create_contact_xm(self): - # '''This method tests that an assertion is raised in the XMDirectory Module's create_contact_in_XM method when the user enters - # a email that is a type dict.''' - # dictEmail = dict() - # with self.assertRaises(AssertionError): - # XMDirectory().create_contact_in_XM(email=dictEmail) - - # #Test Assertion Error is handled: tuple email (Create Contact in XM) - # def test_bad_email_tuple_create_contact_xm(self): - # '''This method tests that an assertion is raised in the XMDirectory Module's create_contact_in_XM method when the user enters - # a email that is a type tuple.''' - # tupleEmail = tuple() - # with self.assertRaises(AssertionError): - # XMDirectory().create_contact_in_XM(email=tupleEmail) - - # #Test Assertion Error is handled: bool phone (Create Contact in XM) - # def test_bad_phone_bool_create_contact_xm(self): - # '''This method tests that an assertion is raised in the XMDirectory Module's create_contact_in_XM method when the user enters - # a phone that is a type bool.''' - # boolPhone = bool() - # with self.assertRaises(AssertionError): - # XMDirectory().create_contact_in_XM(phone=boolPhone) - - # #Test Assertion Error is handled: list phone (Create Contact in XM) - # def test_bad_phone_list_create_contact_xm(self): - # '''This method tests that an assertion is raised in the XMDirectory Module's create_contact_in_XM method when the user enters - # a phone that is a type list.''' - # listPhone = list() - # with self.assertRaises(AssertionError): - # XMDirectory().create_contact_in_XM(phone=listPhone) - - # #Test Assertion Error is handled: float phone (Create Contact in XM) - # def test_bad_phone_float_create_contact_xm(self): - # '''This method tests that an assertion is raised in the XMDirectory Module's create_contact_in_XM method when the user enters - # a phone that is a type float.''' - # floatPhone = float() - # with self.assertRaises(AssertionError): - # XMDirectory().create_contact_in_XM(phone=floatPhone) - - # #Test Assertion Error is handled: int phone (Create Contact in XM) - # def test_bad_phone_int_create_contact_xm(self): - # '''This method tests that an assertion is raised in the XMDirectory Module's create_contact_in_XM method when the user enters - # a phone that is a type int.''' - # intPhone = int() - # with self.assertRaises(AssertionError): - # XMDirectory().create_contact_in_XM(phone=intPhone) - - # #Test Assertion Error is handled: dict phone (Create Contact in XM) - # def test_bad_phone_dict_create_contact_xm(self): - # '''This method tests that an assertion is raised in the XMDirectory Module's create_contact_in_XM method when the user enters - # a phone that is a type dict.''' - # dictPhone = dict() - # with self.assertRaises(AssertionError): - # XMDirectory().create_contact_in_XM(phone=dictPhone) - - # #Test Assertion Error is handled: tuple phone (Create Contact in XM) - # def test_bad_phone_tuple_create_contact_xm(self): - # '''This method tests that an assertion is raised in the XMDirectory Module's create_contact_in_XM method when the user enters - # a phone that is a type tuple.''' - # tuplePhone = tuple() - # with self.assertRaises(AssertionError): - # XMDirectory().create_contact_in_XM(phone=tuplePhone) - - # #Test Assertion Error is handled: bool language (Create Contact in XM) - # def test_bad_language_bool_create_contact_xm(self): - # '''This method tests that an assertion is raised in the XMDirectory Module's create_contact_in_XM method when the user enters - # a language that is a type bool.''' - # boolLanguage = bool() - # with self.assertRaises(AssertionError): - # XMDirectory().create_contact_in_XM(language=boolLanguage) - - # #Test Assertion Error is handled: list language (Create Contact in XM) - # def test_bad_language_list_create_contact_xm(self): - # '''This method tests that an assertion is raised in the XMDirectory Module's create_contact_in_XM method when the user enters - # a language that is a type list.''' - # listLanguage = list() - # with self.assertRaises(AssertionError): - # XMDirectory().create_contact_in_XM(language=listLanguage) - - # #Test Assertion Error is handled: float language (Create Contact in XM) - # def test_bad_language_float_create_contact_xm(self): - # '''This method tests that an assertion is raised in the XMDirectory Module's create_contact_in_XM method when the user enters - # a language that is a type float.''' - # floatLanguage = float() - # with self.assertRaises(AssertionError): - # XMDirectory().create_contact_in_XM(language=floatLanguage) - - # #Test Assertion Error is handled: int language (Create Contact in XM) - # def test_bad_language_int_create_contact_xm(self): - # '''This method tests that an assertion is raised in the XMDirectory Module's create_contact_in_XM method when the user enters - # a language that is a type int.''' - # intLanguage = int() - # with self.assertRaises(AssertionError): - # XMDirectory().create_contact_in_XM(language=intLanguage) - - # #Test Assertion Error is handled: dict language (Create Contact in XM) - # def test_bad_language_dict_create_contact_xm(self): - # '''This method tests that an assertion is raised in the XMDirectory Module's create_contact_in_XM method when the user enters - # a language that is a type dict.''' - # dictLanguage = dict() - # with self.assertRaises(AssertionError): - # XMDirectory().create_contact_in_XM(language=dictLanguage) - - # #Test Assertion Error is handled: tuple language (Create Contact in XM) - # def test_bad_language_tuple_create_contact_xm(self): - # '''This method tests that an assertion is raised in the XMDirectory Module's create_contact_in_XM method when the user enters - # a language that is a type tuple.''' - # tupleLanguage = tuple() - # with self.assertRaises(AssertionError): - # XMDirectory().create_contact_in_XM(language=tupleLanguage) - - # #Test Assertion Error is handled: bool metadata (Create Contact in XM) - # def test_bad_metadata_bool_create_contact_xm(self): - # '''This method tests that an assertion is raised in the XMDirectory Module's create_contact_in_XM method when the user enters - # a metadata that is a type bool.''' - # boolMetadata = bool() - # with self.assertRaises(AssertionError): - # XMDirectory().create_contact_in_XM(metadata=boolMetadata) - - # #Test Assertion Error is handled: list Metadata (Create Contact in XM) - # def test_bad_metadata_list_create_contact_xm(self): - # '''This method tests that an assertion is raised in the XMDirectory Module's create_contact_in_XM method when the user enters - # a metadata that is a type list.''' - # listMetadata = list() - # with self.assertRaises(AssertionError): - # XMDirectory().create_contact_in_XM(metadata=listMetadata) - - # #Test Assertion Error is handled: float Metadata (Create Contact in XM) - # def test_bad_metadata_float_create_contact_xm(self): - # '''This method tests that an assertion is raised in the XMDirectory Module's create_contact_in_XM method when the user enters - # a metadata that is a type float.''' - # floatMetadata = float() - # with self.assertRaises(AssertionError): - # XMDirectory().create_contact_in_XM(metadata=floatMetadata) - - # #Test Assertion Error is handled: int Metadata (Create Contact in XM) - # def test_bad_metadata_int_create_contact_xm(self): - # '''This method tests that an assertion is raised in the XMDirectory Module's create_contact_in_XM method when the user enters - # a metadata that is a type int.''' - # intMetadata = int() - # with self.assertRaises(AssertionError): - # XMDirectory().create_contact_in_XM(metadata=intMetadata) - - # #Test Assertion Error is handled: str Metadata (Create Contact in XM) - # def test_bad_metadata_str_create_contact_xm(self): - # '''This method tests that an assertion is raised in the XMDirectory Module's create_contact_in_XM method when the user enters - # a metadata that is a type dict.''' - # strMetadata = str() - # with self.assertRaises(AssertionError): - # XMDirectory().create_contact_in_XM(metadata=strMetadata) - - # #Test Assertion Error is handled: tuple Metadata (Create Contact in XM) - # def test_bad_metadata_tuple_create_contact_xm(self): - # '''This method tests that an assertion is raised in the XMDirectory Module's create_contact_in_XM method when the user enters - # a metadata that is a type tuple.''' - # tupleMetadata = tuple() - # with self.assertRaises(AssertionError): - # XMDirectory().create_contact_in_XM(metadata=tupleMetadata) - -if __name__ == "__main__": - unittest.main() diff --git a/setup.py b/setup.py index e7aaa46..2c6e504 100644 --- a/setup.py +++ b/setup.py @@ -5,7 +5,7 @@ setuptools.setup( name='QualtricsAPI', - version='0.6.1', + version='0.6.3', author='Jeremy A. Seibert', author_email='jeremy@seibert.industries', description="QualtricsAPI is a lightweight Python library for the Qualtrics Web API. ", @@ -23,9 +23,9 @@ "Operating System :: OS Independent", ], install_requires=[ - 'pandas', - 'numpy', - 'requests', - 'python-dateutil' - ], + 'pandas', + 'numpy', + 'requests', + 'python-dateutil' + ], )