rda-python-miscs 3.0.3__py3-none-any.whl → 3.0.4__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.
@@ -140,10 +140,10 @@ class PgRST(PgFile, PgUtil):
140
140
  """
141
141
  self.OPTS = opts
142
142
  self.ALIAS = alias
143
+ self.DOCS['DOCNAM'] = docname
143
144
 
144
145
  self.parse_docs(docname)
145
146
  if not self.sections: self.pglog(docname + ": empty document", self.LGWNEX)
146
- self.DOCS['DOCNAM'] = docname
147
147
  if docname in self.LINKS: self.LINKS.remove(docname)
148
148
  self.DOCS['DOCLNK'] = r"({})".format('|'.join(self.LINKS))
149
149
  self.DOCS['DOCTIT'] = docname.upper()
@@ -152,6 +152,7 @@ class PgRST(PgFile, PgUtil):
152
152
  self.write_index(self.sections[0])
153
153
  for section in self.sections:
154
154
  self.write_section(section)
155
+ self.write_appendix()
155
156
 
156
157
  #
157
158
  # parse the original document and return a array of sections,
@@ -172,7 +173,9 @@ class PgRST(PgFile, PgUtil):
172
173
  with open(docfile, 'r') as fh:
173
174
  line = fh.readline()
174
175
  while line:
175
- if re.match(r'\s*#', line):
176
+ # Skip full-line authoring comments, but keep '#!' shebang lines so
177
+ # shell scripts shown in example content blocks stay intact.
178
+ if re.match(r'\s*#(?!!)', line):
176
179
  line = fh.readline()
177
180
  continue # skip comment lines
178
181
  ms = re.match(r'^(.*\S)\s+#', line)
@@ -191,13 +194,21 @@ class PgRST(PgFile, PgUtil):
191
194
  option = self.record_option(section, option, example, ms.group(1), ms.group(2))
192
195
  example = None
193
196
  elif option:
194
- ms = re.match(r'^ For( | another )example, (.*)$', line)
195
- if ms: # found example
196
- example = self.record_example(option, example, ms.group(2))
197
- elif example:
198
- example['desc'] += line + "\n"
197
+ if option.get('inexm'):
198
+ # inside an 'Examples:' block: collect raw lines verbatim
199
+ # (split into individual examples later in split_examples)
200
+ option['exmraw'] += line + "\n"
199
201
  else:
200
- option['desc'] += line + "\n"
202
+ ms = re.match(r'^ (?:For(?: | another )example,|Example[ ]*[,\-])\s*(.*)$', line)
203
+ if ms: # found a single labeled example
204
+ example = self.record_example(option, example, ms.group(1))
205
+ elif re.match(r'^ Examples:\s*$', line):
206
+ option['inexm'] = True # start of a multi-example block
207
+ option['exmraw'] = ""
208
+ elif example:
209
+ example['desc'] += line + "\n"
210
+ else:
211
+ option['desc'] += line + "\n"
201
212
  else:
202
213
  section['desc'] += line + "\n"
203
214
 
@@ -261,11 +272,62 @@ class PgRST(PgFile, PgUtil):
261
272
  """
262
273
  if option:
263
274
  if example: self.record_example(option, example)
275
+ self.split_examples(option)
264
276
  self.options[option['opt']] = option # record option globally
265
277
  section['opts'].append(option['opt']) # record option short name in section
266
278
 
267
279
  if nopt: return self.init_option(section['secid'], nopt, ndesc)
268
280
 
281
+ def split_examples(self, option):
282
+ """Split an option's pending ``Examples:`` block into individual examples.
283
+
284
+ The raw text collected after an ``Examples:`` header is segmented into
285
+ blank-line-separated blocks. A block whose last line ends with ``:`` and
286
+ whose first line is descriptive prose (not a command, option flag, or a
287
+ ``<<Content ...>>`` header) starts a new example; following blocks
288
+ (command synopsis, script content, trailing notes) belong to that
289
+ example until the next title block.
290
+
291
+ Args:
292
+ option (dict): The option whose ``exmraw`` buffer is parsed; the
293
+ buffer is removed and one example is recorded per
294
+ title block found.
295
+ """
296
+ buf = option.pop('exmraw', None)
297
+ option.pop('inexm', None)
298
+ if not buf: return
299
+
300
+ blocks = []
301
+ cur = []
302
+ for ln in buf.split('\n'):
303
+ if ln.strip() == '':
304
+ if cur: blocks.append(cur); cur = []
305
+ else:
306
+ cur.append(ln)
307
+ if cur: blocks.append(cur)
308
+
309
+ def is_title(block):
310
+ if not block[-1].rstrip().endswith(':'): return False
311
+ first = block[0].strip()
312
+ if first.startswith('<<'): return False
313
+ if re.match(r'[-*(]', first): return False
314
+ if re.match(r'{}\b'.format(self.DOCS['DOCNAM']), first): return False
315
+ return True
316
+
317
+ exmtext = None
318
+ for block in blocks:
319
+ btext = '\n'.join(block)
320
+ if is_title(block):
321
+ if exmtext is not None:
322
+ self.record_example(option, self.init_example(option['opt'], exmtext))
323
+ exmtext = btext + "\n"
324
+ elif exmtext is not None:
325
+ exmtext += "\n" + btext + "\n"
326
+ else:
327
+ option['desc'] += btext + "\n" # stray text before the first example
328
+ if exmtext is not None:
329
+ self.record_example(option, self.init_example(option['opt'], exmtext))
330
+
269
331
  def record_example(self, option, example, ndesc=None):
270
332
  """Append the completed *example* to ``self.examples`` and optionally start a new one.
271
333
 
@@ -478,18 +540,21 @@ class PgRST(PgFile, PgUtil):
478
540
  """Build and return the RST table-of-contents string of a given section.
479
541
 
480
542
  Produces a nested bullet list of section links (indented by section
481
- level) followed by a flat Appendix A list of all example links.
543
+ level). For the index (``csection is None``) the example appendix is a
544
+ standalone page (``appendixA``) added to the toctree; for a section the
545
+ examples in its subtree are listed inline as a local Appendix A.
482
546
 
483
547
  Returns:
484
548
  str: RST-formatted TOC content ready for ``__TOC__`` substitution.
485
549
  """
486
-
550
+
487
551
  content = ""
488
552
  clevel = csection['level'] if csection else 0
489
553
  csecid = csection['secid'] if csection else ""
490
554
  depth = self.TLEVEL - clevel
491
555
  level = clevel+1
492
556
  preid = csecid+'.'
557
+ is_index = csection is None
493
558
 
494
559
  # nested bullet list for all sections
495
560
  for section in self.sections:
@@ -497,9 +562,14 @@ class PgRST(PgFile, PgUtil):
497
562
  if csecid and not secid.startswith(preid): continue
498
563
  if section['level'] == level: content += " section{}\n".format(secid)
499
564
 
565
+ # The full list of examples lives on its own appendix page in the index.
566
+ if is_index and self.examples: content += " appendixA\n"
567
+
500
568
  if not content: return ""
501
569
 
502
570
  content = f".. toctree::\n :maxdepth: {depth}\n :caption: Table of Contents\n\n{content}\n"
571
+ if is_index: return content
572
+
503
573
  # appendix A: list of examples for the parent section and its subsections
504
574
  appendix = ""
505
575
  idx = 1 # used as example index
@@ -507,7 +577,7 @@ class PgRST(PgFile, PgUtil):
507
577
  opt = exm['opt']
508
578
  option = self.options[opt]
509
579
  secid = option['secid']
510
- if not csecid or secid == csecid or secid.startswith(preid):
580
+ if secid == csecid or secid.startswith(preid):
511
581
  appendix += "- :ref:`A.{}. {} Option -{} (-{}) <{}_e{}>`\n".format(
512
582
  idx, option['type'], opt, option['name'], secid, idx)
513
583
  idx += 1
@@ -516,6 +586,28 @@ class PgRST(PgFile, PgUtil):
516
586
 
517
587
  return content
518
588
 
589
+ #
590
+ # write the appendix page listing all examples in the document
591
+ #
592
+ def write_appendix(self):
593
+ """Write ``appendixA.rst`` listing every example with a link.
594
+
595
+ Each entry links to the example anchor on its section page. Does nothing
596
+ when the document has no examples.
597
+ """
598
+ if not self.examples: return
599
+ content = ""
600
+ idx = 1
601
+ for exm in self.examples:
602
+ option = self.options[exm['opt']]
603
+ secid = option['secid']
604
+ title = exm['title'].strip().rstrip(':')
605
+ content += "- :ref:`A.{}. {} Option -{} (-{}): {} <{}_e{}>`\n".format(
606
+ idx, option['type'], exm['opt'], option['name'], title, secid, idx)
607
+ idx += 1
608
+
609
+ self.template_to_rst("appendix", {'CONTENT': content}, "A")
610
+
519
611
  #
520
612
  # create a section rst content
521
613
  #
@@ -672,7 +764,8 @@ class PgRST(PgFile, PgUtil):
672
764
 
673
765
  for optary in opts:
674
766
  opt = self.get_short_option(optary[1])
675
-
767
+ if opt is None: continue # not an option of this document; leave as-is
768
+
676
769
  pre = optary[0]
677
770
  after = optary[2]
678
771
  secid = self.options[opt]['secid']
@@ -826,7 +919,7 @@ class PgRST(PgFile, PgUtil):
826
919
  line0 = lines[0]
827
920
  normal = 1
828
921
  if dtype == 2:
829
- ms = re.match(r'^<<(Content .*)>>$', line0)
922
+ ms = re.match(r'^\s*<<(Content .*)>>$', line0)
830
923
  if ms: # input files for examples
831
924
  content += ms.group(1) + ":\n\n.. code-block:: none\n\n"
832
925
  normal = 0
@@ -928,13 +1021,23 @@ class PgRST(PgFile, PgUtil):
928
1021
  rows.append(tuple(prev_vals))
929
1022
  content = self.build_rst_list_table(rows)
930
1023
  else:
931
- # multi-column table split on 2+ spaces
932
- rows = []
933
- for i in range(cnt):
934
- line = lines[i].strip()
935
- vals = re.split(r'\s{2,}', self.replace_option_link(line, secid, 1))
936
- rows.append(vals)
937
- content = self.build_rst_simple_table(rows) + "\n"
1024
+ raw = [lines[i].strip() for i in range(cnt)]
1025
+ cmdpat = r'(?:[*\d][\d* ]*\s+)?{}(\s|$)'.format(re.escape(self.DOCS['DOCNAM']))
1026
+ if raw and all(re.match(cmdpat, r) for r in raw):
1027
+ # Command line(s) following a label (e.g. a Quick Start entry):
1028
+ # render as a literal block instead of a (degenerate) table.
1029
+ content = ".. code-block:: none\n\n"
1030
+ for r in raw:
1031
+ content += " " + r + "\n"
1032
+ content += "\n"
1033
+ else:
1034
+ # multi-column table split on 2+ spaces
1035
+ rows = []
1036
+ for i in range(cnt):
1037
+ line = lines[i].strip()
1038
+ vals = re.split(r'\s{2,}', self.replace_option_link(line, secid, 1))
1039
+ rows.append(vals)
1040
+ content = self.build_rst_simple_table(rows) + "\n"
938
1041
 
939
1042
  return content
940
1043
 
@@ -1046,10 +1149,10 @@ class PgRST(PgFile, PgUtil):
1046
1149
  p (str): Option name to look up (short, long, or alias).
1047
1150
 
1048
1151
  Returns:
1049
- str: Canonical two-letter option short name.
1050
-
1051
- Raises:
1052
- PgLOG error (LGWNEX) if *p* cannot be resolved.
1152
+ str | None: Canonical two-letter option short name, or ``None`` when
1153
+ *p* does not name an option of this document (e.g. an option of a
1154
+ different program referenced in prose). Callers skip such tokens
1155
+ so unrelated option-like text is left untouched.
1053
1156
  """
1054
1157
  plen = len(p)
1055
1158
  if plen == 2 and p in self.options: return p
@@ -1061,7 +1164,7 @@ class PgRST(PgFile, PgUtil):
1061
1164
  for alias in self.ALIAS[opt]:
1062
1165
  if re.match(r'^{}$'.format(alias), p, re.I): return opt
1063
1166
 
1064
- self.pglog("{} - unknown option for {}".format(p, self.DOCS['DOCNAM']), self.LGWNEX)
1167
+ return None
1065
1168
 
1066
1169
  #
1067
1170
  # replace with rst link for a given section title
@@ -0,0 +1,19 @@
1
+ ################################################################################
2
+ #
3
+ # Title : appendix_rst.temp
4
+ # Author : Zaihua Ji, zji@ucar.edu
5
+ # Date : 03/17/2026
6
+ # Purpose : template file for help document appendixA.rst (reStructuredText)
7
+ # Github : https://github.com/NCAR/rda-python-mics.git
8
+ #
9
+ ################################################################################
10
+
11
+ .. _appendixA:
12
+
13
+ ============================
14
+ Appendix A: List of Examples
15
+ ============================
16
+
17
+ __CONTENT__
18
+
19
+ | :ref:`Back to Table of Contents <index>`
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rda_python_miscs
3
- Version: 3.0.3
3
+ Version: 3.0.4
4
4
  Summary: RDA Python package to hold RDA miscellaneous utility programs
5
5
  Author-email: Zaihua Ji <zji@ucar.edu>
6
6
  Project-URL: Homepage, https://github.com/NCAR/rda-python-miscs
@@ -21,7 +21,7 @@ rda_python_miscs/gdexsub.usg,sha256=SChXnDzo6larOdpR9eZ2CMu8ExJYQUdfFHUzxcGoqJ0,
21
21
  rda_python_miscs/gdexzip.py,sha256=wzMVTqeahXAUHsKAtqYG6wrM4J2EahnncrpliCqFyNQ,3252
22
22
  rda_python_miscs/gdexzip.usg,sha256=cG1Uwa8WZ3KQNSaSkr29edUEaaLb_4cHTU3GRoZSQ84,1918
23
23
  rda_python_miscs/pg_docs.py,sha256=_AoqrWroUu7FQMVWaTSTZBQMwi1BH1-RjKb1nDHgxOI,25369
24
- rda_python_miscs/pg_rst.py,sha256=XldjKneKuciYvZxrHC3h3_OHwyhh51LKYOuKr0s_2Gg,48480
24
+ rda_python_miscs/pg_rst.py,sha256=Wd4qfeetQYvRio9P2YE2x4kUCDI6ZEcX8CQiI0Xqmyk,53063
25
25
  rda_python_miscs/pg_rst.usg,sha256=oYvVEqzHeVmDntN7hfpM8vc6eoYRyQTruQQg2mPfOo4,2484
26
26
  rda_python_miscs/pg_wget.py,sha256=YK8EJQtTwGXxHav_SveXOwE_oA9KZ9l12lGSf77JQnE,7571
27
27
  rda_python_miscs/pgwget.py,sha256=TFHyquKT0tyz-r-RUAV_wpdwktpVRwyZGrHnZF2B3Vk,8115
@@ -38,11 +38,12 @@ rda_python_miscs/rdals.usg,sha256=ChF-nn3Qb2pds3wMXIWubB_tjwZslxHfSha0dTDqOiY,29
38
38
  rda_python_miscs/tcsh_qsub.py,sha256=P4Obzbp5Dvy-N0eRR5F51R9yj3ttWJo6g1NqyVDO6-Y,6670
39
39
  rda_python_miscs/tcshqsub.py,sha256=QxBq9MdVIUs9t2d6vHhkxM1nrcLwRNqcq1lJiWhXKUM,10124
40
40
  rda_python_miscs/tcshqsub.usg,sha256=JYfhrK7cqme-Sij_JfquONOs3HMu-d5dDGI9K_RdudU,2180
41
+ rda_python_miscs/rst_templates/appendix.rst.temp,sha256=HCujxbj-R4_8FgOrLSlMZcBQHUu8f6kfBMWVRygl7jc,560
41
42
  rda_python_miscs/rst_templates/index.rst.temp,sha256=YSa1JM6X9x2SC6UiqJu_9xRrVYGLKwNI43DBJEGDX08,523
42
43
  rda_python_miscs/rst_templates/section.rst.temp,sha256=-CUtutvctG2tIdkqrkFxVEzmNN3atRJXBDQaTnMJ6Gw,572
43
- rda_python_miscs-3.0.3.dist-info/licenses/LICENSE,sha256=1dck4EAQwv8QweDWCXDx-4Or0S8YwiCstaso_H57Pno,1097
44
- rda_python_miscs-3.0.3.dist-info/METADATA,sha256=b4yrhKT1F_QySBljOiOujWrWLMStJO0Vymjx8dO47f4,5803
45
- rda_python_miscs-3.0.3.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
46
- rda_python_miscs-3.0.3.dist-info/entry_points.txt,sha256=pBgb-_g4yZhm6YynwDHtNTAzxVrb8SoDMd7Eiys8gv4,806
47
- rda_python_miscs-3.0.3.dist-info/top_level.txt,sha256=W5rz7DrWb7hXABUbGgWcwe6D644X338LR8_zdgmtLhg,17
48
- rda_python_miscs-3.0.3.dist-info/RECORD,,
44
+ rda_python_miscs-3.0.4.dist-info/licenses/LICENSE,sha256=1dck4EAQwv8QweDWCXDx-4Or0S8YwiCstaso_H57Pno,1097
45
+ rda_python_miscs-3.0.4.dist-info/METADATA,sha256=nxRaTHxAU0aTXLaNZj9RChQZ70oCj0qHdWtZLVAnOOc,5803
46
+ rda_python_miscs-3.0.4.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
47
+ rda_python_miscs-3.0.4.dist-info/entry_points.txt,sha256=pBgb-_g4yZhm6YynwDHtNTAzxVrb8SoDMd7Eiys8gv4,806
48
+ rda_python_miscs-3.0.4.dist-info/top_level.txt,sha256=W5rz7DrWb7hXABUbGgWcwe6D644X338LR8_zdgmtLhg,17
49
+ rda_python_miscs-3.0.4.dist-info/RECORD,,