Skip to content

Commit

Permalink
Move definition of ValidationError class next to definition
Browse files Browse the repository at this point in the history
of validate() function. This change organizes the module so
that functions and classes are defined in the order they
are used in the validate() function itself.
  • Loading branch information
shawnbrown committed Nov 28, 2018
1 parent e49bd45 commit d0d2887
Showing 1 changed file with 111 additions and 111 deletions.
222 changes: 111 additions & 111 deletions datatest/validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,117 +90,6 @@ def _normalize_requirement(requirement):
return requirement


class ValidationError(AssertionError):
"""This exception is raised when data validation fails."""

__module__ = 'datatest'

def __init__(self, differences, description=None):
if isinstance(differences, BaseDifference):
differences = [differences]
elif not nonstringiter(differences):
msg = 'expected an iterable of differences, got {0!r}'
raise TypeError(msg.format(differences.__class__.__name__))

# Normalize *differences* argument.
if _is_collection_of_items(differences):
differences = dict(differences)
elif exhaustible(differences):
differences = list(differences)

if not differences:
raise ValueError('differences container must not be empty')

# Initialize properties.
self._differences = differences
self._description = description
self._should_truncate = None
self._truncation_notice = None

@property
def differences(self):
"""A collection of "difference" objects to describe elements
in the data under test that do not satisfy the requirement.
"""
return self._differences

@property
def description(self):
"""An optional description of the failed requirement."""
return self._description

@property
def args(self):
"""The tuple of arguments given to the exception constructor."""
return (self._differences, self._description)

def __str__(self):
# Prepare a format-differences callable.
if isinstance(self._differences, dict):
begin, end = '{', '}'
all_keys = sorted(self._differences.keys(), key=_safesort_key)
def sorted_value(key):
value = self._differences[key]
if nonstringiter(value):
sort_args = lambda diff: _safesort_key(diff.args)
return sorted(value, key=sort_args)
return value
iterator = iter((key, sorted_value(key)) for key in all_keys)
format_diff = lambda x: ' {0!r}: {1!r},'.format(x[0], x[1])
else:
begin, end = '[', ']'
sort_args = lambda diff: _safesort_key(diff.args)
iterator = iter(sorted(self._differences, key=sort_args))
format_diff = lambda x: ' {0!r},'.format(x)

# Format differences as a list of strings and get line count.
if self._should_truncate:
line_count = 0
char_count = 0
list_of_strings = []
for x in iterator: # For-loop used to build list
line_count += 1 # iteratively to optimize for
diff_string = format_diff(x) # memory (in case the iter of
char_count += len(diff_string) # diffs is extremely long).
if self._should_truncate(line_count, char_count):
line_count += sum(1 for x in iterator)
end = ' ...'
if self._truncation_notice:
end += '\n\n{0}'.format(self._truncation_notice)
break
list_of_strings.append(diff_string)
else:
list_of_strings = [format_diff(x) for x in iterator]
line_count = len(list_of_strings)

# Prepare count-of-differences string.
count_message = '{0} difference{1}'.format(
line_count,
'' if line_count == 1 else 's',
)

# Prepare description string.
if self._description:
description = '{0} ({1})'.format(self._description, count_message)
else:
description = count_message

# Prepare final output.
output = '{0}: {1}\n{2}\n{3}'.format(
description,
begin,
'\n'.join(list_of_strings),
end,
)
return output

def __repr__(self):
cls_name = self.__class__.__name__
if self.description:
return '{0}({1!r}, {2!r})'.format(cls_name, self.differences, self.description)
return '{0}({1!r})'.format(cls_name, self.differences)


def _get_group_requirement(requirement, show_expected=False):
"""Make sure *requirement* is a group requirement."""
if getattr(requirement, '_group_requirement', False):
Expand Down Expand Up @@ -320,6 +209,117 @@ def _datadict_vs_requirementdict(data, requirement):
return differences, description


class ValidationError(AssertionError):
"""This exception is raised when data validation fails."""

__module__ = 'datatest'

def __init__(self, differences, description=None):
if isinstance(differences, BaseDifference):
differences = [differences]
elif not nonstringiter(differences):
msg = 'expected an iterable of differences, got {0!r}'
raise TypeError(msg.format(differences.__class__.__name__))

# Normalize *differences* argument.
if _is_collection_of_items(differences):
differences = dict(differences)
elif exhaustible(differences):
differences = list(differences)

if not differences:
raise ValueError('differences container must not be empty')

# Initialize properties.
self._differences = differences
self._description = description
self._should_truncate = None
self._truncation_notice = None

@property
def differences(self):
"""A collection of "difference" objects to describe elements
in the data under test that do not satisfy the requirement.
"""
return self._differences

@property
def description(self):
"""An optional description of the failed requirement."""
return self._description

@property
def args(self):
"""The tuple of arguments given to the exception constructor."""
return (self._differences, self._description)

def __str__(self):
# Prepare a format-differences callable.
if isinstance(self._differences, dict):
begin, end = '{', '}'
all_keys = sorted(self._differences.keys(), key=_safesort_key)
def sorted_value(key):
value = self._differences[key]
if nonstringiter(value):
sort_args = lambda diff: _safesort_key(diff.args)
return sorted(value, key=sort_args)
return value
iterator = iter((key, sorted_value(key)) for key in all_keys)
format_diff = lambda x: ' {0!r}: {1!r},'.format(x[0], x[1])
else:
begin, end = '[', ']'
sort_args = lambda diff: _safesort_key(diff.args)
iterator = iter(sorted(self._differences, key=sort_args))
format_diff = lambda x: ' {0!r},'.format(x)

# Format differences as a list of strings and get line count.
if self._should_truncate:
line_count = 0
char_count = 0
list_of_strings = []
for x in iterator: # For-loop used to build list
line_count += 1 # iteratively to optimize for
diff_string = format_diff(x) # memory (in case the iter of
char_count += len(diff_string) # diffs is extremely long).
if self._should_truncate(line_count, char_count):
line_count += sum(1 for x in iterator)
end = ' ...'
if self._truncation_notice:
end += '\n\n{0}'.format(self._truncation_notice)
break
list_of_strings.append(diff_string)
else:
list_of_strings = [format_diff(x) for x in iterator]
line_count = len(list_of_strings)

# Prepare count-of-differences string.
count_message = '{0} difference{1}'.format(
line_count,
'' if line_count == 1 else 's',
)

# Prepare description string.
if self._description:
description = '{0} ({1})'.format(self._description, count_message)
else:
description = count_message

# Prepare final output.
output = '{0}: {1}\n{2}\n{3}'.format(
description,
begin,
'\n'.join(list_of_strings),
end,
)
return output

def __repr__(self):
cls_name = self.__class__.__name__
if self.description:
return '{0}({1!r}, {2!r})'.format(cls_name, self.differences, self.description)
return '{0}({1!r})'.format(cls_name, self.differences)


def validate(data, requirement, msg=None):
"""Raise a :exc:`ValidationError` if *data* does not satisfy
*requirement* or pass without error if data is valid.
Expand Down

0 comments on commit d0d2887

Please sign in to comment.