chgksuite 0.25.1__py3-none-any.whl → 0.26.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- chgksuite/cli.py +292 -31
- chgksuite/composer/composer_common.py +2 -0
- chgksuite/composer/docx.py +520 -292
- chgksuite/composer/pptx.py +16 -4
- chgksuite/composer/telegram.py +68 -46
- chgksuite/handouter/__init__.py +0 -0
- chgksuite/handouter/gen.py +143 -0
- chgksuite/handouter/installer.py +245 -0
- chgksuite/handouter/pack.py +79 -0
- chgksuite/handouter/runner.py +237 -0
- chgksuite/handouter/tex_internals.py +47 -0
- chgksuite/handouter/utils.py +88 -0
- chgksuite/parser.py +210 -17
- chgksuite/resources/regexes_by.json +1 -1
- chgksuite/resources/regexes_en.json +1 -1
- chgksuite/resources/regexes_kz_cyr.json +1 -1
- chgksuite/resources/regexes_ru.json +2 -2
- chgksuite/resources/regexes_sr.json +1 -1
- chgksuite/resources/regexes_ua.json +1 -1
- chgksuite/resources/regexes_uz_cyr.json +1 -1
- chgksuite/version.py +1 -1
- {chgksuite-0.25.1.dist-info → chgksuite-0.26.0.dist-info}/METADATA +4 -2
- {chgksuite-0.25.1.dist-info → chgksuite-0.26.0.dist-info}/RECORD +27 -21
- {chgksuite-0.25.1.dist-info → chgksuite-0.26.0.dist-info}/WHEEL +1 -1
- chgksuite/resources/template_shorin.pptx +0 -0
- {chgksuite-0.25.1.dist-info → chgksuite-0.26.0.dist-info}/entry_points.txt +0 -0
- {chgksuite-0.25.1.dist-info → chgksuite-0.26.0.dist-info}/licenses/LICENSE +0 -0
- {chgksuite-0.25.1.dist-info → chgksuite-0.26.0.dist-info}/top_level.txt +0 -0
chgksuite/parser.py
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import base64
|
|
4
4
|
import codecs
|
|
5
5
|
import datetime
|
|
6
|
+
import hashlib
|
|
6
7
|
import itertools
|
|
7
8
|
import json
|
|
8
9
|
import os
|
|
@@ -13,12 +14,14 @@ import subprocess
|
|
|
13
14
|
import sys
|
|
14
15
|
import tempfile
|
|
15
16
|
import urllib
|
|
17
|
+
import time
|
|
16
18
|
|
|
17
19
|
import bs4
|
|
18
20
|
import chardet
|
|
19
21
|
import dashtable
|
|
20
22
|
import mammoth
|
|
21
23
|
import pypandoc
|
|
24
|
+
import requests
|
|
22
25
|
import toml
|
|
23
26
|
from bs4 import BeautifulSoup
|
|
24
27
|
from parse import parse
|
|
@@ -26,11 +29,11 @@ from parse import parse
|
|
|
26
29
|
import chgksuite.typotools as typotools
|
|
27
30
|
from chgksuite.common import (
|
|
28
31
|
QUESTION_LABELS,
|
|
29
|
-
DefaultArgs,
|
|
30
32
|
DefaultNamespace,
|
|
31
33
|
DummyLogger,
|
|
32
34
|
check_question,
|
|
33
35
|
compose_4s,
|
|
36
|
+
get_chgksuite_dir,
|
|
34
37
|
get_lastdir,
|
|
35
38
|
init_logger,
|
|
36
39
|
load_settings,
|
|
@@ -40,6 +43,7 @@ from chgksuite.common import (
|
|
|
40
43
|
from chgksuite.composer import gui_compose
|
|
41
44
|
from chgksuite.composer.composer_common import make_filename
|
|
42
45
|
from chgksuite.parser_db import chgk_parse_db
|
|
46
|
+
from chgksuite.typotools import re_url
|
|
43
47
|
from chgksuite.typotools import remove_excessive_whitespace as rew
|
|
44
48
|
|
|
45
49
|
ENC = sys.stdout.encoding or "utf8"
|
|
@@ -91,10 +95,23 @@ class ChgkParser:
|
|
|
91
95
|
BADNEXTFIELDS = set(["question", "answer"])
|
|
92
96
|
RE_NUM = re.compile("^([0-9]+)\\.?$")
|
|
93
97
|
RE_NUM_START = re.compile("^([0-9]+)\\.")
|
|
98
|
+
ZERO_PREFIXES = ("Нулевой вопрос", "Разминочный вопрос")
|
|
99
|
+
TOUR_NUMBERS_AS_WORDS = (
|
|
100
|
+
"Первый",
|
|
101
|
+
"Второй",
|
|
102
|
+
"Третий",
|
|
103
|
+
"Четвертый",
|
|
104
|
+
"Пятый",
|
|
105
|
+
"Шестой",
|
|
106
|
+
"Седьмой",
|
|
107
|
+
"Восьмой",
|
|
108
|
+
"Девятый",
|
|
109
|
+
"Десятый",
|
|
110
|
+
)
|
|
94
111
|
|
|
95
112
|
def __init__(self, defaultauthor=None, args=None, logger=None):
|
|
96
113
|
self.defaultauthor = defaultauthor
|
|
97
|
-
args = args or
|
|
114
|
+
args = args or DefaultNamespace()
|
|
98
115
|
self.regexes = load_regexes(args.regexes)
|
|
99
116
|
self.logger = logger or init_logger("parser")
|
|
100
117
|
self.args = args
|
|
@@ -108,6 +125,148 @@ class ChgkParser:
|
|
|
108
125
|
if self.args.language == "en":
|
|
109
126
|
self.args.typography_quotes = "off"
|
|
110
127
|
|
|
128
|
+
def _setup_image_cache(self):
|
|
129
|
+
"""Setup image download cache directory and load existing cache"""
|
|
130
|
+
if not hasattr(self, "_image_cache"):
|
|
131
|
+
self.image_cache_dir = os.path.join(
|
|
132
|
+
get_chgksuite_dir(), "downloaded_images"
|
|
133
|
+
)
|
|
134
|
+
os.makedirs(self.image_cache_dir, exist_ok=True)
|
|
135
|
+
|
|
136
|
+
self.image_cache_file = os.path.join(
|
|
137
|
+
get_chgksuite_dir(), "image_download_cache.json"
|
|
138
|
+
)
|
|
139
|
+
if os.path.isfile(self.image_cache_file):
|
|
140
|
+
try:
|
|
141
|
+
with open(self.image_cache_file, encoding="utf8") as f:
|
|
142
|
+
self._image_cache = json.load(f)
|
|
143
|
+
except (json.JSONDecodeError, OSError):
|
|
144
|
+
self._image_cache = {}
|
|
145
|
+
else:
|
|
146
|
+
self._image_cache = {}
|
|
147
|
+
|
|
148
|
+
def _download_image(self, url):
|
|
149
|
+
"""Download image from URL and return local filename"""
|
|
150
|
+
self._setup_image_cache()
|
|
151
|
+
url = url.replace("\\", "")
|
|
152
|
+
|
|
153
|
+
# Check cache first
|
|
154
|
+
url_hash = hashlib.sha256(url.encode("utf-8")).hexdigest()[:20]
|
|
155
|
+
if url_hash in self._image_cache:
|
|
156
|
+
cached_filename = self._image_cache[url_hash]
|
|
157
|
+
cached_path = os.path.join(self.image_cache_dir, cached_filename)
|
|
158
|
+
if os.path.isfile(cached_path):
|
|
159
|
+
return cached_path
|
|
160
|
+
|
|
161
|
+
# Determine file extension
|
|
162
|
+
parsed_url = urllib.parse.urlparse(url)
|
|
163
|
+
path_lower = parsed_url.path.lower()
|
|
164
|
+
ext = None
|
|
165
|
+
for image_ext in [".jpg", ".jpeg", ".png", ".webp", ".gif", ".bmp", ".svg"]:
|
|
166
|
+
if path_lower.endswith(image_ext):
|
|
167
|
+
ext = image_ext
|
|
168
|
+
break
|
|
169
|
+
|
|
170
|
+
if not ext:
|
|
171
|
+
# Try to guess from URL structure
|
|
172
|
+
if any(
|
|
173
|
+
img_ext in path_lower
|
|
174
|
+
for img_ext in [
|
|
175
|
+
".jpg",
|
|
176
|
+
".jpeg",
|
|
177
|
+
".png",
|
|
178
|
+
".webp",
|
|
179
|
+
".gif",
|
|
180
|
+
".bmp",
|
|
181
|
+
".svg",
|
|
182
|
+
]
|
|
183
|
+
):
|
|
184
|
+
for image_ext in [
|
|
185
|
+
".jpg",
|
|
186
|
+
".jpeg",
|
|
187
|
+
".png",
|
|
188
|
+
".webp",
|
|
189
|
+
".gif",
|
|
190
|
+
".bmp",
|
|
191
|
+
".svg",
|
|
192
|
+
]:
|
|
193
|
+
if image_ext in path_lower:
|
|
194
|
+
ext = image_ext
|
|
195
|
+
break
|
|
196
|
+
else:
|
|
197
|
+
ext = ".jpg" # Default extension
|
|
198
|
+
|
|
199
|
+
filename = url_hash + ext
|
|
200
|
+
filepath = os.path.join(self.image_cache_dir, filename)
|
|
201
|
+
|
|
202
|
+
try:
|
|
203
|
+
self.logger.info(f"Downloading image from {url}")
|
|
204
|
+
headers = {
|
|
205
|
+
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36",
|
|
206
|
+
"Accept": "image/png,image/jpeg,image/webp,image/gif,image/*,*/*;q=0.8",
|
|
207
|
+
"Accept-Language": "en-US,en;q=0.9",
|
|
208
|
+
"Accept-Encoding": "gzip, deflate, br",
|
|
209
|
+
"Connection": "keep-alive",
|
|
210
|
+
"Upgrade-Insecure-Requests": "1",
|
|
211
|
+
}
|
|
212
|
+
response = requests.get(url, timeout=30, stream=True, headers=headers)
|
|
213
|
+
response.raise_for_status()
|
|
214
|
+
time.sleep(0.5) # rate limiting
|
|
215
|
+
|
|
216
|
+
with open(filepath, "wb") as f:
|
|
217
|
+
for chunk in response.iter_content(chunk_size=8192):
|
|
218
|
+
f.write(chunk)
|
|
219
|
+
|
|
220
|
+
# Update cache
|
|
221
|
+
self._image_cache[url_hash] = filename
|
|
222
|
+
with open(self.image_cache_file, "w", encoding="utf8") as f:
|
|
223
|
+
json.dump(self._image_cache, f, indent=2, sort_keys=True)
|
|
224
|
+
|
|
225
|
+
return filepath
|
|
226
|
+
|
|
227
|
+
except Exception as e:
|
|
228
|
+
self.logger.warning(f"Failed to download image from {url}: {e}")
|
|
229
|
+
return None
|
|
230
|
+
|
|
231
|
+
def _process_images_in_text(self, text):
|
|
232
|
+
"""Process text to find image URLs and replace them with local references"""
|
|
233
|
+
if not text or not getattr(self.args, "download_images", False):
|
|
234
|
+
return text
|
|
235
|
+
|
|
236
|
+
if isinstance(text, list):
|
|
237
|
+
return [self._process_images_in_text(item) for item in text]
|
|
238
|
+
|
|
239
|
+
if not isinstance(text, str):
|
|
240
|
+
return text
|
|
241
|
+
|
|
242
|
+
# Find all URLs in the text
|
|
243
|
+
for match in re_url.finditer(text):
|
|
244
|
+
url = match.group(0)
|
|
245
|
+
url_lower = url.lower()
|
|
246
|
+
|
|
247
|
+
# Check if it's a direct image URL
|
|
248
|
+
if any(
|
|
249
|
+
url_lower.endswith(ext)
|
|
250
|
+
for ext in [".jpg", ".jpeg", ".png", ".webp", ".gif", ".bmp", ".svg"]
|
|
251
|
+
):
|
|
252
|
+
local_filename = self._download_image(url)
|
|
253
|
+
if local_filename:
|
|
254
|
+
# Replace URL with chgksuite image syntax
|
|
255
|
+
img_reference = f"(img {local_filename})"
|
|
256
|
+
text = text.replace(url, img_reference)
|
|
257
|
+
|
|
258
|
+
return text
|
|
259
|
+
|
|
260
|
+
def _process_question_images(self, question):
|
|
261
|
+
"""Process a question dict to download images from URLs"""
|
|
262
|
+
if not getattr(self.args, "download_images", False):
|
|
263
|
+
return
|
|
264
|
+
|
|
265
|
+
# Process all fields except 'source'
|
|
266
|
+
for field in question:
|
|
267
|
+
if field != "source":
|
|
268
|
+
question[field] = self._process_images_in_text(question[field])
|
|
269
|
+
|
|
111
270
|
def merge_to_previous(self, index):
|
|
112
271
|
target = index - 1
|
|
113
272
|
if self.structure[target][1]:
|
|
@@ -200,7 +359,7 @@ class ChgkParser:
|
|
|
200
359
|
@classmethod
|
|
201
360
|
def _replace(cls, obj, val, new_val):
|
|
202
361
|
if isinstance(obj, str):
|
|
203
|
-
return obj.replace(val, new_val)
|
|
362
|
+
return obj.replace(val, new_val).strip()
|
|
204
363
|
elif isinstance(obj, list):
|
|
205
364
|
for i, el in enumerate(obj):
|
|
206
365
|
obj[i] = cls._replace(el, val, new_val)
|
|
@@ -214,6 +373,11 @@ class ChgkParser:
|
|
|
214
373
|
for el in val:
|
|
215
374
|
self._get_strings(el, list_)
|
|
216
375
|
|
|
376
|
+
def _get_strings_joined(self, val):
|
|
377
|
+
strings = []
|
|
378
|
+
self._get_strings(val, strings)
|
|
379
|
+
return "\n".join(strings)
|
|
380
|
+
|
|
217
381
|
def _try_extract_field(self, question, k):
|
|
218
382
|
regex = self.regexes[k]
|
|
219
383
|
keys = sorted(question.keys())
|
|
@@ -255,14 +419,18 @@ class ChgkParser:
|
|
|
255
419
|
and not question["number"].strip()
|
|
256
420
|
):
|
|
257
421
|
question.pop("number")
|
|
422
|
+
question_str = self._get_strings_joined(question["question"])
|
|
423
|
+
for prefix in self.ZERO_PREFIXES:
|
|
424
|
+
if question_str.startswith(prefix):
|
|
425
|
+
question["question"] = self._replace(question["question"], prefix, "")
|
|
426
|
+
question["number"] = 0
|
|
427
|
+
question_str = self._get_strings_joined(question["question"])
|
|
258
428
|
for k in ("zachet", "nezachet", "source", "comment", "author"):
|
|
259
429
|
if k not in question:
|
|
260
430
|
self._try_extract_field(question, k)
|
|
261
|
-
|
|
262
|
-
self._get_strings(question["question"], strings)
|
|
263
|
-
strings = "\n".join(strings)
|
|
431
|
+
question_str = self._get_strings_joined(question["question"])
|
|
264
432
|
handout = self.labels["question_labels"]["handout"]
|
|
265
|
-
srch = re.search(f"{handout}:([ \n]+)\\[",
|
|
433
|
+
srch = re.search(f"{handout}:([ \n]+)\\[", question_str, flags=re.DOTALL)
|
|
266
434
|
if srch:
|
|
267
435
|
question["question"] = self._replace(
|
|
268
436
|
question["question"],
|
|
@@ -502,17 +670,30 @@ class ChgkParser:
|
|
|
502
670
|
if element[0] == "question":
|
|
503
671
|
try:
|
|
504
672
|
num = regexes["question"].search(element[1])
|
|
505
|
-
if num:
|
|
506
|
-
self.structure.insert(_id, ["number", num.group(
|
|
673
|
+
if num and num.group("number"):
|
|
674
|
+
self.structure.insert(_id, ["number", num.group("number")])
|
|
507
675
|
except Exception as e:
|
|
508
676
|
sys.stderr.write(
|
|
509
677
|
f"exception at line 445 of parser: {type(e)} {e}\n"
|
|
510
678
|
)
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
679
|
+
if (
|
|
680
|
+
not num
|
|
681
|
+
and ("нулевой вопрос" in element[1].lower())
|
|
682
|
+
or ("разминочный вопрос" in element[1].lower())
|
|
683
|
+
):
|
|
684
|
+
self.structure.insert(_id, ["number", "0"])
|
|
685
|
+
if element[0] == "question":
|
|
686
|
+
lines = element[1].split(SEP)
|
|
687
|
+
for i, line in enumerate(lines):
|
|
688
|
+
if regexes["question"].search(line):
|
|
689
|
+
lines[i] = regexes["question"].sub("", line, 1)
|
|
690
|
+
element[1] = SEP.join([x.strip() for x in lines if x.strip()])
|
|
691
|
+
else:
|
|
692
|
+
before_replacement = element[1]
|
|
693
|
+
element[1] = regexes[element[0]].sub("", element[1], 1)
|
|
514
694
|
if element[1].startswith(SEP):
|
|
515
695
|
element[1] = element[1][len(SEP) :]
|
|
696
|
+
# TODO: переделать корявую обработку авторки на нормальную
|
|
516
697
|
if element[0] == "author" and "авторка:" in before_replacement.lower():
|
|
517
698
|
element[1] = "!!Авторка" + element[1]
|
|
518
699
|
|
|
@@ -529,7 +710,7 @@ class ChgkParser:
|
|
|
529
710
|
try:
|
|
530
711
|
num = regexes["question"].search(element[1])
|
|
531
712
|
if num:
|
|
532
|
-
self.structure.insert(_id, ["number", num.group(
|
|
713
|
+
self.structure.insert(_id, ["number", num.group("number")])
|
|
533
714
|
except Exception as e:
|
|
534
715
|
sys.stderr.write(
|
|
535
716
|
f"exception at line 470 of parser: {type(e)} {e}\n"
|
|
@@ -537,7 +718,6 @@ class ChgkParser:
|
|
|
537
718
|
element[1] = regexes["question"].sub("", element[1])
|
|
538
719
|
|
|
539
720
|
# detect inner lists
|
|
540
|
-
|
|
541
721
|
mo = {
|
|
542
722
|
m for m in re.finditer(r"(\s+|^)(\d+)[\.\)]\s*(?!\d)", element[1], re.U)
|
|
543
723
|
}
|
|
@@ -608,11 +788,13 @@ class ChgkParser:
|
|
|
608
788
|
|
|
609
789
|
for element in self.structure:
|
|
610
790
|
if (
|
|
611
|
-
element[0]
|
|
791
|
+
element[0]
|
|
792
|
+
in set(["number", "tour", "tourrev", "question", "meta", "editor"])
|
|
612
793
|
and "question" in current_question
|
|
613
794
|
):
|
|
614
795
|
if self.defaultauthor and "author" not in current_question:
|
|
615
796
|
current_question["author"] = self.defaultauthor
|
|
797
|
+
self._process_question_images(current_question)
|
|
616
798
|
check_question(current_question, logger=logger)
|
|
617
799
|
final_structure.append(["Question", current_question])
|
|
618
800
|
current_question = {}
|
|
@@ -646,6 +828,7 @@ class ChgkParser:
|
|
|
646
828
|
if current_question != {}:
|
|
647
829
|
if self.defaultauthor and "author" not in current_question:
|
|
648
830
|
current_question["author"] = self.defaultauthor
|
|
831
|
+
self._process_question_images(current_question)
|
|
649
832
|
check_question(current_question, logger=logger)
|
|
650
833
|
final_structure.append(["Question", current_question])
|
|
651
834
|
|
|
@@ -682,9 +865,18 @@ class ChgkParser:
|
|
|
682
865
|
except ValueError:
|
|
683
866
|
pass
|
|
684
867
|
|
|
868
|
+
tour_cnt = 0
|
|
685
869
|
for i, element in enumerate(final_structure):
|
|
686
870
|
if element[0] == "Question":
|
|
687
871
|
self.postprocess_question(element[1])
|
|
872
|
+
elif element[0] == "tour" and self.args.tour_numbers_as_words == "on":
|
|
873
|
+
element[1] = f"{self.TOUR_NUMBERS_AS_WORDS[tour_cnt]} тур"
|
|
874
|
+
tour_cnt += 1
|
|
875
|
+
elif element[0] not in ["Question", "source"] and getattr(
|
|
876
|
+
self.args, "download_images", False
|
|
877
|
+
):
|
|
878
|
+
# Process images in metadata fields (excluding source)
|
|
879
|
+
element[1] = self._process_images_in_text(element[1])
|
|
688
880
|
|
|
689
881
|
if debug:
|
|
690
882
|
with codecs.open("debug_final.json", "w", "utf8") as f:
|
|
@@ -694,7 +886,8 @@ class ChgkParser:
|
|
|
694
886
|
|
|
695
887
|
def chgk_parse(text, defaultauthor=None, args=None):
|
|
696
888
|
parser = ChgkParser(defaultauthor=defaultauthor, args=args)
|
|
697
|
-
|
|
889
|
+
parsed = parser.parse(text)
|
|
890
|
+
return parsed
|
|
698
891
|
|
|
699
892
|
|
|
700
893
|
class UnknownEncodingException(Exception):
|
|
@@ -740,7 +933,7 @@ def ensure_line_breaks(tag):
|
|
|
740
933
|
|
|
741
934
|
def chgk_parse_docx(docxfile, defaultauthor="", args=None, logger=None):
|
|
742
935
|
logger = logger or DummyLogger()
|
|
743
|
-
args = args or
|
|
936
|
+
args = args or DefaultNamespace()
|
|
744
937
|
for_ol = {}
|
|
745
938
|
|
|
746
939
|
def get_number(tag):
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"tour": "^(#\\s+)?Т[Уу][Рр]\\s?№?\\s?([0-9IVXLCDM]*)([\\.:])?$",
|
|
3
3
|
"tourrev": "^([0-9IVXLCDM]+)\\s[Тт][Уу][Рр]([\\.:])?$",
|
|
4
|
-
"question": "П[Ыы][Тт][Аа][Нн][Ьь]?[Нн][Ее]\\s?[№N]?([0-9\\s]*)\\s?([\\.:]|\n|\r\n|$)",
|
|
4
|
+
"question": "П[Ыы][Тт][Аа][Нн][Ьь]?[Нн][Ее]\\s?[№N]?(?P<number>[0-9\\s]*)\\s?([\\.:]|\n|\r\n|$)",
|
|
5
5
|
"handout": "Р[Аа][Зз][Дд][Аа][Тт]([Аа][Чч][Нн]|[Кк][Аа][Вв])[Ыы][\\s\\s][Мм][Аа][Тт][Ээ][Рр][Ыы][Яя][Лл][\\.:]",
|
|
6
6
|
"answer": "А[Дд][Кк][Аа][Зз][Ыы]?\\s?[№N]?([0-9]+)?\\s?[\\.:]",
|
|
7
7
|
"zachet": "З[Аа][Лл][Іі][Кк]\\s?[\\.:]",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"tour": "^(#\\s+)?(B[Ll][Oo][Cc][Kk]|R[Oo][Uu][Nn][Dd])\\s?№?\\s?([0-9IVXLCDM]*)([\\.:])?$",
|
|
3
3
|
"tourrev": "^([0-9IVXLCDM]+)\\s(B[Ll][Oo][Cc][Kk]|R[Oo][Uu][Nn][Dd])([\\.:])?$",
|
|
4
|
-
"question": "Q[Uu][Ee][Ss][Tt][Ii][Oo][Nn]\\s?[№N]?([0-9\\s]*)\\s?([\\.:]|\n|\r\n|$)",
|
|
4
|
+
"question": "Q[Uu][Ee][Ss][Tt][Ii][Oo][Nn]\\s?[№N]?(?P<number>[0-9\\s]*)\\s?([\\.:]|\n|\r\n|$)",
|
|
5
5
|
"answer": "A[Nn][Ss][Ww][Ee][Rr]\\s?[№N]?([0-9]+)?\\s?[\\.:]",
|
|
6
6
|
"handout": "^H[Aa][Nn][Dd][Oo][Uu][Tt][\\.:]",
|
|
7
7
|
"zachet": "A[Cc][Ee][Pp][Tt]\\s?[\\.:]",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"tour": "^(#\\s+)?([0-9]+)\\s?[-–—]\\s?[Тт][Уу][Рр]\\s*$",
|
|
3
|
-
"question": "([0-9]+)\\s?[-–—]\\s?\\sС[Ұұ][Рр][Аа][Ққ]([\\.:]|\n|\r\n|$)",
|
|
3
|
+
"question": "(?P<number>[0-9]+)\\s?[-–—]\\s?\\sС[Ұұ][Рр][Аа][Ққ]([\\.:]|\n|\r\n|$)",
|
|
4
4
|
"handout": "^Ү[Лл][Ее][Сс][Тт][Іі][Рр][Уу][\\s\\s][Мм][Аа][Тт][Ее][Рр][Ии][Аа][Лл][Ыы][\\.:]",
|
|
5
5
|
"answer": "Ж[Аа][Уу][Аа][Пп]\\s?[№N]?([0-9]+)?\\s?[\\.:]",
|
|
6
6
|
"zachet": "Қ[Аа][Бб][Ыы][Лл][Дд][Аа][Нн][Аа][Тт][Ыы][Нн]\\s[Жж][Аа][Уу][Аа][Пп](\\([Тт][Аа][Рр]\\))?\\s?[\\.:]",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"tour": "^(#\\s+)?Т[Уу][Рр]\\s?№?\\s?([0-9IVXLCDM]*)([\\.:])?$",
|
|
3
|
-
"tourrev": "^([0-9IVXLCDM]
|
|
4
|
-
"question": "
|
|
3
|
+
"tourrev": "^([0-9IVXLCDM]+|[Пп][Ее][Рр][Вв][Ыы][Йй]|[Вв][Тт][Оо][Рр][Оо][Йй]|[Тт][Рр][Ее][Тт][Ии][Йй]|[Чч][Ее][Тт][Вв][Ее][Рр][Тт][Ыы][Йй]|[Пп][Яя][Тт][Ыы][Йй]|[Шш][Ее][Сс][Тт][Оо][Йй]|[Сс][Ее][Дд][Ьь][Мм][Оо][Йй]|[Вв][Оо][Сс][Ьь][Мм][Оо][Йй]|[Дд][Ее][Вв][Яя][Тт][Ыы][Йй]|[Дд][Ее][Сс][Яя][Тт][Ыы][Йй])\\s[Тт][Уу][Рр]([\\.:])?$",
|
|
4
|
+
"question": "^([Нн][Уу][Лл][Ее][Вв][Оо][Йй]|[Рр][Аа][Зз][Мм][Ии][Нн][Оо][Чч][Нн][Ыы][Йй])? ?[Вв][Оо][Пп][Рр][Оо][Сс]\\s?[№N]?(?P<number>[0-9\\s]*)\\s?([\\.:]|\n|\r\n|$)",
|
|
5
5
|
"handout": "^Р[Аа][Зз][Дд][Аа][Тт][Оо][Чч][Нн][Ыы][Йй]\\s+[Мм][Аа][Тт][Ее][Рр][Ии][Аа][Лл][\\.:]",
|
|
6
6
|
"answer": "О[Тт][Вв][Ее][Тт][Ыы]?\\s?[№N]?([0-9]+)?\\s?[\\.:]",
|
|
7
7
|
"zachet": "З[Аа][Чч][ЕеЁё][Тт]\\s?[\\.:]",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"tour": "^(#\\s+)?R[Uu][Nn][Dd][Aa]\\s?№?\\s?([0-9IVXLCDM]*)([\\.:])?$",
|
|
3
3
|
"tourrev": "^([0-9IVXLCDM]+)\\sR[Uu][Nn][Dd][Aa]([\\.:])?$",
|
|
4
|
-
"question": "P[Ii][Tt][Aa][Nn][Jj][Ee]\\s?[№N]?([0-9\\s]*)\\s?([\\.:]|\n|\r\n|$)",
|
|
4
|
+
"question": "P[Ii][Tt][Aa][Nn][Jj][Ee]\\s?[№N]?(?P<number>[0-9\\s]*)\\s?([\\.:]|\n|\r\n|$)",
|
|
5
5
|
"answer": "O[Dd][Gg][Oo][Vv][Oo][Rr]\\s?[№N]?([0-9]+)?\\s?[\\.:]",
|
|
6
6
|
"handout": "^(M[Aa][Tt][Ee][Rr][Ii][Jj][Aa][Ll]|P[Oo][Dd][Ee][Ll][Jj][Ee][Nn][Oo])[\\.:]",
|
|
7
7
|
"zachet": "P[Rr][Ii][Hh][Vv][Aa][Tt][Aa]\\s[Ss][Ee]\\s?[\\.:]",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"tour": "^(#\\s+)?Т[Уу][Рр]\\s?№?\\s?([0-9IVXLCDM]*)([\\.:])?$",
|
|
3
3
|
"tourrev": "^([0-9IVXLCDM]+)\\s[Тт][Уу][Рр]([\\.:])?$",
|
|
4
|
-
"question": "З[Аа][Пп][Ии][Тт][Аа][Нн][Нн][Яя]\\s?[№N]?([0-9\\s]*)\\s?([\\.:]|\n|\r\n|$)",
|
|
4
|
+
"question": "З[Аа][Пп][Ии][Тт][Аа][Нн][Нн][Яя]\\s?[№N]?(?P<number>[0-9\\s]*)\\s?([\\.:]|\n|\r\n|$)",
|
|
5
5
|
"handout": "Р[Оо][Зз][Дд][Аа][Тт][Кк][Оо][Вв][Ии][Йй][\\s\\s][Мм][Аа][Тт][Ее][Рр][Іі][Аа][Лл][\\.:]",
|
|
6
6
|
"answer": "В[Іі][Дд][Пп][Оо][Вв][Іі][Дд][Ьь]?\\s?[№N]?([0-9]+)?\\s?[\\.:]",
|
|
7
7
|
"zachet": "З[Аа][Лл][Іі][Кк]\\s?[\\.:]",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"tour": "^(#\\s+)?([0-9]+)\\s?[-–—]\\s?[Тт][Уу][Рр]\\s*$",
|
|
3
|
-
"question": "([0-9]+)\\s?[-–—]\\s?\\sС[Аа][Вв][Оо][Лл]([\\.:]|\n|\r\n|$)",
|
|
3
|
+
"question": "(?P<number>[0-9]+)\\s?[-–—]\\s?\\sС[Аа][Вв][Оо][Лл]([\\.:]|\n|\r\n|$)",
|
|
4
4
|
"answer": "Ж[Аа][Вв][Оо][Бб]\\s?[№N]?([0-9]+)?\\s?[\\.:]",
|
|
5
5
|
"handout": "Т[Аа][Рр][Ққ][Аа][Тт][Мм][Аа][\\s\\s][Мм][Аа][Тт][Ее][Рр][Ии][Аа][Лл][\\.:]",
|
|
6
6
|
"zachet": "Қ[Аа][Бб][Уу][Лл]\\s?[\\.:]",
|
chgksuite/version.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "0.
|
|
1
|
+
__version__ = "0.26.0"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: chgksuite
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.26.0
|
|
4
4
|
Summary: A package for chgk automation
|
|
5
5
|
Home-page: https://gitlab.com/peczony/chgksuite
|
|
6
6
|
Author: Alexander Pecheny
|
|
@@ -20,12 +20,14 @@ Requires-Dist: parse
|
|
|
20
20
|
Requires-Dist: Pillow
|
|
21
21
|
Requires-Dist: ply
|
|
22
22
|
Requires-Dist: pypandoc
|
|
23
|
+
Requires-Dist: pypdf
|
|
23
24
|
Requires-Dist: pyperclip
|
|
24
25
|
Requires-Dist: python-docx
|
|
25
26
|
Requires-Dist: python-pptx
|
|
26
|
-
Requires-Dist: requests
|
|
27
27
|
Requires-Dist: python-telegram-bot
|
|
28
|
+
Requires-Dist: requests
|
|
28
29
|
Requires-Dist: toml
|
|
30
|
+
Requires-Dist: watchdog
|
|
29
31
|
Dynamic: author
|
|
30
32
|
Dynamic: author-email
|
|
31
33
|
Dynamic: classifier
|
|
@@ -1,27 +1,34 @@
|
|
|
1
1
|
chgksuite/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
2
|
chgksuite/__main__.py,sha256=0-_jfloveTW3SZYW5XEagbyaHKGCiDhGNgcLxsT_dMs,140
|
|
3
|
-
chgksuite/cli.py,sha256=
|
|
3
|
+
chgksuite/cli.py,sha256=iZGpx4-_vTxdKsKsRXCu7vjpiFhR_oyhLRGXyvGl7i8,40901
|
|
4
4
|
chgksuite/common.py,sha256=VkOhoBA_P3qY5VgtvfrBjOsm5uVNL2s2Th2AhGB2pg8,11207
|
|
5
|
-
chgksuite/parser.py,sha256=
|
|
5
|
+
chgksuite/parser.py,sha256=n-NAYRdxHwgvc-4oSpoLGQW6CYniQKLo4iR6PGaSdPw,44962
|
|
6
6
|
chgksuite/parser_db.py,sha256=W1--OcDnx18mehH1T2ISHu3Saeq-9mqHo-xJopNySXI,11135
|
|
7
7
|
chgksuite/trello.py,sha256=BG1Qb_W7Uu4o3Mfc_tK71ElU8ysdSplGlj_sAKfvUn4,14730
|
|
8
8
|
chgksuite/typotools.py,sha256=Jdk65Wn_bXqpQtOT7PkBZyD2ZG1MBeeZFPMzcHEPkf4,12771
|
|
9
|
-
chgksuite/version.py,sha256=
|
|
9
|
+
chgksuite/version.py,sha256=S1dNBNSmHJkAHkq1vL1Yg-dFpQk0fri_CstNlL1u5qw,23
|
|
10
10
|
chgksuite/vulture_whitelist.py,sha256=P__p_X0zt10ivddIf81uyxsobV14vFg8uS2lt4foYpc,3582
|
|
11
11
|
chgksuite/composer/__init__.py,sha256=MAOVZIYXmZmD6nNQSo9DueV6b5RgxF7_HGeLvsAhMJs,6490
|
|
12
12
|
chgksuite/composer/chgksuite_parser.py,sha256=MFcLUWbccMqo3OYEuaAIA0loEvWM_PNS9vR7c1z_c60,8843
|
|
13
|
-
chgksuite/composer/composer_common.py,sha256=
|
|
13
|
+
chgksuite/composer/composer_common.py,sha256=f48tUeZH5UIZxBaODcqhHGwmIdEGpMVP8lxMcl4rwTQ,15433
|
|
14
14
|
chgksuite/composer/db.py,sha256=71cINE_V8s6YidvqpmBmmlWbcXraUEGZA1xpVFAUENw,8173
|
|
15
|
-
chgksuite/composer/docx.py,sha256=
|
|
15
|
+
chgksuite/composer/docx.py,sha256=kJMpWHFyxIZJSA9Ul_2xRsWZnuVkjfko5D08Xi45HiU,23059
|
|
16
16
|
chgksuite/composer/latex.py,sha256=WtLdUICxeX4_5vHEJRF0YhFLpTsOUwBkQFunQS488FA,9248
|
|
17
17
|
chgksuite/composer/lj.py,sha256=nty3Zs3N1H0gNK378U04aAHo71_5cABhCM1Mm9jiUEA,15213
|
|
18
18
|
chgksuite/composer/openquiz.py,sha256=4adZewvRXpZhKrh9H4epKoMMDhmki9US55-Q0LcpZW0,7019
|
|
19
|
-
chgksuite/composer/pptx.py,sha256=
|
|
19
|
+
chgksuite/composer/pptx.py,sha256=KszvRAbSbKmbPS257YcYhE6wB1gSf7gIXRH8VwiSqyg,23775
|
|
20
20
|
chgksuite/composer/reddit.py,sha256=-Eg4CqMHhyGGfCteVwdQdtE1pfUXQ42XcP5OYUrBXmo,3878
|
|
21
21
|
chgksuite/composer/stats.py,sha256=GbraSrjaZ8Mc2URs5aGAsI4ekboAKzlJJOqsbe96ELA,3995
|
|
22
|
-
chgksuite/composer/telegram.py,sha256=
|
|
22
|
+
chgksuite/composer/telegram.py,sha256=ZiCBFXxKJJ5vD5ttkfvmURd4Q9Gif6eT8R93nz-LAq0,47146
|
|
23
23
|
chgksuite/composer/telegram_bot.py,sha256=xT5D39m4zGmIbHV_ZfyQ9Rc8PAmG2V5FGUeDKpkgyTw,3767
|
|
24
24
|
chgksuite/composer/telegram_parser.py,sha256=50WqOuvzzdMJJm5wsSLS49oURAQRYToPnbPJjQbMYC4,8096
|
|
25
|
+
chgksuite/handouter/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
26
|
+
chgksuite/handouter/gen.py,sha256=Rnrcg1APBt35Joloce-q3gA4OJUXudH8snbGLSmVXJw,5045
|
|
27
|
+
chgksuite/handouter/installer.py,sha256=u4jQKeCn0VjOnaDFezx35g8oRjji5edvYGj5xSHCEW4,7574
|
|
28
|
+
chgksuite/handouter/pack.py,sha256=H-Ln1JqKK2u3jFI5wwsh7pQdJBpQJ-s8gV9iECQ3kgU,2504
|
|
29
|
+
chgksuite/handouter/runner.py,sha256=SHxGCAbQ9s6h23IaqNhJtWN0VMjM9hwy6oIgt0-WuD0,8380
|
|
30
|
+
chgksuite/handouter/tex_internals.py,sha256=GtcoGd1FD4Oi9nnMzb2KcdCNIHNQV1fcKmQyW9AXA1k,1394
|
|
31
|
+
chgksuite/handouter/utils.py,sha256=0RoECvHzfmwWnRL2jj4WKh22oTCPh2MXid_a9ShplDA,2243
|
|
25
32
|
chgksuite/resources/cheader.tex,sha256=Jfe3LESk0VIV0HCObbajSQpEMljaIDAIEGSs6YY9rTk,3454
|
|
26
33
|
chgksuite/resources/fix-unnumbered-sections.sty,sha256=FN6ZSWC6MvoRoThPm5AxCF98DdgcxbxyBYG6YImM05s,1409
|
|
27
34
|
chgksuite/resources/labels_by.toml,sha256=kSbIYBnxneRJAcDmeoFGlPpjogWuoMO11302p0BxB-s,824
|
|
@@ -34,20 +41,19 @@ chgksuite/resources/labels_ua.toml,sha256=sUZdwwpkddb_56bmrZyO56cDrm68ft_JoMqR38
|
|
|
34
41
|
chgksuite/resources/labels_uz.toml,sha256=uRnf6tjBf1rYpWjt675ecB2MPn_Ohz-Hj6XDYNPpe3o,609
|
|
35
42
|
chgksuite/resources/labels_uz_cyr.toml,sha256=ztqHItwhJjfBTOIj_vA1hrneYo8s5gvZkkSr0k9S3rs,814
|
|
36
43
|
chgksuite/resources/pptx_config.toml,sha256=pbdQpZTBZajfXxf9Ej6jFQv8luA9_h2Lsihx9hs2jkI,570
|
|
37
|
-
chgksuite/resources/regexes_by.json,sha256=
|
|
38
|
-
chgksuite/resources/regexes_en.json,sha256=
|
|
39
|
-
chgksuite/resources/regexes_kz_cyr.json,sha256=
|
|
40
|
-
chgksuite/resources/regexes_ru.json,sha256=
|
|
41
|
-
chgksuite/resources/regexes_sr.json,sha256=
|
|
42
|
-
chgksuite/resources/regexes_ua.json,sha256=
|
|
43
|
-
chgksuite/resources/regexes_uz_cyr.json,sha256=
|
|
44
|
+
chgksuite/resources/regexes_by.json,sha256=ps_dLYxgPnZRCUkLo_ti1tsZAWZNIf48UobRvQ88z6E,1306
|
|
45
|
+
chgksuite/resources/regexes_en.json,sha256=XdpKRlT2azLglFeXRKv3BdZKHDem2qXFbwRixiUVmbU,1013
|
|
46
|
+
chgksuite/resources/regexes_kz_cyr.json,sha256=wkkf_Gll07i9V1QLdexKG2DjxAhV9ZZOWMjvbX7Tjvg,1689
|
|
47
|
+
chgksuite/resources/regexes_ru.json,sha256=3OrNLq6LkIB2rVErPRYYHrljrKK-mOdna1zfXCaIUK0,2187
|
|
48
|
+
chgksuite/resources/regexes_sr.json,sha256=S8IRDUh3E4y3G8Cavb4F6gPDfHzOk2HH3RXy_D32RFw,935
|
|
49
|
+
chgksuite/resources/regexes_ua.json,sha256=vLUP9nRsVB7nPk4Ea3CpC7zcg57N62Uf4A24YJjRMFA,1340
|
|
50
|
+
chgksuite/resources/regexes_uz_cyr.json,sha256=GlGkA6ys2e1-9xPcgOL8Sy9ZuDZHQZXp_p_MvGJirMU,1116
|
|
44
51
|
chgksuite/resources/template.docx,sha256=Do29TAsg3YbH0rRSaXhVzKEoh4pwXkklW_idWA34HVE,11189
|
|
45
52
|
chgksuite/resources/template.pptx,sha256=hEFWqE-yYpwZ8ejrMCJIPEyoMT3eDqaqtiEeQ7I4fyk,29777
|
|
46
|
-
chgksuite/resources/template_shorin.pptx,sha256=hEFWqE-yYpwZ8ejrMCJIPEyoMT3eDqaqtiEeQ7I4fyk,29777
|
|
47
53
|
chgksuite/resources/trello.json,sha256=M5Q9JR-AAJF1u16YtNAxDX-7c7VoVTXuq4POTqYvq8o,555
|
|
48
|
-
chgksuite-0.
|
|
49
|
-
chgksuite-0.
|
|
50
|
-
chgksuite-0.
|
|
51
|
-
chgksuite-0.
|
|
52
|
-
chgksuite-0.
|
|
53
|
-
chgksuite-0.
|
|
54
|
+
chgksuite-0.26.0.dist-info/licenses/LICENSE,sha256=_a1yfntuPmctLsuiE_08xMSORuCfGS8X5hQph2U_PUw,1081
|
|
55
|
+
chgksuite-0.26.0.dist-info/METADATA,sha256=hi39ekThVjt85G9FFedbR1QdYk6pqEE0_oSbt-I-G5Y,1339
|
|
56
|
+
chgksuite-0.26.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
57
|
+
chgksuite-0.26.0.dist-info/entry_points.txt,sha256=lqjX6ULQZGDt0rgouTXBuwEPiwKkDQkSiNsT877A_Jg,54
|
|
58
|
+
chgksuite-0.26.0.dist-info/top_level.txt,sha256=cSWiRBOGZW9nIO6Rv1IrEfwPgV2ZWs87QV9wPXeBGqM,10
|
|
59
|
+
chgksuite-0.26.0.dist-info/RECORD,,
|
|
Binary file
|
|
File without changes
|
|
File without changes
|
|
File without changes
|