Skip to content

Commit 6b28b6c

Browse files
committed
🧹 Formatting
1 parent 7be869d commit 6b28b6c

File tree

3 files changed

+129
-72
lines changed

3 files changed

+129
-72
lines changed

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
from setuptools import setup
22

33
if __name__ == "__main__":
4-
setup()
4+
setup()

src/campusnet/__init__.py

Lines changed: 67 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,12 @@ class Exam:
3232

3333

3434
class CampusNetSession:
35-
def __init__(self, username: str = None, password: str = None, base_url="https://dualis.dhbw.de/"):
35+
def __init__(
36+
self,
37+
username: str = None,
38+
password: str = None,
39+
base_url="https://dualis.dhbw.de/",
40+
):
3641
"""
3742
Initialize a new CampusNetSession.
3843
:param username: The username of the user.
@@ -81,20 +86,23 @@ def _login(self):
8186
:raises:
8287
LoginError: If the login failed.
8388
"""
84-
response = self.session.post(self.mgrqispi, data={
85-
'usrname': self.username,
86-
'pass': self.password,
87-
'APPNAME': 'CampusNet',
88-
'PRGNAME': 'LOGINCHECK',
89-
'ARGUMENTS': 'clino,usrname,pass,menuno,menu_type,browser,platform',
90-
'clino': '000000000000001',
91-
'menuno': '000324',
92-
'menu_type': 'classic',
93-
'browser': '',
94-
'platform': '',
95-
})
89+
response = self.session.post(
90+
self.mgrqispi,
91+
data={
92+
"usrname": self.username,
93+
"pass": self.password,
94+
"APPNAME": "CampusNet",
95+
"PRGNAME": "LOGINCHECK",
96+
"ARGUMENTS": "clino,usrname,pass,menuno,menu_type,browser,platform",
97+
"clino": "000000000000001",
98+
"menuno": "000324",
99+
"menu_type": "classic",
100+
"browser": "",
101+
"platform": "",
102+
},
103+
)
96104
if len(response.cookies) == 0: # We didn't get a session token in response
97-
raise LoginError('Login failed.')
105+
raise LoginError("Login failed.")
98106

99107
# The header looks like this
100108
# 0; URL=/scripts/mgrqispi.dll?APPNAME=CampusNet&PRGNAME=STARTPAGE_DISPATCH&ARGUMENTS=-N954433323189667,-N000019,-N000000000000000
@@ -110,16 +118,16 @@ def _get_semesters(self):
110118
Get the semesters from the CampusNet.
111119
:return: A list of semesters.
112120
"""
113-
response = self.session.get(self.create_url('COURSERESULTS'))
121+
response = self.session.get(self.create_url("COURSERESULTS"))
114122
# The webservice doesn't correctly set Content-Type: text/html; charset=utf-8
115123
# so requests uses ISO-8859-1 which is not correct. Requests is smart enough to
116124
# convert the response to UTF-8 if we tell it to take a guess at the real encoding.
117125
# also see https://stackoverflow.com/a/52615216
118126
response.encoding = response.apparent_encoding
119-
soup = BeautifulSoup(response.text, 'html.parser')
127+
soup = BeautifulSoup(response.text, "html.parser")
120128
semesters = {}
121-
for semester in soup.find_all('option'):
122-
semesters[semester.text] = semester.get('value')
129+
for semester in soup.find_all("option"):
130+
semesters[semester.text] = semester.get("value")
123131
return semesters
124132

125133
@property
@@ -139,24 +147,27 @@ def _get_modules(self):
139147
"""
140148
modules = []
141149
for semester in self.semesters:
142-
response = self.session.post(self.mgrqispi, data={
143-
'APPNAME': 'CampusNet',
144-
'semester': self.semesters[semester],
145-
'Refresh': 'Aktualisieren',
146-
'PRGNAME': 'COURSERESULTS',
147-
'ARGUMENTS': 'sessionno,menuno,semester',
148-
'sessionno': self.session_number,
149-
'menuno': '000307'
150-
})
150+
response = self.session.post(
151+
self.mgrqispi,
152+
data={
153+
"APPNAME": "CampusNet",
154+
"semester": self.semesters[semester],
155+
"Refresh": "Aktualisieren",
156+
"PRGNAME": "COURSERESULTS",
157+
"ARGUMENTS": "sessionno,menuno,semester",
158+
"sessionno": self.session_number,
159+
"menuno": "000307",
160+
},
161+
)
151162
# The webservice doesn't correctly set Content-Type: text/html; charset=utf-8
152163
# so requests uses ISO-8859-1 which is not correct. Requests is smart enough to
153164
# convert the response to UTF-8 if we tell it to take a guess at the real encoding.
154165
# also see https://stackoverflow.com/a/52615216
155166
response.encoding = response.apparent_encoding
156-
soup = BeautifulSoup(response.text, 'html.parser')
157-
table = soup.find('table', {'class': 'nb list'})
158-
for row in table.find_all('tr')[1:]:
159-
cells = row.find_all('td')
167+
soup = BeautifulSoup(response.text, "html.parser")
168+
table = soup.find("table", {"class": "nb list"})
169+
for row in table.find_all("tr")[1:]:
170+
cells = row.find_all("td")
160171
if len(cells) == 7:
161172
try:
162173
grade = float(cells[2].text.strip().replace(",", "."))
@@ -167,25 +178,25 @@ def _get_modules(self):
167178
exams_id = exams_button.get("href").split(",-N")[-2]
168179
num = cells[0].text.strip()
169180
if not any(module.num == num for module in modules):
170-
modules.append(Module(
171-
num=num,
172-
name=cells[1].text.strip(),
173-
credits=float(
174-
cells[3].text.strip().replace(',', '.')),
175-
status=cells[4].text.strip(),
176-
semesters=[semester],
177-
id=exams_id,
178-
grade=grade
179-
))
181+
modules.append(
182+
Module(
183+
num=num,
184+
name=cells[1].text.strip(),
185+
credits=float(cells[3].text.strip().replace(",", ".")),
186+
status=cells[4].text.strip(),
187+
semesters=[semester],
188+
id=exams_id,
189+
grade=grade,
190+
)
191+
)
180192
else:
181193
for module in modules:
182194
if module.num == num:
183195
module.semesters.append(semester)
184196
break
185197
elif len(cells) != 0:
186198
# FIXME: proper logging
187-
print("Unexpected number of cells:",
188-
len(cells), file=sys.stderr)
199+
print("Unexpected number of cells:", len(cells), file=sys.stderr)
189200
return modules
190201

191202
@property
@@ -204,31 +215,32 @@ def get_exams_for_module(self, module: Module):
204215
:param module: The module.
205216
:return: A list of exams.
206217
"""
207-
response = self.session.get(self.create_url(
208-
'RESULTDETAILS', f",-N{module.id}"))
218+
response = self.session.get(self.create_url("RESULTDETAILS", f",-N{module.id}"))
209219
# The webservice doesn't correctly set Content-Type: text/html; charset=utf-8
210220
# so requests uses ISO-8859-1 which is not correct. Requests is smart enough to
211221
# convert the response to UTF-8 if we tell it to take a guess at the real encoding.
212222
# also see https://stackoverflow.com/a/52615216
213223
response.encoding = response.apparent_encoding
214-
soup = BeautifulSoup(response.text, 'html.parser')
215-
exam_table = soup.find('table', {'class': 'tb'})
224+
soup = BeautifulSoup(response.text, "html.parser")
225+
exam_table = soup.find("table", {"class": "tb"})
216226
exams = []
217227
current_heading = None
218228
for row in exam_table.find_all("tr"):
219-
cells = row.find_all('td')
220-
if len(cells) == 1 and 'level02' in cells[0]["class"]:
229+
cells = row.find_all("td")
230+
if len(cells) == 1 and "level02" in cells[0]["class"]:
221231
# variable to persist header into the next iteration
222232
current_heading = cells[0].text.strip()
223233
if len(cells) == 6 and all("tbdata" in cell["class"] for cell in cells):
224234
try:
225235
grade = float(cells[3].text.strip().replace(",", "."))
226236
except ValueError:
227237
grade = None
228-
exams.append(Exam(
229-
name=current_heading,
230-
semester=cells[0].text.strip(),
231-
description=cells[1].text.strip(),
232-
grade=grade,
233-
))
238+
exams.append(
239+
Exam(
240+
name=current_heading,
241+
semester=cells[0].text.strip(),
242+
description=cells[1].text.strip(),
243+
grade=grade,
244+
)
245+
)
234246
return exams

src/campusnet/__main__.py

Lines changed: 61 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,41 @@
22
from argparse import ArgumentParser
33

44
if __name__ == "__main__":
5-
parser = ArgumentParser(prog="python -m campusnet",
6-
description="Get exams from CampusNet instance.")
5+
parser = ArgumentParser(
6+
prog="python -m campusnet", description="Get exams from CampusNet instance."
7+
)
78
parser.add_argument("username", help="Username (including domain)")
89
parser.add_argument(
9-
"password", help="Password (will be read from stdin if not supplied)", nargs="?", default=None)
10+
"password",
11+
help="Password (will be read from stdin if not supplied)",
12+
nargs="?",
13+
default=None,
14+
)
1015
parser.add_argument(
11-
"-b", "--base-url", help="Base URL of the CampusNet instance (default: https://dualis.dhbw.de/)", default="https://dualis.dhbw.de/")
12-
parser.add_argument("-o", "--output", help="Output format of the data (default: table)",
13-
default="table", choices=["table", "json", "csv"])
16+
"-b",
17+
"--base-url",
18+
help="Base URL of the CampusNet instance (default: https://dualis.dhbw.de/)",
19+
default="https://dualis.dhbw.de/",
20+
)
21+
parser.add_argument(
22+
"-o",
23+
"--output",
24+
help="Output format of the data (default: table)",
25+
default="table",
26+
choices=["table", "json", "csv"],
27+
)
1428

1529
args = parser.parse_args()
1630
if not args.password:
1731
from getpass import getpass
32+
1833
password = getpass()
1934
else:
2035
password = args.password
2136

2237
while True:
2338
try:
24-
s = campusnet.CampusNetSession(
25-
args.username, password, args.base_url)
39+
s = campusnet.CampusNetSession(args.username, password, args.base_url)
2640
break
2741
except campusnet.LoginError as e:
2842
print("Invalid username or password.")
@@ -33,29 +47,60 @@
3347

3448
if args.output == "table":
3549
from tabulate import tabulate
50+
3651
table = []
3752
for module in s.modules:
3853
for exam in s.get_exams_for_module(module):
39-
table.append([module.num, module.name, exam.name,
40-
exam.semester, exam.description, exam.grade])
54+
table.append(
55+
[
56+
module.num,
57+
module.name,
58+
exam.name,
59+
exam.semester,
60+
exam.description,
61+
exam.grade,
62+
]
63+
)
4164

42-
print(tabulate(table, headers=[
43-
"Module", "Name", "Exam", "Semester", "Description", "Grade"]))
65+
print(
66+
tabulate(
67+
table,
68+
headers=["Module", "Name", "Exam", "Semester", "Description", "Grade"],
69+
)
70+
)
4471
elif args.output == "json":
4572
import json
73+
4674
out = []
4775
for module in s.modules:
4876
for exam in s.get_exams_for_module(module):
49-
out.append({"module": module.num, "name": module.name, "exam": exam.name,
50-
"semester": exam.semester, "description": exam.description, "grade": exam.grade})
77+
out.append(
78+
{
79+
"module": module.num,
80+
"name": module.name,
81+
"exam": exam.name,
82+
"semester": exam.semester,
83+
"description": exam.description,
84+
"grade": exam.grade,
85+
}
86+
)
5187
print(json.dumps(out, indent=4))
5288
elif args.output == "csv":
5389
import csv
5490
import sys
91+
5592
out = [["Module", "Name", "Exam", "Semester", "Description", "Grade"]]
5693
for module in s.modules:
5794
for exam in s.get_exams_for_module(module):
58-
out.append([module.num, module.name, exam.name,
59-
exam.semester, exam.description, exam.grade])
95+
out.append(
96+
[
97+
module.num,
98+
module.name,
99+
exam.name,
100+
exam.semester,
101+
exam.description,
102+
exam.grade,
103+
]
104+
)
60105
writer = csv.writer(sys.stdout)
61106
writer.writerows(out)

0 commit comments

Comments
 (0)