chgksuite 0.26.1__tar.gz → 0.27.0b1__tar.gz

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 (72) hide show
  1. {chgksuite-0.26.1/chgksuite.egg-info → chgksuite-0.27.0b1}/PKG-INFO +6 -13
  2. {chgksuite-0.26.1 → chgksuite-0.27.0b1}/chgksuite/cli.py +12 -8
  3. {chgksuite-0.26.1 → chgksuite-0.27.0b1}/chgksuite/common.py +4 -1
  4. {chgksuite-0.26.1 → chgksuite-0.27.0b1}/chgksuite/composer/composer_common.py +14 -5
  5. {chgksuite-0.26.1 → chgksuite-0.27.0b1}/chgksuite/composer/docx.py +29 -8
  6. {chgksuite-0.26.1 → chgksuite-0.27.0b1}/chgksuite/composer/openquiz.py +1 -1
  7. {chgksuite-0.26.1 → chgksuite-0.27.0b1}/chgksuite/composer/pptx.py +2 -2
  8. {chgksuite-0.26.1 → chgksuite-0.27.0b1}/chgksuite/composer/telegram.py +2 -1
  9. {chgksuite-0.26.1 → chgksuite-0.27.0b1}/chgksuite/handouter/gen.py +11 -7
  10. {chgksuite-0.26.1 → chgksuite-0.27.0b1}/chgksuite/handouter/runner.py +10 -4
  11. {chgksuite-0.26.1 → chgksuite-0.27.0b1}/chgksuite/handouter/tex_internals.py +0 -11
  12. {chgksuite-0.26.1 → chgksuite-0.27.0b1}/chgksuite/parser.py +6 -9
  13. {chgksuite-0.26.1 → chgksuite-0.27.0b1}/chgksuite/parser_db.py +3 -4
  14. chgksuite-0.27.0b1/chgksuite/resources/labels_az.toml +22 -0
  15. {chgksuite-0.26.1 → chgksuite-0.27.0b1}/chgksuite/resources/labels_by.toml +1 -2
  16. {chgksuite-0.26.1 → chgksuite-0.27.0b1}/chgksuite/resources/labels_by_tar.toml +1 -2
  17. {chgksuite-0.26.1 → chgksuite-0.27.0b1}/chgksuite/resources/labels_en.toml +1 -2
  18. {chgksuite-0.26.1 → chgksuite-0.27.0b1}/chgksuite/resources/labels_kz_cyr.toml +1 -2
  19. {chgksuite-0.26.1 → chgksuite-0.27.0b1}/chgksuite/resources/labels_ru.toml +1 -2
  20. {chgksuite-0.26.1 → chgksuite-0.27.0b1}/chgksuite/resources/labels_sr.toml +1 -2
  21. {chgksuite-0.26.1 → chgksuite-0.27.0b1}/chgksuite/resources/labels_ua.toml +1 -2
  22. {chgksuite-0.26.1 → chgksuite-0.27.0b1}/chgksuite/resources/labels_uz.toml +0 -3
  23. {chgksuite-0.26.1 → chgksuite-0.27.0b1}/chgksuite/resources/labels_uz_cyr.toml +1 -2
  24. chgksuite-0.27.0b1/chgksuite/resources/regexes_az.json +17 -0
  25. {chgksuite-0.26.1 → chgksuite-0.27.0b1}/chgksuite/resources/regexes_by.json +3 -2
  26. chgksuite-0.27.0b1/chgksuite/resources/regexes_by_tar.json +17 -0
  27. {chgksuite-0.26.1 → chgksuite-0.27.0b1}/chgksuite/resources/regexes_en.json +3 -2
  28. {chgksuite-0.26.1 → chgksuite-0.27.0b1}/chgksuite/resources/regexes_kz_cyr.json +3 -2
  29. {chgksuite-0.26.1 → chgksuite-0.27.0b1}/chgksuite/resources/regexes_ru.json +3 -2
  30. {chgksuite-0.26.1 → chgksuite-0.27.0b1}/chgksuite/resources/regexes_sr.json +3 -2
  31. {chgksuite-0.26.1 → chgksuite-0.27.0b1}/chgksuite/resources/regexes_ua.json +3 -2
  32. chgksuite-0.27.0b1/chgksuite/resources/regexes_uz.json +16 -0
  33. {chgksuite-0.26.1 → chgksuite-0.27.0b1}/chgksuite/resources/regexes_uz_cyr.json +3 -2
  34. {chgksuite-0.26.1 → chgksuite-0.27.0b1}/chgksuite/trello.py +1 -1
  35. {chgksuite-0.26.1 → chgksuite-0.27.0b1}/chgksuite/typotools.py +5 -4
  36. chgksuite-0.27.0b1/chgksuite/version.py +1 -0
  37. {chgksuite-0.26.1 → chgksuite-0.27.0b1/chgksuite.egg-info}/PKG-INFO +6 -13
  38. {chgksuite-0.26.1 → chgksuite-0.27.0b1}/chgksuite.egg-info/SOURCES.txt +5 -2
  39. {chgksuite-0.26.1 → chgksuite-0.27.0b1}/chgksuite.egg-info/requires.txt +1 -0
  40. {chgksuite-0.26.1 → chgksuite-0.27.0b1}/history.md +7 -1
  41. chgksuite-0.27.0b1/pyproject.toml +75 -0
  42. chgksuite-0.26.1/chgksuite/composer/telegram_parser.py +0 -230
  43. chgksuite-0.26.1/chgksuite/version.py +0 -1
  44. chgksuite-0.26.1/setup.py +0 -66
  45. {chgksuite-0.26.1 → chgksuite-0.27.0b1}/LICENSE +0 -0
  46. {chgksuite-0.26.1 → chgksuite-0.27.0b1}/MANIFEST.in +0 -0
  47. {chgksuite-0.26.1 → chgksuite-0.27.0b1}/README.md +0 -0
  48. {chgksuite-0.26.1 → chgksuite-0.27.0b1}/chgksuite/__init__.py +0 -0
  49. {chgksuite-0.26.1 → chgksuite-0.27.0b1}/chgksuite/__main__.py +0 -0
  50. {chgksuite-0.26.1 → chgksuite-0.27.0b1}/chgksuite/composer/__init__.py +0 -0
  51. {chgksuite-0.26.1 → chgksuite-0.27.0b1}/chgksuite/composer/chgksuite_parser.py +0 -0
  52. {chgksuite-0.26.1 → chgksuite-0.27.0b1}/chgksuite/composer/db.py +0 -0
  53. {chgksuite-0.26.1 → chgksuite-0.27.0b1}/chgksuite/composer/latex.py +0 -0
  54. {chgksuite-0.26.1 → chgksuite-0.27.0b1}/chgksuite/composer/lj.py +0 -0
  55. {chgksuite-0.26.1 → chgksuite-0.27.0b1}/chgksuite/composer/reddit.py +0 -0
  56. {chgksuite-0.26.1 → chgksuite-0.27.0b1}/chgksuite/composer/stats.py +0 -0
  57. {chgksuite-0.26.1 → chgksuite-0.27.0b1}/chgksuite/composer/telegram_bot.py +0 -0
  58. {chgksuite-0.26.1 → chgksuite-0.27.0b1}/chgksuite/handouter/__init__.py +0 -0
  59. {chgksuite-0.26.1 → chgksuite-0.27.0b1}/chgksuite/handouter/installer.py +0 -0
  60. {chgksuite-0.26.1 → chgksuite-0.27.0b1}/chgksuite/handouter/pack.py +0 -0
  61. {chgksuite-0.26.1 → chgksuite-0.27.0b1}/chgksuite/handouter/utils.py +0 -0
  62. {chgksuite-0.26.1 → chgksuite-0.27.0b1}/chgksuite/resources/cheader.tex +0 -0
  63. {chgksuite-0.26.1 → chgksuite-0.27.0b1}/chgksuite/resources/fix-unnumbered-sections.sty +0 -0
  64. {chgksuite-0.26.1 → chgksuite-0.27.0b1}/chgksuite/resources/pptx_config.toml +0 -0
  65. {chgksuite-0.26.1 → chgksuite-0.27.0b1}/chgksuite/resources/template.docx +0 -0
  66. {chgksuite-0.26.1 → chgksuite-0.27.0b1}/chgksuite/resources/template.pptx +0 -0
  67. {chgksuite-0.26.1 → chgksuite-0.27.0b1}/chgksuite/resources/trello.json +0 -0
  68. {chgksuite-0.26.1 → chgksuite-0.27.0b1}/chgksuite/vulture_whitelist.py +0 -0
  69. {chgksuite-0.26.1 → chgksuite-0.27.0b1}/chgksuite.egg-info/dependency_links.txt +0 -0
  70. {chgksuite-0.26.1 → chgksuite-0.27.0b1}/chgksuite.egg-info/entry_points.txt +0 -0
  71. {chgksuite-0.26.1 → chgksuite-0.27.0b1}/chgksuite.egg-info/top_level.txt +0 -0
  72. {chgksuite-0.26.1 → chgksuite-0.27.0b1}/setup.cfg +0 -0
@@ -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
 
@@ -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")
@@ -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
 
@@ -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
  ):
@@ -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"