prefig 0.4.6.dev20250929053415__py3-none-any.whl → 0.4.7__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.
prefig/core/arrow.py CHANGED
@@ -5,6 +5,7 @@ import numpy as np
5
5
  from . import utilities as util
6
6
  from . import CTM
7
7
  from . import user_namespace as un
8
+ from . import repeat
8
9
 
9
10
  log = logging.getLogger('prefigure')
10
11
 
@@ -189,6 +190,11 @@ def add_arrowhead_marker(diagram,
189
190
  arrow_width = 13/3
190
191
  dims = (1, arrow_width) #11/3)
191
192
 
193
+ # EPUB does not allow some characters to appear in @id
194
+ # There is a possibility that we have # or . so we will
195
+ # replace them with this function call
196
+ id = repeat.epub_clean(id)
197
+
192
198
  # If we've already created this one, we'll just move on
193
199
  if diagram.has_reusable(id):
194
200
  return id
prefig/core/diagram.py CHANGED
@@ -3,6 +3,7 @@ import lxml.etree as ET
3
3
  import numpy as np
4
4
  import logging
5
5
  import copy
6
+ import re
6
7
  from . import tags
7
8
  from . import user_namespace as un
8
9
  from . import utilities as util
@@ -10,9 +11,13 @@ from . import CTM
10
11
  from . import label
11
12
  from . import math_utilities as math_util
12
13
  from . import annotations
14
+ from . import repeat
13
15
 
14
16
  log = logging.getLogger('prefigure')
15
17
 
18
+ # regular expression to check if id is EPUB compliant
19
+ epub_id_check = re.compile('^[A-Za-z0-9_-]+$')
20
+
16
21
  class Diagram:
17
22
  def __init__(self,
18
23
  diagram_element,
@@ -129,9 +134,25 @@ class Diagram:
129
134
  for child in templates_element:
130
135
  self.defaults[child.tag] = child
131
136
 
137
+ annotations = self.diagram_element.xpath('.//annotations')
138
+ if len(annotations) > 0:
139
+ self.check_annotation_ref(annotations[0])
140
+
132
141
  if self.defaults.get('macros', None) is not None:
133
142
  label.add_macros(self.defaults.get('macros').text)
134
143
 
144
+ def check_annotation_ref(self, element):
145
+ ref = element.get('ref', None)
146
+ if ref is not None:
147
+ if not bool(epub_id_check.fullmatch(ref)):
148
+ log.error(f"@ref {ref} in an annotation has characters disallowed by EPUB")
149
+ log.error(" We will replace these characters but there may be unexpected behavior")
150
+ log.error(" Search for EPUB in the PreFigure documentation https://prefigure.org")
151
+ ref = repeat.epub_clean(ref)
152
+ element.set('ref', ref)
153
+ for child in element:
154
+ self.check_annotation_ref(child)
155
+
135
156
  def add_legend(self, legend):
136
157
  self.legends.append(legend)
137
158
 
@@ -436,6 +457,15 @@ class Diagram:
436
457
  # we're publicly using 'at' rather than 'id' for handles
437
458
  if child.get('at') is not None:
438
459
  child.set('id', child.get('at'))
460
+
461
+ child_id = child.get('id', None)
462
+ if child_id is not None:
463
+ if not bool(epub_id_check.fullmatch(child_id)):
464
+ log.error(f"The id {child_id} has characters disallowed by EPUB")
465
+ log.error(" We will substitute disallowed characters to make the id EPUB compliant")
466
+ log.error(" Search for EPUB in the PreFigure documentation at https://prefigure.org")
467
+ child.set('id', repeat.epub_clean(child_id))
468
+
439
469
  # see if the publication flie has any defaults
440
470
  defaults = self.defaults.get(child.tag, None)
441
471
  if defaults is not None:
prefig/core/repeat.py CHANGED
@@ -2,6 +2,7 @@ import lxml.etree as ET
2
2
  import logging
3
3
  from . import user_namespace as un
4
4
  import copy
5
+ import re
5
6
  import numpy as np
6
7
  from . import group
7
8
  from . import label
@@ -9,6 +10,25 @@ from . import utilities
9
10
 
10
11
  log = logging.getLogger('prefigure')
11
12
 
13
+ # EPUB restricts the characters that can appear in an id to
14
+ # a-z|A-Z|0-9|_|-
15
+ # This is an issue here since <repeat> elements can create id's
16
+ # This regular expression checks characters to see if they are allowed
17
+ epub_check = re.compile(r'[A-Za-z0-9_-]')
18
+
19
+ # We also define substitutions for the most common disallowed characters
20
+ epub_dict = {'(': 'p',
21
+ ')': 'q',
22
+ '[': 'p',
23
+ ']': 'q',
24
+ '{': 'p',
25
+ '}': 'q',
26
+ ',': 'c',
27
+ '.': 'd',
28
+ '=': '_',
29
+ r'#': 'h'}
30
+
31
+
12
32
  # Allows a block of XML to repeat with a changing parameter
13
33
 
14
34
  def repeat(element, diagram, parent, outline_status):
@@ -48,11 +68,12 @@ def repeat(element, diagram, parent, outline_status):
48
68
  else:
49
69
  k_str = str(k)
50
70
 
51
- un.enter_namespace(k_str, k)
71
+ k_str_clean = epub_clean(k_str)
72
+ # This is a change since we use the syntax "var_str" for the id suffix
52
73
  if count:
53
- suffix_str = var + "=" + k_str
74
+ suffix_str = var + "_" + k_str_clean
54
75
  else:
55
- suffix_str = var + "=" + str(num)
76
+ suffix_str = var + "_" + str(num)
56
77
 
57
78
  definition = ET.SubElement(element, 'definition')
58
79
  definition.text = var + '=' + k_str
@@ -78,3 +99,13 @@ def repeat(element, diagram, parent, outline_status):
78
99
 
79
100
  if annotation is not None:
80
101
  diagram.pop_from_annotation_branch()
102
+
103
+ def epub_clean(s):
104
+ epub_clean = [bool(epub_check.fullmatch(ch)) for ch in s]
105
+ chars = []
106
+ for index, ch in enumerate(s):
107
+ if epub_clean[index]:
108
+ chars.append(ch)
109
+ continue
110
+ chars.append(epub_dict.get(ch, '_'))
111
+ return "".join(chars)
@@ -48,7 +48,7 @@ DefinitionElements =
48
48
  Derivative?,
49
49
  DE-Solution?,
50
50
  Define-Shapes?,
51
- Read
51
+ Read?
52
52
 
53
53
  Definition = element definition {
54
54
  text,
@@ -177,7 +177,9 @@ LabelAttributes =
177
177
  attribute rotate {text}?,
178
178
  attribute clear-background {"yes"|"no"}?,
179
179
  attribute background-margin {text}?,
180
- attribute color {text}?
180
+ attribute color {text}?,
181
+ attribute font {text}?,
182
+ attribute font-size {text}?
181
183
 
182
184
  Math = element m {attribute color {text}? & text}
183
185
  Bold = element b {attribute color {text}? & text & Italic*}