Skip to content

Commit ca004a9

Browse files
timobrembeckclaudep
authored andcommitted
Move coverage view to management command
1 parent 905ab74 commit ca004a9

File tree

11 files changed

+163
-128
lines changed

11 files changed

+163
-128
lines changed

CHANGELOG

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
Unreleased
22

3+
* Move coverage view to management command (Timo Brembeck, #187)
4+
* Add new management command `linkcheck_suggest_config`
5+
* Delete coverage view
36
* Improve formatting for `NameResolutionError` (Timo Brembeck, #192)
47
* Fix internal redirect checker (Timo Ludwig, #180)
58
* Fix SSL status of unreachable domains (Timo Ludwig, #184)

README.rst

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@ Basic usage
4444
#) can be the target of a link - i.e. is addressed by a url - in this case
4545
make sure it has an instance method named 'get_absolute_url'
4646

47+
*Hint:* You can create a sample config for your model with::
48+
49+
manage.py linkcheck_suggest_config --model sampleapp.SampleModel > sampleapp/linklists.py
50+
4751
#. Run ``./manage.py migrate``.
4852

4953
#. Add to your root url config::
@@ -116,6 +120,15 @@ interval can be adapted per-invocation by using the ``--externalinterval``
116120
You can also limit the maximum number of links to be checked by passing a number
117121
to the ``--limit`` (``--l``) command option.
118122

123+
linkcheck_suggest_config
124+
~~~~~~~~~~~~~~~~~~~~~~~~
125+
126+
This command goes through all models and checks whether they contain fields that
127+
can potentially be checked by linkcheck.
128+
If they are not yet registered, a sample config is suggested.
129+
130+
You can also pass the option ``--model`` to generate a sample config for the given model.
131+
119132
Settings
120133
--------
121134

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
from django.apps import apps
2+
from django.core.management.base import BaseCommand, CommandError
3+
from django.utils.termcolors import make_style
4+
5+
from linkcheck.utils import get_coverage_data, get_suggested_linklist_config
6+
7+
8+
class Command(BaseCommand):
9+
10+
cyan = staticmethod(make_style(fg='cyan'))
11+
12+
help = 'Go through all models and check whether they are registered with linkcheck'
13+
14+
def add_arguments(self, parser):
15+
parser.add_argument(
16+
'--model',
17+
help="Generate the suggested config for this model",
18+
)
19+
20+
def handle(self, *args, model, **options):
21+
if model:
22+
try:
23+
model_class = apps.get_model(model)
24+
except Exception as e:
25+
raise CommandError(
26+
f'Model "{model}" does not exist.'
27+
) from e
28+
self.stdout.write(get_suggested_linklist_config(model_class))
29+
else:
30+
covered, uncovered = get_coverage_data()
31+
self.stdout.write('All covered models:\n')
32+
self.stdout.write(', '.join(map(self.cyan, covered)))
33+
for model, suggested_config in uncovered:
34+
self.stdout.write(f'\nSuggested config for model {model}:')
35+
self.stdout.write(self.cyan(suggested_config))

linkcheck/templates/linkcheck/coverage.html

Lines changed: 0 additions & 40 deletions
This file was deleted.

linkcheck/templates/linkcheck/suggested_configs.html

Lines changed: 0 additions & 3 deletions
This file was deleted.

linkcheck/templates/linkcheck/suggested_linklist.html

Lines changed: 0 additions & 14 deletions
This file was deleted.

linkcheck/templatetags/linkcheck_coverage_tags.py

Lines changed: 0 additions & 17 deletions
This file was deleted.

linkcheck/tests/sampleapp/models.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,11 @@ class Journal(models.Model):
2626
title = models.CharField(max_length=50)
2727
description = models.TextField()
2828
version = models.PositiveIntegerField(default=0)
29+
30+
31+
class UncoveredModel(models.Model):
32+
book = models.ForeignKey(Book, on_delete=models.CASCADE)
33+
website = models.URLField(blank=True)
34+
35+
def get_absolute_url(self):
36+
return f'/uncovered/{self.id}'

linkcheck/tests/test_linkcheck.py

Lines changed: 58 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from django.conf import settings
88
from django.contrib.auth.models import User
99
from django.core.management import call_command
10+
from django.core.management.base import CommandError
1011
from django.test import LiveServerTestCase, TestCase
1112
from django.test.utils import override_settings
1213
from django.urls import reverse
@@ -924,6 +925,52 @@ def test_findlinks_command(self):
924925
)
925926

926927

928+
class ManagementCommandTestCase(TestCase):
929+
930+
def test_linkcheck_suggest_config(self):
931+
"""
932+
Test that the config of uncovered models is correctly suggested
933+
"""
934+
out, err = get_command_output('linkcheck_suggest_config')
935+
self.assertEqual(
936+
out,
937+
'All covered models:\n'
938+
'\x1b[36msampleapp.Book\x1b[0m, \x1b[36msampleapp.Page\x1b[0m\n\n'
939+
'Suggested config for model sampleapp.UncoveredModel:\n'
940+
'\x1b[36mfrom sampleapp.models import UncoveredModel\n\n'
941+
'class UncoveredModelLinklist(Linklist):\n'
942+
' model = UncoveredModel\n\n'
943+
'linklists = {\n'
944+
' "UncoveredModel": UncoveredModelLinklist,\n'
945+
'}\n\x1b[0m\n'
946+
)
947+
self.assertEqual(err, '')
948+
949+
def test_linkcheck_suggest_config_model(self):
950+
"""
951+
Test that the config of given model is correctly printed
952+
"""
953+
out, err = get_command_output('linkcheck_suggest_config', '--model', 'sampleapp.Author')
954+
self.assertEqual(
955+
out,
956+
'from sampleapp.models import Author\n\n'
957+
'class AuthorLinklist(Linklist):\n'
958+
' model = Author\n\n'
959+
'linklists = {\n'
960+
' "Author": AuthorLinklist,\n'
961+
'}\n'
962+
)
963+
self.assertEqual(err, '')
964+
965+
def test_linkcheck_suggest_config_model_non_existing(self):
966+
"""
967+
Test that the command raises an error when the model does not exist
968+
"""
969+
with self.assertRaises(CommandError) as cm:
970+
get_command_output('linkcheck_suggest_config', '--model', 'non-existing')
971+
self.assertEqual(str(cm.exception), 'Model "non-existing" does not exist.')
972+
973+
927974
class ObjectsUpdateTestCase(TestCase):
928975
def test_update_object(self):
929976
"""
@@ -1068,17 +1115,6 @@ def test_report_recheck(self):
10681115
'message': '404 Not Found',
10691116
})
10701117

1071-
def test_coverage_view(self):
1072-
self.client.force_login(self.user)
1073-
response = self.client.get(reverse('linkcheck_coverage'))
1074-
self.assertContains(
1075-
response,
1076-
'<tr><td>sampleapp.Book</td>'
1077-
'<td style="font-weight: bold;color:green;">Yes</td>'
1078-
'<td style="font-weight: bold;color:green;"></td></tr>',
1079-
html=True,
1080-
)
1081-
10821118

10831119
class GetJqueryMinJsTestCase(TestCase):
10841120
def test(self):
@@ -1115,10 +1151,18 @@ def test_filter_callable(self):
11151151
)
11161152

11171153

1154+
def get_command_output(command, *args, **kwargs):
1155+
"""
1156+
Helper function for running a management command and checking its output
1157+
"""
1158+
out = StringIO()
1159+
err = StringIO()
1160+
call_command(command, *args, stdout=out, stderr=err, **kwargs)
1161+
return out.getvalue(), err.getvalue()
1162+
1163+
11181164
def findlinks():
11191165
"""
11201166
Helper function for running the findlinks command and checking its output
11211167
"""
1122-
out = StringIO()
1123-
call_command('findlinks', stdout=out)
1124-
return out.getvalue()
1168+
return get_command_output('findlinks')[0]

linkcheck/urls.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,5 @@
33
from . import views
44

55
urlpatterns = [
6-
path('coverage/', views.coverage, name='linkcheck_coverage'),
76
path('', views.report, name='linkcheck_report'),
87
]

0 commit comments

Comments
 (0)