rolfedh-doc-utils 0.1.29__py3-none-any.whl → 0.1.31__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.
- callout_lib/converter_bullets.py +10 -2
- callout_lib/converter_deflist.py +37 -2
- callout_lib/detector.py +55 -21
- callout_lib/table_parser.py +299 -87
- convert_callouts_interactive.py +18 -3
- convert_callouts_to_deflist.py +137 -14
- doc_utils/version.py +1 -1
- doc_utils/warnings_report.py +237 -0
- {rolfedh_doc_utils-0.1.29.dist-info → rolfedh_doc_utils-0.1.31.dist-info}/METADATA +1 -1
- {rolfedh_doc_utils-0.1.29.dist-info → rolfedh_doc_utils-0.1.31.dist-info}/RECORD +14 -13
- {rolfedh_doc_utils-0.1.29.dist-info → rolfedh_doc_utils-0.1.31.dist-info}/WHEEL +0 -0
- {rolfedh_doc_utils-0.1.29.dist-info → rolfedh_doc_utils-0.1.31.dist-info}/entry_points.txt +0 -0
- {rolfedh_doc_utils-0.1.29.dist-info → rolfedh_doc_utils-0.1.31.dist-info}/licenses/LICENSE +0 -0
- {rolfedh_doc_utils-0.1.29.dist-info → rolfedh_doc_utils-0.1.31.dist-info}/top_level.txt +0 -0
callout_lib/converter_bullets.py
CHANGED
|
@@ -16,7 +16,7 @@ class BulletListConverter:
|
|
|
16
16
|
USER_VALUE_PATTERN = re.compile(r'(?<!<)<([a-zA-Z][^>]*)>')
|
|
17
17
|
|
|
18
18
|
@staticmethod
|
|
19
|
-
def convert(callout_groups: List[CalloutGroup], explanations: Dict[int, Callout]) -> List[str]:
|
|
19
|
+
def convert(callout_groups: List[CalloutGroup], explanations: Dict[int, Callout], table_title: str = "") -> List[str]:
|
|
20
20
|
"""
|
|
21
21
|
Create bulleted list from callout groups and explanations.
|
|
22
22
|
|
|
@@ -33,12 +33,20 @@ class BulletListConverter:
|
|
|
33
33
|
|
|
34
34
|
Args:
|
|
35
35
|
callout_groups: List of CalloutGroup objects from code block
|
|
36
|
+
table_title: Optional table title (e.g., ".Descriptions of delete event")
|
|
37
|
+
Will be converted to lead-in sentence
|
|
36
38
|
explanations: Dict mapping callout numbers to Callout objects
|
|
37
39
|
|
|
38
40
|
Returns:
|
|
39
41
|
List of strings representing the bulleted list
|
|
40
42
|
"""
|
|
41
|
-
|
|
43
|
+
# Convert table title to lead-in sentence if present
|
|
44
|
+
if table_title:
|
|
45
|
+
# Remove leading dot and trailing period if present
|
|
46
|
+
title_text = table_title.lstrip('.').rstrip('.')
|
|
47
|
+
lines = [f'\n{title_text}:'] # Use colon for bulleted list lead-in
|
|
48
|
+
else:
|
|
49
|
+
lines = [''] # Start with blank line before list
|
|
42
50
|
|
|
43
51
|
# Process each group (which may contain one or more callouts)
|
|
44
52
|
for group in callout_groups:
|
callout_lib/converter_deflist.py
CHANGED
|
@@ -16,7 +16,7 @@ class DefListConverter:
|
|
|
16
16
|
USER_VALUE_PATTERN = re.compile(r'(?<!<)<([a-zA-Z][^>]*)>')
|
|
17
17
|
|
|
18
18
|
@staticmethod
|
|
19
|
-
def convert(callout_groups: List[CalloutGroup], explanations: Dict[int, Callout]) -> List[str]:
|
|
19
|
+
def convert(callout_groups: List[CalloutGroup], explanations: Dict[int, Callout], table_title: str = "") -> List[str]:
|
|
20
20
|
"""
|
|
21
21
|
Create definition list from callout groups and explanations.
|
|
22
22
|
|
|
@@ -29,11 +29,19 @@ class DefListConverter:
|
|
|
29
29
|
Args:
|
|
30
30
|
callout_groups: List of CalloutGroup objects from code block
|
|
31
31
|
explanations: Dict mapping callout numbers to Callout objects
|
|
32
|
+
table_title: Optional table title (e.g., ".Descriptions of delete event")
|
|
33
|
+
Will be converted to lead-in sentence (e.g., "Descriptions of delete event, where:")
|
|
32
34
|
|
|
33
35
|
Returns:
|
|
34
36
|
List of strings representing the definition list
|
|
35
37
|
"""
|
|
36
|
-
|
|
38
|
+
# Convert table title to lead-in sentence if present
|
|
39
|
+
if table_title:
|
|
40
|
+
# Remove leading dot and trailing period if present
|
|
41
|
+
title_text = table_title.lstrip('.').rstrip('.')
|
|
42
|
+
lines = [f'\n{title_text}, where:']
|
|
43
|
+
else:
|
|
44
|
+
lines = ['\nwhere:']
|
|
37
45
|
|
|
38
46
|
# Process each group (which may contain one or more callouts)
|
|
39
47
|
for group in callout_groups:
|
|
@@ -70,10 +78,37 @@ class DefListConverter:
|
|
|
70
78
|
lines.append('+')
|
|
71
79
|
|
|
72
80
|
# Add explanation lines, prepending "Optional. " to first line if needed
|
|
81
|
+
# Handle blank lines and conditionals by inserting continuation markers
|
|
82
|
+
need_continuation = False
|
|
83
|
+
had_content = False # Track if we've output any non-conditional content
|
|
84
|
+
|
|
73
85
|
for line_idx, line in enumerate(explanation.lines):
|
|
86
|
+
stripped = line.strip()
|
|
87
|
+
|
|
88
|
+
# Check if this is a blank line
|
|
89
|
+
if stripped == '':
|
|
90
|
+
# Next non-blank line will need a continuation marker
|
|
91
|
+
need_continuation = True
|
|
92
|
+
continue # Skip blank lines
|
|
93
|
+
|
|
94
|
+
# Check if this is a conditional directive
|
|
95
|
+
is_conditional = stripped.startswith(('ifdef::', 'ifndef::', 'endif::'))
|
|
96
|
+
|
|
97
|
+
# Add continuation marker if:
|
|
98
|
+
# 1. Previous line was blank (need_continuation=True), OR
|
|
99
|
+
# 2. This is a conditional and we've had content before (need separator)
|
|
100
|
+
if need_continuation or (is_conditional and had_content and line_idx > 0):
|
|
101
|
+
lines.append('+')
|
|
102
|
+
need_continuation = False
|
|
103
|
+
|
|
104
|
+
# Add the line
|
|
74
105
|
if line_idx == 0 and explanation.is_optional:
|
|
75
106
|
lines.append(f'Optional. {line}')
|
|
76
107
|
else:
|
|
77
108
|
lines.append(line)
|
|
78
109
|
|
|
110
|
+
# Track that we've output content (not just conditionals)
|
|
111
|
+
if not is_conditional:
|
|
112
|
+
had_content = True
|
|
113
|
+
|
|
79
114
|
return lines
|
callout_lib/detector.py
CHANGED
|
@@ -60,6 +60,8 @@ class CalloutDetector:
|
|
|
60
60
|
def __init__(self):
|
|
61
61
|
"""Initialize detector with table parser."""
|
|
62
62
|
self.table_parser = TableParser()
|
|
63
|
+
self.last_table_title = "" # Track title from most recent table extraction
|
|
64
|
+
self.last_table = None # Track last table found for validation diagnostics
|
|
63
65
|
|
|
64
66
|
def find_code_blocks(self, lines: List[str]) -> List[CodeBlock]:
|
|
65
67
|
"""Find all code blocks in the document."""
|
|
@@ -181,17 +183,24 @@ class CalloutDetector:
|
|
|
181
183
|
|
|
182
184
|
def _extract_from_table(self, table) -> Tuple[Dict[int, Callout], int]:
|
|
183
185
|
"""Extract callout explanations from a table format."""
|
|
186
|
+
# Store table for use by converters and validation
|
|
187
|
+
self.last_table = table
|
|
188
|
+
self.last_table_title = table.title if hasattr(table, 'title') else ""
|
|
189
|
+
|
|
184
190
|
explanations = {}
|
|
185
191
|
table_data = self.table_parser.extract_callout_explanations_from_table(table)
|
|
186
192
|
|
|
187
|
-
for callout_num, (explanation_lines,
|
|
188
|
-
#
|
|
193
|
+
for callout_num, (explanation_lines, row_conditionals) in table_data.items():
|
|
194
|
+
# explanation_lines now includes blank lines and conditionals inline
|
|
195
|
+
# row_conditionals are before/after the entire row (rarely used)
|
|
189
196
|
all_lines = []
|
|
190
|
-
for line in explanation_lines:
|
|
191
|
-
all_lines.append(line)
|
|
192
197
|
|
|
193
|
-
# Add
|
|
194
|
-
|
|
198
|
+
# Add any row-level conditionals before
|
|
199
|
+
if row_conditionals:
|
|
200
|
+
all_lines.extend(row_conditionals)
|
|
201
|
+
|
|
202
|
+
# Add explanation lines (already includes inline conditionals and blank lines)
|
|
203
|
+
all_lines.extend(explanation_lines)
|
|
195
204
|
|
|
196
205
|
# Check if marked as optional
|
|
197
206
|
is_optional = False
|
|
@@ -212,14 +221,22 @@ class CalloutDetector:
|
|
|
212
221
|
Extract callout explanations from a 3-column table format.
|
|
213
222
|
Format: Item (number) | Value | Description
|
|
214
223
|
"""
|
|
224
|
+
# Store table for use by converters and validation
|
|
225
|
+
self.last_table = table
|
|
226
|
+
self.last_table_title = table.title if hasattr(table, 'title') else ""
|
|
227
|
+
|
|
215
228
|
explanations = {}
|
|
216
229
|
table_data = self.table_parser.extract_3column_callout_explanations(table)
|
|
217
230
|
|
|
218
|
-
for callout_num, (value_lines, description_lines,
|
|
231
|
+
for callout_num, (value_lines, description_lines, row_conditionals) in table_data.items():
|
|
219
232
|
# Combine value and description into explanation lines
|
|
220
|
-
#
|
|
233
|
+
# Both value_lines and description_lines now include conditionals and blank lines inline
|
|
221
234
|
all_lines = []
|
|
222
235
|
|
|
236
|
+
# Add any row-level conditionals before
|
|
237
|
+
if row_conditionals:
|
|
238
|
+
all_lines.extend(row_conditionals)
|
|
239
|
+
|
|
223
240
|
# Add value lines with context
|
|
224
241
|
if value_lines:
|
|
225
242
|
# Format: "`value`:"
|
|
@@ -228,16 +245,13 @@ class CalloutDetector:
|
|
|
228
245
|
if value_text:
|
|
229
246
|
all_lines.append(f"{value_text}:")
|
|
230
247
|
|
|
231
|
-
# Add additional value lines if multi-line
|
|
248
|
+
# Add additional value lines if multi-line (includes conditionals and blank lines)
|
|
232
249
|
for line in value_lines[1:]:
|
|
233
250
|
all_lines.append(line)
|
|
234
251
|
|
|
235
|
-
# Add description lines
|
|
252
|
+
# Add description lines (already includes conditionals and blank lines)
|
|
236
253
|
all_lines.extend(description_lines)
|
|
237
254
|
|
|
238
|
-
# Add conditionals as separate lines (they'll be preserved in output)
|
|
239
|
-
all_lines.extend(conditionals)
|
|
240
|
-
|
|
241
255
|
# Check if marked as optional
|
|
242
256
|
is_optional = False
|
|
243
257
|
if all_lines and (all_lines[0].lower().startswith('optional.') or
|
|
@@ -252,6 +266,10 @@ class CalloutDetector:
|
|
|
252
266
|
|
|
253
267
|
def _extract_from_list(self, lines: List[str], start_line: int) -> Tuple[Dict[int, Callout], int]:
|
|
254
268
|
"""Extract callout explanations from list format (<1> text)."""
|
|
269
|
+
# Clear table data since list format doesn't have tables
|
|
270
|
+
self.last_table = None
|
|
271
|
+
self.last_table_title = ""
|
|
272
|
+
|
|
255
273
|
explanations = {}
|
|
256
274
|
i = start_line + 1 # Start after the closing delimiter
|
|
257
275
|
|
|
@@ -306,17 +324,33 @@ class CalloutDetector:
|
|
|
306
324
|
cleaned.append(self.CALLOUT_WITH_COMMENT.sub('', line).rstrip())
|
|
307
325
|
return cleaned
|
|
308
326
|
|
|
309
|
-
def validate_callouts(self, callout_groups: List[CalloutGroup], explanations: Dict[int, Callout]) -> Tuple[bool,
|
|
327
|
+
def validate_callouts(self, callout_groups: List[CalloutGroup], explanations: Dict[int, Callout]) -> Tuple[bool, List[int], List[int]]:
|
|
310
328
|
"""
|
|
311
329
|
Validate that callout numbers in code match explanation numbers.
|
|
312
|
-
Returns tuple of (is_valid,
|
|
330
|
+
Returns tuple of (is_valid, code_nums_list, explanation_nums_list).
|
|
331
|
+
|
|
332
|
+
Returns:
|
|
333
|
+
- is_valid: True if unique callout numbers match
|
|
334
|
+
- code_nums_list: List of callout numbers from code (unique, sorted)
|
|
335
|
+
- explanation_nums_list: List of callout numbers from explanations
|
|
336
|
+
(preserves duplicates if from table, sorted)
|
|
313
337
|
"""
|
|
314
|
-
# Extract
|
|
315
|
-
|
|
338
|
+
# Extract unique callout numbers from code groups
|
|
339
|
+
code_nums_set = set()
|
|
316
340
|
for group in callout_groups:
|
|
317
|
-
|
|
341
|
+
code_nums_set.update(group.callout_numbers)
|
|
342
|
+
|
|
343
|
+
# Get explanation numbers, preserving duplicates if from a table
|
|
344
|
+
if self.last_table:
|
|
345
|
+
# Use table parser to get raw callout numbers (with duplicates)
|
|
346
|
+
explanation_nums_list = self.table_parser.get_table_callout_numbers(self.last_table)
|
|
347
|
+
else:
|
|
348
|
+
# List format: dict keys are already unique
|
|
349
|
+
explanation_nums_list = list(explanations.keys())
|
|
350
|
+
|
|
351
|
+
explanation_nums_set = set(explanation_nums_list)
|
|
318
352
|
|
|
319
|
-
|
|
353
|
+
# Validation compares unique numbers only
|
|
354
|
+
is_valid = code_nums_set == explanation_nums_set
|
|
320
355
|
|
|
321
|
-
is_valid
|
|
322
|
-
return is_valid, code_nums, explanation_nums
|
|
356
|
+
return is_valid, sorted(code_nums_set), sorted(explanation_nums_list)
|