diff --git a/.travis.yml b/.travis.yml index a0a605e..329b454 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,6 +7,7 @@ python: - '3.5' install: - pip install coveralls +- pip install nose nose-parameterized script: - coverage run --source=postcodepy setup.py test after_success: diff --git a/docs/conf.py b/docs/conf.py index 248becf..2bf6bda 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -358,6 +358,41 @@ #epub_use_index = True on_rtd = os.environ.get('READTHEDOCS', None) == 'True' +# custom directive (stackoverflow.com: 7250659) +from os.path import basename + +try: + from StringIO import StringIO +except ImportError: + from io import StringIO + +from sphinx.util.compat import Directive +from docutils import nodes, statemachine + +class ExecDirective(Directive): + """Execute the specified python code and insert the output into the document""" + has_content = True + + def run(self): + oldStdout, sys.stdout = sys.stdout, StringIO() + + tab_width = self.options.get('tab-width', self.state.document.settings.tab_width) + source = self.state_machine.input_lines.source(self.lineno - self.state_machine.input_offset - 1) + + try: + exec('\n'.join(self.content)) + text = sys.stdout.getvalue() + lines = statemachine.string2lines(text, tab_width, convert_whitespace=True) + self.state_machine.insert_input(lines, source) + return [] + except Exception: + return [nodes.error(None, nodes.paragraph(text = "Unable to execute python code at %s:%d:" % (basename(source), self.lineno)), nodes.paragraph(text = str(sys.exc_info()[1])))] + finally: + sys.stdout = oldStdout + +def setup(app): + app.add_directive('exec', ExecDirective) + if not on_rtd: # only import and set the theme if we're building docs locally import sphinx_rtd_theme html_theme = 'sphinx_rtd_theme' diff --git a/docs/examples.rst b/docs/examples.rst index 7498d40..36c79ea 100644 --- a/docs/examples.rst +++ b/docs/examples.rst @@ -6,207 +6,205 @@ Get information by ``postcode``: .. code-block:: python - import sys import os + import sys import json - from postcodepy import API, PostcodeError - # First and third are OK, the 2nd is not OK and raises an Exception - # the exception is written to stderr + import postcodepy + + access_key = os.getenv("ACCESS_KEY") + access_secret = os.getenv("ACCESS_SECRET") + # get your access key and secret at https://api.postcode.nl + + """First and third are OK, the 2nd is not OK and raises an Exception + the exception is written to stderr + """ + api = postcodepy.API(environment='live', + access_key=access_key, access_secret=access_secret) - api = API(environment='live', - access_key=os.getenv("ACCESS_KEY"), - access_secret=os.getenv("ACCESS_SECRET")) + # exit program if one of these exceptions occurs + fatals = [ + 'PostcodeNl_Controller_Plugin_HttpBasicAuthentication_NotAuthorizedException', + 'PostcodeNl_Controller_Plugin_HttpBasicAuthentication_PasswordNotCorrectException' + ] + + # 2nd and last should fail for pc in [('1071XX', 1), - ('8422DH', 34, 'B'), ('1077XX', 1), - ('7514BP', 129)]: + ('7514BP', 129), + ('7514BP', 129, 'A'), + ('7514BP', 129, 'B')]: try: retValue = api.get_postcodedata(*pc) - # the raw resultvalue - print("\n--- RAW: ----------------------") + print("\nresults for: {}".format(str(pc))) print(json.dumps(retValue, sort_keys=True, indent=2)) - # The parsed result - print("\n--- Formatted: ----------------") - print("\nresults for: {}".format(pc)) - for K in retValue.keys(): - try: - print("{0:30s} : {1}".format(K, retValue[K])) - except Exception as e: - print("ERROR: {} {}".format( (K, retValue[K]))) - except PostcodeError as e: - sys.stdout.write("--- EXCEPTION -----------------\n") - sys.stdout.write(" {0}\n {1}\n {2}\n {3}\n". - format(e, pc, e.exceptionId, - json.dumps(e.response_data, sort_keys=True, indent=2))) + except postcodepy.PostcodeError as e: + if e.exceptionId in fatals: + sys.stderr.write("Exiting on fatal exception: {} [{}]". + format(e.exceptionId, e.msg)) + sys.exit(2) + else: + sys.stderr.write("---------------------------\n") + sys.stderr.write("{}\n".format(str(pc))) + sys.stderr.write("{}\n".format(e.exceptionId)) + sys.stderr.write("{}\n".format(json.dumps( + e.response_data, sort_keys=True, indent=2)) + ) Output `````` .. code-block:: text - - --- RAW: ---------------------- - {u'province': u'Noord-Holland', u'city': u'Amsterdam', u'bagAddressableObjectId': u'0363010012073352', u'addressType': u'building', u'rdY': 485901, u'bagNumberDesignationId': u'0363200012073684', u'municipality': u'Amsterdam', u'rdX': 120816, u'longitude': 4.88538896, u'purposes': [u'assembly'], u'houseNumberAddition': u'', u'street': u'Museumstraat', u'postcode': u'1071XX', u'houseNumberAdditions': [u''], u'latitude': 52.35994439, u'surfaceArea': 38149, u'houseNumber': 1} - - --- Formatted: ---------------- - results for: ('1071XX', 1) - province : Noord-Holland - city : Amsterdam - bagAddressableObjectId : 0363010012073352 - addressType : building - rdY : 485901 - bagNumberDesignationId : 0363200012073684 - municipality : Amsterdam - rdX : 120816 - longitude : 4.88538896 - purposes : [u'assembly'] - houseNumberAddition : - street : Museumstraat - postcode : 1071XX - houseNumberAdditions : [u''] - latitude : 52.35994439 - surfaceArea : 38149 - houseNumber : 1 - EXCEPTION: - Invalid housenumber addition: 'None' ('8422DH', 34, 'B') ERRHouseNumberAdditionInvalid {'validHouseNumberAdditions': [u'', u'A'], 'exception': "Invalid housenumber addition: 'None'", 'exceptionId': 'ERRHouseNumberAdditionInvalid'} - EXCEPTION: - Combination does not exist. ('1077XX', 1) PostcodeNl_Service_PostcodeAddress_AddressNotFoundException {u'exception': u'Combination does not exist.', u'exceptionId': u'PostcodeNl_Service_PostcodeAddress_AddressNotFoundException'} - - --- RAW: ---------------------- - {u'province': u'Overijssel', u'city': u'Enschede', u'bagAddressableObjectId': u'0153010000345343', u'addressType': u'building', u'rdY': 472143, u'bagNumberDesignationId': u'0153200000345342', u'municipality': u'Enschede', u'rdX': 258149, u'longitude': 6.89701549, u'purposes': [u'assembly'], u'houseNumberAddition': u'', u'street': u'Lasondersingel', u'postcode': u'7514BP', u'houseNumberAdditions': [u'', u'A'], u'latitude': 52.22770127, u'surfaceArea': 6700, u'houseNumber': 129} - - --- Formatted: ---------------- + { + "addressType": "building", + "bagAddressableObjectId": "0363010012073352", + "bagNumberDesignationId": "0363200012073684", + "city": "Amsterdam", + "houseNumber": 1, + "houseNumberAddition": "", + "houseNumberAdditions": [ + "" + ], + "latitude": 52.35994439, + "longitude": 4.88538896, + "municipality": "Amsterdam", + "postcode": "1071XX", + "province": "Noord-Holland", + "purposes": [ + "assembly" + ], + "rdX": 120816, + "rdY": 485901, + "street": "Museumstraat", + "surfaceArea": 38149 + } results for: ('7514BP', 129) - province : Overijssel - city : Enschede - bagAddressableObjectId : 0153010000345343 - addressType : building - rdY : 472143 - bagNumberDesignationId : 0153200000345342 - municipality : Enschede - rdX : 258149 - longitude : 6.89701549 - purposes : [u'assembly'] - houseNumberAddition : - street : Lasondersingel - postcode : 7514BP - houseNumberAdditions : [u'', u'A'] - latitude : 52.22770127 - surfaceArea : 6700 - houseNumber : 129 - ---- RAW: ---------------------- -{ - "addressType": "building", - "bagAddressableObjectId": "0363010012073352", - "bagNumberDesignationId": "0363200012073684", - "city": "Amsterdam", - "houseNumber": 1, - "houseNumberAddition": "", - "houseNumberAdditions": [ - "" - ], - "latitude": 52.35994439, - "longitude": 4.88538896, - "municipality": "Amsterdam", - "postcode": "1071XX", - "province": "Noord-Holland", - "purposes": [ - "assembly" - ], - "rdX": 120816, - "rdY": 485901, - "street": "Museumstraat", - "surfaceArea": 38149 -} - ---- Formatted: ---------------- - -results for: ('1071XX', 1) -province : Noord-Holland -city : Amsterdam -bagAddressableObjectId : 0363010012073352 -addressType : building -rdY : 485901 -bagNumberDesignationId : 0363200012073684 -municipality : Amsterdam -rdX : 120816 -longitude : 4.88538896 -purposes : [u'assembly'] -houseNumberAddition : -street : Museumstraat -postcode : 1071XX -houseNumberAdditions : [u''] -latitude : 52.35994439 -surfaceArea : 38149 -houseNumber : 1 ---- EXCEPTION ----------------- - Invalid housenumber addition: 'None' - ('8422DH', 34, 'B') - ERRHouseNumberAdditionInvalid - { - "exception": "Invalid housenumber addition: 'None'", - "exceptionId": "ERRHouseNumberAdditionInvalid", - "validHouseNumberAdditions": [ - "", - "A" - ] -} ---- EXCEPTION ----------------- - Combination does not exist. - ('1077XX', 1) - PostcodeNl_Service_PostcodeAddress_AddressNotFoundException - { - "exception": "Combination does not exist.", - "exceptionId": "PostcodeNl_Service_PostcodeAddress_AddressNotFoundException" -} - ---- RAW: ---------------------- -{ - "addressType": "building", - "bagAddressableObjectId": "0153010000345343", - "bagNumberDesignationId": "0153200000345342", - "city": "Enschede", - "houseNumber": 129, - "houseNumberAddition": "", - "houseNumberAdditions": [ - "", - "A" - ], - "latitude": 52.22770127, - "longitude": 6.89701549, - "municipality": "Enschede", - "postcode": "7514BP", - "province": "Overijssel", - "purposes": [ - "assembly" - ], - "rdX": 258149, - "rdY": 472143, - "street": "Lasondersingel", - "surfaceArea": 6700 -} - ---- Formatted: ---------------- - -results for: ('7514BP', 129) -province : Overijssel -city : Enschede -bagAddressableObjectId : 0153010000345343 -addressType : building -rdY : 472143 -bagNumberDesignationId : 0153200000345342 -municipality : Enschede -rdX : 258149 -longitude : 6.89701549 -purposes : [u'assembly'] -houseNumberAddition : -street : Lasondersingel -postcode : 7514BP -houseNumberAdditions : [u'', u'A'] -latitude : 52.22770127 -surfaceArea : 6700 -houseNumber : 129 + { + "addressType": "building", + "bagAddressableObjectId": "0153010000345343", + "bagNumberDesignationId": "0153200000345342", + "city": "Enschede", + "houseNumber": 129, + "houseNumberAddition": "", + "houseNumberAdditions": [ + "", + "A" + ], + "latitude": 52.22770127, + "longitude": 6.89701549, + "municipality": "Enschede", + "postcode": "7514BP", + "province": "Overijssel", + "purposes": [ + "assembly" + ], + "rdX": 258149, + "rdY": 472143, + "street": "Lasondersingel", + "surfaceArea": 6700 + } + + results for: ('7514BP', 129, 'A') + { + "addressType": "building", + "bagAddressableObjectId": "0153010000329929", + "bagNumberDesignationId": "0153200000329928", + "city": "Enschede", + "houseNumber": 129, + "houseNumberAddition": "A", + "houseNumberAdditions": [ + "", + "A" + ], + "latitude": 52.22770127, + "longitude": 6.89701549, + "municipality": "Enschede", + "postcode": "7514BP", + "province": "Overijssel", + "purposes": [ + "residency" + ], + "rdX": 258149, + "rdY": 472143, + "street": "Lasondersingel", + "surfaceArea": 119 + } + +Exceptions +~~~~~~~~~~ + +.. code-block:: text + + --------------------------- + ('1077XX', 1) + PostcodeNl_Service_PostcodeAddress_AddressNotFoundException + { + "exception": "Combination does not exist.", + "exceptionId": "PostcodeNl_Service_PostcodeAddress_AddressNotFoundException" + } + --------------------------- + ('7514BP', 129, 'B') + ERRHouseNumberAdditionInvalid + { + "exception": "Invalid housenumber addition: 'None'", + "exceptionId": "ERRHouseNumberAdditionInvalid", + "validHouseNumberAdditions": [ + "", + "A" + ] + } + + +Using typedefs on API responses +``````````````````````````````` + +The example below applies the decorators to `parse_result`, this function +will translate the `addressType` field and the values of the `purposes` field. + +.. code-block:: python + :caption: Typedef example + + ... + from postcodepy import typedefs + ... + + @typedefs.translate_purposes + @typedefs.translate_addresstype + def parse_result(r, pc): + return r + + rv = api.get_postcodedata(*pc) + rv = parse_result(rv, pc) + +Will result in: + +.. code-block:: json + + { + "addressType": "verblijfsobject", + "bagAddressableObjectId": "0080010000394794", + "bagNumberDesignationId": "0080200000394793", + "city": "Leeuwarden", + "houseNumber": 7, + "houseNumberAddition": "", + "houseNumberAdditions": [ + "" + ], + "latitude": 53.1926878, + "longitude": 5.83081603, + "municipality": "Leeuwarden", + "postcode": "8936AS", + "province": "Friesland", + "purposes": [ + "celfunctie" + ], + "rdX": 184649, + "rdY": 578538, + "street": "Holstmeerweg", + "surfaceArea": 19570 + } + +In this output are the values of `addressType` and `purposes` translation results. diff --git a/docs/postcode-api-wrapper.rst b/docs/postcode-api-wrapper.rst index 4be898a..9b711ff 100644 --- a/docs/postcode-api-wrapper.rst +++ b/docs/postcode-api-wrapper.rst @@ -21,3 +21,5 @@ Exceptions :inherited-members: :show-inheritance: :special-members: __init__ + +.. include:: typedefs/typedefs.rst diff --git a/docs/typedefs/typedefs.rst b/docs/typedefs/typedefs.rst new file mode 100644 index 0000000..36b1154 --- /dev/null +++ b/docs/typedefs/typedefs.rst @@ -0,0 +1,34 @@ +Typedefs +---------- + +.. automodule:: postcodepy.typedefs + :members: + +.. exec:: + import json + from postcodepy.typedefs import POSTCODE_API_TYPEDEFS_ADDRESS_TYPES + lines = [ " POSTCODE_API_TYPEDEFS_ADDRES_TYPES = " ] + for x in json.dumps(POSTCODE_API_TYPEDEFS_ADDRESS_TYPES, + indent=4).split("\n"): + lines.append(" {}".format(x)) + print("\n\n.. code-block:: python\n\n{}\n\n".format("\n".join(lines))) + +.. exec:: + import json + from postcodepy.typedefs import POSTCODE_API_TYPEDEFS_PURPOSES + lines = [ " POSTCODE_API_TYPEDEFS_PURPOSES = " ] + for x in json.dumps(POSTCODE_API_TYPEDEFS_PURPOSES, indent=4).split("\n"): + lines.append(" {}".format(x)) + print("\n\n.. code-block:: python\n\n{}\n\n".format("\n".join(lines))) + +The REST responses may contain fields that can be translated into the standard +descriptions as provided by postcode.nl. +This translation can be accomplished by simply applying the decorators to a +function that parses the return value of the API-call. + + +Logging +~~~~~~~ + +In case values can't be translated, a warning is logged by `logger`. The +message will contain the `postcode` that was responsible for the warning. diff --git a/postcodepy/postcodepy.py b/postcodepy/postcodepy.py index 43b0d86..1d4d06b 100644 --- a/postcodepy/postcodepy.py +++ b/postcodepy/postcodepy.py @@ -35,7 +35,7 @@ def get_postcodedata(self, postcode, nr, addition="", **params): if addition: endpoint += '/' + addition - retValue = self.request(endpoint, params=params) + retValue = self._API__request(endpoint, params=params) # then it should match the houseNumberAdditions if addition and addition.upper() not in \ @@ -69,7 +69,8 @@ def get_signalcheck(self, sar, **params): # The 'sar'-request dictionary should be sent as valid JSON data, so # we need to convert it to JSON # when we construct the request in API.request - retValue = self.request(endpoint, 'POST', params=params, convJSON=True) + retValue = self._API__request(endpoint, 'POST', + params=params, convJSON=True) return retValue @@ -118,10 +119,10 @@ def __init__(self, environment="practice", access_key=None, # Enable basic authentication self.client.auth = (access_key, access_secret) - def request(self, endpoint, method='GET', params=None, convJSON=False): + def __request(self, endpoint, method='GET', params=None, convJSON=False): """request - Returns dict of response from postcode.nl API. - this method is called by the EndpointMixin methods + This method is called only by the EndpointMixin methods. """ url = '%s/%s' % (self.api_url, endpoint) @@ -182,6 +183,7 @@ class PostcodeError(Exception): 'PostcodeNl_Controller_Address_InvalidHouseNumberException', 'PostcodeNl_Controller_Address_NoPostcodeSpecifiedException', 'PostcodeNl_Controller_Address_NoHouseNumberSpecifiedException', + 'PostcodeNl_Controller_Address_PostcodeTooLongException', 'React_Model_Property_Validation_Number_ValueTooHighException', 'PostcodeNl_Service_PostcodeAddress_AddressNotFoundException', # diff --git a/postcodepy/typedefs.py b/postcodepy/typedefs.py new file mode 100644 index 0000000..b801379 --- /dev/null +++ b/postcodepy/typedefs.py @@ -0,0 +1,95 @@ +"""Type definitions.""" +import logging +from functools import wraps + +logger = logging.getLogger(__name__) +logger.addHandler(logging.NullHandler()) + +POSTCODE_API_TYPEDEFS_ADDRESS_TYPES = { + "building": "verblijfsobject", + "house boat site": 'location used for mooring house boats', + "mobile home site": 'location used for mobile homes and trailers', + "PO box": 'PO box', +} + +POSTCODE_API_TYPEDEFS_PURPOSES = { + "residency": "woonfunctie", + "assembly": "bijeenkomstfunctie", + "detention": "celfunctie", + "healthcare": "gezondheidszorgfunctie", + "industry": "industriefunctie", + "office": "kantoorfunctie", + "lodging": "logiesfunctie", + "education": "onderwijsfunctie", + "sport": "sportfunctie", + "shopping": "winkelfunctie", + "other": "overige gebruiksfunctie", +} + +SIGNAL_API_TYPEDEFS = { + # signalTransactionStatus + "new": "The transaction is being constructed, but has not yet been " + + "agreed upon. (customer is shopping)", + "new-checkout": "The transaction is being constructed, and customer is a" + + " checkout process", + "pending": "The transaction is agreed upon, but customer needs to " + "complete some final steps.", + "pending-payment": "The transaction is agreed upon, but customer needs " + "to complete the payment process.", + "processing": "Customer has finished all steps of transaction creation, " + "shop needs to package & ship order.", + "complete": "The transaction has been shipped. (but not necessarily " + "delivered)", + "closed": "The transaction has been shipped, and (assumed) delivered, " + "cannot be cancelled anymore.", + "cancelled": "The transaction cancelled from any state. The transaction " + "will not continue and will not be restarted later.", + "cancelled-by-customer": "The transaction was cancelled by the customer.", + "cancelled-by-shop": "The transaction was cancelled by the shop.", + "onhold": "The transaction needs some custom interaction by customer or " + "shop before it can continue.", + "other": "Another status not listed here.", +} + + +def translate_addresstype(f): + """decorator to translate the addressType field. + + translate the value of the addressType field of the API response into a + translated type. + """ + @wraps(f) + def wr(r, pc): + at = r["addressType"] + try: + r.update({"addressType": POSTCODE_API_TYPEDEFS_ADDRESS_TYPES[at]}) + except: + logger.warn("Warning: {}: " + "unknown 'addressType': {}".format(pc, at)) + + return f(r, pc) + + return wr + + +def translate_purposes(f): + """decorator to translate the purposes field. + + translate the values of the purposes field of the API response into + translated values. + """ + @wraps(f) + def wr(r, pc): + tmp = [] + for P in r["purposes"]: + try: + tmp.append(POSTCODE_API_TYPEDEFS_PURPOSES[P]) + except: + logger.warn("Warning: {}: " + "cannot translate 'purpose': {}".format(pc, P)) + tmp.append(P) + + r.update({"purposes": tmp}) + return f(r, pc) + + return wr diff --git a/tests/test_adres_api.py b/tests/test_adres_api.py index 8fd6ae9..d7ea34f 100644 --- a/tests/test_adres_api.py +++ b/tests/test_adres_api.py @@ -1,9 +1,16 @@ """Adres API tests.""" import unittest import postcodepy +from postcodepy import typedefs from postcodepy import PostcodeError from . import unittestsetup +try: + from nose_parameterized import parameterized, param +except: + print("*** Please install 'nose_parameterized' to run these tests ***") + exit(0) + import os import sys @@ -12,6 +19,13 @@ api = None +@typedefs.translate_addresstype +@typedefs.translate_purposes +def parse_response(r, pc): + """manipulate the response.""" + return r + + class Test_Adres_API(unittest.TestCase): """Tests for Adres API.""" @@ -34,15 +48,89 @@ def setUp(self): access_key=access_key, access_secret=access_secret) - def test_PostcodeDataOK(self): - """TEST: retrieval of data. - - should return testvalues for city and street - """ - pc = ('1071XX', 1) + @parameterized.expand([ + ("Rijksmuseum", + ('1071XX', 1), + 'verblijfsobject', + ["bijeenkomstfunctie"], + "Amsterdam", + "Museumstraat", + ), + ("Sportschool", + ('8431NJ', 23), + 'verblijfsobject', + ["overige gebruiksfunctie"], + "Oosterwolde", + "Veengang", + ), + ("Gamma", + ('8431NJ', 8), + 'verblijfsobject', + ["kantoorfunctie", "winkelfunctie"], + "Oosterwolde", + "Veengang", + ), + ("Industrieterrein Douwe Egberts Joure", + ('8501ZD', 1), + 'verblijfsobject', + ["industriefunctie", "kantoorfunctie", "overige gebruiksfunctie"], + "Joure", + "Leeuwarderweg", + ), + ("Ziekenhuis Tjongerschans Heerenveen", + ('8441PW', 44), + 'verblijfsobject', + ["gezondheidszorgfunctie"], + "Heerenveen", + "Thialfweg", + ), + ("De Marwei te Leeuwarden", + ('8936AS', 7), + 'verblijfsobject', + ["celfunctie"], + "Leeuwarden", + "Holstmeerweg", + ), + ("Hotel de Zon Oosterwolde", + ('8431ET', 1), + 'verblijfsobject', + ["overige gebruiksfunctie"], + "Oosterwolde", + "Stationsstraat", + ), + ("Hotel de Zon Oosterwolde", + ('8431ET', 1), + 'error_building', + ["overige gebruiksfunctie"], + "Oosterwolde", + "Stationsstraat", + 1 + ), + ("Hotel de Zon Oosterwolde", + ('8431ET', 1), + 'verblijfsobject', + ["overige gebruiksfunctie", "cannot_find"], + "Oosterwolde", + "Stationsstraat", + 2 + ), + ]) + def test_Postcode_and_translation(self, description, + pc, addressType, + purpose, city, street, errFlag=0): + """verify response data.""" retValue = api.get_postcodedata(*pc) - self.assertEqual((retValue['city'], retValue['street']), - ("Amsterdam", "Museumstraat")) + if errFlag == 1: + # force a lookup error + retValue['addressType'] = "error_building" + if errFlag == 2: + # force a lookup error + retValue['purposes'].append("cannot_find") + retValue = parse_response(retValue, pc) + self.assertTrue(retValue['addressType'] == addressType and + retValue['purposes'].sort() == purpose.sort() and + retValue['city'] == city and + retValue['street'] == street) def test_PostcodeDataWithAdditionOK(self): """TEST: retrieval of data. @@ -127,9 +215,11 @@ def test_PostcodeInvalidUserAccount(self): caught_exception = cm.exception expected_exception = PostcodeError( - "PostcodeNl_Controller_Plugin_HttpBasicAuthentication_NotAuthorizedException", { + "PostcodeNl_Controller_Plugin_HttpBasic" + "Authentication_NotAuthorizedException", { "exception": "User `1%s` not correct." % access_key, - "exceptionId": "PostcodeNl_Controller_Plugin_HttpBasicAuthentication_NotAuthorizedException"}) + "exceptionId": "PostcodeNl_Controller_Plugin_HttpBasic" + "Authentication_NotAuthorizedException"}) self.assertEqual(expected_exception.msg, caught_exception.msg) @@ -150,9 +240,11 @@ def test_PostcodeInvalidUserSecret(self): caught_exception = cm.exception expected_exception = PostcodeError( - "PostcodeNl_Controller_Plugin_HttpBasicAuthentication_PasswordNotCorrectException", { + "PostcodeNl_Controller_Plugin_HttpBasic" + "Authentication_PasswordNotCorrectException", { "exception": "Password not correct.", - "exceptionId": "PostcodeNl_Controller_Plugin_HttpBasicAuthentication_PasswordNotCorrectException"}) + "exceptionId": "PostcodeNl_Controller_Plugin_HttpBasic" + "Authentication_PasswordNotCorrectException"}) self.assertEqual(expected_exception.msg, caught_exception.msg)