Skip to content

Commit

Permalink
Refactor all error-related code into vcard_errors
Browse files Browse the repository at this point in the history
  • Loading branch information
Zearin authored and Zearin committed Feb 21, 2014
1 parent c3d6400 commit 42c860c
Show file tree
Hide file tree
Showing 5 changed files with 254 additions and 235 deletions.
60 changes: 31 additions & 29 deletions vcard/test/test_package.py
Expand Up @@ -19,6 +19,7 @@
from vcard import (
vcard,
vcard_defs,
vcard_errors,
vcard_utils,
vcard_validators
)
Expand Down Expand Up @@ -50,88 +51,88 @@ def _get_vcard_file(path):

# vCards with errors
VCARDS_CONTINUATION_AT_START = {
'message': vcard_defs.MSG_CONTINUATION_AT_START,
'message': vcard_errors.MSG_CONTINUATION_AT_START,
'vcards': ('continuation_at_start.vcf',)}
VCARDS_DOT_AT_LINE_START = {
'message': vcard_defs.MSG_DOT_AT_LINE_START,
'message': vcard_errors.MSG_DOT_AT_LINE_START,
'vcards': ('dot_at_line_start.vcf',)}
VCARDS_EMPTY_VCARD = {
'message': vcard_defs.MSG_EMPTY_VCARD,
'message': vcard_errors.MSG_EMPTY_VCARD,
'vcards': (
'',
None)}
VCARDS_INVALID_DATE = {
'message': vcard_defs.MSG_INVALID_DATE,
'message': vcard_errors.MSG_INVALID_DATE,
'vcards': tuple()}
VCARDS_INVALID_LANGUAGE_VALUE = {
'message': vcard_defs.MSG_INVALID_LANGUAGE_VALUE,
'message': vcard_errors.MSG_INVALID_LANGUAGE_VALUE,
'vcards': ('invalid_language_value.vcf',)}
VCARDS_INVALID_LINE_SEPARATOR = {
'message': vcard_defs.MSG_INVALID_LINE_SEPARATOR,
'message': vcard_errors.MSG_INVALID_LINE_SEPARATOR,
'vcards': (
'line_ending_mac.vcf',
'line_ending_unix.vcf',
'line_ending_mixed.vcf',)}
VCARDS_INVALID_PARAM_NAME = {
'message': vcard_defs.MSG_INVALID_PARAM_NAME,
'message': vcard_errors.MSG_INVALID_PARAM_NAME,
'vcards': ('invalid_param_name.vcf',)}
VCARDS_INVALID_PARAM_VALUE = {
'message': vcard_defs.MSG_INVALID_PARAM_VALUE,
'message': vcard_errors.MSG_INVALID_PARAM_VALUE,
'vcards': ('invalid_param_value.vcf',)}
VCARDS_INVALID_PROPERTY_NAME = {
'message': vcard_defs.MSG_INVALID_PROPERTY_NAME,
'message': vcard_errors.MSG_INVALID_PROPERTY_NAME,
'vcards': ('invalid_property_foo.vcf',)}
VCARDS_INVALID_SUBVALUE = {
'message': vcard_defs.MSG_INVALID_SUBVALUE,
'message': vcard_errors.MSG_INVALID_SUBVALUE,
'vcards': tuple()}
VCARDS_INVALID_SUBVALUE_COUNT = {
'message': vcard_defs.MSG_INVALID_SUBVALUE_COUNT,
'message': vcard_errors.MSG_INVALID_SUBVALUE_COUNT,
'vcards': tuple()}
VCARDS_INVALID_TEXT_VALUE = {
'message': vcard_defs.MSG_INVALID_TEXT_VALUE,
'message': vcard_errors.MSG_INVALID_TEXT_VALUE,
'vcards': tuple()}
VCARDS_INVALID_TIME = {
'message': vcard_defs.MSG_INVALID_TIME,
'message': vcard_errors.MSG_INVALID_TIME,
'vcards': tuple()}
VCARDS_INVALID_TIME_ZONE = {
'message': vcard_defs.MSG_INVALID_TIME_ZONE,
'message': vcard_errors.MSG_INVALID_TIME_ZONE,
'vcards': tuple()}
VCARDS_INVALID_URI = {
'message': vcard_defs.MSG_INVALID_URI,
'message': vcard_errors.MSG_INVALID_URI,
'vcards': tuple()}
VCARDS_INVALID_VALUE = {
'message': vcard_defs.MSG_INVALID_VALUE,
'message': vcard_errors.MSG_INVALID_VALUE,
'vcards': (
'invalid_begin.vcf',)}
VCARDS_INVALID_VALUE_COUNT = {
'message': vcard_defs.MSG_INVALID_VALUE_COUNT,
'message': vcard_errors.MSG_INVALID_VALUE_COUNT,
'vcards': (
# http://en.wikipedia.org/wiki/VCard
'invalid_value_count_wp.vcf',)}
VCARDS_INVALID_X_NAME = {
'message': vcard_defs.MSG_INVALID_X_NAME,
'message': vcard_errors.MSG_INVALID_X_NAME,
'vcards': tuple()}
VCARDS_MISMATCH_GROUP = {
'message': vcard_defs.MSG_MISMATCH_GROUP,
'message': vcard_errors.MSG_MISMATCH_GROUP,
'vcards': (
'mismatch_group.vcf',)}
VCARDS_MISMATCH_PARAM = {
'message': vcard_defs.MSG_MISMATCH_PARAM,
'message': vcard_errors.MSG_MISMATCH_PARAM,
'vcards': tuple()}
VCARDS_MISSING_GROUP = {
'message': vcard_defs.MSG_MISSING_GROUP,
'message': vcard_errors.MSG_MISSING_GROUP,
'vcards': (
'missing_group.vcf',)}
VCARDS_MISSING_PARAM = {
'message': vcard_defs.MSG_MISSING_PARAM,
'message': vcard_errors.MSG_MISSING_PARAM,
'vcards': (
'missing_photo_param.vcf',)}
VCARDS_MISSING_PARAM_VALUE = {
'message': vcard_defs.MSG_MISSING_PARAM_VALUE,
'message': vcard_errors.MSG_MISSING_PARAM_VALUE,
'vcards': (
'missing_param_value.vcf',)}
VCARDS_MISSING_PROPERTY = {
'message': vcard_defs.MSG_MISSING_PROPERTY,
'message': vcard_errors.MSG_MISSING_PROPERTY,
'vcards': (
'missing_properties.vcf',
'missing_start.vcf',
Expand All @@ -140,11 +141,11 @@ def _get_vcard_file(path):
'missing_n.vcf',
'missing_fn.vcf',)}
VCARDS_MISSING_VALUE_STRING = {
'message': vcard_defs.MSG_MISSING_VALUE_STRING,
'message': vcard_errors.MSG_MISSING_VALUE_STRING,
'vcards': (
'missing_n_value.vcf',)}
VCARDS_NON_EMPTY_PARAM = {
'message': vcard_defs.MSG_NON_EMPTY_PARAM,
'message': vcard_errors.MSG_NON_EMPTY_PARAM,
'vcards': (
'http://aspaass.no/kontakt/Aspaas%20Sykler.vcf',
'http://www.troywolf.com/articles/php/class_vcard/vcard_example.php')}
Expand Down Expand Up @@ -209,7 +210,7 @@ def test_failing(self):
with warnings.catch_warnings(record=True):
vcard.VCard(vcard_text, filename=vcard_file)
self.fail('Invalid vCard created:\n{0}'.format(vcard_text))
except vcard_validators.VCardFormatError as error:
except vcard_errors.VCardFormatError as error:
message = str(error).splitlines(False)[0].split(':')[0]
error_msg = '\n\n'.join((
'Wrong message for vCard {vcard_file!r}:'.format(vcard_file=vcard_file),
Expand All @@ -232,7 +233,7 @@ def test_valid(self):
with warnings.catch_warnings(record=True):
vc_obj = vcard.VCard(vcard_text, filename=vcard_file)
self.assertNotEqual(vc_obj, None)
except vcard_validators.VCardFormatError as error:
except vcard_errors.VCardFormatError as error:
error_msg = '\n\n'.join((
'Expected valid vCard for {vcard_file!r}, but it failed to validate'.format(
vcard_file=vcard_file
Expand All @@ -250,13 +251,14 @@ def test_online(self):

with warnings.catch_warnings(record=True):
self.assertRaises(
vcard_validators.VCardFormatError,
vcard_errors.VCardFormatError,
vcard.VCard,
vcard_text)

def test_doc(self):
"""Run DocTests"""
self.assertEqual(doctest.testmod(vcard)[0], 0)
self.assertEqual(doctest.testmod(vcard_defs)[0], 0)
self.assertEqual(doctest.testmod(vcard_errors)[0], 0)
self.assertEqual(doctest.testmod(vcard_utils)[0], 0)
self.assertEqual(doctest.testmod(vcard_validators)[0], 0)
68 changes: 32 additions & 36 deletions vcard/vcard.py
Expand Up @@ -27,6 +27,14 @@
CRLF_CHARS,
ID_CHARS,
MANDATORY_PROPERTIES,
QSAFE_CHARS,
SAFE_CHARS,
SP_CHAR,
VALUE_CHARS,
VCARD_LINE_MAX_LENGTH_RAW
)
from vcard_errors import (
# Error literals
MSG_CONTINUATION_AT_START,
MSG_DOT_AT_LINE_START,
MSG_EMPTY_VCARD,
Expand All @@ -40,11 +48,9 @@
MSG_MISSING_PARAM_VALUE,
MSG_MISSING_PROPERTY,
MSG_MISSING_VALUE_STRING,
QSAFE_CHARS,
SAFE_CHARS,
SP_CHAR,
VALUE_CHARS,
VCARD_LINE_MAX_LENGTH_RAW
# Classes
VCardFormatError,
UsageError
)
import vcard_utils
import vcard_validators
Expand All @@ -61,7 +67,7 @@ def unfold_vcard_lines(lines):
for index in range(len(lines)):
line = lines[index]
if not line.endswith(CRLF_CHARS):
raise vcard_validators.VCardFormatError(
raise VCardFormatError(
MSG_INVALID_LINE_SEPARATOR,
{'File line': index + 1})

Expand All @@ -71,7 +77,7 @@ def unfold_vcard_lines(lines):

if line.startswith(' '):
if index == 0:
raise vcard_validators.VCardFormatError(
raise VCardFormatError(
MSG_CONTINUATION_AT_START,
{'File line': index + 1})
elif len(lines[index - 1]) < VCARD_LINE_MAX_LENGTH_RAW:
Expand Down Expand Up @@ -105,17 +111,17 @@ def get_vcard_group(lines):

# Validate
if len(group) == 0:
raise vcard_validators.VCardFormatError(MSG_DOT_AT_LINE_START, {})
raise VCardFormatError(MSG_DOT_AT_LINE_START, {})

for index in range(len(lines)):
line = lines[index]
next_match = group_re.match(line)
if not next_match:
raise vcard_validators.VCardFormatError(
raise VCardFormatError(
MSG_MISSING_GROUP,
{'File line': index + 1})
if next_match.group(1) != group:
raise vcard_validators.VCardFormatError(
raise VCardFormatError(
'{0}: {1} != {2}'.format(
MSG_MISMATCH_GROUP,
next_match.group(1),
Expand All @@ -126,7 +132,7 @@ def get_vcard_group(lines):
for index in range(len(lines)):
next_match = group_re.match(lines[index])
if next_match:
raise vcard_validators.VCardFormatError(
raise VCardFormatError(
'{0}: {1} != {2}'.format(
MSG_MISMATCH_GROUP,
next_match.group(1), group
Expand Down Expand Up @@ -163,7 +169,7 @@ def get_vcard_property_param_values(values_string):
# Validate
for value in values:
if not re.match(u'^[{0}]+$|^"[{1}]+"$'.format(re.escape(SAFE_CHARS), re.escape(QSAFE_CHARS)), value):
raise vcard_validators.VCardFormatError(
raise VCardFormatError(
'{0}: {1}'.format(MSG_INVALID_VALUE, value),
{})

Expand All @@ -182,15 +188,15 @@ def get_vcard_property_param(param_string):
param_string,
'=')
except ValueError as error:
raise vcard_validators.VCardFormatError(
raise VCardFormatError(
'{0}: {1}'.format(MSG_MISSING_PARAM_VALUE, str(error)),
{})

values = get_vcard_property_param_values(values_string)

# Validate
if not re.match('^[{0}]+$'.format(re.escape(ID_CHARS)), param_name):
raise vcard_validators.VCardFormatError(
raise VCardFormatError(
'{0}: {1}'.format(
MSG_INVALID_PARAM_NAME,
param_name),
Expand Down Expand Up @@ -237,7 +243,7 @@ def get_vcard_property_subvalues(value_string):
# Validate string
for subvalue in subvalues:
if not re.match(u'^[{0}]*$'.format(re.escape(VALUE_CHARS)), subvalue):
raise vcard_validators.VCardFormatError(
raise VCardFormatError(
'{0}: {1}'.format(MSG_INVALID_SUBVALUE, subvalue),
{})

Expand Down Expand Up @@ -274,7 +280,7 @@ def get_vcard_property(property_line):

property_parts = vcard_utils.split_unescaped(property_line, ':')
if len(property_parts) < 2:
raise vcard_validators.VCardFormatError(
raise VCardFormatError(
'{0}: {1}'.format(MSG_MISSING_VALUE_STRING, property_line),
{})
elif len(property_parts) > 2:
Expand All @@ -296,7 +302,7 @@ def get_vcard_property(property_line):
prop['name'],
re.IGNORECASE
):
raise vcard_validators.VCardFormatError(
raise VCardFormatError(
'{0}: {1[name]}'.format(MSG_INVALID_PROPERTY_NAME, prop),
{})

Expand All @@ -308,10 +314,10 @@ def get_vcard_property(property_line):

# Validate
vcard_validators.validate_vcard_property(prop)
except vcard_validators.VCardFormatError as error:
except VCardFormatError as error:
# Add parameter name to error
error.context['Property line'] = property_line
raise vcard_validators.VCardFormatError(error.message, error.context)
raise VCardFormatError(error.message, error.context)

return prop

Expand All @@ -331,15 +337,15 @@ def get_vcard_properties(lines):
if property_line != CRLF_CHARS:
try:
properties.append(get_vcard_property(property_line))
except vcard_validators.VCardFormatError as error:
except VCardFormatError as error:
error.context['vCard line'] = index
raise vcard_validators.VCardFormatError(
raise VCardFormatError(
error.message,
error.context)

for mandatory_property in MANDATORY_PROPERTIES:
if mandatory_property not in [prop['name'].upper() for prop in properties]:
raise vcard_validators.VCardFormatError(
raise VCardFormatError(
'{0}: {1}'.format(MSG_MISSING_PROPERTY, mandatory_property),
{'Property': mandatory_property})

Expand All @@ -357,7 +363,7 @@ def __init__(self, text, filename=None):
@param text: String containing a single vCard
"""
if text == '' or text is None:
raise vcard_validators.VCardFormatError(
raise VCardFormatError(
MSG_EMPTY_VCARD,
{'vCard line': 1, 'File line': 1})

Expand Down Expand Up @@ -406,14 +412,14 @@ def validate_file(filename, verbose=False):
vcard_text = ''
if verbose:
print(vcard)
except vcard_validators.VCardFormatError as error:
except VCardFormatError as error:
error.context['File'] = filename
error.context['File line'] = index
raise vcard_validators.VCardFormatError(
raise VCardFormatError(
error.message,
error.context)

except vcard_validators.VCardFormatError as error:
except VCardFormatError as error:
result += str(error)

if vcard_text != '' and result == '':
Expand All @@ -426,16 +432,6 @@ def validate_file(filename, verbose=False):
return result


class UsageError(Exception):
"""Raise in case of invalid parameters."""
def __init__(self, message):
Exception.__init__(self)
self._message = message

def __str__(self):
return self._message.encode('utf-8')


def main(argv=None):
"""Argument handling."""

Expand Down

0 comments on commit 42c860c

Please sign in to comment.