Refactor and enhance type hints across multiple modules #17
@@ -3,6 +3,8 @@ __author__ = "Alexander Kirchner"
|
|||||||
__all__ = ["__version__", "__author__", "Icon", "settings"]
|
__all__ = ["__version__", "__author__", "Icon", "settings"]
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Union
|
||||||
|
|
||||||
from appdirs import AppDirs
|
from appdirs import AppDirs
|
||||||
|
|
||||||
@@ -18,7 +20,7 @@ if not os.path.exists(CONFIG_DIR): # type: ignore
|
|||||||
|
|
||||||
|
|
||||||
settings = Config(f"{CONFIG_DIR}/config.yaml")
|
settings = Config(f"{CONFIG_DIR}/config.yaml")
|
||||||
DATABASE_DIR = ( # type: ignore
|
DATABASE_DIR: Union[Path, str] = ( # type: ignore
|
||||||
app.user_config_dir if settings.database.path is None else settings.database.path # type: ignore
|
app.user_config_dir if settings.database.path is None else settings.database.path # type: ignore
|
||||||
)
|
)
|
||||||
if not os.path.exists(DATABASE_DIR): # type: ignore
|
if not os.path.exists(DATABASE_DIR): # type: ignore
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
from typing import List
|
||||||
|
|
||||||
import regex
|
import regex
|
||||||
import requests
|
import requests
|
||||||
from bs4 import BeautifulSoup
|
from bs4 import BeautifulSoup
|
||||||
@@ -33,13 +35,13 @@ class Catalogue:
|
|||||||
response = requests.get(link, timeout=self.timeout)
|
response = requests.get(link, timeout=self.timeout)
|
||||||
return response.text
|
return response.text
|
||||||
|
|
||||||
def get_book_links(self, searchterm: str):
|
def get_book_links(self, searchterm: str) -> List[str]:
|
||||||
response = self.search_book(searchterm)
|
response = self.search_book(searchterm)
|
||||||
soup = BeautifulSoup(response, "html.parser")
|
soup = BeautifulSoup(response, "html.parser")
|
||||||
links = soup.find_all("a", class_="title getFull")
|
links = soup.find_all("a", class_="title getFull")
|
||||||
res = []
|
res: List[str] = []
|
||||||
for link in links:
|
for link in links:
|
||||||
res.append(BASE + link["href"])
|
res.append(BASE + link["href"]) # type: ignore
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def get_book(self, searchterm: str):
|
def get_book(self, searchterm: str):
|
||||||
|
|||||||
@@ -144,7 +144,7 @@ class Database:
|
|||||||
self.create_tables()
|
self.create_tables()
|
||||||
self.insertSubjects()
|
self.insertSubjects()
|
||||||
|
|
||||||
def getElsaMediaID(self, work_author, signature, pages):
|
def getElsaMediaID(self, work_author: str, signature: str, pages: str):
|
||||||
query = (
|
query = (
|
||||||
"SELECT id FROM elsa_media WHERE work_author=? AND signature=? AND pages=?"
|
"SELECT id FROM elsa_media WHERE work_author=? AND signature=? AND pages=?"
|
||||||
)
|
)
|
||||||
@@ -160,7 +160,7 @@ class Database:
|
|||||||
query = "SELECT type FROM elsa_media WHERE id=?"
|
query = "SELECT type FROM elsa_media WHERE id=?"
|
||||||
return self.query_db(query, (id,), one=True)[0]
|
return self.query_db(query, (id,), one=True)[0]
|
||||||
|
|
||||||
def get_db_contents(self) -> Union[List[Tuple], None]:
|
def get_db_contents(self) -> Union[List[Tuple[Any]], None]:
|
||||||
"""
|
"""
|
||||||
Get the contents of the
|
Get the contents of the
|
||||||
|
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ def _text(elem: Optional[ET.Element]) -> str:
|
|||||||
return (elem.text or "") if elem is not None else ""
|
return (elem.text or "") if elem is not None else ""
|
||||||
|
|
||||||
|
|
||||||
def _req_text(parent: ET.Element, path: str) -> str:
|
def _req_text(parent: ET.Element, path: str) -> Optional[str]:
|
||||||
el = parent.find(path, NS)
|
el = parent.find(path, NS)
|
||||||
if el is None or el.text is None:
|
if el is None or el.text is None:
|
||||||
return None
|
return None
|
||||||
@@ -98,7 +98,7 @@ def parse_marc_record(record_el: ET.Element) -> MarcRecord:
|
|||||||
record_el is the <marc:record> element (default ns MARC in your sample)
|
record_el is the <marc:record> element (default ns MARC in your sample)
|
||||||
"""
|
"""
|
||||||
# leader
|
# leader
|
||||||
leader_text = _req_text(record_el, "marc:leader")
|
leader_text = _req_text(record_el, "marc:leader") or ""
|
||||||
|
|
||||||
# controlfields
|
# controlfields
|
||||||
controlfields: List[ControlField] = []
|
controlfields: List[ControlField] = []
|
||||||
@@ -124,8 +124,8 @@ def parse_marc_record(record_el: ET.Element) -> MarcRecord:
|
|||||||
|
|
||||||
|
|
||||||
def parse_record(zs_record_el: ET.Element) -> Record:
|
def parse_record(zs_record_el: ET.Element) -> Record:
|
||||||
recordSchema = _req_text(zs_record_el, "zs:recordSchema")
|
recordSchema = _req_text(zs_record_el, "zs:recordSchema") or ""
|
||||||
recordPacking = _req_text(zs_record_el, "zs:recordPacking")
|
recordPacking = _req_text(zs_record_el, "zs:recordPacking") or ""
|
||||||
|
|
||||||
# recordData contains a MARC <record> with default MARC namespace in your sample
|
# recordData contains a MARC <record> with default MARC namespace in your sample
|
||||||
recordData_el = zs_record_el.find("zs:recordData", NS)
|
recordData_el = zs_record_el.find("zs:recordData", NS)
|
||||||
@@ -140,7 +140,7 @@ def parse_record(zs_record_el: ET.Element) -> Record:
|
|||||||
|
|
||||||
marc_record = parse_marc_record(marc_record_el)
|
marc_record = parse_marc_record(marc_record_el)
|
||||||
|
|
||||||
recordPosition = int(_req_text(zs_record_el, "zs:recordPosition"))
|
recordPosition = int(_req_text(zs_record_el, "zs:recordPosition") or "0")
|
||||||
return Record(
|
return Record(
|
||||||
recordSchema=recordSchema,
|
recordSchema=recordSchema,
|
||||||
recordPacking=recordPacking,
|
recordPacking=recordPacking,
|
||||||
|
|||||||
@@ -1,36 +1,4 @@
|
|||||||
def parse_semester(semester: str):
|
def parse_semester(semester: str) -> tuple[int, int]:
|
||||||
"""
|
|
||||||
Parses the semester string into a sortable format.
|
|
||||||
Returns a tuple of (year, type), where type is 0 for SoSe and 1 for WiSe.
|
|
||||||
"""
|
|
||||||
if semester.startswith("SoSe"):
|
|
||||||
return int(semester.split()[1]), 0
|
|
||||||
elif semester.startswith("WiSe"):
|
|
||||||
year_part = semester.split()[1]
|
|
||||||
start_year, _ = map(int, year_part.split("/"))
|
|
||||||
return start_year, 1
|
|
||||||
else:
|
|
||||||
raise ValueError(f"Invalid semester format: {semester}")
|
|
||||||
|
|
||||||
|
|
||||||
def custom_sort(entries):
|
|
||||||
"""
|
|
||||||
Sorts the list of tuples based on the custom schema.
|
|
||||||
|
|
||||||
:param entries: List of tuples in the format (str, int, int).
|
|
||||||
:return: Sorted list of tuples.
|
|
||||||
"""
|
|
||||||
return sorted(
|
|
||||||
entries,
|
|
||||||
key=lambda entry: (
|
|
||||||
parse_semester(entry[0]), # Sort by semester parsed as (year, type)
|
|
||||||
entry[1], # Then by the second element of the tuple
|
|
||||||
entry[2], # Finally by the third element of the tuple
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def parse_semester(semester: str):
|
|
||||||
"""
|
"""
|
||||||
Parses the semester string into a sortable format.
|
Parses the semester string into a sortable format.
|
||||||
Returns a tuple of (year, type), where type is 0 for SoSe and 1 for WiSe.
|
Returns a tuple of (year, type), where type is 0 for SoSe and 1 for WiSe.
|
||||||
@@ -48,6 +16,23 @@ def parse_semester(semester: str):
|
|||||||
raise ValueError(f"Invalid semester format: {semester}")
|
raise ValueError(f"Invalid semester format: {semester}")
|
||||||
|
|
||||||
|
|
||||||
|
def custom_sort(entries) -> list:
|
||||||
|
"""
|
||||||
|
Sorts the list of tuples based on the custom schema.
|
||||||
|
|
||||||
|
:param entries: List of tuples in the format (str, int, int).
|
||||||
|
:return: Sorted list of tuples.
|
||||||
|
"""
|
||||||
|
return sorted(
|
||||||
|
entries,
|
||||||
|
key=lambda entry: (
|
||||||
|
parse_semester(entry[0]), # Sort by semester parsed as (year, type)
|
||||||
|
entry[1], # Then by the second element of the tuple
|
||||||
|
entry[2], # Finally by the third element of the tuple
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def sort_semesters_list(semesters: list) -> list:
|
def sort_semesters_list(semesters: list) -> list:
|
||||||
"""
|
"""
|
||||||
Sorts a list of semester strings based on year and type.
|
Sorts a list of semester strings based on year and type.
|
||||||
|
|||||||
@@ -30,184 +30,184 @@ PROF_TITLES = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
SEMAP_MEDIA_ACCOUNTS = {
|
SEMAP_MEDIA_ACCOUNTS = {
|
||||||
"1": "1008000055",
|
1: "1008000055",
|
||||||
"2": "1008000188",
|
2: "1008000188",
|
||||||
"3": "1008000211",
|
3: "1008000211",
|
||||||
"4": "1008000344",
|
4: "1008000344",
|
||||||
"5": "1008000477",
|
5: "1008000477",
|
||||||
"6": "1008000500",
|
6: "1008000500",
|
||||||
"7": "1008000633",
|
7: "1008000633",
|
||||||
"8": "1008000766",
|
8: "1008000766",
|
||||||
"9": "1008000899",
|
9: "1008000899",
|
||||||
"10": "1008000922",
|
10: "1008000922",
|
||||||
"11": "1008001044",
|
11: "1008001044",
|
||||||
"12": "1008001177",
|
12: "1008001177",
|
||||||
"13": "1008001200",
|
13: "1008001200",
|
||||||
"14": "1008001333",
|
14: "1008001333",
|
||||||
"15": "1008001466",
|
15: "1008001466",
|
||||||
"16": "1008001599",
|
16: "1008001599",
|
||||||
"17": "1008001622",
|
17: "1008001622",
|
||||||
"18": "1008001755",
|
18: "1008001755",
|
||||||
"19": "1008001888",
|
19: "1008001888",
|
||||||
"20": "1008001911",
|
20: "1008001911",
|
||||||
"21": "1008002033",
|
21: "1008002033",
|
||||||
"22": "1008002166",
|
22: "1008002166",
|
||||||
"23": "1008002299",
|
23: "1008002299",
|
||||||
"24": "1008002322",
|
24: "1008002322",
|
||||||
"25": "1008002455",
|
25: "1008002455",
|
||||||
"26": "1008002588",
|
26: "1008002588",
|
||||||
"27": "1008002611",
|
27: "1008002611",
|
||||||
"28": "1008002744",
|
28: "1008002744",
|
||||||
"29": "1008002877",
|
29: "1008002877",
|
||||||
"30": "1008002900",
|
30: "1008002900",
|
||||||
"31": "1008003022",
|
31: "1008003022",
|
||||||
"32": "1008003155",
|
32: "1008003155",
|
||||||
"33": "1008003288",
|
33: "1008003288",
|
||||||
"34": "1008003311",
|
34: "1008003311",
|
||||||
"35": "1008003444",
|
35: "1008003444",
|
||||||
"36": "1008003577",
|
36: "1008003577",
|
||||||
"37": "1008003600",
|
37: "1008003600",
|
||||||
"38": "1008003733",
|
38: "1008003733",
|
||||||
"39": "1008003866",
|
39: "1008003866",
|
||||||
"40": "1008003999",
|
40: "1008003999",
|
||||||
"41": "1008004011",
|
41: "1008004011",
|
||||||
"42": "1008004144",
|
42: "1008004144",
|
||||||
"43": "1008004277",
|
43: "1008004277",
|
||||||
"44": "1008004300",
|
44: "1008004300",
|
||||||
"45": "1008004433",
|
45: "1008004433",
|
||||||
"46": "1008004566",
|
46: "1008004566",
|
||||||
"47": "1008004699",
|
47: "1008004699",
|
||||||
"48": "1008004722",
|
48: "1008004722",
|
||||||
"49": "1008004855",
|
49: "1008004855",
|
||||||
"50": "1008004988",
|
50: "1008004988",
|
||||||
"51": "1008005000",
|
51: "1008005000",
|
||||||
"52": "1008005133",
|
52: "1008005133",
|
||||||
"53": "1008005266",
|
53: "1008005266",
|
||||||
"54": "1008005399",
|
54: "1008005399",
|
||||||
"55": "1008005422",
|
55: "1008005422",
|
||||||
"56": "1008005555",
|
56: "1008005555",
|
||||||
"57": "1008005688",
|
57: "1008005688",
|
||||||
"58": "1008005711",
|
58: "1008005711",
|
||||||
"59": "1008005844",
|
59: "1008005844",
|
||||||
"60": "1008005977",
|
60: "1008005977",
|
||||||
"61": "1008006099",
|
61: "1008006099",
|
||||||
"62": "1008006122",
|
62: "1008006122",
|
||||||
"63": "1008006255",
|
63: "1008006255",
|
||||||
"64": "1008006388",
|
64: "1008006388",
|
||||||
"65": "1008006411",
|
65: "1008006411",
|
||||||
"66": "1008006544",
|
66: "1008006544",
|
||||||
"67": "1008006677",
|
67: "1008006677",
|
||||||
"68": "1008006700",
|
68: "1008006700",
|
||||||
"69": "1008006833",
|
69: "1008006833",
|
||||||
"70": "1008006966",
|
70: "1008006966",
|
||||||
"71": "1008007088",
|
71: "1008007088",
|
||||||
"72": "1008007111",
|
72: "1008007111",
|
||||||
"73": "1008007244",
|
73: "1008007244",
|
||||||
"74": "1008007377",
|
74: "1008007377",
|
||||||
"75": "1008007400",
|
75: "1008007400",
|
||||||
"76": "1008007533",
|
76: "1008007533",
|
||||||
"77": "1008007666",
|
77: "1008007666",
|
||||||
"78": "1008007799",
|
78: "1008007799",
|
||||||
"79": "1008007822",
|
79: "1008007822",
|
||||||
"80": "1008007955",
|
80: "1008007955",
|
||||||
"81": "1008008077",
|
81: "1008008077",
|
||||||
"82": "1008008100",
|
82: "1008008100",
|
||||||
"83": "1008008233",
|
83: "1008008233",
|
||||||
"84": "1008008366",
|
84: "1008008366",
|
||||||
"85": "1008008499",
|
85: "1008008499",
|
||||||
"86": "1008008522",
|
86: "1008008522",
|
||||||
"87": "1008008655",
|
87: "1008008655",
|
||||||
"88": "1008008788",
|
88: "1008008788",
|
||||||
"89": "1008008811",
|
89: "1008008811",
|
||||||
"90": "1008008944",
|
90: "1008008944",
|
||||||
"91": "1008009066",
|
91: "1008009066",
|
||||||
"92": "1008009199",
|
92: "1008009199",
|
||||||
"93": "1008009222",
|
93: "1008009222",
|
||||||
"94": "1008009355",
|
94: "1008009355",
|
||||||
"95": "1008009488",
|
95: "1008009488",
|
||||||
"96": "1008009511",
|
96: "1008009511",
|
||||||
"97": "1008009644",
|
97: "1008009644",
|
||||||
"98": "1008009777",
|
98: "1008009777",
|
||||||
"99": "1008009800",
|
99: "1008009800",
|
||||||
"100": "1008009933",
|
100: "1008009933",
|
||||||
"101": "1008010022",
|
101: "1008010022",
|
||||||
"102": "1008010155",
|
102: "1008010155",
|
||||||
"103": "1008010288",
|
103: "1008010288",
|
||||||
"104": "1008010311",
|
104: "1008010311",
|
||||||
"105": "1008010444",
|
105: "1008010444",
|
||||||
"106": "1008010577",
|
106: "1008010577",
|
||||||
"107": "1008010600",
|
107: "1008010600",
|
||||||
"108": "1008010733",
|
108: "1008010733",
|
||||||
"109": "1008010866",
|
109: "1008010866",
|
||||||
"110": "1008010999",
|
110: "1008010999",
|
||||||
"111": "1008011011",
|
111: "1008011011",
|
||||||
"112": "1008011144",
|
112: "1008011144",
|
||||||
"113": "1008011277",
|
113: "1008011277",
|
||||||
"114": "1008011300",
|
114: "1008011300",
|
||||||
"115": "1008011433",
|
115: "1008011433",
|
||||||
"116": "1008011566",
|
116: "1008011566",
|
||||||
"117": "1008011699",
|
117: "1008011699",
|
||||||
"118": "1008011722",
|
118: "1008011722",
|
||||||
"119": "1008011855",
|
119: "1008011855",
|
||||||
"120": "1008011988",
|
120: "1008011988",
|
||||||
"121": "1008012000",
|
121: "1008012000",
|
||||||
"122": "1008012133",
|
122: "1008012133",
|
||||||
"123": "1008012266",
|
123: "1008012266",
|
||||||
"124": "1008012399",
|
124: "1008012399",
|
||||||
"125": "1008012422",
|
125: "1008012422",
|
||||||
"126": "1008012555",
|
126: "1008012555",
|
||||||
"127": "1008012688",
|
127: "1008012688",
|
||||||
"128": "1008012711",
|
128: "1008012711",
|
||||||
"129": "1008012844",
|
129: "1008012844",
|
||||||
"130": "1008012977",
|
130: "1008012977",
|
||||||
"131": "1008013099",
|
131: "1008013099",
|
||||||
"132": "1008013122",
|
132: "1008013122",
|
||||||
"133": "1008013255",
|
133: "1008013255",
|
||||||
"134": "1008013388",
|
134: "1008013388",
|
||||||
"135": "1008013411",
|
135: "1008013411",
|
||||||
"136": "1008013544",
|
136: "1008013544",
|
||||||
"137": "1008013677",
|
137: "1008013677",
|
||||||
"138": "1008013700",
|
138: "1008013700",
|
||||||
"139": "1008013833",
|
139: "1008013833",
|
||||||
"140": "1008013966",
|
140: "1008013966",
|
||||||
"141": "1008014088",
|
141: "1008014088",
|
||||||
"142": "1008014111",
|
142: "1008014111",
|
||||||
"143": "1008014244",
|
143: "1008014244",
|
||||||
"144": "1008014377",
|
144: "1008014377",
|
||||||
"145": "1008014400",
|
145: "1008014400",
|
||||||
"146": "1008014533",
|
146: "1008014533",
|
||||||
"147": "1008014666",
|
147: "1008014666",
|
||||||
"148": "1008014799",
|
148: "1008014799",
|
||||||
"149": "1008014822",
|
149: "1008014822",
|
||||||
"150": "1008014955",
|
150: "1008014955",
|
||||||
"151": "1008015077",
|
151: "1008015077",
|
||||||
"152": "1008015100",
|
152: "1008015100",
|
||||||
"153": "1008015233",
|
153: "1008015233",
|
||||||
"154": "1008015366",
|
154: "1008015366",
|
||||||
"155": "1008015499",
|
155: "1008015499",
|
||||||
"156": "1008015522",
|
156: "1008015522",
|
||||||
"157": "1008015655",
|
157: "1008015655",
|
||||||
"158": "1008015788",
|
158: "1008015788",
|
||||||
"159": "1008015811",
|
159: "1008015811",
|
||||||
"160": "1008015944",
|
160: "1008015944",
|
||||||
"161": "1008016066",
|
161: "1008016066",
|
||||||
"162": "1008016199",
|
162: "1008016199",
|
||||||
"163": "1008016222",
|
163: "1008016222",
|
||||||
"164": "1008016355",
|
164: "1008016355",
|
||||||
"165": "1008016488",
|
165: "1008016488",
|
||||||
"166": "1008016511",
|
166: "1008016511",
|
||||||
"167": "1008016644",
|
167: "1008016644",
|
||||||
"168": "1008016777",
|
168: "1008016777",
|
||||||
"169": "1008016800",
|
169: "1008016800",
|
||||||
"170": "1008016933",
|
170: "1008016933",
|
||||||
"171": "1008017055",
|
171: "1008017055",
|
||||||
"172": "1008017188",
|
172: "1008017188",
|
||||||
"173": "1008017211",
|
173: "1008017211",
|
||||||
"174": "1008017344",
|
174: "1008017344",
|
||||||
"175": "1008017477",
|
175: "1008017477",
|
||||||
"176": "1008017500",
|
176: "1008017500",
|
||||||
"177": "1008017633",
|
177: "1008017633",
|
||||||
"178": "1008017766",
|
178: "1008017766",
|
||||||
"179": "1008017899",
|
179: "1008017899",
|
||||||
"180": "1008017922",
|
180: "1008017922",
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ class Prof:
|
|||||||
self._title = value
|
self._title = value
|
||||||
|
|
||||||
# add function that sets the data from a tuple
|
# add function that sets the data from a tuple
|
||||||
def from_tuple(self, data: tuple[Union[str, int], ...]):
|
def from_tuple(self, data: tuple[Union[str, int], ...]) -> "Prof":
|
||||||
setattr(self, "id", data[0])
|
setattr(self, "id", data[0])
|
||||||
setattr(self, "_title", data[1])
|
setattr(self, "_title", data[1])
|
||||||
setattr(self, "firstname", data[2])
|
setattr(self, "firstname", data[2])
|
||||||
@@ -222,6 +222,7 @@ class Subjects(Enum):
|
|||||||
for i in cls:
|
for i in cls:
|
||||||
if i.name == name:
|
if i.name == name:
|
||||||
return i.id - 1
|
return i.id - 1
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
|
|||||||
@@ -134,10 +134,10 @@ class LehmannsClient:
|
|||||||
enriched.append(r)
|
enriched.append(r)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
soup = BeautifulSoup(html, "html.parser")
|
soup = BeautifulSoup(html, "html.parser") # type: ignore
|
||||||
|
|
||||||
# Pages
|
# Pages
|
||||||
pages_node = soup.select_one(
|
pages_node = soup.select_one( # type: ignore
|
||||||
"span.book-meta.meta-seiten[itemprop='numberOfPages'], "
|
"span.book-meta.meta-seiten[itemprop='numberOfPages'], "
|
||||||
"span.book-meta.meta-seiten[itemprop='numberofpages'], "
|
"span.book-meta.meta-seiten[itemprop='numberofpages'], "
|
||||||
".meta-seiten [itemprop='numberOfPages'], "
|
".meta-seiten [itemprop='numberOfPages'], "
|
||||||
@@ -151,7 +151,7 @@ class LehmannsClient:
|
|||||||
r.pages = f"{m.group(0)} Seiten"
|
r.pages = f"{m.group(0)} Seiten"
|
||||||
|
|
||||||
# Availability via li.availability-3
|
# Availability via li.availability-3
|
||||||
avail_li = soup.select_one("li.availability-3")
|
avail_li = soup.select_one("li.availability-3") # type: ignore
|
||||||
if avail_li:
|
if avail_li:
|
||||||
avail_text = " ".join(
|
avail_text = " ".join(
|
||||||
avail_li.get_text(" ", strip=True).split()
|
avail_li.get_text(" ", strip=True).split()
|
||||||
@@ -200,12 +200,12 @@ class LehmannsClient:
|
|||||||
if not a:
|
if not a:
|
||||||
continue
|
continue
|
||||||
url = urljoin(BASE, a["href"].strip())
|
url = urljoin(BASE, a["href"].strip())
|
||||||
base_title = (block.select_one(".title [itemprop='name']") or a).get_text(
|
base_title = (block.select_one(".title [itemprop='name']") or a).get_text( # type: ignore
|
||||||
strip=True
|
strip=True
|
||||||
)
|
)
|
||||||
|
|
||||||
# Alternative headline => extend title
|
# Alternative headline => extend title
|
||||||
alt_tag = block.select_one(".description[itemprop='alternativeHeadline']")
|
alt_tag = block.select_one(".description[itemprop='alternativeHeadline']") # type: ignore
|
||||||
alternative_headline = alt_tag.get_text(strip=True) if alt_tag else None
|
alternative_headline = alt_tag.get_text(strip=True) if alt_tag else None
|
||||||
title = (
|
title = (
|
||||||
f"{base_title} : {alternative_headline}"
|
f"{base_title} : {alternative_headline}"
|
||||||
@@ -216,7 +216,7 @@ class LehmannsClient:
|
|||||||
|
|
||||||
# Authors from .author
|
# Authors from .author
|
||||||
authors: list[str] = []
|
authors: list[str] = []
|
||||||
author_div = block.select_one("div.author")
|
author_div = block.select_one("div.author") # type: ignore
|
||||||
if author_div:
|
if author_div:
|
||||||
t = author_div.get_text(" ", strip=True)
|
t = author_div.get_text(" ", strip=True)
|
||||||
t = re.sub(r"^\s*von\s+", "", t, flags=re.I)
|
t = re.sub(r"^\s*von\s+", "", t, flags=re.I)
|
||||||
@@ -228,7 +228,7 @@ class LehmannsClient:
|
|||||||
# Media + format
|
# Media + format
|
||||||
media_type = None
|
media_type = None
|
||||||
book_format = None
|
book_format = None
|
||||||
type_text = block.select_one(".type")
|
type_text = block.select_one(".type") # type: ignore
|
||||||
if type_text:
|
if type_text:
|
||||||
t = type_text.get_text(" ", strip=True)
|
t = type_text.get_text(" ", strip=True)
|
||||||
m = re.search(r"\b(Buch|eBook|Hörbuch)\b", t)
|
m = re.search(r"\b(Buch|eBook|Hörbuch)\b", t)
|
||||||
@@ -240,7 +240,7 @@ class LehmannsClient:
|
|||||||
|
|
||||||
# Year
|
# Year
|
||||||
year = None
|
year = None
|
||||||
y = block.select_one("[itemprop='copyrightYear']")
|
y = block.select_one("[itemprop='copyrightYear']") # type: ignore
|
||||||
if y:
|
if y:
|
||||||
try:
|
try:
|
||||||
year = int(y.get_text(strip=True))
|
year = int(y.get_text(strip=True))
|
||||||
@@ -249,7 +249,7 @@ class LehmannsClient:
|
|||||||
|
|
||||||
# Edition
|
# Edition
|
||||||
edition = None
|
edition = None
|
||||||
ed = block.select_one("[itemprop='bookEdition']")
|
ed = block.select_one("[itemprop='bookEdition']") # type: ignore
|
||||||
if ed:
|
if ed:
|
||||||
m = re.search(r"\d+", ed.get_text(strip=True))
|
m = re.search(r"\d+", ed.get_text(strip=True))
|
||||||
if m:
|
if m:
|
||||||
@@ -257,15 +257,15 @@ class LehmannsClient:
|
|||||||
|
|
||||||
# Publisher
|
# Publisher
|
||||||
publisher = None
|
publisher = None
|
||||||
pub = block.select_one(
|
pub = block.select_one( # type: ignore
|
||||||
".publisherprop [itemprop='name']"
|
".publisherprop [itemprop='name']"
|
||||||
) or block.select_one(".publisher [itemprop='name']")
|
) or block.select_one(".publisher [itemprop='name']") # type: ignore
|
||||||
if pub:
|
if pub:
|
||||||
publisher = pub.get_text(strip=True)
|
publisher = pub.get_text(strip=True)
|
||||||
|
|
||||||
# ISBN-13
|
# ISBN-13
|
||||||
isbn13 = None
|
isbn13 = None
|
||||||
isbn_tag = block.select_one(".isbn [itemprop='isbn'], [itemprop='isbn']")
|
isbn_tag = block.select_one(".isbn [itemprop='isbn'], [itemprop='isbn']") # type: ignore
|
||||||
if isbn_tag:
|
if isbn_tag:
|
||||||
digits = re.sub(r"[^0-9Xx]", "", isbn_tag.get_text(strip=True))
|
digits = re.sub(r"[^0-9Xx]", "", isbn_tag.get_text(strip=True))
|
||||||
m = re.search(r"(97[89]\d{10})", digits)
|
m = re.search(r"(97[89]\d{10})", digits)
|
||||||
@@ -288,7 +288,7 @@ class LehmannsClient:
|
|||||||
|
|
||||||
# Image (best-effort)
|
# Image (best-effort)
|
||||||
image = None
|
image = None
|
||||||
left_img = block.find_previous("img")
|
left_img = block.find_previous("img") # type: ignore
|
||||||
if left_img and left_img.get("src"):
|
if left_img and left_img.get("src"):
|
||||||
image = urljoin(BASE, left_img["src"])
|
image = urljoin(BASE, left_img["src"])
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
from openai import OpenAI
|
|
||||||
from src import settings
|
|
||||||
import json
|
import json
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
from openai import OpenAI
|
||||||
|
|
||||||
|
from src import settings
|
||||||
|
|
||||||
|
|
||||||
|
def init_client() -> OpenAI:
|
||||||
def init_client():
|
|
||||||
"""Initialize the OpenAI client with the API key and model from settings."""
|
"""Initialize the OpenAI client with the API key and model from settings."""
|
||||||
global client, model, api_key
|
global client, model, api_key
|
||||||
if not settings.openAI.api_key:
|
if not settings.openAI.api_key:
|
||||||
@@ -16,9 +18,11 @@ def init_client():
|
|||||||
api_key = settings.openAI.api_key
|
api_key = settings.openAI.api_key
|
||||||
client = OpenAI(api_key=api_key)
|
client = OpenAI(api_key=api_key)
|
||||||
return client
|
return client
|
||||||
def run_shortener(title:str, length:int):
|
|
||||||
|
|
||||||
|
def run_shortener(title: str, length: int) -> list[dict[str, Any]]:
|
||||||
client = init_client()
|
client = init_client()
|
||||||
response = client.responses.create(
|
response = client.responses.create( # type: ignore
|
||||||
model=model,
|
model=model,
|
||||||
instructions="""you are a sentence shortener. The next message will contain the string to shorten and the length limit.
|
instructions="""you are a sentence shortener. The next message will contain the string to shorten and the length limit.
|
||||||
You need to shorten the string to be under the length limit, while keeping as much detail as possible. The result may NOT be longer than the length limit.
|
You need to shorten the string to be under the length limit, while keeping as much detail as possible. The result may NOT be longer than the length limit.
|
||||||
@@ -27,26 +31,27 @@ based on that, please reply only the shortened string. Give me 5 choices. if the
|
|||||||
)
|
)
|
||||||
answers = response.output_text
|
answers = response.output_text
|
||||||
return eval(answers) # type: ignore
|
return eval(answers) # type: ignore
|
||||||
#answers are strings in json format, so we need to convert them to a list of dicts
|
# answers are strings in json format, so we need to convert them to a list of dicts
|
||||||
|
|
||||||
|
|
||||||
def name_tester(name: str):
|
def name_tester(name: str) -> dict:
|
||||||
client = init_client()
|
client = init_client()
|
||||||
response = client.responses.create(
|
response = client.responses.create( # type: ignore
|
||||||
model = model,
|
model=model,
|
||||||
instructions="""you are a name tester, You are given a name and will have to split the name into first name, last name, and if present the title. Return the name in a json format with the keys "title", "first_name", "last_name". If no title is present, set title to none. Do NOt return the answer in a codeblock, use a pure json string. Assume the names are in the usual german naming scheme""",
|
instructions="""you are a name tester, You are given a name and will have to split the name into first name, last name, and if present the title. Return the name in a json format with the keys "title", "first_name", "last_name". If no title is present, set title to none. Do NOt return the answer in a codeblock, use a pure json string. Assume the names are in the usual german naming scheme""",
|
||||||
input = f'{{"name":"{name}"}}'
|
input=f'{{"name":"{name}"}}',
|
||||||
)
|
)
|
||||||
answers = response.output_text
|
answers = response.output_text
|
||||||
|
|
||||||
return json.loads(answers)
|
return json.loads(answers)
|
||||||
|
|
||||||
def semester_converter(semester:str):
|
|
||||||
|
def semester_converter(semester: str) -> str:
|
||||||
client = init_client()
|
client = init_client()
|
||||||
response = client.responses.create(
|
response = client.responses.create( # type: ignore
|
||||||
model = model,
|
model=model,
|
||||||
instructions="""you are a semester converter. You will be given a string. Convert this into a string like this: SoSe YY or WiSe YY/YY+1. Do not return the answer in a codeblock, use a pure string.""",
|
instructions="""you are a semester converter. You will be given a string. Convert this into a string like this: SoSe YY or WiSe YY/YY+1. Do not return the answer in a codeblock, use a pure string.""",
|
||||||
input = semester
|
input=semester,
|
||||||
)
|
)
|
||||||
answers = response.output_text
|
answers = response.output_text
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
# add depend path to system path
|
# add depend path to system path
|
||||||
|
|
||||||
import pandas as pd
|
|
||||||
from pdfquery import PDFQuery
|
from pdfquery import PDFQuery
|
||||||
|
|
||||||
|
|
||||||
def pdf_to_csv(path: str) -> pd.DataFrame:
|
def pdf_to_csv(path: str) -> str:
|
||||||
"""
|
"""
|
||||||
Extracts the data from a pdf file and returns it as a pandas dataframe
|
Extracts the data from a pdf file and returns it as a pandas dataframe
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -232,3 +232,17 @@ if __name__ == "__main__":
|
|||||||
# print("generate_missing:", [str(s) for s in chain])
|
# print("generate_missing:", [str(s) for s in chain])
|
||||||
|
|
||||||
# Parsing demo ---------------------------------------------------------
|
# Parsing demo ---------------------------------------------------------
|
||||||
|
examples = [
|
||||||
|
"SoSe 6",
|
||||||
|
"WiSe 6/7",
|
||||||
|
"WiSe 6",
|
||||||
|
"SoSe 23",
|
||||||
|
"WiSe 23/24",
|
||||||
|
"WiSe 24",
|
||||||
|
"WiSe 99/00",
|
||||||
|
"SoSe 00",
|
||||||
|
"WiSe 100/101", # test large year
|
||||||
|
]
|
||||||
|
for ex in examples:
|
||||||
|
parsed = Semester.from_string(ex)
|
||||||
|
print(f"'{ex}' → {parsed} ({parsed.year=}, {parsed.semester=})")
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ class Settings:
|
|||||||
default_apps: bool = True
|
default_apps: bool = True
|
||||||
custom_applications: list[dict] = field(default_factory=list)
|
custom_applications: list[dict] = field(default_factory=list)
|
||||||
|
|
||||||
def save_settings(self):
|
def save_settings(self) -> None:
|
||||||
"""Save the settings to the config file."""
|
"""Save the settings to the config file."""
|
||||||
with open("config.yaml", "w") as f:
|
with open("config.yaml", "w") as f:
|
||||||
yaml.dump(self.__dict__, f)
|
yaml.dump(self.__dict__, f)
|
||||||
|
|||||||
@@ -51,14 +51,14 @@ class WebRequest:
|
|||||||
log.info("Using any book")
|
log.info("Using any book")
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def set_apparat(self, apparat: int):
|
def set_apparat(self, apparat: int) -> "WebRequest":
|
||||||
self.apparat = apparat
|
self.apparat = apparat
|
||||||
if int(self.apparat) < 10:
|
if int(self.apparat) < 10:
|
||||||
self.apparat = f"0{self.apparat}"
|
self.apparat = f"0{self.apparat}"
|
||||||
log.info(f"Set apparat to {self.apparat}")
|
log.info(f"Set apparat to {self.apparat}")
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def get_ppn(self, signature: str):
|
def get_ppn(self, signature: str) -> "WebRequest":
|
||||||
self.signature = signature
|
self.signature = signature
|
||||||
if "+" in signature:
|
if "+" in signature:
|
||||||
signature = signature.replace("+", "%2B")
|
signature = signature.replace("+", "%2B")
|
||||||
@@ -90,7 +90,7 @@ class WebRequest:
|
|||||||
|
|
||||||
@sleep_and_retry
|
@sleep_and_retry
|
||||||
@limits(calls=RATE_LIMIT, period=RATE_PERIOD)
|
@limits(calls=RATE_LIMIT, period=RATE_PERIOD)
|
||||||
def search(self, link: str):
|
def search(self, link: str) -> Optional[str]:
|
||||||
try:
|
try:
|
||||||
response = requests.get(link, timeout=self.timeout)
|
response = requests.get(link, timeout=self.timeout)
|
||||||
return response.text
|
return response.text
|
||||||
@@ -98,7 +98,7 @@ class WebRequest:
|
|||||||
log.error(f"Request failed: {e}")
|
log.error(f"Request failed: {e}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def get_data(self) -> Union[list[str], None]:
|
def get_data(self) -> Optional[list[str]]:
|
||||||
links = self.get_book_links(self.ppn)
|
links = self.get_book_links(self.ppn)
|
||||||
log.debug(f"Links: {links}")
|
log.debug(f"Links: {links}")
|
||||||
return_data: list[str] = []
|
return_data: list[str] = []
|
||||||
@@ -156,7 +156,7 @@ class WebRequest:
|
|||||||
|
|
||||||
return return_data
|
return return_data
|
||||||
|
|
||||||
def get_data_elsa(self):
|
def get_data_elsa(self) -> Optional[list[str]]:
|
||||||
links = self.get_book_links(self.ppn)
|
links = self.get_book_links(self.ppn)
|
||||||
for link in links:
|
for link in links:
|
||||||
result = self.search(link)
|
result = self.search(link)
|
||||||
@@ -197,12 +197,12 @@ class BibTextTransformer:
|
|||||||
self.data = None
|
self.data = None
|
||||||
# self.bookdata = BookData(**self.data)
|
# self.bookdata = BookData(**self.data)
|
||||||
|
|
||||||
def use_signature(self, signature: str):
|
def use_signature(self, signature: str) -> "BibTextTransformer":
|
||||||
"""use the exact signature to search for the book"""
|
"""use the exact signature to search for the book"""
|
||||||
self.signature = signature
|
self.signature = signature
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def get_data(self, data: Union[list[str]] = None) -> "BibTextTransformer":
|
def get_data(self, data: Optional[list[str]] = None) -> "BibTextTransformer":
|
||||||
RIS_IDENT = "TY -"
|
RIS_IDENT = "TY -"
|
||||||
ARRAY_IDENT = "[kid]"
|
ARRAY_IDENT = "[kid]"
|
||||||
COinS_IDENT = "ctx_ver"
|
COinS_IDENT = "ctx_ver"
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import zipfile
|
import zipfile
|
||||||
from typing import Any
|
from typing import Any, Optional
|
||||||
|
|
||||||
import fitz # PyMuPDF
|
import fitz # PyMuPDF
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
@@ -35,7 +35,7 @@ def word_docx_to_csv(path: str) -> list[pd.DataFrame]:
|
|||||||
return m_data
|
return m_data
|
||||||
|
|
||||||
|
|
||||||
def get_fach(path: str) -> str:
|
def get_fach(path: str) -> Optional[str]:
|
||||||
document = zipfile.ZipFile(path)
|
document = zipfile.ZipFile(path)
|
||||||
xml_data = document.read("word/document.xml")
|
xml_data = document.read("word/document.xml")
|
||||||
document.close()
|
document.close()
|
||||||
@@ -49,10 +49,12 @@ def get_fach(path: str) -> str:
|
|||||||
# get the data in the w:t
|
# get the data in the w:t
|
||||||
for run in para.find_all("w:r"):
|
for run in para.find_all("w:r"):
|
||||||
data = run.find("w:t")
|
data = run.find("w:t")
|
||||||
|
if data and data.contents:
|
||||||
return data.contents[0]
|
return data.contents[0]
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
def makeDict():
|
def makeDict() -> dict[str, Optional[str]]:
|
||||||
return {
|
return {
|
||||||
"work_author": None,
|
"work_author": None,
|
||||||
"section_author": None,
|
"section_author": None,
|
||||||
@@ -70,8 +72,8 @@ def makeDict():
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def tuple_to_dict(tlist: tuple, type: str) -> dict:
|
def tuple_to_dict(tlist: tuple, type: str) -> list[dict[str, Optional[str]]]:
|
||||||
ret = []
|
ret: list[dict[str, Optional[str]]] = []
|
||||||
for line in tlist:
|
for line in tlist:
|
||||||
data = makeDict()
|
data = makeDict()
|
||||||
if type == "Monografien":
|
if type == "Monografien":
|
||||||
@@ -111,7 +113,7 @@ def tuple_to_dict(tlist: tuple, type: str) -> dict:
|
|||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
def elsa_word_to_csv(path: str):
|
def elsa_word_to_csv(path: str) -> tuple[list[dict[str, Optional[str]]], str]:
|
||||||
doc = Document(path)
|
doc = Document(path)
|
||||||
# # print all lines in doc
|
# # print all lines in doc
|
||||||
doctype = [para.text for para in doc.paragraphs if para.text != ""][-1]
|
doctype = [para.text for para in doc.paragraphs if para.text != ""][-1]
|
||||||
|
|||||||
@@ -56,8 +56,8 @@ def eml_parser(path: str) -> XMLMailSubmission:
|
|||||||
return parse_xml_submission(xml_content)
|
return parse_xml_submission(xml_content)
|
||||||
|
|
||||||
|
|
||||||
def eml_to_semap(path: str) -> SemapDocument:
|
def eml_to_semap(xml_mail: XMLMailSubmission) -> SemapDocument:
|
||||||
submission = eml_parser(path)
|
submission = eml_parser(xml_mail)
|
||||||
semap_doc = SemapDocument(
|
semap_doc = SemapDocument(
|
||||||
# prof=Prof(name=submission.name, lastname=submission.lastname, email=submission.email),
|
# prof=Prof(name=submission.name, lastname=submission.lastname, email=submission.email),
|
||||||
apparat=Apparat(name=submission.app_name, subject=submission.subject),
|
apparat=Apparat(name=submission.app_name, subject=submission.subject),
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
from pyzotero import zotero
|
from pyzotero import zotero
|
||||||
|
|
||||||
@@ -12,11 +13,11 @@ class Creator:
|
|||||||
lastName: str = None
|
lastName: str = None
|
||||||
creatorType: str = "author"
|
creatorType: str = "author"
|
||||||
|
|
||||||
def from_dict(self, data: dict):
|
def from_dict(self, data: dict) -> None:
|
||||||
for key, value in data.items():
|
for key, value in data.items():
|
||||||
setattr(self, key, value)
|
setattr(self, key, value)
|
||||||
|
|
||||||
def from_string(self, data: str):
|
def from_string(self, data: str) -> "Creator":
|
||||||
if "," in data:
|
if "," in data:
|
||||||
self.firstName = data.split(",")[1]
|
self.firstName = data.split(",")[1]
|
||||||
self.lastName = data.split(",")[0]
|
self.lastName = data.split(",")[0]
|
||||||
@@ -56,7 +57,7 @@ class Book:
|
|||||||
rights: str = None
|
rights: str = None
|
||||||
extra: str = None
|
extra: str = None
|
||||||
|
|
||||||
def to_dict(self):
|
def to_dict(self) -> dict:
|
||||||
ret = {}
|
ret = {}
|
||||||
for key, value in self.__dict__.items():
|
for key, value in self.__dict__.items():
|
||||||
if value:
|
if value:
|
||||||
@@ -95,14 +96,14 @@ class BookSection:
|
|||||||
collections = list
|
collections = list
|
||||||
relations = dict
|
relations = dict
|
||||||
|
|
||||||
def to_dict(self):
|
def to_dict(self) -> dict:
|
||||||
ret = {}
|
ret = {}
|
||||||
for key, value in self.__dict__.items():
|
for key, value in self.__dict__.items():
|
||||||
if value:
|
if value:
|
||||||
ret[key] = value
|
ret[key] = value
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
def assign(self, book):
|
def assign(self, book) -> None:
|
||||||
for key, value in book.__dict__.items():
|
for key, value in book.__dict__.items():
|
||||||
if key in self.__dict__.keys():
|
if key in self.__dict__.keys():
|
||||||
try:
|
try:
|
||||||
@@ -142,14 +143,14 @@ class JournalArticle:
|
|||||||
collections = list
|
collections = list
|
||||||
relations = dict
|
relations = dict
|
||||||
|
|
||||||
def to_dict(self):
|
def to_dict(self) -> dict:
|
||||||
ret = {}
|
ret = {}
|
||||||
for key, value in self.__dict__.items():
|
for key, value in self.__dict__.items():
|
||||||
if value:
|
if value:
|
||||||
ret[key] = value
|
ret[key] = value
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
def assign(self, book: dict):
|
def assign(self, book: dict) -> None:
|
||||||
for key, value in book.__dict__.items():
|
for key, value in book.__dict__.items():
|
||||||
if key in self.__dict__.keys():
|
if key in self.__dict__.keys():
|
||||||
try:
|
try:
|
||||||
@@ -164,15 +165,15 @@ class ZoteroController:
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
if self.zoterocfg.library_id is None:
|
if self.zoterocfg.library_id is None:
|
||||||
return
|
return
|
||||||
self.zot = zotero.Zotero(
|
self.zot = zotero.Zotero( # type: ignore
|
||||||
self.zoterocfg.library_id,
|
self.zoterocfg.library_id,
|
||||||
self.zoterocfg.library_type,
|
self.zoterocfg.library_type,
|
||||||
self.zoterocfg.api_key,
|
self.zoterocfg.api_key,
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_books(self):
|
def get_books(self) -> list:
|
||||||
ret = []
|
ret = []
|
||||||
items = self.zot.top()
|
items = self.zot.top() # type: ignore
|
||||||
for item in items:
|
for item in items:
|
||||||
if item["data"]["itemType"] == "book":
|
if item["data"]["itemType"] == "book":
|
||||||
ret.append(item)
|
ret.append(item)
|
||||||
@@ -180,7 +181,7 @@ class ZoteroController:
|
|||||||
|
|
||||||
# create item in zotero
|
# create item in zotero
|
||||||
# item is a part of a book
|
# item is a part of a book
|
||||||
def __get_data(self, isbn):
|
def __get_data(self, isbn) -> dict:
|
||||||
web = WebRequest()
|
web = WebRequest()
|
||||||
web.get_ppn(isbn)
|
web.get_ppn(isbn)
|
||||||
data = web.get_data_elsa()
|
data = web.get_data_elsa()
|
||||||
@@ -190,7 +191,7 @@ class ZoteroController:
|
|||||||
return book
|
return book
|
||||||
|
|
||||||
# # #print(zot.item_template("bookSection"))
|
# # #print(zot.item_template("bookSection"))
|
||||||
def createBook(self, isbn):
|
def createBook(self, isbn) -> Book:
|
||||||
book = self.__get_data(isbn)
|
book = self.__get_data(isbn)
|
||||||
|
|
||||||
bookdata = Book()
|
bookdata = Book()
|
||||||
@@ -209,23 +210,23 @@ class ZoteroController:
|
|||||||
bookdata.creators = authors
|
bookdata.creators = authors
|
||||||
return bookdata
|
return bookdata
|
||||||
|
|
||||||
def createItem(self, item):
|
def createItem(self, item) -> Optional[str]:
|
||||||
resp = self.zot.create_items([item])
|
resp = self.zot.create_items([item]) # type: ignore
|
||||||
if "successful" in resp.keys():
|
if "successful" in resp.keys():
|
||||||
# #print(resp["successful"]["0"]["key"])
|
# #print(resp["successful"]["0"]["key"])
|
||||||
return resp["successful"]["0"]["key"]
|
return resp["successful"]["0"]["key"]
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def deleteItem(self, key):
|
def deleteItem(self, key) -> None:
|
||||||
items = self.zot.items()
|
items = self.zot.items()
|
||||||
for item in items:
|
for item in items:
|
||||||
if item["key"] == key:
|
if item["key"] == key:
|
||||||
self.zot.delete_item(item)
|
self.zot.delete_item(item) # type: ignore
|
||||||
# #print(item)
|
# #print(item)
|
||||||
break
|
break
|
||||||
|
|
||||||
def createHGSection(self, book: Book, data: dict):
|
def createHGSection(self, book: Book, data: dict) -> Optional[str]:
|
||||||
chapter = BookSection()
|
chapter = BookSection()
|
||||||
chapter.assign(book)
|
chapter.assign(book)
|
||||||
chapter.pages = data["pages"]
|
chapter.pages = data["pages"]
|
||||||
@@ -247,7 +248,7 @@ class ZoteroController:
|
|||||||
return self.createItem(chapter.to_dict())
|
return self.createItem(chapter.to_dict())
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def createBookSection(self, book: Book, data: dict):
|
def createBookSection(self, book: Book, data: dict) -> Optional[str]:
|
||||||
chapter = BookSection()
|
chapter = BookSection()
|
||||||
chapter.assign(book)
|
chapter.assign(book)
|
||||||
chapter.pages = data["pages"]
|
chapter.pages = data["pages"]
|
||||||
@@ -258,7 +259,7 @@ class ZoteroController:
|
|||||||
return self.createItem(chapter.to_dict())
|
return self.createItem(chapter.to_dict())
|
||||||
# chapter.creators
|
# chapter.creators
|
||||||
|
|
||||||
def createJournalArticle(self, journal, article):
|
def createJournalArticle(self, journal, article) -> Optional[str]:
|
||||||
# #print(type(article))
|
# #print(type(article))
|
||||||
journalarticle = JournalArticle()
|
journalarticle = JournalArticle()
|
||||||
journalarticle.assign(journal)
|
journalarticle.assign(journal)
|
||||||
@@ -279,8 +280,8 @@ class ZoteroController:
|
|||||||
|
|
||||||
return self.createItem(journalarticle.to_dict())
|
return self.createItem(journalarticle.to_dict())
|
||||||
|
|
||||||
def get_citation(self, item):
|
def get_citation(self, item) -> str:
|
||||||
title = self.zot.item(
|
title = self.zot.item( # type: ignore
|
||||||
item,
|
item,
|
||||||
content="bib",
|
content="bib",
|
||||||
style="deutsche-gesellschaft-fur-psychologie",
|
style="deutsche-gesellschaft-fur-psychologie",
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<!DOCTYPE TS>
|
|
||||||
<TS version="2.1">
|
|
||||||
</TS>
|
|
||||||
@@ -110,10 +110,10 @@ class DocumentPrintDialog(QtWidgets.QDialog, Ui_Dialog):
|
|||||||
def on_pushButton_clicked(self):
|
def on_pushButton_clicked(self):
|
||||||
apparats: list[tuple[int, str]] = []
|
apparats: list[tuple[int, str]] = []
|
||||||
apps = self.db.getAllAparats(0)
|
apps = self.db.getAllAparats(0)
|
||||||
apps = natsorted(apps, key=lambda x: x[4], reverse=True)
|
apps = natsorted(apps, key=lambda x: x.appnr, reverse=True)
|
||||||
for app in apps:
|
for app in apps:
|
||||||
prof = self.db.getProfById(app[2])
|
prof = self.db.getProfById(app.prof_id)
|
||||||
data = (app[4], f"{prof.lastname} ({app[1]})")
|
data = (app.appnr, f"{prof.lastname} ({app.name})")
|
||||||
apparats.append(data)
|
apparats.append(data)
|
||||||
SemesterDocument(
|
SemesterDocument(
|
||||||
semester=self.semester.value,
|
semester=self.semester.value,
|
||||||
|
|||||||
@@ -1349,7 +1349,7 @@
|
|||||||
</property>
|
</property>
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string>Die Apparatsdetails werden aus dem Dokument gelesen und eingetragen
|
<string>Die Apparatsdetails werden aus dem Dokument gelesen und eingetragen
|
||||||
Einige Angaben müssen ggf angepasst werden</string>
|
Die gewünschten Medien werden automatisch in die Medienliste eingetragen, evtl. unvollständig, da eBooks nicht erfasst werden könnenEinige Angaben müssen ggf angepasst werden</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Daten aus Dokument
|
<string>Daten aus Dokument
|
||||||
@@ -1618,28 +1618,31 @@ Einige Angaben müssen ggf angepasst werden</string>
|
|||||||
<attribute name="title">
|
<attribute name="title">
|
||||||
<string>Admin</string>
|
<string>Admin</string>
|
||||||
</attribute>
|
</attribute>
|
||||||
<widget class="QLabel" name="label_21">
|
<widget class="QFrame" name="frame">
|
||||||
<property name="geometry">
|
<property name="geometry">
|
||||||
<rect>
|
<rect>
|
||||||
<x>10</x>
|
<x>0</x>
|
||||||
<y>30</y>
|
<y>0</y>
|
||||||
<width>47</width>
|
<width>1251</width>
|
||||||
<height>22</height>
|
<height>711</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="frameShape">
|
||||||
|
<enum>QFrame::StyledPanel</enum>
|
||||||
|
</property>
|
||||||
|
<property name="frameShadow">
|
||||||
|
<enum>QFrame::Raised</enum>
|
||||||
|
</property>
|
||||||
|
<layout class="QFormLayout" name="formLayout_2">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="label_21">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Aktion:</string>
|
<string>Aktion:</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
<widget class="QComboBox" name="select_action_box">
|
<widget class="QComboBox" name="select_action_box">
|
||||||
<property name="geometry">
|
|
||||||
<rect>
|
|
||||||
<x>60</x>
|
|
||||||
<y>30</y>
|
|
||||||
<width>181</width>
|
|
||||||
<height>22</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
|
||||||
<item>
|
<item>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Nutzer anlegen</string>
|
<string>Nutzer anlegen</string>
|
||||||
@@ -1661,15 +1664,9 @@ Einige Angaben müssen ggf angepasst werden</string>
|
|||||||
</property>
|
</property>
|
||||||
</item>
|
</item>
|
||||||
</widget>
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
<widget class="QGroupBox" name="admin_action">
|
<widget class="QGroupBox" name="admin_action">
|
||||||
<property name="geometry">
|
|
||||||
<rect>
|
|
||||||
<x>10</x>
|
|
||||||
<y>70</y>
|
|
||||||
<width>570</width>
|
|
||||||
<height>291</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
|
||||||
<property name="font">
|
<property name="font">
|
||||||
<font>
|
<font>
|
||||||
<bold>false</bold>
|
<bold>false</bold>
|
||||||
@@ -1685,6 +1682,9 @@ Einige Angaben müssen ggf angepasst werden</string>
|
|||||||
<bool>false</bool>
|
<bool>false</bool>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
</widget>
|
</widget>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
|||||||
@@ -638,24 +638,37 @@ class Ui_MainWindow(object):
|
|||||||
self.tabWidget.addTab(self.elsatab, "")
|
self.tabWidget.addTab(self.elsatab, "")
|
||||||
self.admin = QWidget()
|
self.admin = QWidget()
|
||||||
self.admin.setObjectName(u"admin")
|
self.admin.setObjectName(u"admin")
|
||||||
self.label_21 = QLabel(self.admin)
|
self.frame = QFrame(self.admin)
|
||||||
|
self.frame.setObjectName(u"frame")
|
||||||
|
self.frame.setGeometry(QRect(0, 0, 1251, 711))
|
||||||
|
self.frame.setFrameShape(QFrame.StyledPanel)
|
||||||
|
self.frame.setFrameShadow(QFrame.Raised)
|
||||||
|
self.formLayout_2 = QFormLayout(self.frame)
|
||||||
|
self.formLayout_2.setObjectName(u"formLayout_2")
|
||||||
|
self.label_21 = QLabel(self.frame)
|
||||||
self.label_21.setObjectName(u"label_21")
|
self.label_21.setObjectName(u"label_21")
|
||||||
self.label_21.setGeometry(QRect(10, 30, 47, 22))
|
|
||||||
self.select_action_box = QComboBox(self.admin)
|
self.formLayout_2.setWidget(0, QFormLayout.ItemRole.LabelRole, self.label_21)
|
||||||
|
|
||||||
|
self.select_action_box = QComboBox(self.frame)
|
||||||
self.select_action_box.addItem("")
|
self.select_action_box.addItem("")
|
||||||
self.select_action_box.addItem("")
|
self.select_action_box.addItem("")
|
||||||
self.select_action_box.addItem("")
|
self.select_action_box.addItem("")
|
||||||
self.select_action_box.addItem("")
|
self.select_action_box.addItem("")
|
||||||
self.select_action_box.setObjectName(u"select_action_box")
|
self.select_action_box.setObjectName(u"select_action_box")
|
||||||
self.select_action_box.setGeometry(QRect(60, 30, 181, 22))
|
|
||||||
self.admin_action = QGroupBox(self.admin)
|
self.formLayout_2.setWidget(0, QFormLayout.ItemRole.FieldRole, self.select_action_box)
|
||||||
|
|
||||||
|
self.admin_action = QGroupBox(self.frame)
|
||||||
self.admin_action.setObjectName(u"admin_action")
|
self.admin_action.setObjectName(u"admin_action")
|
||||||
self.admin_action.setGeometry(QRect(10, 70, 570, 291))
|
|
||||||
font5 = QFont()
|
font5 = QFont()
|
||||||
font5.setBold(False)
|
font5.setBold(False)
|
||||||
self.admin_action.setFont(font5)
|
self.admin_action.setFont(font5)
|
||||||
self.admin_action.setFlat(True)
|
self.admin_action.setFlat(True)
|
||||||
self.admin_action.setCheckable(False)
|
self.admin_action.setCheckable(False)
|
||||||
|
|
||||||
|
self.formLayout_2.setWidget(1, QFormLayout.ItemRole.FieldRole, self.admin_action)
|
||||||
|
|
||||||
self.tabWidget.addTab(self.admin, "")
|
self.tabWidget.addTab(self.admin, "")
|
||||||
|
|
||||||
self.gridLayout.addWidget(self.tabWidget, 0, 0, 1, 1)
|
self.gridLayout.addWidget(self.tabWidget, 0, 0, 1, 1)
|
||||||
@@ -963,7 +976,7 @@ class Ui_MainWindow(object):
|
|||||||
" hinzuf\u00fcgen", None))
|
" hinzuf\u00fcgen", None))
|
||||||
#if QT_CONFIG(tooltip)
|
#if QT_CONFIG(tooltip)
|
||||||
self.btn_extract_data_from_document.setToolTip(QCoreApplication.translate("MainWindow", u"Die Apparatsdetails werden aus dem Dokument gelesen und eingetragen\n"
|
self.btn_extract_data_from_document.setToolTip(QCoreApplication.translate("MainWindow", u"Die Apparatsdetails werden aus dem Dokument gelesen und eingetragen\n"
|
||||||
"Einige Angaben m\u00fcssen ggf angepasst werden", None))
|
"Die gew\u00fcnschten Medien werden automatisch in die Medienliste eingetragen, evtl. unvollst\u00e4ndig, da eBooks nicht erfasst werden k\u00f6nnenEinige Angaben m\u00fcssen ggf angepasst werden", None))
|
||||||
#endif // QT_CONFIG(tooltip)
|
#endif // QT_CONFIG(tooltip)
|
||||||
self.btn_extract_data_from_document.setText(QCoreApplication.translate("MainWindow", u"Daten aus Dokument\n"
|
self.btn_extract_data_from_document.setText(QCoreApplication.translate("MainWindow", u"Daten aus Dokument\n"
|
||||||
"\u00fcbernehmen", None))
|
"\u00fcbernehmen", None))
|
||||||
|
|||||||
@@ -373,7 +373,7 @@ class Ui(QtWidgets.QMainWindow, Ui_Semesterapparat):
|
|||||||
self.setWidget(UpdateSignatures())
|
self.setWidget(UpdateSignatures())
|
||||||
self.admin_action.setTitle("Medien bearbeiten")
|
self.admin_action.setTitle("Medien bearbeiten")
|
||||||
else:
|
else:
|
||||||
self.hideWidget()
|
# self.hideWidget()
|
||||||
self.admin_action.setTitle("")
|
self.admin_action.setTitle("")
|
||||||
|
|
||||||
def toggleButton(self, button: QtWidgets.QCheckBox):
|
def toggleButton(self, button: QtWidgets.QCheckBox):
|
||||||
@@ -1224,12 +1224,14 @@ class Ui(QtWidgets.QMainWindow, Ui_Semesterapparat):
|
|||||||
signatures = csv_to_list(file)
|
signatures = csv_to_list(file)
|
||||||
# add the data to the database
|
# add the data to the database
|
||||||
return signatures
|
return signatures
|
||||||
if file_type == "docx":
|
if file_type in ("docx", "doc"):
|
||||||
data = word_to_semap(file)
|
data = word_to_semap(file)
|
||||||
log.info("Converted data from semap file")
|
log.info("Converted data from semap file")
|
||||||
log.debug("Got the data: {}", data)
|
log.debug("Got the data: {}", data)
|
||||||
|
|
||||||
return data
|
return data
|
||||||
|
else:
|
||||||
|
raise ValueError("Dateityp wird nicht unterstützt")
|
||||||
|
|
||||||
def import_data_from_document(self):
|
def import_data_from_document(self):
|
||||||
global valid_input
|
global valid_input
|
||||||
@@ -1241,6 +1243,7 @@ class Ui(QtWidgets.QMainWindow, Ui_Semesterapparat):
|
|||||||
|
|
||||||
self.prof_mail.setText(data.mail)
|
self.prof_mail.setText(data.mail)
|
||||||
self.prof_tel_nr.setText(str(data.phoneNumber).replace("-", ""))
|
self.prof_tel_nr.setText(str(data.phoneNumber).replace("-", ""))
|
||||||
|
self.app_name.setText(data.title)
|
||||||
if len(data.title_suggestions) > 0:
|
if len(data.title_suggestions) > 0:
|
||||||
# create a dialog that has a dropdown with the suggestions, and oc and cancel button. on ok return the selected text and set it as title
|
# create a dialog that has a dropdown with the suggestions, and oc and cancel button. on ok return the selected text and set it as title
|
||||||
dialog = QtWidgets.QDialog()
|
dialog = QtWidgets.QDialog()
|
||||||
@@ -1271,6 +1274,7 @@ class Ui(QtWidgets.QMainWindow, Ui_Semesterapparat):
|
|||||||
self.app_name.setText(dropdown.currentText().split(" [")[0].strip())
|
self.app_name.setText(dropdown.currentText().split(" [")[0].strip())
|
||||||
else:
|
else:
|
||||||
self.app_name.setText("CHANGEME")
|
self.app_name.setText("CHANGEME")
|
||||||
|
|
||||||
# self.app_name.setText(data.title)
|
# self.app_name.setText(data.title)
|
||||||
subjects = self.db.getSubjects()
|
subjects = self.db.getSubjects()
|
||||||
subjects = [subject[1] for subject in subjects]
|
subjects = [subject[1] for subject in subjects]
|
||||||
@@ -1287,8 +1291,10 @@ class Ui(QtWidgets.QMainWindow, Ui_Semesterapparat):
|
|||||||
if data.eternal:
|
if data.eternal:
|
||||||
self.check_eternal_app.setChecked(True)
|
self.check_eternal_app.setChecked(True)
|
||||||
self.validate_semester()
|
self.validate_semester()
|
||||||
|
if data.books != []:
|
||||||
|
self.btn_check_file_threaded(data)
|
||||||
|
|
||||||
def btn_check_file_threaded(self):
|
def btn_check_file_threaded(self, c_document: Optional[SemapDocument] = None):
|
||||||
for runner in self.bookGrabber:
|
for runner in self.bookGrabber:
|
||||||
if not runner.isRunning():
|
if not runner.isRunning():
|
||||||
runner.deleteLater()
|
runner.deleteLater()
|
||||||
@@ -1335,6 +1341,9 @@ class Ui(QtWidgets.QMainWindow, Ui_Semesterapparat):
|
|||||||
prof_id = self.db.getProfId(self.profdata)
|
prof_id = self.db.getProfId(self.profdata)
|
||||||
|
|
||||||
# log.debug("Prof ID is None", prof_id)
|
# log.debug("Prof ID is None", prof_id)
|
||||||
|
document = None
|
||||||
|
|
||||||
|
if c_document is None or not isinstance(c_document, SemapDocument):
|
||||||
document = self.extract_document_data()
|
document = self.extract_document_data()
|
||||||
if document is None:
|
if document is None:
|
||||||
log.error("Document is None")
|
log.error("Document is None")
|
||||||
@@ -1410,7 +1419,7 @@ class Ui(QtWidgets.QMainWindow, Ui_Semesterapparat):
|
|||||||
)
|
)
|
||||||
prof.title = self.prof_title.text()
|
prof.title = self.prof_title.text()
|
||||||
apparat = Apparat(
|
apparat = Apparat(
|
||||||
appnr=self.active_apparat,
|
appnr=int(self.drpdwn_app_nr.currentText()),
|
||||||
name=self.app_name.text(),
|
name=self.app_name.text(),
|
||||||
created_semester=self.generateSemester(),
|
created_semester=self.generateSemester(),
|
||||||
eternal=1 if self.check_eternal_app.isChecked() else 0,
|
eternal=1 if self.check_eternal_app.isChecked() else 0,
|
||||||
@@ -1433,7 +1442,8 @@ class Ui(QtWidgets.QMainWindow, Ui_Semesterapparat):
|
|||||||
return
|
return
|
||||||
appdata = self.db.getAllAparats()
|
appdata = self.db.getAllAparats()
|
||||||
# merge self.appdata and appdata, remove duplicates
|
# merge self.appdata and appdata, remove duplicates
|
||||||
self.apparats = list(set(self.apparats + appdata))
|
|
||||||
|
self.apparats = self.__uniques(self.apparats, appdata)
|
||||||
self.apparats = natsorted(self.apparats, key=lambda x: x[4], reverse=True)
|
self.apparats = natsorted(self.apparats, key=lambda x: x[4], reverse=True)
|
||||||
|
|
||||||
self.update_apparat_list()
|
self.update_apparat_list()
|
||||||
@@ -1452,6 +1462,16 @@ class Ui(QtWidgets.QMainWindow, Ui_Semesterapparat):
|
|||||||
self.__clear_fields()
|
self.__clear_fields()
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def __uniques(self, list1, list2):
|
||||||
|
seen = set()
|
||||||
|
unique_list = []
|
||||||
|
for item in list1 + list2:
|
||||||
|
identifier = (item.appnr, item.name)
|
||||||
|
if identifier not in seen:
|
||||||
|
seen.add(identifier)
|
||||||
|
unique_list.append(item)
|
||||||
|
return unique_list
|
||||||
|
|
||||||
def send_mail_preview(self):
|
def send_mail_preview(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ class FilePicker:
|
|||||||
files, _ = filepicker.getOpenFileNames(
|
files, _ = filepicker.getOpenFileNames(
|
||||||
caption="Open file",
|
caption="Open file",
|
||||||
dir=self.last_path,
|
dir=self.last_path,
|
||||||
filter="Unterstützte Dateien (*.docx *.csv *.eml );;Word (*.docx);;CSV Files (*.csv);;Mail (*.eml)",
|
filter="Unterstützte Dateien (*.docx *.doc *.csv *.eml );;Word (*.docx *.doc);;CSV Files (*.csv);;Mail (*.eml)",
|
||||||
)
|
)
|
||||||
if files:
|
if files:
|
||||||
self.last_path = files[0]
|
self.last_path = files[0]
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
def create_blob(file: str):
|
def create_blob(file: str) -> bytes:
|
||||||
"""
|
"""
|
||||||
Creates a blob from a file.
|
Creates a blob from a file.
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import os
|
|
||||||
from pyramid.config import Configurator
|
|
||||||
from wsgiref.simple_server import WSGIRequestHandler
|
|
||||||
from src import LOG_DIR
|
|
||||||
import logging
|
import logging
|
||||||
|
import os
|
||||||
|
from wsgiref.simple_server import WSGIRequestHandler
|
||||||
|
|
||||||
|
from pyramid.config import Configurator
|
||||||
|
|
||||||
|
from src import LOG_DIR
|
||||||
|
|
||||||
log_path = os.path.join(LOG_DIR, "web_documentation.log")
|
log_path = os.path.join(LOG_DIR, "web_documentation.log")
|
||||||
|
|
||||||
@@ -31,7 +32,7 @@ class QuietHandler(WSGIRequestHandler):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def website():
|
def website() -> object:
|
||||||
config = Configurator()
|
config = Configurator()
|
||||||
|
|
||||||
# Set up static file serving from the 'site/' directory
|
# Set up static file serving from the 'site/' directory
|
||||||
@@ -40,4 +41,4 @@ def website():
|
|||||||
)
|
)
|
||||||
|
|
||||||
app = config.make_wsgi_app()
|
app = config.make_wsgi_app()
|
||||||
return app
|
return app # type: ignore
|
||||||
|
|||||||
@@ -2,9 +2,9 @@ import pickle
|
|||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
|
|
||||||
def load_pickle(data: Any):
|
def load_pickle(data: Any) -> Any:
|
||||||
return pickle.loads(data)
|
return pickle.loads(data)
|
||||||
|
|
||||||
|
|
||||||
def dump_pickle(data: Any):
|
def dump_pickle(data: Any) -> bytes:
|
||||||
return pickle.dumps(data)
|
return pickle.dumps(data)
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ logger = log
|
|||||||
font = "Cascadia Mono"
|
font = "Cascadia Mono"
|
||||||
|
|
||||||
|
|
||||||
def print_document(file: str):
|
def print_document(file: str) -> None:
|
||||||
# send document to printer as attachment of email
|
# send document to printer as attachment of email
|
||||||
import smtplib
|
import smtplib
|
||||||
from email.mime.application import MIMEApplication
|
from email.mime.application import MIMEApplication
|
||||||
@@ -98,7 +98,7 @@ class SemesterDocument:
|
|||||||
self.filename = filename
|
self.filename = filename
|
||||||
if full:
|
if full:
|
||||||
log.info("Full document generation")
|
log.info("Full document generation")
|
||||||
self.cleanup()
|
self.cleanup
|
||||||
log.info("Cleanup done")
|
log.info("Cleanup done")
|
||||||
self.make_document()
|
self.make_document()
|
||||||
log.info("Document created")
|
log.info("Document created")
|
||||||
@@ -221,15 +221,15 @@ class SemesterDocument:
|
|||||||
|
|
||||||
self.create_sorted_table()
|
self.create_sorted_table()
|
||||||
|
|
||||||
def save_document(self, name):
|
def save_document(self, name: str) -> None:
|
||||||
# Save the document
|
# Save the document
|
||||||
self.doc.save(name)
|
self.doc.save(name)
|
||||||
|
|
||||||
def create_pdf(self):
|
def create_pdf(self) -> None:
|
||||||
# Save the document
|
# Save the document
|
||||||
import comtypes.client
|
import comtypes.client
|
||||||
|
|
||||||
word = comtypes.client.CreateObject("Word.Application")
|
word = comtypes.client.CreateObject("Word.Application") # type: ignore
|
||||||
self.save_document(self.filename + ".docx")
|
self.save_document(self.filename + ".docx")
|
||||||
docpath = os.path.abspath(self.filename + ".docx")
|
docpath = os.path.abspath(self.filename + ".docx")
|
||||||
doc = word.Documents.Open(docpath)
|
doc = word.Documents.Open(docpath)
|
||||||
@@ -240,13 +240,13 @@ class SemesterDocument:
|
|||||||
log.debug("PDF saved")
|
log.debug("PDF saved")
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def cleanup(self):
|
def cleanup(self) -> None:
|
||||||
if os.path.exists(f"{self.filename}.docx"):
|
if os.path.exists(f"{self.filename}.docx"):
|
||||||
os.remove(f"{self.filename}.docx")
|
os.remove(f"{self.filename}.docx")
|
||||||
os.remove(f"{self.filename}.pdf")
|
os.remove(f"{self.filename}.pdf")
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def send(self):
|
def send(self) -> None:
|
||||||
print_document(self.filename + ".pdf")
|
print_document(self.filename + ".pdf")
|
||||||
log.debug("Document sent to printer")
|
log.debug("Document sent to printer")
|
||||||
|
|
||||||
@@ -309,11 +309,11 @@ class SemapSchilder:
|
|||||||
self.doc.save(f"{self.filename}.docx")
|
self.doc.save(f"{self.filename}.docx")
|
||||||
log.debug(f"Document saved as {self.filename}.docx")
|
log.debug(f"Document saved as {self.filename}.docx")
|
||||||
|
|
||||||
def create_pdf(self):
|
def create_pdf(self) -> None:
|
||||||
# Save the document
|
# Save the document
|
||||||
import comtypes.client
|
import comtypes.client
|
||||||
|
|
||||||
word = comtypes.client.CreateObject("Word.Application")
|
word = comtypes.client.CreateObject("Word.Application") # type: ignore
|
||||||
self.save_document()
|
self.save_document()
|
||||||
docpath = os.path.abspath(f"{self.filename}.docx")
|
docpath = os.path.abspath(f"{self.filename}.docx")
|
||||||
doc = word.Documents.Open(docpath)
|
doc = word.Documents.Open(docpath)
|
||||||
@@ -323,14 +323,14 @@ class SemapSchilder:
|
|||||||
word.Quit()
|
word.Quit()
|
||||||
log.debug("PDF saved")
|
log.debug("PDF saved")
|
||||||
|
|
||||||
def cleanup(self):
|
def cleanup(self) -> None:
|
||||||
if os.path.exists(f"{self.filename}.docx"):
|
if os.path.exists(f"{self.filename}.docx"):
|
||||||
os.remove(f"{self.filename}.docx")
|
os.remove(f"{self.filename}.docx")
|
||||||
if os.path.exists(f"{self.filename}.pdf"):
|
if os.path.exists(f"{self.filename}.pdf"):
|
||||||
os.remove(f"{self.filename}.pdf")
|
os.remove(f"{self.filename}.pdf")
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def send(self):
|
def send(self) -> None:
|
||||||
print_document(self.filename + ".pdf")
|
print_document(self.filename + ".pdf")
|
||||||
log.debug("Document sent to printer")
|
log.debug("Document sent to printer")
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user