diff --git a/setup.py b/setup.py
index 8de8422..62b35f8 100644
--- a/setup.py
+++ b/setup.py
@@ -4,7 +4,7 @@ import sys
 from setuptools import setup, find_packages
 from setuptools.command.test import test as TestCommand
 
-__version__ = '0.0.16'
+__version__ = '0.0.17'
 
 
 class PyTest(TestCommand):
diff --git a/tox.ini b/tox.ini
index 4b85cd7..80f6311 100644
--- a/tox.ini
+++ b/tox.ini
@@ -4,13 +4,29 @@
 # and then run "tox" from this directory.
 
 [tox]
-envlist = py27, py35
+envlist = begin,py{27,35,36},lint,end
+
+[testenv:py27]
+basepython = python2.7
+
+[testenv:py35]
+basepython = python3.5
+
+[testenv:py36]
+basepython = python3.6
+
+[testenv:lint]
+commands = flake8
 
 [testenv]
-commands = coverage erase
-           coverage run --source=vladiate setup.py test
-           coverage combine
-           coverage report --include=*
+commands = coverage run --source=vladiate setup.py test
 deps =
     pytest
     coverage
+    flake8
+
+[testenv:begin]
+commands = coverage erase
+
+[testenv:end]
+commands = coverage report -m --include=*
diff --git a/vladiate/validators.py b/vladiate/validators.py
index bbbb18c..a425c2c 100644
--- a/vladiate/validators.py
+++ b/vladiate/validators.py
@@ -185,16 +185,16 @@ class NotEmptyValidator(Validator):
 
     def __init__(self):
         self.fail_count = 0
+        self.failed = False
 
     def validate(self, field, row={}):
         if field == '':
+            self.failed = True
             raise ValidationException("Row has emtpy field in column")
 
     @property
     def bad(self):
-        # Return an empty set to conform to the protocol. The 'bad' fields
-        # would all be empty strings anyways
-        return set()
+        return self.failed
 
 
 class Ignore(Validator):
diff --git a/vladiate/vlad.py b/vladiate/vlad.py
index b0eb438..0233152 100644
--- a/vladiate/vlad.py
+++ b/vladiate/vlad.py
@@ -41,14 +41,24 @@ class Vlad(object):
                         "  {} failed {} time(s) ({:.1%}) on field: '{}'".format(
                             validator.__class__.__name__, validator.fail_count,
                             validator.fail_count / self.line_count, field_name))
-                    invalid = list(validator.bad)
-                    shown = ["'{}'".format(field) for field in invalid[:99]]
-                    hidden = ["'{}'".format(field) for field in invalid[99:]]
-                    self.logger.error(
-                        "    Invalid fields: [{}]".format(", ".join(shown)))
-                    if hidden:
+                    try:
+                        # If self.bad is iterable, it contains the fields which
+                        # caused it to fail
+                        invalid = list(validator.bad)
+                        shown = [
+                            "'{}'".format(field) for field in invalid[:99]
+                        ]
+                        hidden = [
+                            "'{}'".format(field)
+                            for field in invalid[99:]
+                        ]
                         self.logger.error(
-                            "    ({} more suppressed)".format(len(hidden)))
+                            "    Invalid fields: [{}]".format(", ".join(shown)))
+                        if hidden:
+                            self.logger.error(
+                                "    ({} more suppressed)".format(len(hidden)))
+                    except TypeError:
+                        pass
 
     def _log_missing_validators(self):
         self.logger.error("  Missing validators for:")

NotEmptyValidator minimal logging
NotEmptyValidator always returns an empty set for it's bad property regardless of failure causing the Vlad class to return False and log the general "Failed :(" message without an indication of the field that failed or the times it failed. Solution proposed below avoids repetition of empty strings in logger output while providing logging on par with the other Validators.

```python
class NotEmptyValidator(Validator):
    ''' Validates that a field is not empty '''

    def __init__(self):
        self.fail_count = 0
        self.empty = set([])

    def validate(self, field, row={}):
        if field == '':
            self.empty.add(field)
            raise ValidationException("Row has empty field in column")

    @property
    def bad(self):
        return self.empty
````

diff --git a/vladiate/test/test_validators.py b/vladiate/test/test_validators.py
index 66d431d..7b80686 100644
--- a/vladiate/test/test_validators.py
+++ b/vladiate/test/test_validators.py
@@ -196,7 +196,7 @@ def test_non_empty_validator_fails():
     with pytest.raises(ValidationException):
         validator.validate("")
 
-    assert validator.bad == set()
+    assert validator.bad is True
 
 
 def test_ignore_validator():
diff --git a/vladiate/test/test_vlads.py b/vladiate/test/test_vlads.py
index fd55f94..4b077ae 100644
--- a/vladiate/test/test_vlads.py
+++ b/vladiate/test/test_vlads.py
@@ -3,7 +3,8 @@ import pytest
 from ..vlad import Vlad
 from ..inputs import LocalFile, String
 from ..validators import (
-    EmptyValidator, FloatValidator, SetValidator, UniqueValidator
+    EmptyValidator, FloatValidator, NotEmptyValidator, SetValidator,
+    UniqueValidator,
 )
 
 
@@ -144,3 +145,21 @@ def test_ignore_missing_validators():
 
     assert vlad.validate()
     assert vlad.missing_validators == {'Column B'}
+
+
+def test_when_bad_is_non_iterable():
+    source = String('Column A,Column B\n,foo')
+
+    class TestVlad(Vlad):
+        validators = {
+            'Column A': [NotEmptyValidator()],
+            'Column B': [NotEmptyValidator()],
+        }
+
+    vlad = TestVlad(source=source)
+
+    assert not vlad.validate()
+    assert vlad.validators['Column A'][0].fail_count == 1
+    assert vlad.validators['Column A'][0].bad
+    assert vlad.validators['Column B'][0].fail_count == 0
+    assert not vlad.validators['Column B'][0].bad

pip install -e .[dev]
parse_log_pytest
requirements.txt
pretend pytest flake8
3.9
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
boto==2.49.0
exceptiongroup==1.2.2
flake8==7.2.0
iniconfig==2.1.0
mccabe==0.7.0
packaging==24.2
pluggy==1.5.0
pretend==1.0.9
pycodestyle==2.13.0
pyflakes==3.3.2
pytest==8.3.5
tomli==2.2.1
-e git+https://github.com/di/vladiate.git@577cfae7c7835e89e592af7cd024d6e9de084ed1#egg=vladiate

name: vladiate
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=3.0.16=h5eee18b_0
  - pip=25.0=py39h06a4308_0
  - python=3.9.21=he870216_1
  - readline=8.2=h5eee18b_0
  - setuptools=75.8.0=py39h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - tzdata=2025a=h04d1e81_0
  - wheel=0.45.1=py39h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - boto==2.49.0
      - exceptiongroup==1.2.2
      - flake8==7.2.0
      - iniconfig==2.1.0
      - mccabe==0.7.0
      - packaging==24.2
      - pluggy==1.5.0
      - pretend==1.0.9
      - pycodestyle==2.13.0
      - pyflakes==3.3.2
      - pytest==8.3.5
      - tomli==2.2.1
prefix: /opt/conda/envs/vladiate

vladiate/test/test_validators.py::test_non_empty_validator_fails vladiate/test/test_vlads.py::test_when_bad_is_non_iterable
vladiate/test/test_validators.py::test_cast_validator vladiate/test/test_validators.py::test_float_validator_works[42] vladiate/test/test_validators.py::test_float_validator_works[42.0] vladiate/test/test_validators.py::test_float_validator_works[-42.0] vladiate/test/test_validators.py::test_float_validator_fails[foo] vladiate/test/test_validators.py::test_float_validator_fails[ vladiate/test/test_validators.py::test_float_validator_fails[7..0] vladiate/test/test_validators.py::test_float_validator_fails[4,200] vladiate/test/test_validators.py::test_int_validator_works[42] vladiate/test/test_validators.py::test_int_validator_fails[foo] vladiate/test/test_validators.py::test_int_validator_fails[ vladiate/test/test_validators.py::test_int_validator_fails[7..0] vladiate/test/test_validators.py::test_int_validator_fails[4,200] vladiate/test/test_validators.py::test_int_validator_fails[42.0] vladiate/test/test_validators.py::test_int_validator_fails[-42.0] vladiate/test/test_validators.py::test_set_validator_works[field_set0-foo] vladiate/test/test_validators.py::test_set_validator_works[field_set1-foo] vladiate/test/test_validators.py::test_set_validator_empty_ok vladiate/test/test_validators.py::test_set_validator_fails[field_set0-bar] vladiate/test/test_validators.py::test_set_validator_fails[field_set1-bar] vladiate/test/test_validators.py::test_set_validator_fails[field_set2-baz] vladiate/test/test_validators.py::test_unique_validator_works[fields0-row0-unique_with0] vladiate/test/test_validators.py::test_unique_validator_works[fields1-row1-unique_with1] vladiate/test/test_validators.py::test_unique_validator_works[fields2-row2-unique_with2] vladiate/test/test_validators.py::test_unique_validator_works[fields3-row3-unique_with3] vladiate/test/test_validators.py::test_unique_validator_fails[fields0-row0-unique_with0-ValidationException-bad0] vladiate/test/test_validators.py::test_unique_validator_fails[fields1-row1-unique_with1-ValidationException-bad1] vladiate/test/test_validators.py::test_unique_validator_fails[fields2-row2-unique_with2-BadValidatorException-bad2] vladiate/test/test_validators.py::test_regex_validator_works[foo.*-foo] vladiate/test/test_validators.py::test_regex_validator_works[foo.*-foobar] vladiate/test/test_validators.py::test_regex_validator_allows_empty vladiate/test/test_validators.py::test_regex_validator_fails[foo.*-afoo] vladiate/test/test_validators.py::test_regex_validator_fails[^$-foo] vladiate/test/test_validators.py::test_range_validator_works vladiate/test/test_validators.py::test_range_validator_fails vladiate/test/test_validators.py::test_range_validator_handles_bad_values vladiate/test/test_validators.py::test_empty_validator_works vladiate/test/test_validators.py::test_empty_validator_fails vladiate/test/test_validators.py::test_non_empty_validator_works vladiate/test/test_validators.py::test_ignore_validator vladiate/test/test_validators.py::test_base_class_raises vladiate/test/test_vlads.py::test_initialize_vlad vladiate/test/test_vlads.py::test_initialize_vlad_with_alternative_delimiter vladiate/test/test_vlads.py::test_initialize_vlad_no_source vladiate/test/test_vlads.py::test_unused_validator_fails_validation vladiate/test/test_vlads.py::test_validators_in_class_variable_are_used vladiate/test/test_vlads.py::test_missing_validators vladiate/test/test_vlads.py::test_no_fieldnames vladiate/test/test_vlads.py::test_fails_validation vladiate/test/test_vlads.py::test_gt_99_failures vladiate/test/test_vlads.py::test_ignore_missing_validators
setup.py vladiate/validators.py tox.ini vladiate/vlad.py
setup.py vladiate/validators.py tox.ini vladiate/vlad.py