Skip to content

Commit dc6c82c

Browse files
mmaterarocky
andauthored
Doc code another round of tiny changes 2 (#993)
This PR continues #990 by moving the inner loop that loads chapters in `MathicsMainDocumentation.doc_part` to a new method `MathicsMainDocumentation.doc_chapter`. With this change, the "on the fly" loading of documentation for Pymathics modules loaded in a Django session now is possible (and is implemented in Mathics3/mathics-django#201) --------- Co-authored-by: R. Bernstein <rocky@users.noreply.github.com>
1 parent 60100d8 commit dc6c82c

File tree

2 files changed

+113
-140
lines changed

2 files changed

+113
-140
lines changed

mathics/doc/common_doc.py

+111-119
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
located in static files and docstrings from
55
Mathics3 Builtin Modules. Builtin Modules are written in Python and
66
reside either in the Mathics3 core (mathics.builtin) or are packaged outside,
7-
e.g. pymathics.natlang.
7+
in Mathics3 Modules e.g. pymathics.natlang.
88
99
This data is stored in a way that facilitates:
1010
* organizing information to produce a LaTeX file
@@ -35,7 +35,7 @@
3535
import re
3636
from os import environ, getenv, listdir
3737
from types import ModuleType
38-
from typing import Callable, Iterator, List, Optional, Tuple
38+
from typing import Callable, List, Optional, Tuple
3939

4040
from mathics import settings
4141
from mathics.core.builtin import check_requires_list
@@ -694,13 +694,9 @@ def get_subsection(self, part_slug, chapter_slug, section_slug, subsection_slug)
694694

695695
return None
696696

697-
def get_tests(self, want_sorting=False):
697+
def get_tests(self):
698698
for part in self.parts:
699-
if want_sorting:
700-
chapter_collection_fn = lambda x: sorted_chapters(x)
701-
else:
702-
chapter_collection_fn = lambda x: x
703-
for chapter in chapter_collection_fn(part.chapters):
699+
for chapter in sorted_chapters(part.chapters):
704700
tests = chapter.doc.get_tests()
705701
if tests:
706702
yield Tests(part.title, chapter.title, "", tests)
@@ -1045,10 +1041,97 @@ def add_subsection(
10451041
)
10461042
section.subsections.append(subsection)
10471043

1044+
def doc_chapter(self, module, part, builtins_by_module) -> Optional[DocChapter]:
1045+
"""
1046+
Build documentation structure for a "Chapter" - reference section which
1047+
might be a Mathics Module.
1048+
"""
1049+
modules_seen = set([])
1050+
1051+
title, text = get_module_doc(module)
1052+
chapter = self.chapter_class(part, title, self.doc_class(text, title, None))
1053+
builtins = builtins_by_module.get(module.__name__)
1054+
if module.__file__.endswith("__init__.py"):
1055+
# We have a Guide Section.
1056+
1057+
# This is used to check if a symbol is not duplicated inside
1058+
# a guide.
1059+
submodule_names_seen = set([])
1060+
name = get_doc_name_from_module(module)
1061+
guide_section = self.add_section(
1062+
chapter, name, module, operator=None, is_guide=True
1063+
)
1064+
submodules = [
1065+
value
1066+
for value in module.__dict__.values()
1067+
if isinstance(value, ModuleType)
1068+
]
1069+
1070+
sorted_submodule = lambda x: sorted(
1071+
submodules,
1072+
key=lambda submodule: submodule.sort_order
1073+
if hasattr(submodule, "sort_order")
1074+
else submodule.__name__,
1075+
)
1076+
1077+
# Add sections in the guide section...
1078+
for submodule in sorted_submodule(submodules):
1079+
if skip_module_doc(submodule, modules_seen):
1080+
continue
1081+
elif IS_PYPY and submodule.__name__ == "builtins":
1082+
# PyPy seems to add this module on its own,
1083+
# but it is not something that can be importable
1084+
continue
1085+
1086+
submodule_name = get_doc_name_from_module(submodule)
1087+
if submodule_name in submodule_names_seen:
1088+
continue
1089+
section = self.add_section(
1090+
chapter,
1091+
submodule_name,
1092+
submodule,
1093+
operator=None,
1094+
is_guide=False,
1095+
in_guide=True,
1096+
)
1097+
modules_seen.add(submodule)
1098+
submodule_names_seen.add(submodule_name)
1099+
guide_section.subsections.append(section)
1100+
1101+
builtins = builtins_by_module.get(submodule.__name__, [])
1102+
subsections = [builtin for builtin in builtins]
1103+
for instance in subsections:
1104+
if hasattr(instance, "no_doc") and instance.no_doc:
1105+
continue
1106+
1107+
name = instance.get_name(short=True)
1108+
if name in submodule_names_seen:
1109+
continue
1110+
1111+
submodule_names_seen.add(name)
1112+
modules_seen.add(instance)
1113+
1114+
self.add_subsection(
1115+
chapter,
1116+
section,
1117+
name,
1118+
instance,
1119+
instance.get_operator(),
1120+
in_guide=True,
1121+
)
1122+
else:
1123+
if not builtins:
1124+
return None
1125+
sections = [
1126+
builtin for builtin in builtins if not skip_doc(builtin.__class__)
1127+
]
1128+
self.doc_sections(sections, modules_seen, chapter)
1129+
return chapter
1130+
10481131
def doc_part(self, title, modules, builtins_by_module, start):
10491132
"""
1050-
Produce documentation for a "Part" - reference section or
1051-
possibly Pymathics modules
1133+
Build documentation structure for a "Part" - Reference
1134+
section or collection of Mathics3 Modules.
10521135
"""
10531136

10541137
builtin_part = self.part_class(self, title, is_reference=start)
@@ -1060,20 +1143,6 @@ def doc_part(self, title, modules, builtins_by_module, start):
10601143
# packages inside ``mathics.builtin``.
10611144
modules_seen = set([])
10621145

1063-
want_sorting = True
1064-
if want_sorting:
1065-
module_collection_fn = lambda x: sorted(
1066-
modules,
1067-
key=lambda module: module.sort_order
1068-
if hasattr(module, "sort_order")
1069-
else module.__name__,
1070-
)
1071-
else:
1072-
module_collection_fn = lambda x: x
1073-
1074-
# For some weird reason, it seems that this produces an
1075-
# overflow error in test.builitin.directories.
1076-
'''
10771146
def filter_toplevel_modules(module_list):
10781147
"""
10791148
Keep just the modules at the top level.
@@ -1087,105 +1156,28 @@ def filter_toplevel_modules(module_list):
10871156
)
10881157
top_level = modules_and_levels[0][0]
10891158
return (entry[1] for entry in modules_and_levels if entry[0] == top_level)
1090-
'''
1091-
# This ensures that the chapters are built
1092-
# from the top-level modules. Without this,
1093-
# if this happens is just by chance, or by
1094-
# an obscure combination between the sorting
1095-
# of the modules and the way in which visited
1096-
# modules are skipped.
1097-
#
1098-
# However, if I activate this, some tests are lost.
1159+
1160+
# The loop to load chapters must be run over the top-level modules. Otherwise,
1161+
# modules like ``mathics.builtin.functional.apply_fns_to_lists`` are loaded
1162+
# as chapters and sections of a GuideSection, producing duplicated tests.
10991163
#
1100-
# modules = filter_toplevel_modules(modules)
1101-
for module in module_collection_fn(modules):
1164+
# Also, this provides a more deterministic way to walk the module hierarchy,
1165+
# which can be decomposed in the way proposed in #984.
1166+
1167+
modules = filter_toplevel_modules(modules)
1168+
for module in sorted(
1169+
modules,
1170+
key=lambda module: module.sort_order
1171+
if hasattr(module, "sort_order")
1172+
else module.__name__,
1173+
):
11021174
if skip_module_doc(module, modules_seen):
11031175
continue
1104-
title, text = get_module_doc(module)
1105-
chapter = self.chapter_class(
1106-
builtin_part, title, self.doc_class(text, title, None)
1107-
)
1108-
builtins = builtins_by_module.get(module.__name__)
1109-
if module.__file__.endswith("__init__.py"):
1110-
# We have a Guide Section.
1111-
1112-
# This is used to check if a symbol is not duplicated inside
1113-
# a guide.
1114-
submodule_names_seen = set([])
1115-
name = get_doc_name_from_module(module)
1116-
guide_section = self.add_section(
1117-
chapter, name, module, operator=None, is_guide=True
1118-
)
1119-
submodules = [
1120-
value
1121-
for value in module.__dict__.values()
1122-
if isinstance(value, ModuleType)
1123-
]
1124-
1125-
sorted_submodule = lambda x: sorted(
1126-
submodules,
1127-
key=lambda submodule: submodule.sort_order
1128-
if hasattr(submodule, "sort_order")
1129-
else submodule.__name__,
1130-
)
1131-
1132-
# Add sections in the guide section...
1133-
for submodule in sorted_submodule(submodules):
1134-
if skip_module_doc(submodule, modules_seen):
1135-
continue
1136-
elif IS_PYPY and submodule.__name__ == "builtins":
1137-
# PyPy seems to add this module on its own,
1138-
# but it is not something that can be importable
1139-
continue
1140-
1141-
submodule_name = get_doc_name_from_module(submodule)
1142-
# This has the side effect that Symbols with the same
1143-
# short name but in different contexts be skipped.
1144-
# This happens with ``PlaintextImport`` that appears in
1145-
# the HTML and XML contexts.
1146-
if submodule_name in submodule_names_seen:
1147-
continue
1148-
section = self.add_section(
1149-
chapter,
1150-
submodule_name,
1151-
submodule,
1152-
operator=None,
1153-
is_guide=False,
1154-
in_guide=True,
1155-
)
1156-
modules_seen.add(submodule)
1157-
submodule_names_seen.add(submodule_name)
1158-
guide_section.subsections.append(section)
1159-
1160-
builtins = builtins_by_module.get(submodule.__name__, [])
1161-
subsections = [builtin for builtin in builtins]
1162-
for instance in subsections:
1163-
if hasattr(instance, "no_doc") and instance.no_doc:
1164-
continue
1165-
1166-
name = instance.get_name(short=True)
1167-
if name in submodule_names_seen:
1168-
continue
1169-
1170-
submodule_names_seen.add(name)
1171-
modules_seen.add(instance)
1172-
1173-
self.add_subsection(
1174-
chapter,
1175-
section,
1176-
name,
1177-
instance,
1178-
instance.get_operator(),
1179-
in_guide=True,
1180-
)
1181-
else:
1182-
if not builtins:
1183-
continue
1184-
sections = [
1185-
builtin for builtin in builtins if not skip_doc(builtin.__class__)
1186-
]
1187-
self.doc_sections(sections, modules_seen, chapter)
1176+
chapter = self.doc_chapter(module, builtin_part, builtins_by_module)
1177+
if chapter is None:
1178+
continue
11881179
builtin_part.chapters.append(chapter)
1180+
11891181
self.parts.append(builtin_part)
11901182

11911183
def doc_sections(self, sections, modules_seen, chapter):

mathics/docpipeline.py

+2-21
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,6 @@ def test_chapters(
251251
stop_on_failure=False,
252252
generate_output=False,
253253
reload=False,
254-
want_sorting=False,
255254
keep_going=False,
256255
):
257256
failed = 0
@@ -294,7 +293,6 @@ def test_sections(
294293
stop_on_failure=False,
295294
generate_output=False,
296295
reload=False,
297-
want_sorting=False,
298296
keep_going=False,
299297
):
300298
failed = 0
@@ -354,7 +352,6 @@ def test_all(
354352
texdatafolder=None,
355353
doc_even_if_error=False,
356354
excludes=[],
357-
want_sorting=False,
358355
):
359356
if not quiet:
360357
print(f"Testing {version_string}")
@@ -371,7 +368,7 @@ def test_all(
371368
total = failed = skipped = 0
372369
failed_symbols = set()
373370
output_data = {}
374-
for tests in documentation.get_tests(want_sorting=want_sorting):
371+
for tests in documentation.get_tests():
375372
sub_total, sub_failed, sub_skipped, symbols, index = test_tests(
376373
tests,
377374
index,
@@ -608,21 +605,6 @@ def main():
608605
action="store_true",
609606
help="print cache statistics",
610607
)
611-
# FIXME: historically was weird interacting going on with
612-
# mathics when tests in sorted order. Possibly a
613-
# mpmath precsion reset bug.
614-
# We see a noticeable 2 minute delay in processing.
615-
# WHile the problem is in Mathics itself rather than
616-
# sorting, until we get this fixed, use
617-
# sort as an option only. For normal testing we don't
618-
# want it for speed. But for document building which is
619-
# rarely done, we do want sorting of the sections and chapters.
620-
parser.add_argument(
621-
"--want-sorting",
622-
dest="want_sorting",
623-
action="store_true",
624-
help="Sort chapters and sections",
625-
)
626608
global logfile
627609

628610
args = parser.parse_args()
@@ -635,7 +617,7 @@ def main():
635617
logfile = open(args.logfilename, "wt")
636618

637619
global documentation
638-
documentation = MathicsMainDocumentation(want_sorting=args.want_sorting)
620+
documentation = MathicsMainDocumentation()
639621

640622
# LoadModule Mathics3 modules
641623
if args.pymathics:
@@ -686,7 +668,6 @@ def main():
686668
count=args.count,
687669
doc_even_if_error=args.keep_going,
688670
excludes=excludes,
689-
want_sorting=args.want_sorting,
690671
)
691672
end_time = datetime.now()
692673
print("Tests took ", end_time - start_time)

0 commit comments

Comments
 (0)