linkture 4.0.0__py3-none-any.whl → 4.2.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.
linkture/__main__.py CHANGED
@@ -26,7 +26,7 @@
26
26
  SOFTWARE.
27
27
  """
28
28
 
29
- import argparse
29
+ import argparse, sys, traceback
30
30
  from .linkture import _available_languages, __app__, __version__, Scriptures
31
31
  from ast import literal_eval
32
32
 
@@ -34,24 +34,31 @@ from ast import literal_eval
34
34
  def main(args):
35
35
 
36
36
  def switchboard(text):
37
- if args['l'] is not None:
38
- prefix = '<a href="'
39
- suffix = '">'
40
- if len(args['l']) > 1 and args['l'][1] != '':
41
- suffix = args['l'][1]
42
- if len(args['l']) > 0 and args['l'][0] != '':
43
- prefix = args['l'][0]
44
- return s.link_scriptures(text, prefix, suffix)
45
- elif args['c']:
46
- return s.code_scriptures(text)
47
- elif args['d']:
48
- return s.decode_scriptures(literal_eval(text))
49
- elif args['x']:
50
- return s.list_scriptures(text)
51
- elif args['t']:
52
- return s.tag_scriptures(text)
53
- else:
54
- return s.rewrite_scriptures(text)
37
+ try:
38
+ if args['l'] is not None:
39
+ prefix = '<a href="'
40
+ suffix = '">'
41
+ if len(args['l']) > 1 and args['l'][1] != '':
42
+ suffix = args['l'][1]
43
+ if len(args['l']) > 0 and args['l'][0] != '':
44
+ prefix = args['l'][0]
45
+ return s.link_scriptures(text, prefix, suffix)
46
+ elif args['c']:
47
+ return s.code_scriptures(text)
48
+ elif args['d']:
49
+ return s.decode_scriptures(literal_eval(text))
50
+ elif args['x']:
51
+ return s.list_scriptures(text)
52
+ elif args['t']:
53
+ return s.tag_scriptures(text)
54
+ else:
55
+ return s.rewrite_scriptures(text)
56
+ except Exception as e:
57
+ print("\n--- CRASH DETECTED ---", file=sys.stderr)
58
+ print("Input causing failure:", repr(text), file=sys.stderr)
59
+ print("Error:", str(e), file=sys.stderr)
60
+ traceback.print_exc()
61
+ raise
55
62
 
56
63
  form = None
57
64
  if args['standard']:
linkture/linkture.py CHANGED
@@ -27,7 +27,7 @@
27
27
  """
28
28
 
29
29
  __app__ = 'linkture'
30
- __version__ = 'v4.0.0'
30
+ __version__ = 'v4.2.0'
31
31
 
32
32
 
33
33
  import json, regex, sqlite3
@@ -97,19 +97,16 @@ class Scriptures():
97
97
  normalized = regex.sub(r'\p{P}|\p{Z}', '', item.upper())
98
98
  self._src_book_names[normalized] = row[0]
99
99
 
100
- # Ranges: {(book, chapter): last} (chapter 0 -> num of chapters in book)
101
100
  self._ranges = {}
102
101
  for book, chapter, last in cur.execute("SELECT Book, Chapter, Last FROM Ranges;"):
103
102
  self._ranges[(book, chapter)] = last
104
103
 
105
- # Chapters: two-way mappings
106
104
  self._chapters = {}
107
105
  self._chapters_id = {}
108
106
  for chapter_id, book, chapter in cur.execute("SELECT ChapterId, Book, Chapter FROM Chapters;"):
109
107
  self._chapters[(book, chapter)] = chapter_id
110
108
  self._chapters_id[chapter_id] = (book, chapter)
111
109
 
112
- # Verses: two-way mappings
113
110
  self._verses = {}
114
111
  self._verses_id = {}
115
112
  for verse_id, book, chapter, verse in cur.execute("SELECT VerseId, Book, Chapter, Verse FROM Verses;"):
@@ -276,27 +273,29 @@ class Scriptures():
276
273
  def _code_scripture(self, scripture, bk_num, rest, last):
277
274
 
278
275
  def reform_series(txt): # rewrite comma-separated consecutive sequences (1, 2, 3) as ranges (1-3)
279
- for result in self._d_dd.finditer(txt, overlapped=True):
280
- end = result.group(3)
281
- mid = result.group(2)
282
- start = result.group(1)
283
- if int(end) - int(mid) == 1:
284
- txt = regex.sub(result.group(), f"{start}-{end}", txt)
285
- for result in self._ddd.finditer(txt, overlapped=True):
286
- end = result.group(3)
287
- start = result.group(1)
288
- if int(end) - int(start) == 2:
289
- txt = regex.sub(result.group(), f"{start}-{end}", txt)
290
- for result in self._ddd.finditer(txt, overlapped=True):
291
- end = result.group(3)
292
- start = result.group(1)
293
- if int(end) - int(start) == 2:
294
- txt = regex.sub(result.group(), f"{start}-{end}", txt)
295
- for result in self._dd.finditer(txt, overlapped=True):
296
- end = result.group(2)
297
- start = result.group(1)
298
- if int(end) - int(start) == 1:
299
- txt = regex.sub(result.group(), f"{start}-{end}", txt)
276
+ numbers = []
277
+ for match in regex.finditer(r'\d+', txt):
278
+ numbers.append((int(match.group()), match.start(), match.end()))
279
+ if not numbers:
280
+ return txt
281
+ sequences = []
282
+ current_seq = [numbers[0]]
283
+ for i in range(1, len(numbers)):
284
+ current_num = numbers[i][0]
285
+ prev_num = current_seq[-1][0]
286
+ if current_num == prev_num + 1:
287
+ current_seq.append(numbers[i])
288
+ else:
289
+ if len(current_seq) >= 3:
290
+ sequences.append(current_seq)
291
+ current_seq = [numbers[i]]
292
+ if len(current_seq) >= 3:
293
+ sequences.append(current_seq)
294
+ for seq in sorted(sequences, key=lambda x: x[0][1], reverse=True):
295
+ start_pos = seq[0][1]
296
+ end_pos = seq[-1][2]
297
+ replacement = f"{seq[0][0]}-{seq[-1][0]}"
298
+ txt = txt[:start_pos] + replacement + txt[end_pos:]
300
299
  return txt
301
300
 
302
301
  def validate(b, ch, vs):
@@ -435,6 +434,26 @@ class Scriptures():
435
434
 
436
435
  return None, None
437
436
 
437
+ def merge_ranges(ranges):
438
+ if not ranges:
439
+ return []
440
+ merged = []
441
+ current_start, current_end = ranges[0]
442
+ for start, end in ranges[1:]:
443
+ end_bk = int(current_end[:2])
444
+ end_ch = int(current_end[2:5])
445
+ end_vs = int(current_end[5:])
446
+ next_bk = int(start[:2])
447
+ next_ch = int(start[2:5])
448
+ next_vs = int(start[5:])
449
+ if (end_bk == next_bk and ((end_ch == next_ch and end_vs + 1 == next_vs) or (end_ch + 1 == next_ch and end_vs == self._ranges.get((end_bk, end_ch), 0) and next_vs == 1))):
450
+ current_end = end
451
+ else:
452
+ merged.append((current_start, current_end))
453
+ current_start, current_end = start, end
454
+ merged.append((current_start, current_end))
455
+ return merged
456
+
438
457
  lst = []
439
458
  if rest == '': # whole book
440
459
  v = self._ranges.get((bk_num, last))
@@ -444,6 +463,7 @@ class Scriptures():
444
463
  rest = f'1:1-{last}:{v}'
445
464
  else:
446
465
  rest = reform_series(rest)
466
+ all_ranges = []
447
467
  for chunk in rest.split(';'):
448
468
  ch = None
449
469
  for bit in chunk.split(','):
@@ -454,7 +474,8 @@ class Scriptures():
454
474
  if not tup:
455
475
  self._error_report(scripture, f'"{bit.strip()}" OUT OF RANGE')
456
476
  return None
457
- lst.append(tup)
477
+ all_ranges.append(tup)
478
+ lst = merge_ranges(all_ranges)
458
479
  return lst
459
480
 
460
481
  def code_scriptures(self, text):
linkture/res/custom.json CHANGED
@@ -17,7 +17,7 @@
17
17
  [19, "Psalm, Psal, Pss, Psa"],
18
18
  [20, "Pro"],
19
19
  [21, "Ecc, Eccles, Qoh"],
20
- [22, "Cant, Son, Sng"],
20
+ [22, "Cant, Son, Sng, SoS"],
21
21
  [26, "Ezek"],
22
22
  [30, "Amo"],
23
23
  [31, "Oba"],
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: linkture
3
- Version: 4.0.0
3
+ Version: 4.2.0
4
4
  Summary: PARSE and PROCESS BIBLE SCRIPTURE REFERENCES: extract, tag, link, rewrite, translate, BCV-encode and decode
5
5
  Keywords: bible,scriptures,scripture-references,scripture-translation,scripture-parser,scripture-linker
6
6
  Author-Email: "Eryk J." <infiniti@inventati.org>
@@ -11,6 +11,7 @@ Classifier: Programming Language :: Python :: 3.9
11
11
  Classifier: Programming Language :: Python :: 3.10
12
12
  Classifier: Programming Language :: Python :: 3.11
13
13
  Classifier: Programming Language :: Python :: 3.12
14
+ Classifier: Programming Language :: Python :: 3.13
14
15
  Classifier: Development Status :: 5 - Production/Stable
15
16
  Classifier: Environment :: Console
16
17
  Classifier: Topic :: Religion
@@ -0,0 +1,10 @@
1
+ linkture-4.2.0.dist-info/METADATA,sha256=riCJFu9iG4egWkaYw0oq_7JGA2STaI-dtpMcX6SnadA,11701
2
+ linkture-4.2.0.dist-info/WHEEL,sha256=9P2ygRxDrTJz3gsagc0Z96ukrxjr-LFBGOgv3AuKlCA,90
3
+ linkture-4.2.0.dist-info/entry_points.txt,sha256=6OYgBcLyFCUgeqLgnvMyOJxPCWzgy7se4rLPKtNonMs,34
4
+ linkture-4.2.0.dist-info/licenses/LICENSE,sha256=kPqKoVmo3Tx1HgQvqfjBZuYkjT1mZXnQ5R0KBbEeFfs,1064
5
+ linkture/__init__.py,sha256=-CsRDvXLUig8T6RvwkktRP8e8DWrpjlyqBcw26kOv1E,47
6
+ linkture/__main__.py,sha256=NC11m6wICSMyme8AVDLezTBH_XrnMG1MMtmr3ZDbxDk,6980
7
+ linkture/linkture.py,sha256=Kdu6ngFJv6BCJFCv21P3pH39adCTLoDJNbH-6LThc1E,25998
8
+ linkture/res/custom.json,sha256=DKoN6Q_PcZ9EF4UdqpBtpB4ckz_lOEJhjpivfzsqUl8,2144
9
+ linkture/res/resources.db,sha256=4CToCzX_3kkWFUpVF4RoRguIHDUwbzd5AjKgt4QPYKo,573440
10
+ linkture-4.2.0.dist-info/RECORD,,
@@ -1,10 +0,0 @@
1
- linkture-4.0.0.dist-info/METADATA,sha256=l8Z9vxEgLZk2g_Yt0vjAfAg34aTDM68r0A7gEm5-4uI,11650
2
- linkture-4.0.0.dist-info/WHEEL,sha256=9P2ygRxDrTJz3gsagc0Z96ukrxjr-LFBGOgv3AuKlCA,90
3
- linkture-4.0.0.dist-info/entry_points.txt,sha256=6OYgBcLyFCUgeqLgnvMyOJxPCWzgy7se4rLPKtNonMs,34
4
- linkture-4.0.0.dist-info/licenses/LICENSE,sha256=kPqKoVmo3Tx1HgQvqfjBZuYkjT1mZXnQ5R0KBbEeFfs,1064
5
- linkture/__init__.py,sha256=-CsRDvXLUig8T6RvwkktRP8e8DWrpjlyqBcw26kOv1E,47
6
- linkture/__main__.py,sha256=IjxrpZGZKIr7mHPGs_mMVaB6ipou_ArYgvs4wRFkxXM,6607
7
- linkture/linkture.py,sha256=398iSQwC0pSc_j5jRlJIRcRsWm2-YWyJGO1xTTGMMFk,25256
8
- linkture/res/custom.json,sha256=ngpVe8OrnhBUTpJKcJc_W9rwxtEWq7qbt3_NPbGL6h0,2139
9
- linkture/res/resources.db,sha256=4CToCzX_3kkWFUpVF4RoRguIHDUwbzd5AjKgt4QPYKo,573440
10
- linkture-4.0.0.dist-info/RECORD,,