From bcd523c877c261b4e976a22f5345b7b6b151e5e3 Mon Sep 17 00:00:00 2001 From: mmatera Date: Thu, 1 Feb 2024 20:21:56 -0300 Subject: [PATCH 1/7] compatibility with mathics-core PR 986 --- mathics_django/doc/django_doc.py | 93 ++++++++++++++++---------------- 1 file changed, 46 insertions(+), 47 deletions(-) diff --git a/mathics_django/doc/django_doc.py b/mathics_django/doc/django_doc.py index ed676d06c..98b2c90c3 100644 --- a/mathics_django/doc/django_doc.py +++ b/mathics_django/doc/django_doc.py @@ -6,20 +6,23 @@ import pickle import re +from typing import Optional from django.utils.safestring import mark_safe from mathics import settings from mathics.doc.common_doc import ( DocChapter, DocGuideSection, + DocSection, + DocSubsection, DocTest, DocTests, DocText, - Documentation, + DocumentationEntry, + MathicsMainDocumentation, Tests, - XMLDoc, - gather_tests, get_results_by_test, + parse_docstring_to_DocumentationEntry_items, sorted_chapters, ) from mathics.doc.utils import slugify @@ -37,7 +40,7 @@ doc_data = {} -class DjangoDocElement(object): +class DjangoDocElement: def href(self, ajax=False): if ajax: return "javascript:loadDoc('%s')" % self.get_uri() @@ -64,11 +67,11 @@ def get_title_html(self): return mark_safe(escape_html(self.title, single_line=True)) -class DjangoDocumentation(Documentation, DjangoDocElement): +class DjangoDocumentationMixin(DjangoDocElement): def __str__(self): return "\n\n\n".join(str(part) for part in self.parts) - def get_tests(self): + def ___get_tests(self): for part in self.parts: for chapter in sorted_chapters(part.chapters): tests = chapter.doc.get_tests() @@ -117,6 +120,23 @@ def get_tests(self): pass return + +class MathicsDjangoDocumentation(MathicsMainDocumentation, DjangoDocElement): + def __init__(self, want_sorting=True): + + self.chapter_class = DjangoDocChapter + self.doc_dir = settings.DOC_DIR + self.doc_class = DjangoDocumentationEntry + self.guide_section_class = DjangoDocGuideSection + self.part_class = DjangoDocPart + self.section_class = DjangoDocSection + self.subsection_class = DjangoDocSubsection + # Initialize the superclass + super().__init__(want_sorting) + # Now, let's load the documentation + self.load_documentation_sources() + self.title = "Mathics Documentation" + def get_uri(self) -> str: return "/" @@ -161,7 +181,7 @@ def search_sections(section, result): for chapter in sorted_chapters(part.chapters): if matches(chapter.title): result.append((False, chapter)) - for section in chapter.sections: + for section in chapter.all_sections: if matches(section.title): if not isinstance(section, DjangoDocGuideSection): result.append((section.title == query, section)) @@ -174,39 +194,13 @@ def search_sections(section, result): return sorted_results -class MathicsDjangoDocumentation(DjangoDocumentation): - def __init__(self, want_sorting=True): - - self.doc_chapter_fn = DjangoDocChapter - self.doc_dir = settings.DOC_DIR - self.doc_fn = DjangoDoc - self.doc_guide_section_fn = DjangoDocGuideSection - self.doc_part_fn = DjangoDocPart - self.doc_section_fn = DjangoDocSection - self.doc_subsection_fn = DjangoDocSubsection - self.parts = [] - self.parts_by_slug = {} - self.title = "Overview" - - self.gather_doctest_data() - - -class DjangoDoc(XMLDoc): - def __init__(self, doc, title, section): - self.title = title - if section: - chapter = section.chapter - part = chapter.part - # Note: we elide section.title - key_prefix = (part.title, chapter.title, title) - else: - key_prefix = None - self.rawdoc = doc - self.items = gather_tests( - self.rawdoc, DjangoDocTests, DjangoDocTest, DjangoDocText, key_prefix - ) - return +class DjangoDocumentationEntry(DocumentationEntry): + def __init__(self, doc_str:str, title:str, section:Optional["DjangoDocSection"]): + self.docTest_collection_class = DjangoDocTests + self.docTest_class = DjangoDocTest + self.docText_class = DjangoDocText + super().__init__(doc_str, title, section) def __str__(self): return "\n".join(str(item) for item in self.items) @@ -281,7 +275,7 @@ def get_uri(self) -> str: return f"/{self.slug}/" -class DjangoDocSection(DjangoDocElement): +class DjangoDocSection(DocSection, DjangoDocElement): """An object for a Django Documented Section. A Section is part of a Chapter. It can contain subsections. """ @@ -313,8 +307,8 @@ def __init__( ) # Needs to come after self.chapter is initialized since - # XMLDoc uses self.chapter. - self.doc = DjangoDoc(text, title, self) + # DocumentationEntry uses self.chapter. + self.doc = DjangoDocumentationEntry(text, title, self) chapter.sections_by_slug[self.slug] = self @@ -324,7 +318,7 @@ def __str__(self): def get_collection(self): """Return a list of subsections for this section that this section belongs to.""" - return self.chapter.sections + return self.chapter.all_sections def html_data(self): indices = set() @@ -353,7 +347,7 @@ def __init__( self, chapter: str, title: str, text: str, submodule, installed: bool = True ): self.chapter = chapter - self.doc = DjangoDoc(text, title, None) + self.doc = DjangoDocumentationEntry(text, title, None) self.in_guide = False self.installed = installed self.slug = slugify(title) @@ -381,7 +375,7 @@ def get_uri(self) -> str: return f"/{self.chapter.part.slug}/{self.chapter.slug}/guide/" -class DjangoDocSubsection(DjangoDocElement): +class DjangoDocSubsection(DocSubsection, DjangoDocElement): """An object for a Django Documented Subsection. A Subsection is part of a Section. """ @@ -417,13 +411,18 @@ def __init__( mathics/builtin/colors/named-colors.py we have the "section" name for the class Read (the subsection) inside it. """ - + super().__init__( + chapter, section, title, text, operator, installed, in_guide, summary_text + ) + self.doc = DjangoDocumentationEntry(text, title, section) + return + # Check if any of this is actually needed. title_summary_text = re.split(" -- ", title) n = len(title_summary_text) self.title = title_summary_text[0] if n > 0 else "" self.summary_text = title_summary_text[1] if n > 1 else summary_text - self.doc = DjangoDoc(text, title, section) + self.doc = DjangoDocumentationEntry(text, title, section) self.chapter = chapter self.installed = installed self.operator = operator From 9572a48ebf5383d4b14b2bbaf166fd3fbd21a4c6 Mon Sep 17 00:00:00 2001 From: mmatera Date: Sun, 4 Feb 2024 19:32:19 -0300 Subject: [PATCH 2/7] some of the rocky's changes in #202 --- mathics_django/doc/django_doc.py | 26 ++++++------- mathics_django/settings.py | 2 +- mathics_django/web/controllers/doc.py | 51 +++++++++++++++++++++---- mathics_django/web/templates/about.html | 2 +- 4 files changed, 56 insertions(+), 25 deletions(-) diff --git a/mathics_django/doc/django_doc.py b/mathics_django/doc/django_doc.py index 98b2c90c3..cc5dc3c8b 100644 --- a/mathics_django/doc/django_doc.py +++ b/mathics_django/doc/django_doc.py @@ -31,8 +31,8 @@ from mathics_django.settings import get_doctest_html_data_path # FIXME: remove globalness +doctest_html_data_path = get_doctest_html_data_path(should_be_readable=True) try: - doctest_html_data_path = get_doctest_html_data_path(should_be_readable=True) with open(doctest_html_data_path, "rb") as doctest_html_data_file: doc_data = pickle.load(doctest_html_data_file) except IOError: @@ -43,9 +43,9 @@ class DjangoDocElement: def href(self, ajax=False): if ajax: - return "javascript:loadDoc('%s')" % self.get_uri() + return f"javascript:loadDoc('{self.get_uri()}')" else: - return "/doc%s" % self.get_uri() + return f"/doc{self.get_uri()}" def get_prev(self): return self.get_prev_next()[0] @@ -212,7 +212,6 @@ def get_tests(self): return tests def html(self): - counters = {} items = [item for item in self.items if not item.is_private()] title_line = self.title + "\n" if len(items) and items[0].text.startswith(title_line): @@ -221,7 +220,7 @@ def html(self): # Or that is the intent. This code is a bit hacky. items[0].text = items[0].text[len(title_line) :] - text = "\n".join(item.html(counters) for item in items if not item.is_private()) + text = "\n".join(item.html() for item in items if not item.is_private()) if text == "": # HACK ALERT if text is "" we may have missed some test markup. return mark_safe(escape_html(self.rawdoc)) @@ -262,7 +261,7 @@ def get_collection(self): """Return a list of parts in this doc""" return self.doc.parts - def html(self, counters=None): + def html(self): if len(self.tests) == 0: return "\n" return '' % ( @@ -302,8 +301,7 @@ def __init__( if text.count("
") != text.count("
"): raise ValueError( - "Missing opening or closing
tag in " - "{} documentation".format(title) + f"Missing opening or closing
tag in {title} documentation" ) # Needs to come after self.chapter is initialized since @@ -364,8 +362,7 @@ def __init__( if text.count("
") != text.count("
"): raise ValueError( - "Missing opening or closing
tag in " - "{} documentation".format(title) + f"Missing opening or closing
tag in {title} documentation" ) # print("YYY Adding section", title) chapter.sections_by_slug[self.slug] = self @@ -450,8 +447,7 @@ def __init__( if text.count("
") != text.count("
"): raise ValueError( - "Missing opening or closing
tag in " - "{} documentation".format(title) + f"Missing opening or closing
tag in {title} documentation" ) self.section.subsections_by_slug[self.slug] = self @@ -520,7 +516,7 @@ def html(self) -> str: class DjangoDocTests(DocTests): - def html(self, counters=None): + def html(self): if len(self.tests) == 0: return "\n" return '
    %s
' % ( @@ -531,6 +527,6 @@ def html(self, counters=None): class DjangoDocText(DocText): - def html(self, counters=None) -> str: - result = escape_html(self.text, counters=counters) + def html(self) -> str: + result = escape_html(self.text) return result diff --git a/mathics_django/settings.py b/mathics_django/settings.py index 96fa92fd8..d618d8013 100644 --- a/mathics_django/settings.py +++ b/mathics_django/settings.py @@ -74,7 +74,7 @@ def get_bool_from_environment(env_var: str, default_value: str): ) # We need another version as a fallback, and that is distributed with the -# package. It is note user writable and not in the user space. +# package. It is not user writable and not in the user space. DOC_SYSTEM_HTML_DATA_PATH = os.environ.get( "DOC_SYSTEM_HTML_DATA_PATH", osp.join(ROOT_DIR, "doc", "doc_html_data.pcl") ) diff --git a/mathics_django/web/controllers/doc.py b/mathics_django/web/controllers/doc.py index 191be91f6..4f9111006 100644 --- a/mathics_django/web/controllers/doc.py +++ b/mathics_django/web/controllers/doc.py @@ -8,7 +8,8 @@ from django.core.handlers.wsgi import WSGIRequest from django.http import Http404, HttpResponse from django.shortcuts import render -from mathics.eval.pymathics import pymathics_modules +from mathics.doc.common_doc import get_module_doc +from mathics.eval.pymathics import pymathics_builtins_by_module, pymathics_modules from mathics_django.doc import documentation from mathics_django.doc.django_doc import ( @@ -21,12 +22,47 @@ DocResponse = Union[HttpResponse, JsonResponse] +seen_pymathics_modules = copy(pymathics_modules) + + def check_for_pymathics_load(): + global seen_pymathics_modules if seen_pymathics_modules != pymathics_modules: - # print("XXX refresh pymathics doc") - global documentation - documentation = MathicsDjangoDocumentation() + print("XXX refresh pymathics doc", pymathics_modules) + new_modules = pymathics_modules - seen_pymathics_modules + for new_module in new_modules: + title, _ = get_module_doc(new_module) + mathics3_module_part = documentation.parts_by_slug.get("Mathics3 Modules", None) + # If this is the first loaded module, we need to create the Part + if mathics3_module_part is None: + mathics3_module_part = self.doc_part( + "Mathics3 Modules", pymathics_modules, pymathics_builtins_by_module, True + ) + seen_pymathics_modules = copy(pymathics_modules) + return + + # The part already exists. Lets add the new chapter. + + chapter = mathics3_module_part.doc.gather_chapter_doc_fn( + mathics3_module_part, + title, + mathics3_module_part.doc, + ) + from trepan.api import debug + + debug() + submodule_names_seen = set() + chapter.doc.doc_chapter( + new_module, + mathics3_module_part, + pymathics_builtins_by_module, + seen_pymathics_modules, + submodule_names_seen, + ) + chapter.get_tests() + seen_pymathics_modules = copy(pymathics_modules) + pass def doc(request: WSGIRequest, ajax: bool = False) -> DocResponse: @@ -44,7 +80,9 @@ def doc(request: WSGIRequest, ajax: bool = False) -> DocResponse: def doc_chapter(request: WSGIRequest, part, chapter, ajax: bool = False) -> DocResponse: """ - Produces HTML via jinja templating for a chapter. Some examples of Chapters: + Produces HTML via jinja templating for a chapter. Some examples of + Chapters: + * Introduction (in part Manual) * Procedural Programming (in part Reference of Built-in Symbols) """ @@ -87,9 +125,6 @@ def doc_part(request: WSGIRequest, part, ajax: bool = False) -> DocResponse: ) -seen_pymathics_modules = copy(pymathics_modules) - - def doc_search(request: WSGIRequest) -> DocResponse: check_for_pymathics_load() query = request.GET.get("query", "") diff --git a/mathics_django/web/templates/about.html b/mathics_django/web/templates/about.html index 45a12a6c3..e390df2fc 100644 --- a/mathics_django/web/templates/about.html +++ b/mathics_django/web/templates/about.html @@ -165,7 +165,7 @@

Connection Information

Mathics3 is a general-purpose computer algebra system.

-

Copyright (C) 2021-2023 The Mathics3 Team


+

Copyright (C) 2021-2024 The Mathics3 Team


This program comes with ABSOLUTELY NO WARRANTY; This is free software, and you are welcome to redistribute it From 6e85fbe2ee5b504653e4ba5932941c112f43532b Mon Sep 17 00:00:00 2001 From: mmatera Date: Sun, 4 Feb 2024 20:36:17 -0300 Subject: [PATCH 3/7] line --- mathics_django/web/controllers/doc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mathics_django/web/controllers/doc.py b/mathics_django/web/controllers/doc.py index 4f9111006..0a66cd919 100644 --- a/mathics_django/web/controllers/doc.py +++ b/mathics_django/web/controllers/doc.py @@ -33,7 +33,7 @@ def check_for_pymathics_load(): new_modules = pymathics_modules - seen_pymathics_modules for new_module in new_modules: title, _ = get_module_doc(new_module) - mathics3_module_part = documentation.parts_by_slug.get("Mathics3 Modules", None) + mathics3_module_part = documentation.parts_by_slug.get("mathics3-modules", None) # If this is the first loaded module, we need to create the Part if mathics3_module_part is None: mathics3_module_part = self.doc_part( From 2142048e7f0e62a9a9ae20bb2728106868cebb0e Mon Sep 17 00:00:00 2001 From: mmatera Date: Sun, 4 Feb 2024 20:48:10 -0300 Subject: [PATCH 4/7] fix loading documentation --- .github/workflows/ubuntu.yml | 2 +- mathics_django/docpipeline.py | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index 11a13af08..b006e453d 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-22.04 strategy: matrix: - python-version: ['3.7', '3.8', '3.9', '3.10'] + python-version: ['3.8', '3.9', '3.10', '3.11'] steps: - uses: actions/checkout@v3 - name: Set up Python ${{ matrix.python-version }} diff --git a/mathics_django/docpipeline.py b/mathics_django/docpipeline.py index 04a1854f6..7b2d42863 100644 --- a/mathics_django/docpipeline.py +++ b/mathics_django/docpipeline.py @@ -598,8 +598,6 @@ def main(): if args.logfilename: logfile = open(args.logfilename, "wt") - global documentation - documentation = MathicsDjangoDocumentation() # LoadModule Mathics3 modules if args.pymathics: @@ -614,7 +612,11 @@ def main(): else: print(f"Mathics3 Module {module_name} loaded") - documentation.gather_doctest_data() + # MathicsDjangoDocumentation load the documentation automatically. + # It must be loaded after loading modules. + global documentation + documentation = MathicsDjangoDocumentation() + if args.sections: sections = set(args.sections.split(",")) From 8170935875d3daa147203e4efcae2410feaefb7d Mon Sep 17 00:00:00 2001 From: mmatera Date: Sun, 4 Feb 2024 20:49:37 -0300 Subject: [PATCH 5/7] black --- mathics_django/doc/django_doc.py | 3 +-- mathics_django/docpipeline.py | 2 -- mathics_django/web/controllers/doc.py | 10 +++++++--- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/mathics_django/doc/django_doc.py b/mathics_django/doc/django_doc.py index cc5dc3c8b..73f679d69 100644 --- a/mathics_django/doc/django_doc.py +++ b/mathics_django/doc/django_doc.py @@ -194,9 +194,8 @@ def search_sections(section, result): return sorted_results - class DjangoDocumentationEntry(DocumentationEntry): - def __init__(self, doc_str:str, title:str, section:Optional["DjangoDocSection"]): + def __init__(self, doc_str: str, title: str, section: Optional["DjangoDocSection"]): self.docTest_collection_class = DjangoDocTests self.docTest_class = DjangoDocTest self.docText_class = DjangoDocText diff --git a/mathics_django/docpipeline.py b/mathics_django/docpipeline.py index 7b2d42863..29ac1857e 100644 --- a/mathics_django/docpipeline.py +++ b/mathics_django/docpipeline.py @@ -598,7 +598,6 @@ def main(): if args.logfilename: logfile = open(args.logfilename, "wt") - # LoadModule Mathics3 modules if args.pymathics: for module_name in args.pymathics.split(","): @@ -617,7 +616,6 @@ def main(): global documentation documentation = MathicsDjangoDocumentation() - if args.sections: sections = set(args.sections.split(",")) diff --git a/mathics_django/web/controllers/doc.py b/mathics_django/web/controllers/doc.py index 0a66cd919..bb403b7c1 100644 --- a/mathics_django/web/controllers/doc.py +++ b/mathics_django/web/controllers/doc.py @@ -25,7 +25,6 @@ seen_pymathics_modules = copy(pymathics_modules) - def check_for_pymathics_load(): global seen_pymathics_modules if seen_pymathics_modules != pymathics_modules: @@ -33,11 +32,16 @@ def check_for_pymathics_load(): new_modules = pymathics_modules - seen_pymathics_modules for new_module in new_modules: title, _ = get_module_doc(new_module) - mathics3_module_part = documentation.parts_by_slug.get("mathics3-modules", None) + mathics3_module_part = documentation.parts_by_slug.get( + "mathics3-modules", None + ) # If this is the first loaded module, we need to create the Part if mathics3_module_part is None: mathics3_module_part = self.doc_part( - "Mathics3 Modules", pymathics_modules, pymathics_builtins_by_module, True + "Mathics3 Modules", + pymathics_modules, + pymathics_builtins_by_module, + True, ) seen_pymathics_modules = copy(pymathics_modules) return From 48fc421a0c9aca1e2c5e5256c2cca16c5c84ab8f Mon Sep 17 00:00:00 2001 From: mmatera Date: Mon, 5 Feb 2024 02:26:42 -0300 Subject: [PATCH 6/7] allowing load chapters for Pymathics modules --- mathics_django/web/controllers/doc.py | 22 +++++----------------- 1 file changed, 5 insertions(+), 17 deletions(-) diff --git a/mathics_django/web/controllers/doc.py b/mathics_django/web/controllers/doc.py index bb403b7c1..88847062c 100644 --- a/mathics_django/web/controllers/doc.py +++ b/mathics_django/web/controllers/doc.py @@ -31,7 +31,6 @@ def check_for_pymathics_load(): print("XXX refresh pymathics doc", pymathics_modules) new_modules = pymathics_modules - seen_pymathics_modules for new_module in new_modules: - title, _ = get_module_doc(new_module) mathics3_module_part = documentation.parts_by_slug.get( "mathics3-modules", None ) @@ -46,25 +45,14 @@ def check_for_pymathics_load(): seen_pymathics_modules = copy(pymathics_modules) return - # The part already exists. Lets add the new chapter. - - chapter = mathics3_module_part.doc.gather_chapter_doc_fn( - mathics3_module_part, - title, - mathics3_module_part.doc, - ) - from trepan.api import debug - - debug() - submodule_names_seen = set() - chapter.doc.doc_chapter( + # The "Mathics3 modules" part already exists. Lets add the new chapter. + chapter = documentation.doc_chapter( new_module, mathics3_module_part, - pymathics_builtins_by_module, - seen_pymathics_modules, - submodule_names_seen, + pymathics_builtins_by_module ) - chapter.get_tests() + mathics3_module_part.chapters.append(chapter) + seen_pymathics_modules = copy(pymathics_modules) pass From 103ee46bfa7197a0958a5c306b6acb72b41d85db Mon Sep 17 00:00:00 2001 From: mmatera Date: Mon, 5 Feb 2024 02:30:01 -0300 Subject: [PATCH 7/7] black --- mathics_django/web/controllers/doc.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/mathics_django/web/controllers/doc.py b/mathics_django/web/controllers/doc.py index 88847062c..299e1744c 100644 --- a/mathics_django/web/controllers/doc.py +++ b/mathics_django/web/controllers/doc.py @@ -47,9 +47,7 @@ def check_for_pymathics_load(): # The "Mathics3 modules" part already exists. Lets add the new chapter. chapter = documentation.doc_chapter( - new_module, - mathics3_module_part, - pymathics_builtins_by_module + new_module, mathics3_module_part, pymathics_builtins_by_module ) mathics3_module_part.chapters.append(chapter)