chgksuite 0.26.1__py3-none-any.whl → 0.27.0b1__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.
Files changed (43) hide show
  1. chgksuite/cli.py +12 -8
  2. chgksuite/common.py +4 -1
  3. chgksuite/composer/composer_common.py +14 -5
  4. chgksuite/composer/docx.py +29 -8
  5. chgksuite/composer/openquiz.py +1 -1
  6. chgksuite/composer/pptx.py +2 -2
  7. chgksuite/composer/telegram.py +2 -1
  8. chgksuite/handouter/gen.py +11 -7
  9. chgksuite/handouter/runner.py +10 -4
  10. chgksuite/handouter/tex_internals.py +0 -11
  11. chgksuite/parser.py +6 -9
  12. chgksuite/parser_db.py +3 -4
  13. chgksuite/resources/labels_az.toml +22 -0
  14. chgksuite/resources/labels_by.toml +1 -2
  15. chgksuite/resources/labels_by_tar.toml +1 -2
  16. chgksuite/resources/labels_en.toml +1 -2
  17. chgksuite/resources/labels_kz_cyr.toml +1 -2
  18. chgksuite/resources/labels_ru.toml +1 -2
  19. chgksuite/resources/labels_sr.toml +1 -2
  20. chgksuite/resources/labels_ua.toml +1 -2
  21. chgksuite/resources/labels_uz.toml +0 -3
  22. chgksuite/resources/labels_uz_cyr.toml +1 -2
  23. chgksuite/resources/regexes_az.json +17 -0
  24. chgksuite/resources/regexes_by.json +3 -2
  25. chgksuite/resources/regexes_by_tar.json +17 -0
  26. chgksuite/resources/regexes_en.json +3 -2
  27. chgksuite/resources/regexes_kz_cyr.json +3 -2
  28. chgksuite/resources/regexes_ru.json +3 -2
  29. chgksuite/resources/regexes_sr.json +3 -2
  30. chgksuite/resources/regexes_ua.json +3 -2
  31. chgksuite/resources/regexes_uz.json +16 -0
  32. chgksuite/resources/regexes_uz_cyr.json +3 -2
  33. chgksuite/trello.py +1 -1
  34. chgksuite/typotools.py +5 -4
  35. chgksuite/version.py +1 -1
  36. {chgksuite-0.26.1.dist-info → chgksuite-0.27.0b1.dist-info}/METADATA +6 -13
  37. chgksuite-0.27.0b1.dist-info/RECORD +62 -0
  38. chgksuite/composer/telegram_parser.py +0 -230
  39. chgksuite-0.26.1.dist-info/RECORD +0 -59
  40. {chgksuite-0.26.1.dist-info → chgksuite-0.27.0b1.dist-info}/WHEEL +0 -0
  41. {chgksuite-0.26.1.dist-info → chgksuite-0.27.0b1.dist-info}/entry_points.txt +0 -0
  42. {chgksuite-0.26.1.dist-info → chgksuite-0.27.0b1.dist-info}/licenses/LICENSE +0 -0
  43. {chgksuite-0.26.1.dist-info → chgksuite-0.27.0b1.dist-info}/top_level.txt +0 -0
chgksuite/cli.py CHANGED
@@ -13,12 +13,14 @@ from chgksuite.common import (
13
13
  )
14
14
  from chgksuite.composer import gui_compose
15
15
  from chgksuite.handouter.runner import gui_handouter
16
- from chgksuite.handouter.tex_internals import GREYTEXT_LANGS
17
16
  from chgksuite.parser import gui_parse
18
17
  from chgksuite.trello import gui_trello
19
18
  from chgksuite.version import __version__
20
19
 
21
- LANGS = ["by", "by_tar", "en", "kz_cyr", "ru", "sr", "ua", "uz", "uz_cyr"] + ["custom"]
20
+ LANGS = ["az", "by", "by_tar", "en", "kz_cyr", "ru", "sr", "ua", "uz", "uz_cyr"] + [
21
+ "custom"
22
+ ]
23
+ HANDOUT_LANGS = [lang for lang in LANGS if lang != "custom"]
22
24
 
23
25
  debug = False
24
26
 
@@ -889,10 +891,11 @@ class ArgparseBuilder:
889
891
  )
890
892
  self.add_argument(
891
893
  cmdhandouts_run,
892
- "--lang",
894
+ "--language",
895
+ "-lang",
893
896
  default="ru",
894
897
  argtype="radiobutton",
895
- choices=sorted(GREYTEXT_LANGS.keys()),
898
+ choices=sorted(HANDOUT_LANGS),
896
899
  help="language",
897
900
  caption="Язык",
898
901
  advanced=True,
@@ -1012,12 +1015,13 @@ class ArgparseBuilder:
1012
1015
  )
1013
1016
  self.add_argument(
1014
1017
  cmdhandouts_generate,
1015
- "--lang",
1018
+ "--language",
1019
+ "-lang",
1016
1020
  default="ru",
1017
1021
  help="language",
1018
1022
  caption="Язык",
1019
1023
  argtype="radiobutton",
1020
- choices=sorted(GREYTEXT_LANGS.keys()),
1024
+ choices=sorted(HANDOUT_LANGS),
1021
1025
  advanced=True,
1022
1026
  )
1023
1027
  self.add_argument(
@@ -1084,9 +1088,9 @@ def single_action(args, use_wrapper, resourcedir):
1084
1088
  args.console_mode = True
1085
1089
 
1086
1090
  if args.language in LANGS:
1091
+ args.regexes_file = os.path.join(resourcedir, f"regexes_{args.language}.json")
1087
1092
  if args.action == "parse":
1088
- regex_lang = "by" if args.language == "by_tar" else args.language
1089
- args.regexes = os.path.join(resourcedir, f"regexes_{regex_lang}.json")
1093
+ args.regexes = args.regexes_file
1090
1094
  args.labels_file = os.path.join(resourcedir, f"labels_{args.language}.toml")
1091
1095
  if not args.docx_template:
1092
1096
  args.docx_template = os.path.join(resourcedir, "template.docx")
chgksuite/common.py CHANGED
@@ -29,7 +29,10 @@ QUESTION_LABELS = [
29
29
  "setcounter",
30
30
  ]
31
31
  SEP = os.linesep
32
- ENC = sys.stdout.encoding or "utf8"
32
+ try:
33
+ ENC = sys.stdout.encoding or "utf8"
34
+ except AttributeError:
35
+ ENC = "utf8"
33
36
 
34
37
  lastdir = os.path.join(os.path.dirname(os.path.abspath("__file__")), "lastdir")
35
38
 
@@ -59,8 +59,8 @@ def backtick_replace(el):
59
59
  return el
60
60
 
61
61
 
62
- def remove_accents_standalone(s, labels):
63
- hs = labels["question_labels"]["handout_short"]
62
+ def remove_accents_standalone(s, regexes):
63
+ hs = regexes["handout_short"]
64
64
  re_hs = re.compile(f"\\[{hs}(.+?)\\]", flags=re.DOTALL)
65
65
  replacements = {}
66
66
  n_handouts = 0
@@ -413,6 +413,8 @@ class BaseExporter:
413
413
  self.dir_kwargs = args[2]
414
414
  with open(self.args.labels_file, encoding="utf8") as f:
415
415
  self.labels = toml.load(f)
416
+ with open(self.args.regexes_file, encoding="utf8") as f:
417
+ self.regexes = json.load(f)
416
418
  logger = kwargs.get("logger")
417
419
  if logger:
418
420
  self.logger = logger
@@ -451,10 +453,11 @@ class BaseExporter:
451
453
  return self.labels["question_labels"][field]
452
454
 
453
455
  def remove_square_brackets(self, s):
454
- hs = self.labels["question_labels"]["handout_short"]
456
+ hs = self.regexes["handout_short"]
455
457
  s = s.replace("\\[", "LEFTSQUAREBRACKET")
456
458
  s = s.replace("\\]", "RIGHTSQUAREBRACKET")
457
- s = re.sub(f"\\[{hs}(.+?)\\]", "{" + hs + "\\1}", s, flags=re.DOTALL)
459
+ # Use placeholder to preserve handout brackets during removal
460
+ s = re.sub(f"\\[{hs}(.+?)\\]", "{HANDOUT_PLACEHOLDER\\1}", s, flags=re.DOTALL)
458
461
  i = 0
459
462
  while "[" in s and "]" in s and i < 10:
460
463
  s = re.sub(" *\\[.+?\\]", "", s, flags=re.DOTALL)
@@ -464,7 +467,13 @@ class BaseExporter:
464
467
  sys.stderr.write(
465
468
  f"Error replacing square brackets on question: {s}, retries exceeded\n"
466
469
  )
467
- s = re.sub("\\{" + hs + "(.+?)\\}", "[" + hs + "\\1]", s, flags=re.DOTALL)
470
+ # Restore handout brackets - get the original matched text from the placeholder
471
+ s = re.sub(
472
+ r"\{HANDOUT_PLACEHOLDER(.+?)\}",
473
+ lambda m: "[" + m.group(1) + "]",
474
+ s,
475
+ flags=re.DOTALL,
476
+ )
468
477
  s = s.replace("LEFTSQUAREBRACKET", "[")
469
478
  s = s.replace("RIGHTSQUAREBRACKET", "]")
470
479
  return s
@@ -96,12 +96,13 @@ def get_label_standalone(
96
96
  return labels["question_labels"][field]
97
97
 
98
98
 
99
- def remove_square_brackets_standalone(s, labels):
99
+ def remove_square_brackets_standalone(s, regexes):
100
100
  """Standalone version of remove_square_brackets"""
101
- hs = labels["question_labels"]["handout_short"]
101
+ hs = regexes["handout_short"]
102
102
  s = s.replace("\\[", "LEFTSQUAREBRACKET")
103
103
  s = s.replace("\\]", "RIGHTSQUAREBRACKET")
104
- s = re.sub(f"\\[{hs}(.+?)\\]", "{" + hs + "\\1}", s, flags=re.DOTALL)
104
+ # Use placeholder to preserve handout brackets during removal
105
+ s = re.sub(f"\\[{hs}(.+?)\\]", "{HANDOUT_PLACEHOLDER\\1}", s, flags=re.DOTALL)
105
106
  i = 0
106
107
  while "[" in s and "]" in s and i < 10:
107
108
  s = re.sub(" *\\[.+?\\]", "", s, flags=re.DOTALL)
@@ -111,7 +112,13 @@ def remove_square_brackets_standalone(s, labels):
111
112
  sys.stderr.write(
112
113
  f"Error replacing square brackets on question: {s}, retries exceeded\n"
113
114
  )
114
- s = re.sub("\\{" + hs + "(.+?)\\}", "[" + hs + "\\1]", s, flags=re.DOTALL)
115
+ # Restore handout brackets - get the original matched text from the placeholder
116
+ s = re.sub(
117
+ r"\{HANDOUT_PLACEHOLDER(.+?)\}",
118
+ lambda m: "[" + m.group(1) + "]",
119
+ s,
120
+ flags=re.DOTALL,
121
+ )
115
122
  s = s.replace("LEFTSQUAREBRACKET", "[")
116
123
  s = s.replace("RIGHTSQUAREBRACKET", "]")
117
124
  return s
@@ -140,6 +147,7 @@ def format_docx_element(
140
147
  spoilers="none",
141
148
  logger=None,
142
149
  labels=None,
150
+ regexes=None,
143
151
  language="ru",
144
152
  remove_accents=False,
145
153
  remove_brackets=False,
@@ -157,6 +165,7 @@ def format_docx_element(
157
165
  spoilers: Spoiler handling mode ("none", "whiten", "dots", "pagebreak")
158
166
  logger: Logger instance
159
167
  labels: Labels dictionary
168
+ regexes: Regexes dictionary (for handout_short)
160
169
  language: Language code
161
170
  remove_accents: Whether to remove accents
162
171
  remove_brackets: Whether to remove square brackets
@@ -176,6 +185,7 @@ def format_docx_element(
176
185
  spoilers,
177
186
  logger,
178
187
  labels,
188
+ regexes,
179
189
  language,
180
190
  remove_accents,
181
191
  remove_brackets,
@@ -194,6 +204,7 @@ def format_docx_element(
194
204
  spoilers,
195
205
  logger,
196
206
  labels,
207
+ regexes,
197
208
  language,
198
209
  remove_accents,
199
210
  remove_brackets,
@@ -213,6 +224,7 @@ def format_docx_element(
213
224
  spoilers,
214
225
  logger,
215
226
  labels,
227
+ regexes,
216
228
  language,
217
229
  remove_accents,
218
230
  remove_brackets,
@@ -223,10 +235,10 @@ def format_docx_element(
223
235
  if isinstance(el, str):
224
236
  logger.debug("parsing element {}:".format(log_wrap(el)))
225
237
 
226
- if remove_accents and labels:
227
- el = remove_accents_standalone(el, labels)
228
- if remove_brackets and labels:
229
- el = remove_square_brackets_standalone(el, labels)
238
+ if remove_accents and regexes:
239
+ el = remove_accents_standalone(el, regexes)
240
+ if remove_brackets and regexes:
241
+ el = remove_square_brackets_standalone(el, regexes)
230
242
  else:
231
243
  el = replace_escaped(el)
232
244
 
@@ -309,6 +321,7 @@ def add_question_to_docx(
309
321
  doc,
310
322
  question_data,
311
323
  labels,
324
+ regexes=None,
312
325
  qcount=None,
313
326
  skip_qcount=False,
314
327
  screen_mode=False,
@@ -329,6 +342,7 @@ def add_question_to_docx(
329
342
  doc: docx Document object
330
343
  question_data: Dictionary containing question data
331
344
  labels: Labels dictionary
345
+ regexes: Regexes dictionary (for handout_short)
332
346
  qcount: Current question count (will be incremented if not skip_qcount)
333
347
  skip_qcount: Whether to skip incrementing question count
334
348
  screen_mode: Whether to use screen mode formatting
@@ -392,6 +406,7 @@ def add_question_to_docx(
392
406
  spoilers,
393
407
  logger,
394
408
  labels,
409
+ regexes,
395
410
  language,
396
411
  remove_accents=screen_mode,
397
412
  remove_brackets=screen_mode,
@@ -411,6 +426,7 @@ def add_question_to_docx(
411
426
  spoilers,
412
427
  logger,
413
428
  labels,
429
+ regexes,
414
430
  language,
415
431
  remove_accents=screen_mode,
416
432
  remove_brackets=screen_mode,
@@ -453,6 +469,7 @@ def add_question_to_docx(
453
469
  spoilers,
454
470
  logger,
455
471
  labels,
472
+ regexes,
456
473
  language,
457
474
  remove_accents=screen_mode,
458
475
  replace_no_break_spaces=True,
@@ -481,6 +498,7 @@ def add_question_to_docx(
481
498
  spoilers,
482
499
  logger,
483
500
  labels,
501
+ regexes,
484
502
  language,
485
503
  remove_accents=screen_mode,
486
504
  remove_brackets=screen_mode,
@@ -514,6 +532,7 @@ class DocxExporter(BaseExporter):
514
532
  spoilers=self.args.spoilers,
515
533
  logger=self.logger,
516
534
  labels=self.labels,
535
+ regexes=self.regexes,
517
536
  language=self.args.language,
518
537
  **kwargs,
519
538
  )
@@ -528,6 +547,7 @@ class DocxExporter(BaseExporter):
528
547
  spoilers=self.args.spoilers,
529
548
  logger=self.logger,
530
549
  labels=self.labels,
550
+ regexes=self.regexes,
531
551
  language=self.args.language,
532
552
  **kwargs,
533
553
  )
@@ -542,6 +562,7 @@ class DocxExporter(BaseExporter):
542
562
  self.doc,
543
563
  element[1],
544
564
  self.labels,
565
+ self.regexes,
545
566
  self.qcount,
546
567
  skip_qcount,
547
568
  screen_mode,
@@ -71,7 +71,7 @@ class OpenquizExporter(BaseExporter):
71
71
  )
72
72
  while res.endswith("\n"):
73
73
  res = res[:-1]
74
- hs = self.labels["question_labels"]["handout_short"]
74
+ hs = self.regexes["handout_short"]
75
75
  if images:
76
76
  res = re.sub("\\[" + hs + "(.+?)\\]", "", s, flags=re.DOTALL)
77
77
  res = res.strip()
@@ -121,13 +121,13 @@ class PptxExporter(BaseExporter):
121
121
  replace_spaces=True,
122
122
  do_not_remove_accents=False,
123
123
  ):
124
- hs = self.labels["question_labels"]["handout_short"]
124
+ hs = self.regexes["handout_short"]
125
125
  if isinstance(s, list):
126
126
  for i in range(len(s)):
127
127
  s[i] = self.pptx_process_text(s[i], image=image)
128
128
  return s
129
129
  if not (self.args.do_not_remove_accents or do_not_remove_accents):
130
- s = remove_accents_standalone(s, self.labels)
130
+ s = remove_accents_standalone(s, self.regexes)
131
131
  if strip_brackets:
132
132
  s = self.remove_square_brackets(s)
133
133
  s = s.replace("]\n", "]\n\n")
@@ -6,6 +6,7 @@ import sqlite3
6
6
  import tempfile
7
7
  import time
8
8
  import uuid
9
+ from typing import Optional, Union
9
10
 
10
11
  import requests
11
12
  import toml
@@ -247,7 +248,7 @@ class TelegramExporter(BaseExporter):
247
248
  channel_id_str = channel_id_str[4:]
248
249
  return f"https://t.me/c/{channel_id_str}/{message_id}"
249
250
 
250
- def extract_id_from_link(self, link) -> int | str | None:
251
+ def extract_id_from_link(self, link) -> Optional[Union[int, str]]:
251
252
  """
252
253
  Extract channel or chat ID from a Telegram link.
253
254
  Examples:
@@ -1,6 +1,7 @@
1
1
  #!/usr/bin/env python
2
2
  # -*- coding: utf-8 -*-
3
3
  import itertools
4
+ import json
4
5
  import os
5
6
  import re
6
7
  from collections import defaultdict
@@ -53,13 +54,16 @@ def generate_handouts_list(handouts, output_dir, base_name, parsed):
53
54
 
54
55
  def generate_handouts(args):
55
56
  _, resourcedir = get_source_dirs()
56
- labels = toml.loads(
57
- read_file(os.path.join(resourcedir, f"labels_{args.lang}.toml"))
57
+ toml.loads(read_file(os.path.join(resourcedir, f"labels_{args.language}.toml")))
58
+ with open(
59
+ os.path.join(resourcedir, f"regexes_{args.language}.json"), encoding="utf8"
60
+ ) as f:
61
+ regexes = json.load(f)
62
+ handout_re_text = (
63
+ "\\[" + regexes["handout_short"] + ".+?:( |\n)(?P<handout_text>.+?)\\]"
58
64
  )
59
65
  handout_re = re.compile(
60
- "\\["
61
- + labels["question_labels"]["handout_short"]
62
- + ".+?:( |\n)(?P<handout_text>.+?)\\]",
66
+ handout_re_text,
63
67
  flags=re.DOTALL,
64
68
  )
65
69
 
@@ -82,9 +86,9 @@ def generate_handouts(args):
82
86
  if img:
83
87
  try:
84
88
  parsed_img = parseimg(img[0][1])
85
- except:
89
+ except Exception as e:
86
90
  print(
87
- f"Image file for question {q['number']} not found, add it by hand"
91
+ f"Image file for question {q['number']} not found, add it by hand (exception {type(e)} {e})"
88
92
  )
89
93
  continue
90
94
  else:
@@ -5,15 +5,16 @@ import shutil
5
5
  import subprocess
6
6
  import time
7
7
 
8
+ import toml
8
9
  from watchdog.events import FileSystemEventHandler
9
10
  from watchdog.observers import Observer
10
11
 
12
+ from chgksuite.common import get_source_dirs
11
13
  from chgksuite.handouter.gen import generate_handouts
12
14
  from chgksuite.handouter.pack import pack_handouts
13
15
  from chgksuite.handouter.installer import get_tectonic_path, install_tectonic
14
16
  from chgksuite.handouter.tex_internals import (
15
17
  GREYTEXT,
16
- GREYTEXT_LANGS,
17
18
  HEADER,
18
19
  IMG,
19
20
  IMGWIDTH,
@@ -29,6 +30,10 @@ class HandoutGenerator:
29
30
 
30
31
  def __init__(self, args):
31
32
  self.args = args
33
+ _, resourcedir = get_source_dirs()
34
+ self.labels = toml.loads(
35
+ read_file(os.path.join(resourcedir, f"labels_{args.language}.toml"))
36
+ )
32
37
  self.blocks = [self.get_header()]
33
38
 
34
39
  def get_header(self):
@@ -51,9 +56,10 @@ class HandoutGenerator:
51
56
  return parse_handouts(contents)
52
57
 
53
58
  def generate_for_question(self, question_num):
54
- return GREYTEXT.replace(
55
- "<GREYTEXT>", GREYTEXT_LANGS[self.args.lang].format(question_num)
59
+ handout_text = self.labels["general"]["handout_for_question"].format(
60
+ question_num
56
61
  )
62
+ return GREYTEXT.replace("<GREYTEXT>", handout_text)
57
63
 
58
64
  def make_tikzbox(self, block):
59
65
  if block.get("no_center"):
@@ -141,7 +147,7 @@ class HandoutGenerator:
141
147
 
142
148
  def process_file(args, file_dir, bn):
143
149
  tex_contents = HandoutGenerator(args).generate()
144
- tex_path = os.path.join(file_dir, f"{bn}_{args.lang}.tex")
150
+ tex_path = os.path.join(file_dir, f"{bn}_{args.language}.tex")
145
151
  write_file(tex_path, tex_contents)
146
152
 
147
153
  tectonic_path = get_tectonic_path()
@@ -20,17 +20,6 @@ HEADER = r"""
20
20
 
21
21
  GREYTEXT = r"""{\fontsize{9pt}{11pt}\selectfont \textcolor{gray}{<GREYTEXT>}}"""
22
22
 
23
- GREYTEXT_LANGS = {
24
- "by": "Да пытаньня {}",
25
- "en": "Handout for question {}",
26
- "kz": "{}-сұрақтың үлестіру материалы",
27
- "ro": "Material care urmează a fi distribuit pentru întrebarea {}",
28
- "ru": "К вопросу {}",
29
- "sr": "Materijal za deljenje uz pitanje {}",
30
- "ua": "До запитання {}",
31
- "uz": "{} саволга тарқатма материал",
32
- }
33
-
34
23
  TIKZBOX_START = r"""{<CENTERING>
35
24
  """
36
25
 
chgksuite/parser.py CHANGED
@@ -46,7 +46,7 @@ from chgksuite.parser_db import chgk_parse_db
46
46
  from chgksuite.typotools import re_url
47
47
  from chgksuite.typotools import remove_excessive_whitespace as rew
48
48
 
49
- ENC = sys.stdout.encoding or "utf8"
49
+
50
50
  SEP = os.linesep
51
51
  EDITORS = {
52
52
  "win32": "notepad",
@@ -327,7 +327,7 @@ class ChgkParser:
327
327
  regex,
328
328
  regexes[regex].search(self.remove_formatting(st[i][1])).start(0),
329
329
  )
330
- for regex in set(regexes) - {"number", "date2"}
330
+ for regex in set(regexes) - {"number", "date2", "handout_short"}
331
331
  if regexes[regex].search(self.remove_formatting(st[i][1]))
332
332
  }
333
333
 
@@ -566,8 +566,8 @@ class ChgkParser:
566
566
  # hack for https://gitlab.com/peczony/chgksuite/-/issues/23; TODO: make less hacky
567
567
  for i, element in enumerate(self.structure):
568
568
  if (
569
- "дуплет." in element[1].lower().split()
570
- or "блиц." in element[1].lower().split()
569
+ "Дуплет." in element[1].split()
570
+ or "Блиц." in element[1].split()
571
571
  and element[0] != "question"
572
572
  and (i == 0 or self.structure[i - 1][0] != "question")
573
573
  ):
@@ -688,12 +688,9 @@ class ChgkParser:
688
688
  except Exception as e:
689
689
  num = None
690
690
  sys.stderr.write(
691
- f"exception at setting number: {type(e)} {e}\n"
691
+ f"exception at setting number: {type(e)} {e}\nQuestion: {element[1]}\n"
692
692
  )
693
- if (
694
- num is None
695
- or num and not num.group("number")
696
- ) and (
693
+ if (num is None or num and not num.group("number")) and (
697
694
  ("нулевой вопрос" in element[1].lower())
698
695
  or ("разминочный вопрос" in element[1].lower())
699
696
  ):
chgksuite/parser_db.py CHANGED
@@ -128,7 +128,7 @@ def t_ANSWER(t):
128
128
  t.lexer.text = ""
129
129
  if t.lexer.question["answer"]:
130
130
  logger.warning(
131
- "Bad format: several Answer fields. " "Previous Answer was:" " '%s'",
131
+ "Bad format: several Answer fields. Previous Answer was: '%s'",
132
132
  t.lexer.question["answer"],
133
133
  )
134
134
 
@@ -151,7 +151,7 @@ def t_COMMENT(t):
151
151
  t.lexer.text = ""
152
152
  if t.lexer.question["comment"]:
153
153
  logger.warning(
154
- "Bad format: several Comment fields. " "Previous Comment was:" " '%s'",
154
+ "Bad format: several Comment fields. Previous Comment was: '%s'",
155
155
  t.lexer.question["comment"],
156
156
  )
157
157
 
@@ -162,7 +162,7 @@ def t_SOURCE(t):
162
162
  t.lexer.text = ""
163
163
  if t.lexer.question["source"]:
164
164
  logger.warning(
165
- "Bad format: several Source fields. " "Previous Source was:" " '%s'",
165
+ "Bad format: several Source fields. Previous Source was: '%s'",
166
166
  t.lexer.question["source"],
167
167
  )
168
168
 
@@ -417,7 +417,6 @@ def replace_handouts(match_handout):
417
417
 
418
418
 
419
419
  def chgk_parse_db(text, debug=False, logger=False):
420
-
421
420
  if not logger:
422
421
  logger = init_logger("parser_db", debug=debug)
423
422
 
@@ -0,0 +1,22 @@
1
+ [question_labels]
2
+ question = "Sual"
3
+ answer = "Cavab"
4
+ zachet = "Sayılma meyarı"
5
+ nezachet = "Sayılmır"
6
+ comment = "Şərh"
7
+ source = "Mənbə"
8
+ sources = "Mənbələr"
9
+ author = "Müəllif"
10
+ authors = "Müəlliflər"
11
+ handout = "Paylama materialı"
12
+
13
+ [general]
14
+ section = "Tur"
15
+ editor = "Redaktor"
16
+ date = "Tarix"
17
+ questions_in_comments = "Suallar şərh bölməsindədir."
18
+ general_impressions_caption = "Ümumi təəssüratlar"
19
+ handout_for_question = "Paylama materialı sual {} üçün"
20
+ general_impressions_text = "Paket barədə ümumi təəssüratlar — bu posun altına şərh kimi yazın."
21
+ right_answers_for_stats = "Doğru cavablar"
22
+ cf_image = "Şəklə baxın"
@@ -9,7 +9,6 @@ sources = "Крыніцы"
9
9
  author = "Аўтар"
10
10
  authors = "Аўтары"
11
11
  handout = "Раздаткавы матэрыял"
12
- handout_short = "Раздат"
13
12
 
14
13
  [general]
15
14
  section = "Тур"
@@ -19,4 +18,4 @@ questions_in_comments = "Пытанні ў каментарах."
19
18
  handout_for_question = "Раздаткавы матэрыял да пытання {}"
20
19
  general_impressions_caption = "Агульныя ўражанні"
21
20
  general_impressions_text = "Агульныя ўражанні ад пакета — у каментарах да гэтага паста."
22
- right_answers_for_stats = "Правільных адказаў"
21
+ right_answers_for_stats = "Правільных адказаў"
@@ -9,7 +9,6 @@ sources = "Крыніцы"
9
9
  author = "Аўтар"
10
10
  authors = "Аўтары"
11
11
  handout = "Раздаткавы матэрыял"
12
- handout_short = "Раздат"
13
12
 
14
13
  [general]
15
14
  section = "Тур"
@@ -19,4 +18,4 @@ questions_in_comments = "Пытаньні ў каментарыях."
19
18
  handout_for_question = "Раздатачны матэрыял да пытаньня {}"
20
19
  general_impressions_caption = "Агульныя ўражаньні"
21
20
  general_impressions_text = "Агульныя ўражаньні ад пакета — у каментарыях да гэтага паста."
22
- right_answers_for_stats = "Правільных адказаў"
21
+ right_answers_for_stats = "Правільных адказаў"
@@ -9,7 +9,6 @@ sources = "Sources"
9
9
  author = "Author"
10
10
  authors = "Authors"
11
11
  handout = "Handout"
12
- handout_short = "Handout"
13
12
 
14
13
  [general]
15
14
  section = "Block"
@@ -19,4 +18,4 @@ questions_in_comments = "Questions are in the comments."
19
18
  handout_for_question = "Handout for question {}"
20
19
  general_impressions_caption = "General impression"
21
20
  general_impressions_text = "Please share your general impression of the packet in the comments to this post."
22
- right_answers_for_stats = "Correct answers"
21
+ right_answers_for_stats = "Correct answers"
@@ -9,7 +9,6 @@ sources = "Дереккөздер"
9
9
  author = "Автор"
10
10
  authors = "Авторлар"
11
11
  handout = "Үлестіру материалы"
12
- handout_short = "Материал"
13
12
 
14
13
  [general]
15
14
  section = "Тур"
@@ -20,4 +19,4 @@ general_impressions_caption = "Жалпы әсер"
20
19
  handout_for_question = "{}-сұрақтың үлестіру материалы"
21
20
  general_impressions_text = "Пакеттен алған жалпы әсер — осы пост астындағы комментарийлерде."
22
21
  right_answers_for_stats = "Алған сұрақтар"
23
- cf_image = "суретті қараңыз"
22
+ cf_image = "суретті қараңыз"
@@ -9,7 +9,6 @@ sources = "Источники"
9
9
  author = "Автор"
10
10
  authors = "Авторы"
11
11
  handout = "Раздаточный материал"
12
- handout_short = "Раздат"
13
12
 
14
13
  [general]
15
14
  section = "Тур"
@@ -20,4 +19,4 @@ general_impressions_caption = "Общие впечатления"
20
19
  handout_for_question = "Раздаточный материал к вопросу {}"
21
20
  general_impressions_text = "Общее впечатление от пакета — в комментариях к этому посту."
22
21
  right_answers_for_stats = "Взятия"
23
- cf_image = "см. изображение"
22
+ cf_image = "см. изображение"
@@ -9,7 +9,6 @@ sources = "Izvori"
9
9
  author = "Autor"
10
10
  authors = "Autori"
11
11
  handout = "Materijal za deljenje"
12
- handout_short = "Podeljeno"
13
12
 
14
13
  [general]
15
14
  section = "Runda"
@@ -20,4 +19,4 @@ general_impressions_caption = "Opšti utisci"
20
19
  handout_for_question = "Materijal za deljenje uz pitanje {}"
21
20
  general_impressions_text = "Opšti utisak od paketa — u komentarima na ovu objavu."
22
21
  right_answers_for_stats = "Pogodak"
23
- cf_image = "vidi sliku"
22
+ cf_image = "vidi sliku"
@@ -9,7 +9,6 @@ sources = "Джерела"
9
9
  author = "Автор"
10
10
  authors = "Автори"
11
11
  handout = "Роздатковий матеріал"
12
- handout_short = "Роздат"
13
12
 
14
13
  [general]
15
14
  section = "Тур"
@@ -19,4 +18,4 @@ questions_in_comments = "Запитання у коментарях."
19
18
  handout_for_question = "Роздатковий матеріал до запитання {}"
20
19
  general_impressions_caption = "Загальні враження"
21
20
  general_impressions_text = "Загальні враження про пакет — у коментарях до цього посту."
22
- right_answers_for_stats = "Взяття"
21
+ right_answers_for_stats = "Взяття"
@@ -9,7 +9,6 @@ sources = "Manbalar"
9
9
  author = "Muallif"
10
10
  authors = "Mualliflar"
11
11
  handout = "Tarqatma material"
12
- handout_short = "Tarqat"
13
12
 
14
13
  [general]
15
14
  section = "Tur"
@@ -20,5 +19,3 @@ handout_for_question = "{} savolga tarqatma material."
20
19
  general_impressions_caption = "Umumiy taasurotlar"
21
20
  general_impressions_text = "To‘plamdan umumiy taasurotlar — ushbu postning izohlarida."
22
21
  right_answers_for_stats = "To‘g‘ri javoblar foizi"
23
-
24
-
@@ -9,7 +9,6 @@ sources = "Манбалар"
9
9
  author = "Муаллиф"
10
10
  authors = "Муаллифлар"
11
11
  handout = "Тарқатма материал"
12
- handout_short = "Тарқат"
13
12
 
14
13
  [general]
15
14
  section = "Тур"
@@ -19,4 +18,4 @@ questions_in_comments = "Саволлар изоҳларда."
19
18
  handout_for_question = "{} саволга тарқатма материал."
20
19
  general_impressions_caption = "Умумий таасуротлар"
21
20
  general_impressions_text = "Тўпламдан умумий таасуротлар — ушбу постнинг изоҳларида."
22
- right_answers_for_stats = "Тўғри жавоблар фоизи"
21
+ right_answers_for_stats = "Тўғри жавоблар фоизи"
@@ -0,0 +1,17 @@
1
+ {
2
+ "tour": "^(#\\s+)?T[Uu][Rr]\\s?№?\\s?([0-9IVXLCDM]*)([\\.:])?$",
3
+ "tourrev": "^([0-9IVXLCDM]+)\\s[Tt][Uu][Rr]([\\.:])?$",
4
+ "question": "S[Uu][Aa][Ll]\\s?[№N]?(?P<number>[0-9\\s]*)\\s*([\\.:]|\\n|\\r\\n|$)",
5
+ "handout": "^P[Aa][Yy][Ll][Aa][Mm][Aa]\\s+[Mm][Aa][Tt][Ee][Rr][İi][Aa][Ll][\\.:]",
6
+ "answer": "C[Aa][Vv][Aa][Bb]?\\s?[№N]?([0-9]+)?\\s*[\\.:]?",
7
+ "zachet": "S[Aa][Yy][ıI][Ll][Mm][Aa]\\s+[Mm][Ee][Yy][Aa][Rr][ıI]\\s*[\\.:]?",
8
+ "nezachet": "S[Aa][Yy][ıI][Ll][Mm][ıI][Rr]\\s*[\\.:]?",
9
+ "comment": "Ş[Əə][Rr][Hh]\\s?[№N]?([0-9]+)?\\s*[\\.:]?",
10
+ "author": "M[Üü][Əə][Ll][Ll][İiİı][Ff]\\s*[\\.:]?",
11
+ "source": "M[Əə][Nn][Bb][Əə]\\s*[\\.:]?",
12
+ "editor": "R[Ee][Dd][Aa]([Kk][Tt][Oo][Rr]?\\s*(\\s*[\\.:]|\\s*[\\-–—]+\\s)?)",
13
+ "date": "TT[Aa][Rr][İiİı][Xx]\\s*[\\.:]?",
14
+ "date2": "(^|\\s)[Yy][Aa][Nn][Vv][Aa][Rr]|[Ff][Ee][Vv][Rr][Aa][Ll]|[Mm][Aa][Rr][Tt]|[Aa][Pp][Rr][Ee][Ll]|[Mm][Aa][Yy]|[İi][Yy][Uu][Nn]|[İi][Yy][Uu][Ll]|[Aa][Vv][Qq][Uu][Ss][Tt]|[Ss][Ee][Nn][Tt][Yy][Aa][Bb][Rr]|[Oo][Kk][Tt][Yy][Aa][Bb][Rr]|[Nn][Oo][Yy][Aa][Bb][Rr]|[Dd][Ee][Kk][Aa][Bb][Rr](\\s|$)",
15
+ "number": "^[0-9]+[\\.\\)]\\s*",
16
+ "handout_short": "(P[Aa][Yy][Ll]|R[Ee][Kk][Vv][Ii][Zz][Ii][Tt])"
17
+ }
@@ -12,5 +12,6 @@
12
12
  "editor": "[Рр][Ээ][Дд][Аа][Кк][Тт][Аа][Рр]([Ыы])?(\\s?[\\.:]|\\s[\\-–—]+\\s)",
13
13
  "date": "Д[Аа][Тт][Аа]\\s?[\\.:]",
14
14
  "date2": "(^|\\s)студзеня|лютага|сакавіка|красавіка|мая|чэрвеня|ліпеня|жніўня|верасня|кастрычніка|лістапада|снежня(\\s|$)",
15
- "number": "^[0-9]+[\\.\\)]\\s*"
16
- }
15
+ "number": "^[0-9]+[\\.\\)]\\s*",
16
+ "handout_short": "Р[Аа][Зз][Дд][Аа][Тт]"
17
+ }
@@ -0,0 +1,17 @@
1
+ {
2
+ "tour": "^(#\\s+)?Т[Уу][Рр]\\s?№?\\s?([0-9IVXLCDM]*)([\\.:])?$",
3
+ "tourrev": "^([0-9IVXLCDM]+)\\s[Тт][Уу][Рр]([\\.:])?$",
4
+ "question": "П[Ыы][Тт][Аа][Нн][Ьь][Нн][Ее]\\s?[№N]?(?P<number>[0-9\\s]*)\\s?([\\.:]|\n|\r\n|$)",
5
+ "handout": "Р[Аа][Зз][Дд][Аа][Тт][Кк][Аа][Вв][Ыы][\\s\\s][Мм][Аа][Тт][Ээ][Рр][Ыы][Яя][Лл][\\.:]",
6
+ "answer": "А[Дд][Кк][Аа][Зз][Ыы]?\\s?[№N]?([0-9]+)?\\s?[\\.:]",
7
+ "zachet": "З[Аа][Лл][Іі][Кк]\\s?[\\.:]",
8
+ "nezachet": "Н[Ее][Зз][Аа][Лл][Іі][Кк]\\s?[\\.:]",
9
+ "comment": "К[Аа][Мм][Ее][Нн][Тт][Аа][Рр][Ыы][Йй]\\s?[№N]?([0-9]+)?\\s?[\\.:]",
10
+ "author": "А[Ўў][Тт][Аа][Рр](\\(?[Ыы]?\\)?|[Кк][АаИи])?\\s?[\\.:]",
11
+ "source": "К[Рр][Ыы][Нн][Іі][Цц][АаЫы]\\s?[\\.:]",
12
+ "editor": "[Рр][Ээ][Дд][Аа][Кк][Тт][Аа][Рр]([Ыы])?(\\s?[\\.:]|\\s[\\-–—]+\\s)",
13
+ "date": "Д[Аа][Тт][Аа]\\s?[\\.:]",
14
+ "date2": "(^|\\s)студзеня|лютага|сакавіка|красавіка|мая|траўня|чэрвеня|ліпеня|жніўня|верасьня|кастрычніка|лістапада|сьнежня(\\s|$)",
15
+ "number": "^[0-9]+[\\.\\)]\\s*",
16
+ "handout_short": "Р[Аа][Зз][Дд][Аа][Тт]"
17
+ }
@@ -12,5 +12,6 @@
12
12
  "editor": "E[Dd][Ii][Tt]([Oo][Rr][Ss]?|[Ee][Dd]\\s[Bb][Yy])\\s?(\\s?[\\.:]|\\s[\\-–—]+\\s)",
13
13
  "date": "D[Aa][Tt][Ee]\\s?[\\.:]",
14
14
  "date2": "(^|\\s)Jan(uary)?|Feb(ruary)?|Mar(ch)?|Apr(il)?|May|June?|July?|Aug(ust)?|Sep(tember)?|Oct(ober)?|Nov(ember)?|Dec(ember)?(\\s|$)",
15
- "number": "^[0-9]+[\\.\\)]\\s*"
16
- }
15
+ "number": "^[0-9]+[\\.\\)]\\s*",
16
+ "handout_short": "H[Aa][Nn][Dd][Oo][Uu][Tt]"
17
+ }
@@ -11,5 +11,6 @@
11
11
  "editor": "Р[Ее][Дд][Аа][Кк][Тт][Оо][Рр]([Лл][Аа][Рр])?(\\s?[\\.:]|\\s[\\-–—]+\\s)",
12
12
  "date": "Д[Аа][Тт][Аа]\\s?[\\.:]",
13
13
  "date2": "(^|\\s)[Яя][Нн][Вв][Аа][Рр][ЬьЯя]|[Фф][Ее][Вв][Рр][Аа][Лл][ЬьЯя]|[Мм][Аа][Рр][Тт][Аа]?|[Аа][Пп][Рр][Ее][Лл][ЬьЯя]|[Мм][Аа][ЙйЯя]|[Ии][Юю][Нн][ЬьЯя]|[Ии][Юю][Лл][ЬьЯя]|[Аа][Вв][Гг][Уу][Сс][Тт][Аа]?|[Сс][Ее][Нн][Тт][Яя][Бб][Рр][ЬьЯя]|[Оо][Кк][Тт][Яя][Бб][Рр][ЬьЯя]|[Нн][Оо][Яя][Бб][Рр][ЬьЯя]|[Дд][Ее][Кк][Аа][Бб][Рр][ЬьЯя](\\s|$)",
14
- "number": "^[0-9]+[\\.\\)]\\s*"
15
- }
14
+ "number": "^[0-9]+[\\.\\)]\\s*",
15
+ "handout_short": "М[Аа][Тт][Ее][Рр][Ии][Аа][Лл]"
16
+ }
@@ -12,5 +12,6 @@
12
12
  "editor": "[Рр][Ее][Дд][Аа][Кк][Тт][Оо][Рр]([Ыы]|[Сс][Кк][Аа][Яя]\\s[Гг][Рр][Уу][Пп][Пп][Аа])?(\\s?[\\.:]|\\s[\\-–—]+\\s)",
13
13
  "date": "Д[Аа][Тт][Аа]\\s?[\\.:]",
14
14
  "date2": "(^|\\s)[Яя][Нн][Вв][Аа][Рр][ЬьЯя]|[Фф][Ее][Вв][Рр][Аа][Лл][ЬьЯя]|[Мм][Аа][Рр][Тт][Аа]?|[Аа][Пп][Рр][Ее][Лл][ЬьЯя]|[Мм][Аа][ЙйЯя]|[Ии][Юю][Нн][ЬьЯя]|[Ии][Юю][Лл][ЬьЯя]|[Аа][Вв][Гг][Уу][Сс][Тт][Аа]?|[Сс][Ее][Нн][Тт][Яя][Бб][Рр][ЬьЯя]|[Оо][Кк][Тт][Яя][Бб][Рр][ЬьЯя]|[Нн][Оо][Яя][Бб][Рр][ЬьЯя]|[Дд][Ее][Кк][Аа][Бб][Рр][ЬьЯя](\\s|$)",
15
- "number": "^[0-9]+[\\.\\)]\\s*"
16
- }
15
+ "number": "^[0-9]+[\\.\\)]\\s*",
16
+ "handout_short": "Р[Аа][Зз][Дд][Аа][Тт]"
17
+ }
@@ -12,5 +12,6 @@
12
12
  "editor": "U[Rr][Ee][Dd][Nn][Ii][Kk][Ii]?\\s?(\\s?[\\.:]|\\s[\\-–—]+\\s)",
13
13
  "date": "D[Aa][Tt][Uu][Mm]\\s?[\\.:]",
14
14
  "date2": "WILL_FILL_LATER",
15
- "number": "^[0-9]+[\\.\\)]\\s*"
16
- }
15
+ "number": "^[0-9]+[\\.\\)]\\s*",
16
+ "handout_short": "P[Oo][Dd][Ee][Ll][Jj][Ee][Nn][Oo]"
17
+ }
@@ -12,5 +12,6 @@
12
12
  "editor": "[Рр][Ее][Дд][Аа][Кк][Тт][Оо][Рр]([Ии]|[Сс][Ьь][Кк][Аа]\\s[Гг][Рр][Уу][Пп][Аа])?(\\s?[\\.:]|\\s[\\-–—]+\\s)",
13
13
  "date": "Д[Аа][Тт][Аа]\\s?[\\.:]",
14
14
  "date2": "(^|\\s)cічня|лютого|березня|квітня|травня|червня|липня|серпня|вересня|жовтня|листопада|грудня(\\s|$)",
15
- "number": "^[0-9]+[\\.\\)]\\s*"
16
- }
15
+ "number": "^[0-9]+[\\.\\)]\\s*",
16
+ "handout_short": "Р[Оо][Зз][Дд][Аа][Тт]"
17
+ }
@@ -0,0 +1,16 @@
1
+ {
2
+ "tour": "^(#\\s+)?([0-9]+)\\s?[-–—]\\s?[Tt][Uu][Rr]\\s*$",
3
+ "question": "(?P<number>[0-9]+)\\s?[-–—]\\s?[Ss][Aa][Vv][Oo][Ll]([\\.:]|\n|\r\n|$)",
4
+ "answer": "[Jj][Aa][Vv][Oo][Bb]\\s?[№N]?([0-9]+)?\\s?[\\.:]",
5
+ "handout": "[Tt][Aa][Rr][Qq][Aa][Tt][Mm][Aa][\\s\\s][Mm][Aa][Tt][Ee][Rr][Ii][Aa][Ll][\\.:]",
6
+ "zachet": "[Qq][Aa][Bb][Uu][Ll]\\s?[\\.:]",
7
+ "nezachet": "[Qq][Aa][Bb][Uu][Ll]\\s[Ee][Mm][Aa][Ss]?[\\.:]",
8
+ "comment": "[Ii][Zz][Oo][Hh]\\s?[№N]?([0-9]+)?\\s?[\\.:]",
9
+ "author": "[Mm][Uu][Aa][Ll][Ll][Ii][Ff]([Ll][Aa][Rr])?\\s?[\\.:]",
10
+ "source": "[Mm][Aa][Nn][Bb][Aa]([Ll][Aa][Rr])?\\s?[\\.:]",
11
+ "editor": "(M|Tur\\sm)[Uu][Hh][Aa][Rr][Rr][Ii][Rr]([Ll][Aa][Rr][Ii]?)?(\\s?[\\.:]|\\s[\\-–—]+\\s)",
12
+ "date": "[Ss][Aa][Nn][Aa]\\s?[\\.:]",
13
+ "date2": "(^|\\s)[Yy]anvar|[Ff]evral|[Mm]art|[Aa]prel|[Mm]ay|[Ii]yun|[Ii]yul|[Aa]vgust|[Ss]entabr|[Oo]ktabr|[Nn]oyabr|[Dd]ekabr(\\s|$)",
14
+ "number": "^[0-9]+[\\.\\)]\\s*",
15
+ "handout_short": "T[Aa][Rr][Qq][Aa][Tt]"
16
+ }
@@ -11,5 +11,6 @@
11
11
  "editor": "(М|Тур\\sм)[Уу][Ҳҳ][Аа][Рр][Рр][Ии][Рр]([Лл][Аа][Рр][Ии]?)?(\\s?[\\.:]|\\s[\\-–—]+\\s)",
12
12
  "date": "С[Аа][Нн][Аа]\\s?[\\.:]",
13
13
  "date2": "(^|\\s)январь|февраль|март|апрель|май|июнь|июль|август|сентябрь|октябрь|ноябрь|декабрь(\\s|$)",
14
- "number": "^[0-9]+[\\.\\)]\\s*"
15
- }
14
+ "number": "^[0-9]+[\\.\\)]\\s*",
15
+ "handout_short": "Т[Аа][Рр][Ққ][Аа][Тт]"
16
+ }
chgksuite/trello.py CHANGED
@@ -421,7 +421,7 @@ def get_board_id(path=None):
421
421
  print(" board_id")
422
422
  print()
423
423
  board_id = input(
424
- "Please paste your board_id " "(or the board link, " "we'll parse it): "
424
+ "Please paste your board_id (or the board link, we'll parse it): "
425
425
  ).rstrip()
426
426
  if "trello.com" in board_id:
427
427
  board_id = re_bi.search(board_id).group(1)
chgksuite/typotools.py CHANGED
@@ -258,7 +258,9 @@ def replace_no_break(s, spaces=True, hyphens=True):
258
258
  r_from = "(^|[ \u00a0]){sp} ".format(sp=sp)
259
259
  r_to = "\\g<1>{sp}\u00a0".format(sp=sp)
260
260
  s = re.sub(r_from, r_to, s)
261
- for sp in NO_BREAK_SEQUENCES_LEFT + [x.title() for x in NO_BREAK_SEQUENCES_LEFT]:
261
+ for sp in NO_BREAK_SEQUENCES_LEFT + [
262
+ x.title() for x in NO_BREAK_SEQUENCES_LEFT
263
+ ]:
262
264
  r_from = " {sp}([ \u00a0]|$)".format(sp=sp)
263
265
  r_to = "\u00a0{sp}\\g<1>".format(sp=sp)
264
266
  s = re.sub(r_from, r_to, s)
@@ -298,8 +300,7 @@ def detect_accent(s):
298
300
  s = s[: s.index(word)] + word_new + s[s.index(word) + len(word) :]
299
301
  except Exception as e:
300
302
  sys.stderr.write(
301
- f"exception {type(e)} {e} "
302
- f"while trying to process word {repr(word)}"
303
+ f"exception {type(e)} {e} while trying to process word {repr(word)}"
303
304
  )
304
305
  return s
305
306
 
@@ -313,7 +314,7 @@ def percent_decode(s):
313
314
  s = s.replace(gr, unquote(gr.encode("utf8")).decode("utf8"))
314
315
  except Exception as e:
315
316
  sys.stderr.write(
316
- f"exception {type(e)} {e} " f"while trying to replace percents in {gr}"
317
+ f"exception {type(e)} {e} while trying to replace percents in {gr}"
317
318
  )
318
319
  return s
319
320
 
chgksuite/version.py CHANGED
@@ -1 +1 @@
1
- __version__ = "0.26.1"
1
+ __version__ = "0.27.0b1"
@@ -1,13 +1,13 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: chgksuite
3
- Version: 0.26.1
3
+ Version: 0.27.0b1
4
4
  Summary: A package for chgk automation
5
- Home-page: https://gitlab.com/peczony/chgksuite
6
- Author: Alexander Pecheny
7
- Author-email: ap@pecheny.me
5
+ Author-email: Alexander Pecheny <ap@pecheny.me>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://gitlab.com/peczony/chgksuite
8
8
  Classifier: Programming Language :: Python :: 3
9
- Classifier: License :: OSI Approved :: MIT License
10
9
  Classifier: Operating System :: OS Independent
10
+ Requires-Python: >=3.9
11
11
  Description-Content-Type: text/markdown
12
12
  License-File: LICENSE
13
13
  Requires-Dist: beautifulsoup4
@@ -27,16 +27,9 @@ Requires-Dist: python-pptx
27
27
  Requires-Dist: python-telegram-bot
28
28
  Requires-Dist: requests
29
29
  Requires-Dist: toml
30
+ Requires-Dist: urllib3>=2.6.2
30
31
  Requires-Dist: watchdog
31
- Dynamic: author
32
- Dynamic: author-email
33
- Dynamic: classifier
34
- Dynamic: description
35
- Dynamic: description-content-type
36
- Dynamic: home-page
37
32
  Dynamic: license-file
38
- Dynamic: requires-dist
39
- Dynamic: summary
40
33
 
41
34
  **chgksuite** is an utility that helps chgk editors.
42
35
 
@@ -0,0 +1,62 @@
1
+ chgksuite/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ chgksuite/__main__.py,sha256=0-_jfloveTW3SZYW5XEagbyaHKGCiDhGNgcLxsT_dMs,140
3
+ chgksuite/cli.py,sha256=95Xj1jrnybtso9qSCAwgv6utCrhJF43oFXlH5LWyHKA,40918
4
+ chgksuite/common.py,sha256=G22hjYiaIbx9BYlUhAvxm5u18L-fQHMPxS0fWEloxY4,11259
5
+ chgksuite/parser.py,sha256=2UL-2dJtCFYEjakUfeh3n1E4epMKPo0pjdaC_cBZplM,45775
6
+ chgksuite/parser_db.py,sha256=gh5AM80UR_hQ0r_-AwWLbqZCl2V0j3HAgj6BilImXyc,11116
7
+ chgksuite/trello.py,sha256=I1JmIbZVJjJuuRO0g26fNt8deRo9hDlk1xBIf8w31Rs,14724
8
+ chgksuite/typotools.py,sha256=0fQOjt5H3NRl0JeGTp2x-k-2ZN68E9Z9WX8D7lCwXmA,12765
9
+ chgksuite/version.py,sha256=BMipZbM9Ag16K9oGcrXq6grxJ3pRc1ArXuoS376Fubc,25
10
+ chgksuite/vulture_whitelist.py,sha256=P__p_X0zt10ivddIf81uyxsobV14vFg8uS2lt4foYpc,3582
11
+ chgksuite/composer/__init__.py,sha256=MAOVZIYXmZmD6nNQSo9DueV6b5RgxF7_HGeLvsAhMJs,6490
12
+ chgksuite/composer/chgksuite_parser.py,sha256=XxopZLVY4DQxgxw2a6NT70ga_2XZHzuvn58RnlriiqE,8847
13
+ chgksuite/composer/composer_common.py,sha256=kc-_Tc9NjevfXGj4fXoa9fye9AO0EuMSnEPJnS0n-aQ,16281
14
+ chgksuite/composer/db.py,sha256=71cINE_V8s6YidvqpmBmmlWbcXraUEGZA1xpVFAUENw,8173
15
+ chgksuite/composer/docx.py,sha256=W46glwffZFpIATrwe_100vl5ypobMwXADSfoaApyHl8,23716
16
+ chgksuite/composer/latex.py,sha256=_IKylzdDcokgXYvvxsVSiq-Ba5fVirWcfCp6eOyx6zQ,9242
17
+ chgksuite/composer/lj.py,sha256=nty3Zs3N1H0gNK378U04aAHo71_5cABhCM1Mm9jiUEA,15213
18
+ chgksuite/composer/openquiz.py,sha256=D9q7lcEgUGwR1UF6Qp3I-wBJucy9vMnrxoSOst4V45Q,7001
19
+ chgksuite/composer/pptx.py,sha256=9O0tfx2xpyx9Y4ceatVIXdiwvslnj8gliZIlxsDe5Ow,23971
20
+ chgksuite/composer/reddit.py,sha256=-Eg4CqMHhyGGfCteVwdQdtE1pfUXQ42XcP5OYUrBXmo,3878
21
+ chgksuite/composer/stats.py,sha256=GbraSrjaZ8Mc2URs5aGAsI4ekboAKzlJJOqsbe96ELA,3995
22
+ chgksuite/composer/telegram.py,sha256=KM9Bnkf2bxdJNMrhjCCw2xx-sWcIQioBc1FdSY4OX-g,47431
23
+ chgksuite/composer/telegram_bot.py,sha256=xT5D39m4zGmIbHV_ZfyQ9Rc8PAmG2V5FGUeDKpkgyTw,3767
24
+ chgksuite/handouter/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
25
+ chgksuite/handouter/gen.py,sha256=CJfGl8R2vnElnsjBo0n4u-y8KD-l2qxrIuUHj5WZBuI,5241
26
+ chgksuite/handouter/installer.py,sha256=u4jQKeCn0VjOnaDFezx35g8oRjji5edvYGj5xSHCEW4,7574
27
+ chgksuite/handouter/pack.py,sha256=H-Ln1JqKK2u3jFI5wwsh7pQdJBpQJ-s8gV9iECQ3kgU,2504
28
+ chgksuite/handouter/runner.py,sha256=QPqLKbfNDL0ucJ365lvKCwRcPKrhxRBJ-YFSbQLU9_8,8641
29
+ chgksuite/handouter/tex_internals.py,sha256=pxvMXkqlMfzBbAlTkFCJBlcT7t1XS0Z9XOzVboc2f2Y,966
30
+ chgksuite/handouter/utils.py,sha256=0RoECvHzfmwWnRL2jj4WKh22oTCPh2MXid_a9ShplDA,2243
31
+ chgksuite/resources/cheader.tex,sha256=Jfe3LESk0VIV0HCObbajSQpEMljaIDAIEGSs6YY9rTk,3454
32
+ chgksuite/resources/fix-unnumbered-sections.sty,sha256=FN6ZSWC6MvoRoThPm5AxCF98DdgcxbxyBYG6YImM05s,1409
33
+ chgksuite/resources/labels_az.toml,sha256=hiXt-54nMQ4Ie0RUVbQhXxlj47NEc2qNwe7O1NIMe-8,662
34
+ chgksuite/resources/labels_by.toml,sha256=nZv6fwUYEPPVooyZi8U3LOkn8PZajKxm0fzATWOBVDE,794
35
+ chgksuite/resources/labels_by_tar.toml,sha256=Ba4HGg4MbPTV7GEcfVScpiRL3X8sIpVGi1-dFXm2dms,812
36
+ chgksuite/resources/labels_en.toml,sha256=XEQdFXHXZSl1X7pxeddWoFVwkHaxxxSmvo9IJLHcmus,591
37
+ chgksuite/resources/labels_kz_cyr.toml,sha256=giUX-SDSI_p4Z2G6y4zHc_ZX8uf63OBwvmmKGInD1y8,912
38
+ chgksuite/resources/labels_ru.toml,sha256=nEc-eQdtkMj6Ibcu4QZaLYq-OvLqjxjZzyEGsWZ4UAQ,829
39
+ chgksuite/resources/labels_sr.toml,sha256=xYnZuvvg2f_A314deiqpTI6PcqRfl3hqCp51HR3DmgY,601
40
+ chgksuite/resources/labels_ua.toml,sha256=1xmySvbVXUMltRNQq5Vxjyf0ipBIsvbd--UtJbTBq4M,793
41
+ chgksuite/resources/labels_uz.toml,sha256=YAVut-eYv-xmCfd81hTIYyK01HCR0xMkmA_lzKzOYek,582
42
+ chgksuite/resources/labels_uz_cyr.toml,sha256=vUH4oUzKzjPFQjFE_nACLIiRL5_bV4tcttzpbPKkztQ,784
43
+ chgksuite/resources/pptx_config.toml,sha256=pbdQpZTBZajfXxf9Ej6jFQv8luA9_h2Lsihx9hs2jkI,570
44
+ chgksuite/resources/regexes_az.json,sha256=TOJIo6o1Fd1PMkCPdN9de81kv9txlyOSbz-zTVsbyts,1252
45
+ chgksuite/resources/regexes_by.json,sha256=tWwL03dSuV9SF31fFC26zER6w2Va41Ko5D0gp9fgEYQ,1364
46
+ chgksuite/resources/regexes_by_tar.json,sha256=k5eCNOUinOadqfSVpx6nHj2KW2oleIZYcAACBe_iDc4,1344
47
+ chgksuite/resources/regexes_en.json,sha256=Faj3KAwLaPXOwJEK7d3tnRuSB0NYwAeSG-Vcmy9D06g,1064
48
+ chgksuite/resources/regexes_kz_cyr.json,sha256=Ggu6owq5sLatlDoRgSRhtFNvIeDRvr9tDyezw68IaC4,1759
49
+ chgksuite/resources/regexes_ru.json,sha256=BFZw2FW7Vf49C_DD-nXi5yf9DQYAVpMJUWjDVz3HrGg,2245
50
+ chgksuite/resources/regexes_sr.json,sha256=kyQQ2Ht3ucZRIgEKyqiGtEVUoUiTrmE1JSVasU8FSD8,994
51
+ chgksuite/resources/regexes_ua.json,sha256=SSLjLDKfKzbEIvxJAXwSGCgsmnyKgXnkhUNByjN2gVs,1398
52
+ chgksuite/resources/regexes_uz.json,sha256=07HrBZd9XymcEpHYW9Kf41-hZtvFJQdeJbge-TE-QMM,1015
53
+ chgksuite/resources/regexes_uz_cyr.json,sha256=D4AyaEPEY753I47Ky2Fwol_4kxQsl-Yu96HwbIiyDwI,1174
54
+ chgksuite/resources/template.docx,sha256=Do29TAsg3YbH0rRSaXhVzKEoh4pwXkklW_idWA34HVE,11189
55
+ chgksuite/resources/template.pptx,sha256=hEFWqE-yYpwZ8ejrMCJIPEyoMT3eDqaqtiEeQ7I4fyk,29777
56
+ chgksuite/resources/trello.json,sha256=M5Q9JR-AAJF1u16YtNAxDX-7c7VoVTXuq4POTqYvq8o,555
57
+ chgksuite-0.27.0b1.dist-info/licenses/LICENSE,sha256=_a1yfntuPmctLsuiE_08xMSORuCfGS8X5hQph2U_PUw,1081
58
+ chgksuite-0.27.0b1.dist-info/METADATA,sha256=VDtDhSSqllITQr0WuR2CvuX2tPBJczXfYneoi0zzn_U,1201
59
+ chgksuite-0.27.0b1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
60
+ chgksuite-0.27.0b1.dist-info/entry_points.txt,sha256=lqjX6ULQZGDt0rgouTXBuwEPiwKkDQkSiNsT877A_Jg,54
61
+ chgksuite-0.27.0b1.dist-info/top_level.txt,sha256=cSWiRBOGZW9nIO6Rv1IrEfwPgV2ZWs87QV9wPXeBGqM,10
62
+ chgksuite-0.27.0b1.dist-info/RECORD,,
@@ -1,230 +0,0 @@
1
- # from https://gist.github.com/YouKnow-sys/3d571bdd4857f175d91db8146ec065bf
2
-
3
- from collections import deque
4
- from html import escape
5
- from html.parser import HTMLParser
6
- from typing import Iterable, List, Tuple
7
-
8
- from telethon.helpers import add_surrogate, del_surrogate, strip_text, within_surrogate
9
- from telethon.tl import TLObject
10
- from telethon.types import (
11
- MessageEntityBlockquote,
12
- MessageEntityBold,
13
- MessageEntityCode,
14
- MessageEntityCustomEmoji,
15
- MessageEntityEmail,
16
- MessageEntityItalic,
17
- MessageEntityMentionName,
18
- MessageEntityPre,
19
- MessageEntitySpoiler,
20
- MessageEntityStrike,
21
- MessageEntityTextUrl,
22
- MessageEntityUnderline,
23
- MessageEntityUrl,
24
- TypeMessageEntity,
25
- )
26
-
27
-
28
- class HTMLToTelegramParser(HTMLParser):
29
- def __init__(self):
30
- super().__init__()
31
- self.text = ""
32
- self.entities = []
33
- self._building_entities = {}
34
- self._open_tags = deque()
35
- self._open_tags_meta = deque()
36
-
37
- def handle_starttag(self, tag, attrs):
38
- self._open_tags.appendleft(tag)
39
- self._open_tags_meta.appendleft(None)
40
-
41
- attrs = dict(attrs)
42
- EntityType = None
43
- args = {}
44
- match tag:
45
- case "strong" | "b":
46
- EntityType = MessageEntityBold
47
- case "em" | "i":
48
- EntityType = MessageEntityItalic
49
- case "u":
50
- EntityType = MessageEntityUnderline
51
- case "del" | "s":
52
- EntityType = MessageEntityStrike
53
- case "blockquote":
54
- EntityType = MessageEntityBlockquote
55
- case "spoiler":
56
- EntityType = MessageEntitySpoiler
57
- case "code":
58
- try:
59
- # If we're in the middle of a <pre> tag, this <code> tag is
60
- # probably intended for syntax highlighting.
61
- #
62
- # Syntax highlighting is set with
63
- # <code class='language-...'>codeblock</code>
64
- # inside <pre> tags
65
- pre = self._building_entities["pre"]
66
- try:
67
- pre.language = attrs["class"][len("language-") :] # type: ignore
68
- except KeyError:
69
- pass
70
- except KeyError:
71
- EntityType = MessageEntityCode
72
- case "pre":
73
- EntityType = MessageEntityPre
74
- args["language"] = ""
75
- case "a":
76
- try:
77
- url = attrs["href"]
78
- if not url:
79
- raise KeyError
80
- except KeyError:
81
- return
82
- if url.startswith("mailto:"):
83
- url = url[len("mailto:") :]
84
- EntityType = MessageEntityEmail
85
- else:
86
- if self.get_starttag_text() == url:
87
- EntityType = MessageEntityUrl
88
- else:
89
- EntityType = MessageEntityTextUrl
90
- args["url"] = del_surrogate(url)
91
- url = None
92
- self._open_tags_meta.popleft()
93
- self._open_tags_meta.appendleft(url)
94
- case "tg-emoji":
95
- try:
96
- emoji_id = attrs["emoji-id"]
97
- if not emoji_id:
98
- raise ValueError
99
- emoji_id = int(emoji_id)
100
- except (KeyError, ValueError):
101
- return
102
- EntityType = MessageEntityCustomEmoji
103
- args["document_id"] = emoji_id
104
-
105
- if EntityType and tag not in self._building_entities:
106
- self._building_entities[tag] = EntityType(
107
- offset=len(self.text),
108
- # The length will be determined when closing the tag.
109
- length=0,
110
- **args,
111
- )
112
-
113
- def handle_data(self, data):
114
- previous_tag = self._open_tags[0] if len(self._open_tags) > 0 else ""
115
- if previous_tag == "a":
116
- url = self._open_tags_meta[0]
117
- if url:
118
- data = url
119
-
120
- for tag, entity in self._building_entities.items():
121
- entity.length += len(data)
122
-
123
- self.text += data
124
-
125
- def handle_endtag(self, tag):
126
- try:
127
- self._open_tags.popleft()
128
- self._open_tags_meta.popleft()
129
- except IndexError:
130
- pass
131
- entity = self._building_entities.pop(tag, None)
132
- if entity:
133
- self.entities.append(entity)
134
-
135
-
136
- ENTITY_TO_FORMATTER = {
137
- MessageEntityBold: ("<strong>", "</strong>"),
138
- MessageEntityItalic: ("<em>", "</em>"),
139
- MessageEntityCode: ("<code>", "</code>"),
140
- MessageEntityUnderline: ("<u>", "</u>"),
141
- MessageEntityStrike: ("<del>", "</del>"),
142
- MessageEntityBlockquote: ("<blockquote>", "</blockquote>"),
143
- MessageEntitySpoiler: ("<spoiler>", "</spoiler>"),
144
- MessageEntityPre: lambda e, _: (
145
- "<pre>\n <code class='language-{}'>\n ".format(e.language),
146
- "{}\n </code>\n</pre>",
147
- ),
148
- MessageEntityEmail: lambda _, t: ('<a href="mailto:{}">'.format(t), "</a>"),
149
- MessageEntityUrl: lambda _, t: ('<a href="{}">'.format(t), "</a>"),
150
- MessageEntityTextUrl: lambda e, _: ('<a href="{}">'.format(escape(e.url)), "</a>"),
151
- MessageEntityMentionName: lambda e, _: (
152
- '<a href="tg://user?id={}">'.format(e.user_id),
153
- "</a>",
154
- ),
155
- MessageEntityCustomEmoji: lambda e, _: (
156
- '<tg-emoji emoji-id="{}">'.format(e.document_id),
157
- "</tg-emoji>",
158
- ),
159
- }
160
-
161
-
162
- class CustomHtmlParser:
163
- @staticmethod
164
- def parse(html: str) -> Tuple[str, List[TypeMessageEntity]]:
165
- """
166
- Parses the given HTML message and returns its stripped representation
167
- plus a list of the MessageEntity's that were found.
168
-
169
- :param html: the message with HTML to be parsed.
170
- :return: a tuple consisting of (clean message, [message entities]).
171
- """
172
- if not html:
173
- return html, []
174
-
175
- parser = HTMLToTelegramParser()
176
- parser.feed(add_surrogate(html))
177
- text = strip_text(parser.text, parser.entities)
178
- parser.entities.reverse()
179
- parser.entities.sort(key=lambda entity: entity.offset)
180
- return del_surrogate(text), parser.entities
181
-
182
- @staticmethod
183
- def unparse(text: str, entities: Iterable[TypeMessageEntity]) -> str:
184
- """
185
- Performs the reverse operation to .parse(), effectively returning HTML
186
- given a normal text and its MessageEntity's.
187
-
188
- :param text: the text to be reconverted into HTML.
189
- :param entities: the MessageEntity's applied to the text.
190
- :return: a HTML representation of the combination of both inputs.
191
- """
192
- if not text:
193
- return text
194
- elif not entities:
195
- return escape(text)
196
-
197
- if isinstance(entities, TLObject):
198
- entities = (entities,) # type: ignore
199
-
200
- text = add_surrogate(text)
201
- insert_at = []
202
- for i, entity in enumerate(entities):
203
- s = entity.offset
204
- e = entity.offset + entity.length
205
- delimiter = ENTITY_TO_FORMATTER.get(type(entity), None) # type: ignore
206
- if delimiter:
207
- if callable(delimiter):
208
- delimiter = delimiter(entity, text[s:e])
209
- insert_at.append((s, i, delimiter[0]))
210
- insert_at.append((e, -i, delimiter[1]))
211
-
212
- insert_at.sort(key=lambda t: (t[0], t[1]))
213
- next_escape_bound = len(text)
214
- while insert_at:
215
- # Same logic as markdown.py
216
- at, _, what = insert_at.pop()
217
- while within_surrogate(text, at):
218
- at += 1
219
-
220
- text = (
221
- text[:at]
222
- + what
223
- + escape(text[at:next_escape_bound])
224
- + text[next_escape_bound:]
225
- )
226
- next_escape_bound = at
227
-
228
- text = escape(text[:next_escape_bound]) + text[next_escape_bound:]
229
-
230
- return del_surrogate(text)
@@ -1,59 +0,0 @@
1
- chgksuite/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- chgksuite/__main__.py,sha256=0-_jfloveTW3SZYW5XEagbyaHKGCiDhGNgcLxsT_dMs,140
3
- chgksuite/cli.py,sha256=iZGpx4-_vTxdKsKsRXCu7vjpiFhR_oyhLRGXyvGl7i8,40901
4
- chgksuite/common.py,sha256=VkOhoBA_P3qY5VgtvfrBjOsm5uVNL2s2Th2AhGB2pg8,11207
5
- chgksuite/parser.py,sha256=rv8n1ff0xpcHHMA1fsjKmJZ5EcFupChHwXch8pncCNk,45855
6
- chgksuite/parser_db.py,sha256=W1--OcDnx18mehH1T2ISHu3Saeq-9mqHo-xJopNySXI,11135
7
- chgksuite/trello.py,sha256=BG1Qb_W7Uu4o3Mfc_tK71ElU8ysdSplGlj_sAKfvUn4,14730
8
- chgksuite/typotools.py,sha256=Jdk65Wn_bXqpQtOT7PkBZyD2ZG1MBeeZFPMzcHEPkf4,12771
9
- chgksuite/version.py,sha256=u0eTmljUU0kO8AAW-e1ESQ49mK2SuhpCy7eCliBLlDU,23
10
- chgksuite/vulture_whitelist.py,sha256=P__p_X0zt10ivddIf81uyxsobV14vFg8uS2lt4foYpc,3582
11
- chgksuite/composer/__init__.py,sha256=MAOVZIYXmZmD6nNQSo9DueV6b5RgxF7_HGeLvsAhMJs,6490
12
- chgksuite/composer/chgksuite_parser.py,sha256=XxopZLVY4DQxgxw2a6NT70ga_2XZHzuvn58RnlriiqE,8847
13
- chgksuite/composer/composer_common.py,sha256=AQ14sX2Luo2TAxdMaPCV8m0XckE0Bm14kQ4WO3gKVqw,15962
14
- chgksuite/composer/db.py,sha256=71cINE_V8s6YidvqpmBmmlWbcXraUEGZA1xpVFAUENw,8173
15
- chgksuite/composer/docx.py,sha256=CrefvNynaPyJ5qni9C259LL8DapWobUuLBxbwvPQWCM,23095
16
- chgksuite/composer/latex.py,sha256=_IKylzdDcokgXYvvxsVSiq-Ba5fVirWcfCp6eOyx6zQ,9242
17
- chgksuite/composer/lj.py,sha256=nty3Zs3N1H0gNK378U04aAHo71_5cABhCM1Mm9jiUEA,15213
18
- chgksuite/composer/openquiz.py,sha256=4adZewvRXpZhKrh9H4epKoMMDhmki9US55-Q0LcpZW0,7019
19
- chgksuite/composer/pptx.py,sha256=U7Ekfn_Wvfzp6VOHizom870KdCcReWl4ynw_9DtHRac,23988
20
- chgksuite/composer/reddit.py,sha256=-Eg4CqMHhyGGfCteVwdQdtE1pfUXQ42XcP5OYUrBXmo,3878
21
- chgksuite/composer/stats.py,sha256=GbraSrjaZ8Mc2URs5aGAsI4ekboAKzlJJOqsbe96ELA,3995
22
- chgksuite/composer/telegram.py,sha256=hfU0EF0UhAq3rR8etyQN5S1CUdOnItluc7vuX3UY_TE,47387
23
- chgksuite/composer/telegram_bot.py,sha256=xT5D39m4zGmIbHV_ZfyQ9Rc8PAmG2V5FGUeDKpkgyTw,3767
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
32
- chgksuite/resources/cheader.tex,sha256=Jfe3LESk0VIV0HCObbajSQpEMljaIDAIEGSs6YY9rTk,3454
33
- chgksuite/resources/fix-unnumbered-sections.sty,sha256=FN6ZSWC6MvoRoThPm5AxCF98DdgcxbxyBYG6YImM05s,1409
34
- chgksuite/resources/labels_by.toml,sha256=kSbIYBnxneRJAcDmeoFGlPpjogWuoMO11302p0BxB-s,824
35
- chgksuite/resources/labels_by_tar.toml,sha256=gBDMuMZkPI_rM-nwln2jAf47pAnxZ0xft6jtMtETRS0,842
36
- chgksuite/resources/labels_en.toml,sha256=E_lcA5KmIJVEVlBEGBU9Be6COjvQw4BQ-Vg4KlQqfGk,616
37
- chgksuite/resources/labels_kz_cyr.toml,sha256=mnGxVDuixaOSDQni7MYwCTrpU6YitPh6AaiqEzmBQ84,946
38
- chgksuite/resources/labels_ru.toml,sha256=kUHq6hP9Z60CJ5m5_yAA4CzjXjD9w6_96WHxJ1ptnjU,859
39
- chgksuite/resources/labels_sr.toml,sha256=DReGla_IgdXPtPy7y4pzZa6RvmKu54MivOYca9gnxbQ,628
40
- chgksuite/resources/labels_ua.toml,sha256=sUZdwwpkddb_56bmrZyO56cDrm68ft_JoMqR38M-Dnc,823
41
- chgksuite/resources/labels_uz.toml,sha256=uRnf6tjBf1rYpWjt675ecB2MPn_Ohz-Hj6XDYNPpe3o,609
42
- chgksuite/resources/labels_uz_cyr.toml,sha256=ztqHItwhJjfBTOIj_vA1hrneYo8s5gvZkkSr0k9S3rs,814
43
- chgksuite/resources/pptx_config.toml,sha256=pbdQpZTBZajfXxf9Ej6jFQv8luA9_h2Lsihx9hs2jkI,570
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
51
- chgksuite/resources/template.docx,sha256=Do29TAsg3YbH0rRSaXhVzKEoh4pwXkklW_idWA34HVE,11189
52
- chgksuite/resources/template.pptx,sha256=hEFWqE-yYpwZ8ejrMCJIPEyoMT3eDqaqtiEeQ7I4fyk,29777
53
- chgksuite/resources/trello.json,sha256=M5Q9JR-AAJF1u16YtNAxDX-7c7VoVTXuq4POTqYvq8o,555
54
- chgksuite-0.26.1.dist-info/licenses/LICENSE,sha256=_a1yfntuPmctLsuiE_08xMSORuCfGS8X5hQph2U_PUw,1081
55
- chgksuite-0.26.1.dist-info/METADATA,sha256=mrofe1zLMG4aMVRK_d0FLVa0TYpKNoLLrSaJGdVmowk,1339
56
- chgksuite-0.26.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
57
- chgksuite-0.26.1.dist-info/entry_points.txt,sha256=lqjX6ULQZGDt0rgouTXBuwEPiwKkDQkSiNsT877A_Jg,54
58
- chgksuite-0.26.1.dist-info/top_level.txt,sha256=cSWiRBOGZW9nIO6Rv1IrEfwPgV2ZWs87QV9wPXeBGqM,10
59
- chgksuite-0.26.1.dist-info/RECORD,,