Skip to content

Commit 123dc64

Browse files
hugsyhugsy
andauthored
Apply pylint fixes everywhere (#97)
* modernize pylint settings * pylinting everything, now scoring 9.9 * removed all comments in .pylintrc * in helpers, make hedgedoc.logout follow redirection * in helpers, if hedgedoc.logout got http/ok assume the session was deleted remotely, delete it locally --------- Co-authored-by: hugsy <[email protected]>
1 parent 150ff3d commit 123dc64

26 files changed

+596
-324
lines changed

.github/workflows/test.yml

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -44,18 +44,23 @@ jobs:
4444

4545
- name: Setup environment vars
4646
run: |
47-
echo CTFHUB_PROTOCOL=http >> $GITHUB_ENV
48-
echo CTFHUB_DOMAIN=localhost >> $GITHUB_ENV
49-
echo CTFHUB_PORT=8000 >> $GITHUB_ENV
50-
echo CTFHUB_DB_NAME=ctfhub >> $GITHUB_ENV
51-
echo CTFHUB_DB_USER=ctfhub >> $GITHUB_ENV
52-
echo CTFHUB_DB_PASSWORD=ctfhub >> $GITHUB_ENV
53-
echo CTFHUB_DB_HOST=localhost >> $GITHUB_ENV
54-
echo CTFHUB_DB_PORT=5432 >> $GITHUB_ENV
55-
echo CTFHUB_HEDGEDOC_PRIVATE_URL=http://localhost:3000 >> $GITHUB_ENV
56-
echo CTFHUB_HEDGEDOC_PUBLIC_URL=http://localhost:3000 >> $GITHUB_ENV
57-
echo CTFHUB_ALLOWED_HOSTS="localhost;127.0.0.1" >> $GITHUB_ENV
58-
echo CTFHUB_TRUSTED_ORIGINS="http://127.0.0.1;http://localhost" >> $GITHUB_ENV
47+
echo 127.0.1.1 hedgedoc | sudo tee -a /etc/hosts
48+
49+
echo CTFHUB_PROTOCOL="http" >> ${GITHUB_ENV}
50+
echo CTFHUB_DOMAIN="localhost" >> ${GITHUB_ENV}
51+
echo CTFHUB_PORT="8000" >> ${GITHUB_ENV}
52+
echo CTFHUB_DB_NAME="ctfhub" >> ${GITHUB_ENV}
53+
echo CTFHUB_DB_USER="ctfhub" >> ${GITHUB_ENV}
54+
echo CTFHUB_DB_PASSWORD="ctfhub" >> ${GITHUB_ENV}
55+
echo CTFHUB_DB_HOST="localhost" >> ${GITHUB_ENV}
56+
echo CTFHUB_DB_PORT="5432" >> ${GITHUB_ENV}
57+
echo CTFHUB_HEDGEDOC_USESSL="false" >> ${GITHUB_ENV}
58+
echo CTFHUB_HEDGEDOC_DOMAIN="hedgedoc" >> ${GITHUB_ENV}
59+
echo CTFHUB_HEDGEDOC_PORT="3000" >> ${GITHUB_ENV}
60+
echo CTFHUB_HEDGEDOC_URL="http://hedgedoc:3000" >> ${GITHUB_ENV}
61+
echo CTFHUB_ALLOWED_HOSTS="localhost;127.0.0.1" >> ${GITHUB_ENV}
62+
echo CTFHUB_TRUSTED_ORIGINS="http://127.0.0.1;http://localhost" >> ${GITHUB_ENV}
63+
5964
- name: Setup Python
6065
uses: actions/setup-python@v4
6166
with:

.pylintrc

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
[MASTER]
2+
extension-pkg-allow-list=
3+
extension-pkg-whitelist=
4+
fail-on=
5+
fail-under=10.0
6+
ignore=CVS
7+
ignore-paths=ctfhub/tests/
8+
ignore-patterns=test_.*\.py
9+
jobs=0
10+
limit-inference-results=100
11+
load-plugins= pylint_django
12+
persistent=yes
13+
py-version=3.10
14+
suggestion-mode=yes
15+
unsafe-load-any-extension=no
16+
17+
[MESSAGES CONTROL]
18+
confidence=
19+
enable = all
20+
disable = missing-class-docstring,
21+
missing-function-docstring,
22+
missing-module-docstring,
23+
suppressed-message,
24+
locally-disabled,
25+
useless-return
26+
27+
[REPORTS]
28+
evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
29+
output-format=text
30+
reports=no
31+
score=yes
32+
33+
[REFACTORING]
34+
max-nested-blocks=5
35+
never-returning-functions=sys.exit,argparse.parse_error
36+
37+
[FORMAT]
38+
expected-line-ending-format=LF
39+
ignore-long-lines=^\s*(# )?<?https?://\S+>?$
40+
indent-after-paren=4
41+
indent-string=' '
42+
max-line-length=200
43+
max-module-lines=15000
44+
single-line-class-stmt=no
45+
single-line-if-stmt=no
46+
47+
[SPELLING]
48+
max-spelling-suggestions=4
49+
spelling-dict=
50+
spelling-ignore-comment-directives=fmt: on,fmt: off,noqa:,noqa,nosec,isort:skip,mypy:
51+
spelling-ignore-words=
52+
spelling-private-dict-file=
53+
spelling-store-unknown-words=no
54+
55+
[LOGGING]
56+
logging-format-style=new
57+
logging-modules=logging
58+
59+
[VARIABLES]
60+
additional-builtins=
61+
allow-global-unused-variables=yes
62+
allowed-redefined-builtins=
63+
callbacks=cb_,
64+
_cb
65+
dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_
66+
ignored-argument-names=_.*|^ignored_|^unused_
67+
init-import=no
68+
redefining-builtins-modules=six.moves,past.builtins,future.builtins,builtins,io
69+
70+
[SIMILARITIES]
71+
ignore-comments=yes
72+
ignore-docstrings=yes
73+
ignore-imports=no
74+
ignore-signatures=no
75+
min-similarity-lines=4
76+
77+
[MISCELLANEOUS]
78+
notes=FIXME,
79+
XXX,
80+
TODO
81+
82+
[BASIC]
83+
argument-naming-style=snake_case
84+
attr-naming-style=snake_case
85+
bad-names=foo,
86+
bar,
87+
baz,
88+
toto,
89+
tutu,
90+
tata
91+
bad-names-rgxs=
92+
class-attribute-naming-style=any
93+
class-const-naming-style=UPPER_CASE
94+
class-naming-style=PascalCase
95+
const-naming-style=UPPER_CASE
96+
docstring-min-length=-1
97+
function-naming-style=snake_case
98+
good-names=i,
99+
j,
100+
k,
101+
ex,
102+
Run,
103+
fd,
104+
id,
105+
pk,
106+
_
107+
good-names-rgxs=
108+
include-naming-hint=no
109+
inlinevar-naming-style=any
110+
method-naming-style=snake_case
111+
module-naming-style=snake_case
112+
name-group=
113+
no-docstring-rgx=^_
114+
property-classes=abc.abstractproperty
115+
variable-naming-style=snake_case
116+
117+
[STRING]
118+
check-quote-consistency=no
119+
check-str-concat-over-line-jumps=no
120+
121+
[TYPECHECK]
122+
contextmanager-decorators=contextlib.contextmanager
123+
generated-members=
124+
ignore-mixin-members=yes
125+
ignore-none=yes
126+
ignore-on-opaque-inference=yes
127+
ignored-classes=optparse.Values,thread._local,_thread._local
128+
ignored-modules=
129+
missing-member-hint=yes
130+
missing-member-hint-distance=1
131+
missing-member-max-choices=1
132+
mixin-class-rgx=.*[Mm]ixin
133+
signature-mutators=
134+
135+
[IMPORTS]
136+
allow-any-import-level=
137+
allow-wildcard-with-all=no
138+
analyse-fallback-blocks=no
139+
deprecated-modules=
140+
ext-import-graph=
141+
import-graph=
142+
int-import-graph=
143+
known-standard-library=
144+
known-third-party=enchant
145+
preferred-modules=
146+
147+
[DESIGN]
148+
exclude-too-few-public-methods=
149+
ignored-parents=
150+
max-args=5
151+
max-attributes=7
152+
max-bool-expr=5
153+
max-branches=12
154+
max-locals=15
155+
max-parents=10
156+
max-public-methods=30
157+
max-returns=6
158+
max-statements=50
159+
min-public-methods=2
160+
161+
[CLASSES]
162+
check-protected-access-in-special-methods=no
163+
defining-attr-methods=__init__,
164+
__new__,
165+
setUp,
166+
__post_init__
167+
exclude-protected=_asdict,
168+
_fields,
169+
_replace,
170+
_source,
171+
_make
172+
valid-classmethod-first-arg=cls
173+
valid-metaclass-classmethod-first-arg=cls
174+
175+
[EXCEPTIONS]
176+
overgeneral-exceptions=builtins.BaseException,
177+
builtins.Exception

ctfhub/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
default_app_config = "ctfhub.apps.CtfhubConfig"
1+
default_app_config = "ctfhub.apps.CtfhubConfig" # pylint: disable=invalid-name

ctfhub/context_processors.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,11 @@ def add_timezone_context(
3535
Returns:
3636
dict: _description_
3737
"""
38+
if request.user.is_anonymous:
39+
return {"TZ": "UTC", "NOW": datetime.datetime.now()}
40+
3841
try:
3942
member = Member.objects.get(user=request.user)
4043
return {"TZ": member.timezone, "NOW": datetime.datetime.now()}
41-
except Exception:
42-
return {"TZ": "UTC"}
44+
except Member.DoesNotExist:
45+
return {"TZ": "UTC", "NOW": datetime.datetime.now()}

ctfhub/exceptions.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,3 @@ class ExternalError(Exception):
44
Args:
55
Exception (_type_): _description_
66
"""
7-
8-
pass

ctfhub/forms.py

Lines changed: 32 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
import json
22

3+
from django import forms
4+
import django.contrib.auth
5+
from django.contrib.auth.forms import UserChangeForm
6+
from django.core.exceptions import ValidationError
7+
from django.utils.translation import gettext_lazy as _
8+
39
from ctfhub.models import (
410
Challenge,
511
ChallengeCategory,
@@ -9,15 +15,11 @@
915
Tag,
1016
Team,
1117
)
12-
from django import forms
13-
from django.contrib.auth.forms import UserChangeForm
14-
from django.contrib.auth.models import User
15-
from django.core.exceptions import ValidationError
1618

1719

1820
class UserUpdateForm(UserChangeForm):
1921
class Meta:
20-
model = User
22+
model = django.contrib.auth.get_user_model()
2123
fields = [
2224
"username",
2325
"email",
@@ -93,7 +95,7 @@ def clean(self):
9395
and not self.cleaned_data["selected_ctf"]
9496
):
9597
raise ValidationError("Guests MUST have a selected_ctf")
96-
return super(MemberUpdateForm, self).clean()
98+
return super().clean()
9799

98100

99101
class CtfCreateUpdateForm(forms.ModelForm):
@@ -160,29 +162,37 @@ class ChallengeImportForm(forms.Form):
160162
("rCTF", "rCTF"),
161163
)
162164
format = forms.ChoiceField(choices=FORMAT_CHOICES, initial="CTFd")
163-
data = forms.CharField(widget=forms.Textarea)
165+
data = forms.CharField(widget=forms.Textarea) # type: ignore ## See https://docs.djangoproject.com/en/4.2/ref/forms/widgets/#specifying-widgets
164166

165167
def clean_data(self):
166168
data = self.cleaned_data["data"]
167169

168170
# Choose the cleaning method based on the format field.
169-
if self.cleaned_data["format"] == "RAW":
170-
return self._clean_raw_data(data)
171-
elif self.cleaned_data["format"] == "CTFd":
172-
return self._clean_ctfd_data(data)
173-
elif self.cleaned_data["format"] == "rCTF":
174-
return self._clean_rctf_data(data)
175-
else:
176-
raise forms.ValidationError("Invalid data format.")
171+
if not self.cleaned_data["format"] in ("RAW", "CTFd", "rCTF"):
172+
raise forms.ValidationError(
173+
_("Invalid data format: must be in %(formats)s"),
174+
params={"formats": str([x[0] for x in self.FORMAT_CHOICES])},
175+
)
176+
177+
match self.cleaned_data["format"]:
178+
case "RAW":
179+
return self._clean_raw_data(data)
180+
case "CTFd":
181+
return self._clean_ctfd_data(data)
182+
case "rCTF":
183+
return self._clean_rctf_data(data)
177184

178185
@staticmethod
179186
def _clean_raw_data(data):
180-
challenges = []
181-
for line in data.splitlines():
187+
challenges: list[dict[str, str]] = []
188+
for num, line in enumerate(data.splitlines()):
182189
parts = line.split("|")
183190
if len(parts) != 2:
184191
raise forms.ValidationError(
185-
"RAW data line does not have exactly two parts."
192+
_(
193+
"RAW must respect a two-part format with | as separator: line %(linum)s - %(data)s"
194+
),
195+
params={"linum": str(num + 1), "data": line},
186196
)
187197
challenges.append(
188198
{
@@ -200,10 +210,10 @@ def _clean_ctfd_data(data):
200210
raise ValidationError(
201211
"Invalid JSON format. Please provide valid CTFd JSON data."
202212
)
203-
except json.JSONDecodeError:
213+
except json.JSONDecodeError as exc:
204214
raise ValidationError(
205215
"Invalid JSON format. Please provide valid CTFd JSON data."
206-
)
216+
) from exc
207217

208218
return json_data["data"]
209219

@@ -215,10 +225,10 @@ def _clean_rctf_data(data):
215225
raise ValidationError(
216226
"Invalid JSON format. Please provide valid rCTF JSON data."
217227
)
218-
except json.JSONDecodeError:
228+
except json.JSONDecodeError as exc:
219229
raise ValidationError(
220230
"Invalid JSON format. Please provide valid rCTF JSON data."
221-
)
231+
) from exc
222232

223233
return json_data["data"]
224234

0 commit comments

Comments
 (0)