Skip to content

Commit eb0c9c2

Browse files
authored
Enable quality checks (#449)
* fix: enable quality checks
1 parent 30c4ede commit eb0c9c2

27 files changed

+304
-105
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ jobs:
1414
fail-fast: false
1515
matrix:
1616
python-version: ["3.11", "3.12"]
17-
toxenv: ["django42"] # "quality", "pii_check", "check_keywords"
17+
toxenv: ["django42", "quality", "pii_check", "check_keywords"]
1818

1919
services:
2020
mysql:

.github/workflows/trivy-code-scanning.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ jobs:
2323
scan-type: "fs"
2424
format: "sarif"
2525
output: "trivy-results.sarif"
26+
args: --skip-update
2627

2728
- name: Upload Trivy scan results to GitHub Security tab
2829
uses: github/codeql-action/upload-sarif@v3

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ venv/
1717

1818
.idea/
1919

20-
2120
# Helm dependencies
2221
/helmcharts/**/*.tgz
22+
23+
reports/

.pycodestyle

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
[pycodestyle]
2+
exclude = .git, .tox, migrations
3+
ignore = E731
4+
max-line-length = 120

notesapi/v1/management/commands/bulk_create_notes.py

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,45 +3,47 @@
33
import os
44
import random
55
import uuid
6-
from optparse import make_option
76

87
from django.core.management.base import BaseCommand, CommandError
9-
from django.db import transaction
108

119
from notesapi.v1.models import Note
1210

1311

14-
def extract_comma_separated_list(option, opt_str, value, parser):
12+
def extract_comma_separated_list(option, value, parser):
1513
"""Parse an option string as a comma separated list"""
1614
setattr(parser.values, option.dest, [course_id.strip() for course_id in value.split(',')])
1715

1816

1917
class Command(BaseCommand):
2018
args = '<total_notes>'
19+
2120
def add_arguments(self, parser):
2221
parser.add_argument(
23-
'--per_user',
22+
'--per_user',
2423
action='store',
25-
type='int',
24+
type=int,
2625
default=50,
2726
help='number of notes that should be attributed to each user (default 50)'
28-
),
27+
)
28+
2929
parser.add_argument(
3030
'--course_ids',
3131
action='callback',
3232
callback=extract_comma_separated_list,
33-
type='string',
33+
type=str,
3434
default=['edX/DemoX/Demo_Course'],
3535
help='comma-separated list of course_ids for which notes should be randomly attributed'
36-
),
36+
)
37+
3738
parser.add_argument(
3839
'--batch_size',
3940
action='store',
40-
type='int',
41+
type=int,
4142
default=1000,
4243
help='number of notes that should be bulk inserted at a time - useful for getting around the maximum SQL '
4344
'query size'
4445
)
46+
4547
help = 'Add N random notes to the database'
4648

4749
def handle(self, *args, **options):
@@ -58,6 +60,7 @@ def handle(self, *args, **options):
5860
for notes_chunk in grouper_it(note_iter(total_notes, notes_per_user, course_ids), batch_size):
5961
Note.objects.bulk_create(notes_chunk)
6062

63+
6164
def note_iter(total_notes, notes_per_user, course_ids):
6265
"""
6366
Return an iterable of random notes data of length `total_notes`.
@@ -85,7 +88,9 @@ def weighted_get_words(weighted_num_words):
8588
random.choice([word_count for word_count, weight in weighted_num_words for i in range(weight)])
8689
)
8790

88-
get_new_user_id = lambda: uuid.uuid4().hex
91+
def get_new_user_id():
92+
return uuid.uuid4().hex
93+
8994
user_id = get_new_user_id()
9095

9196
for note_count in range(total_notes):
@@ -108,7 +113,6 @@ def grouper_it(iterable, batch_size):
108113
Return an iterator of iterators. Each child iterator yields the
109114
next `batch_size`-many elements from `iterable`.
110115
"""
111-
iterator = iter(iterable)
112116
while True:
113117
chunk_it = itertools.islice(iterable, batch_size)
114118
try:

notesapi/v1/models.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,13 @@ def create(cls, note_dict):
3333
if len(note_dict) == 0:
3434
raise ValidationError('Note must have a body.')
3535

36-
ranges = note_dict.get('ranges', list())
36+
ranges = note_dict.get('ranges', [])
3737

3838
if len(ranges) < 1:
3939
raise ValidationError('Note must contain at least one range.')
4040

4141
note_dict['ranges'] = json.dumps(ranges)
4242
note_dict['user_id'] = note_dict.pop('user', None)
43-
note_dict['tags'] = json.dumps(note_dict.get('tags', list()), ensure_ascii=False)
43+
note_dict['tags'] = json.dumps(note_dict.get('tags', []), ensure_ascii=False)
4444

4545
return cls(**note_dict)

notesapi/v1/search_indexes/backends/note.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
__all__ = ('CompoundSearchFilterBackend', 'FilteringFilterBackend')
1010

1111

12+
# pylint: disable=abstract-method
1213
class CompoundSearchFilterBackend(CompoundSearchFilterBackendOrigin):
1314
"""
1415
Extends compound search backend.

notesapi/v1/search_indexes/serializers/note.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,6 @@ def get_tags(self, note):
5454
Return note tags.
5555
"""
5656
if hasattr(note.meta, 'highlight') and hasattr(note.meta.highlight, 'tags'):
57-
return [i for i in note.meta.highlight.tags]
57+
return list(note.meta.highlight.tags)
5858

59-
return [i for i in note.tags] if note.tags else []
59+
return list(note.tags) if note.tags else []

notesapi/v1/tests/test_update_index.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
from unittest import skipIf
22

3+
import factory
34
from django.conf import settings
45
from django.core.management import call_command
5-
from django.urls import reverse
66
from django.db.models import signals
7-
import factory
7+
from django.urls import reverse
88

99
from .test_views import BaseAnnotationViewTests
1010

@@ -51,7 +51,7 @@ def test_delete(self):
5151

5252
# Delete first note.
5353
url = reverse('api:v1:annotations_detail', kwargs={'annotation_id': first_note['id']})
54-
response = self.client.delete(url, self.headers)
54+
response = self.client.delete(url, self.headers) # pylint: disable=unused-variable
5555

5656
# Delete second note.
5757
url = reverse('api:v1:annotations_detail', kwargs={'annotation_id': second_note['id']})

notesapi/v1/tests/test_views.py

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,15 @@
1-
import sys
21
import unittest
32
from calendar import timegm
43
from datetime import datetime, timedelta
4+
from unittest.mock import patch
55
from urllib import parse
66

7+
import ddt
8+
import jwt
79
from django.conf import settings
810
from django.core.management import call_command
911
from django.test.utils import override_settings
1012
from django.urls import reverse
11-
from unittest.mock import patch
12-
13-
import ddt
14-
import jwt
1513
from rest_framework import status
1614
from rest_framework.test import APITestCase
1715

@@ -21,9 +19,9 @@
2119
TEST_OTHER_USER = "test_other_user_id"
2220

2321
if not settings.ES_DISABLED:
24-
from notesapi.v1.search_indexes.documents import NoteDocument
22+
from notesapi.v1.search_indexes.documents import NoteDocument # pylint: disable=unused-import
2523
else:
26-
def call_command(*args, **kwargs):
24+
def call_command(*args, **kwargs): # pylint: disable=function-redefined
2725
pass
2826

2927

@@ -111,7 +109,7 @@ def get_annotations(self, query_parameters=None, expected_status=200):
111109
self.assertEqual(expected_status, response.status_code)
112110
return response.data
113111

114-
# pylint: disable=too-many-arguments
112+
# pylint: disable=too-many-positional-arguments
115113
def verify_pagination_info(
116114
self, response,
117115
total_annotations,
@@ -161,7 +159,7 @@ def get_page_value(url, current_page):
161159
self.assertEqual(get_page_value(response['next'], response['current_page']), next_page)
162160
self.assertEqual(response['start'], start)
163161

164-
# pylint: disable=too-many-arguments
162+
# pylint: disable=too-many-positional-arguments
165163
def verify_list_view_pagination(
166164
self,
167165
query_parameters,
@@ -176,7 +174,6 @@ def verify_list_view_pagination(
176174
"""
177175
Verify pagination information for AnnotationListView
178176
"""
179-
total_annotations = total_annotations
180177
for i in range(total_annotations):
181178
self._create_annotation(text=f'annotation {i}')
182179

@@ -192,7 +189,7 @@ def verify_list_view_pagination(
192189
start=start
193190
)
194191

195-
# pylint: disable=too-many-arguments
192+
# pylint: disable=too-many-positional-arguments
196193
def verify_search_view_pagination(
197194
self,
198195
query_parameters,
@@ -207,7 +204,6 @@ def verify_search_view_pagination(
207204
"""
208205
Verify pagination information for AnnotationSearchView
209206
"""
210-
total_annotations = total_annotations
211207
for i in range(total_annotations):
212208
self._create_annotation(text=f'annotation {i}')
213209

@@ -370,15 +366,15 @@ def test_create_maximum_allowed(self):
370366
# if user tries to create note in a different course it should succeed
371367
kwargs = {'course_id': 'test-course-id-2'}
372368
response = self._create_annotation(**kwargs)
373-
self.assertTrue('id' in response)
369+
self.assertIn('id', response)
374370

375371
# if another user to tries to create note in first course it should succeed
376372
token = get_id_token(TEST_OTHER_USER)
377373
self.client.credentials(HTTP_X_ANNOTATOR_AUTH_TOKEN=token)
378374
self.headers = {'user': TEST_OTHER_USER}
379375
kwargs = {'user': TEST_OTHER_USER}
380376
response = self._create_annotation(**kwargs)
381-
self.assertTrue('id' in response)
377+
self.assertIn('id', response)
382378

383379
def test_read_all_no_annotations(self):
384380
"""
@@ -437,7 +433,7 @@ def test_read_all_no_query_param(self):
437433
{'page': 2, 'annotations_per_page': 10, 'previous_page': 1, 'next_page': 3, 'start': 10},
438434
{'page': 3, 'annotations_per_page': 3, 'previous_page': 2, 'next_page': None, 'start': 20}
439435
)
440-
# pylint: disable=too-many-arguments
436+
# pylint: disable=too-many-positional-arguments
441437
def test_pagination_multiple_pages(self, page, annotations_per_page, previous_page, next_page, start):
442438
"""
443439
Verify that pagination info is correct when we have data spanned on multiple pages.
@@ -1081,7 +1077,7 @@ def test_search_highlight_tag(self):
10811077
{'page': 2, 'annotations_per_page': 10, 'previous_page': 1, 'next_page': 3, 'start': 10},
10821078
{'page': 3, 'annotations_per_page': 3, 'previous_page': 2, 'next_page': None, 'start': 20}
10831079
)
1084-
# pylint: disable=too-many-arguments
1080+
# pylint: disable=too-many-positional-arguments
10851081
def test_pagination_multiple_pages(self, page, annotations_per_page, previous_page, next_page, start):
10861082
"""
10871083
Verify that pagination info is correct when we have data spanned on multiple pages.
@@ -1221,7 +1217,7 @@ def test_no_token(self):
12211217
"""
12221218
403 when no token is provided
12231219
"""
1224-
self.client._credentials = {}
1220+
self.client._credentials = {} # pylint: disable=protected-access
12251221
response = self.client.get(self.url, self.headers)
12261222
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
12271223

0 commit comments

Comments
 (0)