@@ -20,3 +20,12 @@ jobs:
- name: Build image and run tests
run: docker/run-tests.sh
+
+ lint:
+ runs-on: ubuntu-latest
+ timeout-minutes: 10
+ steps:
+ - uses: actions/checkout@v5
+
+ - name: Ruff
+ run: pipx run ruff==0.17.0 check --output-format=github .
@@ -8,11 +8,9 @@
#
# Licensed under the MIT license, see COPYING.MIT for details
-import sys, os
from Post.models import Build, BuildFailure
from django.db.models import Count
-import re
-from datetime import datetime, timedelta
+from datetime import timedelta
from django import utils
class Statistics:
@@ -52,7 +50,7 @@ class Statistics:
elif string == "NATIVELSBSTRING":
errors = Build.objects.filter(DATE__range=[enddate, startdate]).values('NATIVELSBSTRING').annotate(dcount=Count('NATIVELSBSTRING')).order_by('-dcount')[:6]
items = list(errors)
- return items;
+ return items
elif string == "TARGET_SYS":
errors = Build.objects.filter(DATE__range=[enddate, startdate]).values('TARGET_SYS').annotate(dcount=Count('TARGET_SYS')).order_by('-dcount')[:6]
items = list(errors)
@@ -7,9 +7,7 @@
# Licensed under the MIT license, see COPYING.MIT for details
from django.db import models
-from django.db.models.signals import post_save
from django.conf import settings
-from datetime import datetime
import Levenshtein
@@ -117,7 +115,7 @@ class BuildFailure(models.Model):
recalc_lev_distance = kwargs.pop('recalc_lev_distance', False)
- if self.LEV_DISTANCE == None or recalc_lev_distance:
+ if self.LEV_DISTANCE is None or recalc_lev_distance:
self.LEV_DISTANCE = self.calc_lev_distance()
super(BuildFailure, self).save(*args, **kwargs)
@@ -8,7 +8,8 @@
#
# Licensed under the MIT license, see COPYING.MIT for details
-import json, re
+import json
+import re
import bleach
from Post.models import Build, BuildFailure, ErrorType
from Post.validators import clean_link_back
@@ -26,7 +27,7 @@ class Parser:
try:
jsondata = json.loads(self.data)
- except:
+ except Exception:
return { 'error' : 'Invalid json' }
# Bleach data going directly into the database so that
@@ -1,4 +1,4 @@
-from datetime import datetime, timedelta
+from datetime import timedelta
from django.utils import timezone
import os
import sys
@@ -1,8 +1,4 @@
-from datetime import datetime, timedelta
-import re
from django import template
-from django.utils import timezone
-from django.template.defaultfilters import filesizeformat
from Post.validators import clean_link_back
register = template.Library()
@@ -1,4 +1,6 @@
-import urllib.request, urllib.parse, urllib.error
+import urllib.request
+import urllib.parse
+import urllib.error
import json
from unittest.mock import patch
from django.core.management import call_command
@@ -389,6 +391,15 @@ class LinkBackSubmissionTest(TestCase):
+@override_settings(ALLOWED_HOSTS=["testhost"])
+class PaginationTest(TestCase):
+ def test_invalid_page_shows_last_page(self):
+ client = Client(HTTP_HOST="testhost")
+ for page in ("999", "abc"):
+ response = client.get("/Errors/Latest/", {"page": page})
+ self.assertEqual(response.status_code, 200)
+
+
@patch("Post.management.commands.culldb.time.sleep")
class CullDbTest(TestCase):
def setUp(self):
@@ -10,19 +10,17 @@
# vi: tabstop=8 expandtab shiftwidth=4 softtabstop=4
from __future__ import division
-from django.shortcuts import get_object_or_404
from django.shortcuts import HttpResponse, render
from django.views.decorators.csrf import csrf_exempt
from django.shortcuts import redirect
-from Post.models import BuildFailure, Build, ErrorType
+from Post.models import BuildFailure, ErrorType
from Post.parser import Parser
from django.conf import settings
from Post.createStatistics import Statistics
-from django.core.paginator import Paginator, EmptyPage
+from django.core.paginator import InvalidPage, Paginator
from django.core.exceptions import FieldError, ObjectDoesNotExist, RequestDataTooBig
from django.http import JsonResponse
from django.db.models import Q
-import json
import re
import urllib
from urllib.parse import urlparse
@@ -76,7 +74,7 @@ def addData(request, return_json=False):
if return_json:
response = JsonResponse(result)
else:
- if not 'error' in result:
+ if 'error' not in result:
response = HttpResponse("Your entry can be found here: "+result['build_url'])
else:
response = HttpResponse(result['error'])
@@ -252,7 +250,7 @@ def search(request, mode=results_mode.LATEST, **kwargs):
try:
build_failures = build_failures.page(page)
- except:
+ except InvalidPage:
build_failures = build_failures.page(build_failures.num_pages)
context['build_failures'] = build_failures
new file mode 100644
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: MIT
+
+[lint]
+# Ruff's classic defaults: bugs, not style.
+select = ["E4", "E7", "E9", "F"]
@@ -3,7 +3,9 @@
# test/example script for sending data to error-report-web
-import urllib.request, urllib.error, urllib.parse
+import urllib.request
+import urllib.error
+import urllib.parse
import sys
def send_data (url, data_file):
Pin ruff and select its classic rules, which find bugs; newer defaults are mostly style. Fix the findings. The paginator now catches InvalidPage, and the JSON parser Exception, so deeply nested JSON (RecursionError) is still reported as invalid. Test bad page numbers. AI-Generated: Claude Opus 5.5 Signed-off-by: Tim Orling <tim.orling@konsulko.com> --- .github/workflows/ci.yml | 9 +++++++++ Post/createStatistics.py | 6 ++---- Post/models.py | 4 +--- Post/parser.py | 5 +++-- Post/purge.py | 2 +- Post/templatetags/projecttags.py | 4 ---- Post/test.py | 13 ++++++++++++- Post/views.py | 10 ++++------ ruff.toml | 5 +++++ test-data/test-send-error.py | 4 +++- 10 files changed, 40 insertions(+), 22 deletions(-) create mode 100644 ruff.toml