Skip to content

Commit 549c0f7

Browse files
authored
Fix coverage count of safelisted Django models (#12)
Also adds a comment to the top of the safelist to clarify that annotations need to be added and highlights that fact in the seed safelist command.
1 parent 168cea7 commit 549c0f7

File tree

5 files changed

+54
-26
lines changed

5 files changed

+54
-26
lines changed

code_annotations/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,4 @@
44

55
from __future__ import absolute_import, unicode_literals
66

7-
__version__ = '0.2.0'
7+
__version__ = '0.2.1'

code_annotations/base.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -220,8 +220,8 @@ def _plugin_load_failed_handler(self, *args, **kwargs):
220220
Raises:
221221
ConfigurationException
222222
"""
223-
self.echo(args)
224-
self.echo(kwargs)
223+
self.echo(str(args), fg='red')
224+
self.echo(str(kwargs), fg='red')
225225
raise ConfigurationException('Failed to load a plugin, aborting.')
226226

227227
def _configure_extensions(self):

code_annotations/find_django.py

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -63,12 +63,24 @@ def seed_safelist(self):
6363
safelist_data = {self.get_model_id(model): {} for model in self.non_local_models}
6464

6565
with open(self.config.safelist_path, 'w') as safelist_file:
66-
yaml_ordered_dump(safelist_data, stream=safelist_file)
67-
68-
self.echo('Successfully created safelist file "{}".'.format(self.config.safelist_path))
69-
self.echo('Now, you need to:')
70-
self.echo(' 1) Make sure that any un-annotated models in the safelist are annotated, and')
71-
self.echo(' 2) Annotate any LOCAL models (see --list_local_models).')
66+
safelist_comment = """
67+
# This is a Code Annotations automatically-generated Django model safelist file.
68+
# These models must be annotated as follows in order to be counted in the coverage report.
69+
# See https://code-annotations.readthedocs.io/en/latest/safelist.html for more information.
70+
#
71+
# fake_app_1.FakeModelName:
72+
# ".. no_pii::": "This model has no PII"
73+
# fake_app_2.FakeModel2:
74+
# ".. choice_annotation::": foo, bar, baz
75+
76+
"""
77+
safelist_file.write(safelist_comment.strip())
78+
yaml_ordered_dump(safelist_data, stream=safelist_file, default_flow_style=False)
79+
80+
self.echo('Successfully created safelist file "{}".'.format(self.config.safelist_path), fg='red')
81+
self.echo('Now, you need to:', fg='red')
82+
self.echo(' 1) Make sure that any un-annotated models in the safelist are annotated, and', fg='red')
83+
self.echo(' 2) Annotate any LOCAL models (see --list_local_models).', fg='red')
7284

7385
def list_local_models(self):
7486
"""
@@ -228,6 +240,8 @@ def search(self):
228240
self.uncovered_model_ids.add(model_id)
229241
self.echo.echo_vv(" {} is in the safelist.".format(model_id))
230242
self._add_error("{} is in the safelist but has no annotations!".format(model_id))
243+
else:
244+
self._increment_count('annotated')
231245

232246
self._append_safelisted_model_annotations(safelisted_models, model_id, model_annotations)
233247
self.format_file_results(annotated_models, [model_annotations])

code_annotations/helpers.py

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -97,67 +97,70 @@ class VerboseEcho(object):
9797

9898
verbosity = 1
9999

100-
def __call__(self, output):
100+
def __call__(self, output, **kwargs):
101101
"""
102102
Echo the given output regardless of verbosity level.
103103
104104
This is just a convenience method to avoid lots of `self.echo.echo()`.
105105
106106
Args:
107107
output: Text to output
108+
kwargs: Any additional keyword args to pass to click.echo
108109
"""
109-
self.echo(output)
110+
self.echo(output, **kwargs)
110111

111112
def set_verbosity(self, verbosity):
112113
"""
113114
Override the default verbosity level.
114115
115116
Args:
116117
verbosity: The verbosity level to set to
117-
118-
Returns:
119-
None
118+
kwargs: Any additional keyword args to pass to click.echo
120119
"""
121120
self.verbosity = verbosity
122121
self.echo_v("Verbosity level set to {}".format(verbosity))
123122

124-
def echo(self, output, verbosity_level=0):
123+
def echo(self, output, verbosity_level=0, **kwargs):
125124
"""
126125
Echo the given output, if over the verbosity threshold.
127126
128127
Args:
129128
output: Text to output
130129
verbosity_level: Only output if our verbosity level is >= this.
130+
kwargs: Any additional keyword args to pass to click.echo
131131
"""
132132
if verbosity_level <= self.verbosity:
133-
click.echo(output)
133+
click.secho(output, **kwargs)
134134

135-
def echo_v(self, output):
135+
def echo_v(self, output, **kwargs):
136136
"""
137137
Echo the given output if verbosity level is >= 1.
138138
139139
Args:
140140
output: Text to output
141+
kwargs: Any additional keyword args to pass to click.echo
141142
"""
142-
self.echo(output, 1)
143+
self.echo(output, 1, **kwargs)
143144

144-
def echo_vv(self, output):
145+
def echo_vv(self, output, **kwargs):
145146
"""
146147
Echo the given output if verbosity level is >= 2.
147148
148149
Args:
149150
output: Text to output
151+
kwargs: Any additional keyword args to pass to click.echo
150152
"""
151-
self.echo(output, 2)
153+
self.echo(output, 2, **kwargs)
152154

153-
def echo_vvv(self, output):
155+
def echo_vvv(self, output, **kwargs):
154156
"""
155157
Echo the given output if verbosity level is >= 3.
156158
157159
Args:
158160
output: Text to output
161+
kwargs: Any additional keyword args to pass to click.echo
159162
"""
160-
self.echo(output, 3)
163+
self.echo(output, 3, **kwargs)
161164

162165

163166
def clean_abs_path(filename_to_clean, parent_path):

tests/test_find_django.py

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,12 @@ def test_find_django_simple_success(**kwargs):
3232
"""
3333
Tests the basic case where all models have annotations, with an empty safelist.
3434
"""
35-
test_models = {FakeChildModelSingleAnnotation, FakeChildModelMultiAnnotation, FakeChildModelSingleWithAnnotation}
35+
test_models = {
36+
FakeChildModelSingleAnnotation,
37+
FakeChildModelMultiAnnotation,
38+
FakeChildModelSingleWithAnnotation,
39+
FakeBaseModelWithNoDocstring
40+
}
3641
mock_get_models_requiring_annotations = kwargs['get_models_requiring_annotations']
3742
mock_get_models_requiring_annotations.return_value = (
3843
test_models,
@@ -54,15 +59,21 @@ def report_callback(report_contents):
5459
for model in test_models:
5560
assert 'object_id: {}'.format(DjangoSearch.get_model_id(model)) in report_contents
5661

62+
fake_safelist = """
63+
fake_app_2.FakeBaseModelWithNoDocstring:
64+
".. no_pii::": "No PII"
65+
"""
66+
5767
result = call_script_isolated(
58-
['django_find_annotations', '--config_file', 'test_config.yml', '--lint', '--report', '--coverage'],
59-
test_filesystem_report_cb=report_callback
68+
['django_find_annotations', '--config_file', 'test_config.yml', '--lint', '--report', '--coverage', '-vvv'],
69+
test_filesystem_report_cb=report_callback,
70+
fake_safelist_data=fake_safelist
6071
)
6172

6273
assert result.exit_code == EXIT_CODE_SUCCESS
6374
assert 'Linting passed without errors' in result.output
6475
assert 'Generating report to' in result.output
65-
assert 'Search found 5 annotations' in result.output
76+
assert 'Search found 6 annotations' in result.output
6677

6778

6879
@patch.multiple(

0 commit comments

Comments
 (0)