supriya-project / uqbar

Tools for building documentation with Sphinx, Graphviz and LaTeX
https://supriya-project.github.io/uqbar
MIT License
13 stars 7 forks source link

Do these tests fail for you? #67

Closed jgarte closed 1 year ago

jgarte commented 1 year ago

Hi, do these tests fail for you also?

=========================== short test summary info ============================
FAILED tests/test_sphinx_api.py::test_sphinx_api_1 - assert ('API\n'\n '***\n...
FAILED tests/test_sphinx_book.py::test_sphinx_book_text_cached - assert ('Fak...
FAILED tests/test_sphinx_book.py::test_sphinx_book_text_uncached - assert ('F...
======================== 3 failed, 101 passed in 6.84s =========================
jgarte commented 1 year ago

more detail:


tests/test_apis_APIBuilder.py::test_collection_01 PASSED                 [  0%]
tests/test_apis_APIBuilder.py::test_collection_02 PASSED                 [  1%]
tests/test_apis_APIBuilder.py::test_collection_03 PASSED                 [  2%]
tests/test_apis_APIBuilder.py::test_collection_04 PASSED                 [  3%]
tests/test_apis_APIBuilder.py::test_output_01 PASSED                     [  4%]
tests/test_apis_APIBuilder.py::test_output_02 PASSED                     [  5%]
tests/test_apis_APIBuilder.py::test_output_03 PASSED                     [  6%]
tests/test_apis_ClassDocumenter.py::test_str_01 PASSED                   [  7%]
tests/test_apis_ClassDocumenter.py::test_str_02 PASSED                   [  8%]
tests/test_apis_ClassDocumenter.py::test_str_03 PASSED                   [  9%]
tests/test_apis_InheritanceGraph.py::test_01 PASSED                      [ 10%]
tests/test_apis_InheritanceGraph.py::test_02 PASSED                      [ 11%]
tests/test_apis_InheritanceGraph.py::test_03 PASSED                      [ 12%]
tests/test_apis_InheritanceGraph.py::test_04 PASSED                      [ 13%]
tests/test_apis_SummarizingClassDocumenter.py::test_str_01 PASSED        [ 14%]
tests/test_apis_SummarizingClassDocumenter.py::test_str_02 PASSED        [ 15%]
tests/test_apis_SummarizingClassDocumenter.py::test_str_03 PASSED        [ 16%]
tests/test_apis_SummarizingClassDocumenter.py::test_str_04 PASSED        [ 17%]
tests/test_apis_SummarizingModuleDocumenter.py::test_str_01 PASSED       [ 18%]
tests/test_apis_SummarizingModuleDocumenter.py::test_str_02 PASSED       [ 19%]
tests/test_apis_SummarizingModuleDocumenter.py::test_str_03 PASSED       [ 20%]
tests/test_apis_SummarizingRootDocumenter.py::test_str_01 PASSED         [ 21%]
tests/test_book_sphinx.py::test_parse_rst_01 PASSED                      [ 22%]
tests/test_book_sphinx.py::test_parse_rst_02 PASSED                      [ 23%]
tests/test_book_sphinx.py::test_collect_literal_blocks_01 PASSED         [ 24%]
tests/test_book_sphinx.py::test_collect_literal_blocks_02 PASSED         [ 25%]
tests/test_book_sphinx.py::test_interpret_code_blocks_01 PASSED          [ 25%]
tests/test_book_sphinx.py::test_interpret_code_blocks_02 PASSED          [ 26%]
tests/test_book_sphinx.py::test_rebuild_document_01 PASSED               [ 27%]
tests/test_book_sphinx.py::test_rebuild_document_02 PASSED               [ 28%]
tests/test_book_sphinx.py::test_rebuild_document_03 PASSED               [ 29%]
tests/test_book_sphinx.py::test_rebuild_document_04 PASSED               [ 30%]
tests/test_containers_DependencyGraph.py::test___contains__ PASSED       [ 31%]
tests/test_containers_DependencyGraph.py::test___eq__ PASSED             [ 32%]
tests/test_containers_DependencyGraph.py::test___getitem__ PASSED        [ 33%]
tests/test_containers_DependencyGraph.py::test___iter__ PASSED           [ 34%]
tests/test_containers_DependencyGraph.py::test___len__ PASSED            [ 35%]
tests/test_containers_DependencyGraph.py::test_add PASSED                [ 36%]
tests/test_containers_DependencyGraph.py::test_children PASSED           [ 37%]
tests/test_containers_DependencyGraph.py::test_copy PASSED               [ 38%]
tests/test_containers_DependencyGraph.py::test_is_acyclic PASSED         [ 39%]
tests/test_containers_DependencyGraph.py::test_parents PASSED            [ 40%]
tests/test_containers_DependencyGraph.py::test_remove PASSED             [ 41%]
tests/test_containers_UniqueTreeContainer.py::TestCase::test___delitem___01 PASSED [ 42%]
tests/test_containers_UniqueTreeContainer.py::TestCase::test___delitem___02 PASSED [ 43%]
tests/test_containers_UniqueTreeContainer.py::TestCase::test___getitem___named PASSED [ 44%]
tests/test_containers_UniqueTreeContainer.py::TestCase::test___getitem___numbered PASSED [ 45%]
tests/test_containers_UniqueTreeContainer.py::TestCase::test___init___01 PASSED [ 46%]
tests/test_containers_UniqueTreeContainer.py::TestCase::test___init___02 PASSED [ 47%]
tests/test_containers_UniqueTreeContainer.py::TestCase::test___iter__ PASSED [ 48%]
tests/test_containers_UniqueTreeContainer.py::TestCase::test___len__ PASSED [ 49%]
tests/test_containers_UniqueTreeContainer.py::TestCase::test___setitem__ PASSED [ 50%]
tests/test_containers_UniqueTreeContainer.py::TestCase::test_append_01 PASSED [ 50%]
tests/test_containers_UniqueTreeContainer.py::TestCase::test_append_02 PASSED [ 51%]
tests/test_containers_UniqueTreeContainer.py::TestCase::test_extend_01 PASSED [ 52%]
tests/test_containers_UniqueTreeContainer.py::TestCase::test_extend_02 PASSED [ 53%]
tests/test_containers_UniqueTreeContainer.py::TestCase::test_forbid_circular_parentage PASSED [ 54%]
tests/test_containers_UniqueTreeContainer.py::TestCase::test_insert PASSED [ 55%]
tests/test_containers_UniqueTreeContainer.py::TestCase::test_pop PASSED  [ 56%]
tests/test_containers_UniqueTreeContainer.py::TestCase::test_remove PASSED [ 57%]
tests/test_containers_UniqueTreeNode.py::TestCase::test___init___01 PASSED [ 58%]
tests/test_containers_UniqueTreeNode.py::TestCase::test___init___02 PASSED [ 59%]
tests/test_containers_UniqueTreeNode.py::TestCase::test_name_01 PASSED   [ 60%]
tests/test_containers_UniqueTreeNode.py::TestCase::test_name_02 PASSED   [ 61%]
tests/test_graphs_Attributes.py::TestCase::test___format___graphviz_01 PASSED [ 62%]
tests/test_graphs_Attributes.py::TestCase::test___format___graphviz_02 PASSED [ 63%]
tests/test_graphs_Attributes.py::TestCase::test___format___str_01 PASSED [ 64%]
tests/test_graphs_Attributes.py::TestCase::test___format___str_02 PASSED [ 65%]
tests/test_graphs_Attributes.py::TestCase::test_mode PASSED              [ 66%]
tests/test_graphs_Edge.py::TestCase::test___format___graphviz PASSED     [ 67%]
tests/test_graphs_Edge.py::TestCase::test___format___str PASSED          [ 68%]
tests/test_graphs_Edge.py::TestCase::test___init__ PASSED                [ 69%]
tests/test_graphs_Graph.py::TestCase::test___format___graphviz_01 PASSED [ 70%]
tests/test_graphs_Graph.py::TestCase::test_functional PASSED             [ 71%]
tests/test_graphs_Graph.py::TestCase::test_initialized_with_attributes PASSED [ 72%]
tests/test_graphs_Grapher.py::test_01 PASSED                             [ 73%]
tests/test_graphs_Node.py::TestCase::test___format___graphviz PASSED     [ 74%]
tests/test_graphs_Node.py::TestCase::test___format___str PASSED          [ 75%]
tests/test_graphs_Node.py::TestCase::test___init__ PASSED                [ 75%]
tests/test_graphs_Node.py::TestCase::test__get_canonical_name PASSED     [ 76%]
tests/test_graphs_RecordField.py::test_graphs_RecordField PASSED         [ 77%]
tests/test_graphs_Table.py::test_graphs_Table PASSED                     [ 78%]
tests/test_io_find_executable.py::test_find_executable PASSED            [ 79%]
tests/test_objects_get_hash.py::test_objects_get_hash_01 PASSED          [ 80%]
tests/test_objects_get_repr.py::test_objects_get_repr_01 PASSED          [ 81%]
tests/test_objects_get_repr.py::test_objects_get_repr_02 PASSED          [ 82%]
tests/test_objects_get_repr.py::test_objects_get_repr_03 PASSED          [ 83%]
tests/test_objects_get_repr.py::test_objects_get_repr_04 PASSED          [ 84%]
tests/test_objects_get_repr.py::test_objects_get_repr_05 PASSED          [ 85%]
tests/test_objects_get_vars.py::test_objects_get_vars_01 PASSED          [ 86%]
tests/test_objects_get_vars.py::test_objects_get_vars_02 PASSED          [ 87%]
tests/test_objects_new.py::test_objects_new_01 PASSED                    [ 88%]
tests/test_sphinx_api.py::test_sphinx_api_1 FAILED                       [ 89%]
tests/test_sphinx_api.py::test_sphinx_api_2 PASSED                       [ 90%]
tests/test_sphinx_book.py::test_sphinx_book_html_cached PASSED           [ 91%]
tests/test_sphinx_book.py::test_sphinx_book_latex_cached PASSED          [ 92%]
tests/test_sphinx_book.py::test_sphinx_book_text_cached FAILED           [ 93%]
tests/test_sphinx_book.py::test_sphinx_book_text_uncached FAILED         [ 94%]
tests/test_sphinx_book.py::test_sphinx_book_text_broken_strict PASSED    [ 95%]
tests/test_sphinx_book.py::test_sphinx_book_text_broken_setup PASSED     [ 96%]
tests/test_sphinx_book.py::test_sphinx_book_text_broken_teardown PASSED  [ 97%]
tests/test_sphinx_inheritance.py::test_sphinx_style_html PASSED          [ 98%]
tests/test_sphinx_inheritance.py::test_sphinx_style_latex PASSED         [ 99%]
tests/test_sphinx_style.py::test_sphinx_style_1 PASSED                   [100%]

=================================== FAILURES ===================================
______________________________ test_sphinx_api_1 _______________________________

app = <SphinxTestApp buildername='text'>
status = <_io.StringIO object at 0x7ffff5090670>
warning = <_io.StringIO object at 0x7ffff50e6700>

    @pytest.mark.sphinx("text", testroot="uqbar-sphinx-api-1")
    def test_sphinx_api_1(app, status, warning):
        app.build()
        index_source = pathlib.Path(app.srcdir) / "api" / "index.rst"
        assert index_source.exists()
        assert "build succeeded" in status.getvalue()
        assert "8 added, 0 changed, 0 removed" in status.getvalue()
        assert "0 added, 0 changed, 0 removed" not in status.getvalue()
        assert not warning.getvalue().strip()
        path = pathlib.Path(app.srcdir) / "_build" / "text" / "api" / "index.txt"
>       assert normalize(path.read_text()) == normalize(
            """
            API
            ***

            * fake_package

              * enums

                * "FakeEnum"

                  * "FakeEnum.BAR"

                  * "FakeEnum.BAZ"

                  * "FakeEnum.FOO"

                  * "FakeEnum.QUUX"

              * module

                * "ChildClass"

                  * "ChildClass.inheritable_method()"

                  * "ChildClass.new_method()"

                * "PublicClass"

                  * "PublicClass.class_method()"

                  * "PublicClass.inheritable_method()"

                  * "PublicClass.method()"

                  * "PublicClass.other_method()"

                  * "PublicClass.read_only_property"

                  * "PublicClass.read_write_property"

                  * "PublicClass.static_method()"

                * "public_function()"

              * multi

                * one

                  * "PublicClass"

                  * "public_function()"

                * two

                  * "PublicClass"

                  * "public_function()"

                * "PublicClass"

                * "public_function()"
            """
        )
E       assert ('API\n'\n '***\n'\n '\n'\n '* fake_package\n'\n '\n'\n '  * enums\n'\n '\n'\n '  * module\n'\n '\n'\n '  * multi\n'\n '\n'\n '    * one\n'\n '\n'\n '    * two') == ('API\n'\n '***\n'\n '\n'\n '* fake_package\n'\n '\n'\n '  * enums\n'\n '\n'\n '    * "FakeEnum"\n'\n '\n'\n '      * "FakeEnum.BAR"\n'\n '\n'\n '      * "FakeEnum.BAZ"\n'\n '\n'\n '      * "FakeEnum.FOO"\n'\n '\n'\n '      * "FakeEnum.QUUX"\n'\n '\n'\n '  * module\n'\n '\n'\n '    * "ChildClass"\n'\n '\n'\n '      * "ChildClass.inheritable_method()"\n'\n '\n'\n '      * "ChildClass.new_method()"\n'\n '\n'\n '    * "PublicClass"\n'\n '\n'\n '      * "PublicClass.class_method()"\n'\n '\n'\n '      * "PublicClass.inheritable_method()"\n'\n '\n'\n '      * "PublicClass.method()"\n'\n '\n'\n '      * "PublicClass.other_method()"\n'\n '\n'\n '      * "PublicClass.read_only_property"\n'\n '\n'\n '      * "PublicClass.read_write_property"\n'\n '\n'\n '      * "PublicClass.static_method()"\n'\n '\n'\n '    * "public_function()"\n'\n '\n'\n '  * multi\n'\n '\n'\n '    * one\n'\n '\n'\n '      * "PublicClass"\n'\n '\n'\n '      * "public_function()"\n'\n '\n'\n '    * two\n'\n '\n'\n '      * "PublicClass"\n'\n '\n'\n '      * "public_function()"\n'\n '\n'\n '    * "PublicClass"\n'\n '\n'\n '    * "public_function()"')
E           API
E           ***
E           
E           * fake_package
E           
E             * enums
E           
E         -     * "FakeEnum"
E         - 
E         -       * "FakeEnum.BAR"
E         - 
E         -       * "FakeEnum.BAZ"
E         - 
E         -       * "FakeEnum.FOO"
E         - 
E         -       * "FakeEnum.QUUX"
E         - 
E             * module
E         - 
E         -     * "ChildClass"
E         - 
E         -       * "ChildClass.inheritable_method()"
E         - 
E         -       * "ChildClass.new_method()"
E         - 
E         -     * "PublicClass"
E         - 
E         -       * "PublicClass.class_method()"
E         - 
E         -       * "PublicClass.inheritable_method()"
E         - 
E         -       * "PublicClass.method()"
E         - 
E         -       * "PublicClass.other_method()"
E         - 
E         -       * "PublicClass.read_only_property"
E         - 
E         -       * "PublicClass.read_write_property"
E         - 
E         -       * "PublicClass.static_method()"
E         - 
E         -     * "public_function()"
E           
E             * multi
E           
E               * one
E           
E         -       * "PublicClass"
E         - 
E         -       * "public_function()"
E         - 
E         -     * two
E         ?          -
E         +     * two
E         - 
E         -       * "PublicClass"
E         - 
E         -       * "public_function()"
E         - 
E         -     * "PublicClass"
E         - 
E         -     * "public_function()"

tests/test_sphinx_api.py:18: AssertionError
--------------------------- Captured stdout teardown ---------------------------
# testroot: root
# builder: text
# srcdir: /tmp/guix-build-python-uqbar-0.6.4.drv-0/pytest-of-nixbld/pytest-0/uqbar-sphinx-api-1
# outdir: /tmp/guix-build-python-uqbar-0.6.4.drv-0/pytest-of-nixbld/pytest-0/uqbar-sphinx-api-1/_build/text
# status: 
Running Sphinx v5.1.1
[uqbar-api] wrote /tmp/guix-build-python-uqbar-0.6.4.drv-0/pytest-of-nixbld/pytest-0/uqbar-sphinx-api-1/api/index.rst
[uqbar-api] wrote /tmp/guix-build-python-uqbar-0.6.4.drv-0/pytest-of-nixbld/pytest-0/uqbar-sphinx-api-1/api/fake_package/index.rst
[uqbar-api] wrote /tmp/guix-build-python-uqbar-0.6.4.drv-0/pytest-of-nixbld/pytest-0/uqbar-sphinx-api-1/api/fake_package/enums.rst
[uqbar-api] wrote /tmp/guix-build-python-uqbar-0.6.4.drv-0/pytest-of-nixbld/pytest-0/uqbar-sphinx-api-1/api/fake_package/module.rst
[uqbar-api] wrote /tmp/guix-build-python-uqbar-0.6.4.drv-0/pytest-of-nixbld/pytest-0/uqbar-sphinx-api-1/api/fake_package/multi/index.rst
[uqbar-api] wrote /tmp/guix-build-python-uqbar-0.6.4.drv-0/pytest-of-nixbld/pytest-0/uqbar-sphinx-api-1/api/fake_package/multi/one.rst
[uqbar-api] wrote /tmp/guix-build-python-uqbar-0.6.4.drv-0/pytest-of-nixbld/pytest-0/uqbar-sphinx-api-1/api/fake_package/multi/two.rst
building [mo]: targets for 0 po files that are out of date
building [text]: targets for 1 source files that are out of date
updating environment: [new config] 8 added, 0 changed, 0 removed
reading sources... [ 12%] api/fake_package/enums                               
reading sources... [ 25%] api/fake_package/index                               
reading sources... [ 37%] api/fake_package/module                              
reading sources... [ 50%] api/fake_package/multi/index                         
reading sources... [ 62%] api/fake_package/multi/one                           
reading sources... [ 75%] api/fake_package/multi/two                           
reading sources... [ 87%] api/index                                            
reading sources... [100%] index                                                
looking for now-outdated files... none found
pickling environment... done
checking consistency... done
preparing documents... done
writing output... [ 12%] api/fake_package/enums                                
writing output... [ 25%] api/fake_package/index                                
writing output... [ 37%] api/fake_package/module                               
writing output... [ 50%] api/fake_package/multi/index                          
writing output... [ 62%] api/fake_package/multi/one                            
writing output... [ 75%] api/fake_package/multi/two                            
writing output... [ 87%] api/index                                             
writing output... [100%] index                                                 
build succeeded.

The text files are in ../pytest-of-nixbld/pytest-0/uqbar-sphinx-api-1/_build/text.

# warning: 

_________________________ test_sphinx_book_text_cached _________________________

app = <SphinxTestApp buildername='text'>
status = <_io.StringIO object at 0x7ffff3f34e50>
warning = <_io.StringIO object at 0x7ffff3f34ee0>, rm_dirs = None

    @pytest.mark.sphinx(
        "text", testroot="uqbar-sphinx-book", confoverrides={"uqbar_book_use_cache": True}
    )
    def test_sphinx_book_text_cached(app, status, warning, rm_dirs):
        app.build()
        assert not warning.getvalue().strip()
        assert app.config["uqbar_book_use_cache"]
        assert list(
            app.connection.execute("SELECT path, hits FROM cache ORDER BY path")
        ) == [
            ("fake.Child", 0),
            ("fake.Child.two", 0),
            ("fake.GrandParent", 0),
            ("fake.GrandParent.one", 1),
            ("fake.GrandParent.three", 3),
            ("fake.GrandParent.two", 2),
            ("fake.Outer", 0),
            ("fake.Outer.Inner", 0),
            ("fake.Outer.Inner.inner_method", 0),
            ("fake.Outer.outer_method", 0),
            ("fake.Parent", 0),
            ("fake.Parent.one", 1),
            ("fake.just_a_function", 0),
        ]
        assert not warning.getvalue().strip()
        for filename, expected_content in [
            ("api.txt", api_content),
            ("directives.txt", directives_content),
            ("index.txt", index_content),
        ]:
            path = pathlib.Path(app.srcdir) / "_build" / "text" / filename
            actual_content = normalize(path.read_text())
>           assert actual_content == expected_content
E           assert ('Fake Docs\n'\n '*********\n'\n '\n'\n '   >>> print("hello, world!");\n'\n '   hello, world!\n'\n '\n'\n '   >>> print("foo bar baz!");\n'\n '   foo bar baz!\n'\n '\n'\n '   >>> print("i\'m on my own line too!");\n'\n "   i'm on my own line too!\n"\n '\n'\n '   >>> import uqbar.graphs\n'\n '\n'\n '   >>> g = uqbar.graphs.Graph()\n'\n '   >>> n1 = uqbar.graphs.Node()\n'\n '   >>> g.append(n1)\n'\n '\n'\n '   >>> for i in range(3):\n'\n '   ...     n2 = uqbar.graphs.Node()\n'\n '   ...     g.append(n2)\n'\n '   ...     e = n1.attach(n2)\n'\n '   ...     uqbar.graphs.Grapher(g)()\n'\n '   ...     print(i)\n'\n '   ...     n1 = n2\n'\n '   ...\n'\n '\n'\n '   digraph G {\n'\n '       node_0;\n'\n '       node_1;\n'\n '       node_0 -> node_1;\n'\n '   }\n'\n '\n'\n '   0\n'\n '\n'\n '   digraph G {\n'\n '       node_0;\n'\n '       node_1;\n'\n '       node_2;\n'\n '       node_0 -> node_1;\n'\n '       node_1 -> node_2;\n'\n '   }\n'\n '\n'\n '   1\n'\n '\n'\n '   digraph G {\n'\n '       node_0;\n'\n '       node_1;\n'\n '       node_2;\n'\n '       node_3;\n'\n '       node_0 -> node_1;\n'\n '       node_1 -> node_2;\n'\n '       node_2 -> node_3;\n'\n '   }\n'\n '\n'\n '   2\n'\n '\n'\n '   >>> print(format(g, "graphviz"))\n'\n '   digraph G {\n'\n '       node_0;\n'\n '       node_1;\n'\n '       node_2;\n'\n '       node_3;\n'\n '       node_0 -> node_1;\n'\n '       node_1 -> node_2;\n'\n '       node_2 -> node_3;\n'\n '   }\n'\n '\n'\n '* API\n'\n '\n'\n '* Directives') == ('Fake Docs\n'\n '*********\n'\n '\n'\n '   >>> print("hello, world!");\n'\n '   hello, world!\n'\n '\n'\n '   >>> print("foo bar baz!");\n'\n '   foo bar baz!\n'\n '\n'\n '   >>> print("i\'m on my own line too!");\n'\n "   i'm on my own line too!\n"\n '\n'\n '   >>> import uqbar.graphs\n'\n '\n'\n '   >>> g = uqbar.graphs.Graph()\n'\n '   >>> n1 = uqbar.graphs.Node()\n'\n '   >>> g.append(n1)\n'\n '\n'\n '   >>> for i in range(3):\n'\n '   ...     n2 = uqbar.graphs.Node()\n'\n '   ...     g.append(n2)\n'\n '   ...     e = n1.attach(n2)\n'\n '   ...     uqbar.graphs.Grapher(g)()\n'\n '   ...     print(i)\n'\n '   ...     n1 = n2\n'\n '   ...\n'\n '\n'\n '   digraph G {\n'\n '       node_0;\n'\n '       node_1;\n'\n '       node_0 -> node_1;\n'\n '   }\n'\n '\n'\n '   0\n'\n '\n'\n '   digraph G {\n'\n '       node_0;\n'\n '       node_1;\n'\n '       node_2;\n'\n '       node_0 -> node_1;\n'\n '       node_1 -> node_2;\n'\n '   }\n'\n '\n'\n '   1\n'\n '\n'\n '   digraph G {\n'\n '       node_0;\n'\n '       node_1;\n'\n '       node_2;\n'\n '       node_3;\n'\n '       node_0 -> node_1;\n'\n '       node_1 -> node_2;\n'\n '       node_2 -> node_3;\n'\n '   }\n'\n '\n'\n '   2\n'\n '\n'\n '   >>> print(format(g, "graphviz"))\n'\n '   digraph G {\n'\n '       node_0;\n'\n '       node_1;\n'\n '       node_2;\n'\n '       node_3;\n'\n '       node_0 -> node_1;\n'\n '       node_1 -> node_2;\n'\n '       node_2 -> node_3;\n'\n '   }\n'\n '\n'\n '* API\n'\n '\n'\n '  * "just_a_function()"\n'\n '\n'\n '  * "GrandParent"\n'\n '\n'\n '    * "GrandParent.one()"\n'\n '\n'\n '    * "GrandParent.three()"\n'\n '\n'\n '    * "GrandParent.two()"\n'\n '\n'\n '  * "Parent"\n'\n '\n'\n '    * "Parent.one()"\n'\n '\n'\n '    * "Parent.three()"\n'\n '\n'\n '    * "Parent.two()"\n'\n '\n'\n '  * "Uncle"\n'\n '\n'\n '    * "Uncle.one()"\n'\n '\n'\n '    * "Uncle.three()"\n'\n '\n'\n '    * "Uncle.two()"\n'\n '\n'\n '  * "Child"\n'\n '\n'\n '    * "Child.one()"\n'\n '\n'\n '    * "Child.three()"\n'\n '\n'\n '    * "Child.two()"\n'\n '\n'\n '  * "Outer"\n'\n '\n'\n '    * "Outer.Inner"\n'\n '\n'\n '      * "Outer.Inner.inner_method()"\n'\n '\n'\n '    * "Outer.outer_method()"\n'\n '\n'\n '* Directives')
E               Fake Docs
E               *********
E               
E                  >>> print("hello, world!");
E                  hello, world!
E               
E                  >>> print("foo bar baz!");
E                  foo bar baz!
E               
E                  >>> print("i'm on my own line too!");
E                  i'm on my own line too!
E               
E                  >>> import uqbar.graphs
E               
E                  >>> g = uqbar.graphs.Graph()
E                  >>> n1 = uqbar.graphs.Node()
E                  >>> g.append(n1)
E               
E                  >>> for i in range(3):
E                  ...     n2 = uqbar.graphs.Node()
E                  ...     g.append(n2)
E                  ...     e = n1.attach(n2)
E                  ...     uqbar.graphs.Grapher(g)()
E                  ...     print(i)
E                  ...     n1 = n2
E                  ...
E               
E                  digraph G {
E                      node_0;
E                      node_1;
E                      node_0 -> node_1;
E                  }
E               
E                  0
E               
E                  digraph G {
E                      node_0;
E                      node_1;
E                      node_2;
E                      node_0 -> node_1;
E                      node_1 -> node_2;
E                  }
E               
E                  1
E               
E                  digraph G {
E                      node_0;
E                      node_1;
E                      node_2;
E                      node_3;
E                      node_0 -> node_1;
E                      node_1 -> node_2;
E                      node_2 -> node_3;
E                  }
E               
E                  2
E               
E                  >>> print(format(g, "graphviz"))
E                  digraph G {
E                      node_0;
E                      node_1;
E                      node_2;
E                      node_3;
E                      node_0 -> node_1;
E                      node_1 -> node_2;
E                      node_2 -> node_3;
E                  }
E               
E               * API
E               
E             -   * "just_a_function()"
E             - 
E             -   * "GrandParent"
E             - 
E             -     * "GrandParent.one()"
E             - 
E             -     * "GrandParent.three()"
E             - 
E             -     * "GrandParent.two()"
E             - 
E             -   * "Parent"
E             - 
E             -     * "Parent.one()"
E             - 
E             -     * "Parent.three()"
E             - 
E             -     * "Parent.two()"
E             - 
E             -   * "Uncle"
E             - 
E             -     * "Uncle.one()"
E             - 
E             -     * "Uncle.three()"
E             - 
E             -     * "Uncle.two()"
E             - 
E             -   * "Child"
E             - 
E             -     * "Child.one()"
E             - 
E             -     * "Child.three()"
E             - 
E             -     * "Child.two()"
E             - 
E             -   * "Outer"
E             - 
E             -     * "Outer.Inner"
E             - 
E             -       * "Outer.Inner.inner_method()"
E             - 
E             -     * "Outer.outer_method()"
E             - 
E               * Directives

tests/test_sphinx_book.py:538: AssertionError
--------------------------- Captured stdout teardown ---------------------------
# testroot: root
# builder: text
# srcdir: /tmp/guix-build-python-uqbar-0.6.4.drv-0/pytest-of-nixbld/pytest-0/uqbar-sphinx-book
# outdir: /tmp/guix-build-python-uqbar-0.6.4.drv-0/pytest-of-nixbld/pytest-0/uqbar-sphinx-book/_build/text
# status: 
Running Sphinx v5.1.1
loading pickled environment... done
[uqbar-book] initializing cache db
building [mo]: targets for 0 po files that are out of date
building [text]: targets for 3 source files that are out of date
updating environment: 0 added, 3 changed, 0 removed
reading sources... [ 33%] api                                                  
reading sources... [ 66%] directives                                           
reading sources... [100%] index                                                
looking for now-outdated files... none found
pickling environment... done
checking consistency... done
preparing documents... done
writing output... [ 33%] api                                                   
writing output... [ 66%] directives                                            
writing output... [100%] index                                                 

[uqbar-book] Cache hits for fake.GrandParent.one: 1
[uqbar-book] Cache hits for fake.GrandParent.three: 3
[uqbar-book] Cache hits for fake.GrandParent.two: 2
[uqbar-book] Cache hits for fake.Parent.one: 1
build succeeded.

The text files are in ../pytest-of-nixbld/pytest-0/uqbar-sphinx-book/_build/text.

# warning: 

________________________ test_sphinx_book_text_uncached ________________________

app = <SphinxTestApp buildername='text'>
status = <_io.StringIO object at 0x7ffff3f28430>
warning = <_io.StringIO object at 0x7ffff3f284c0>, rm_dirs = None

    @pytest.mark.sphinx(
        "text", testroot="uqbar-sphinx-book", confoverrides={"uqbar_book_use_cache": False}
    )
    def test_sphinx_book_text_uncached(app, status, warning, rm_dirs):
        app.build()
        assert not warning.getvalue().strip()
        assert not app.config["uqbar_book_use_cache"]
        for filename, expected_content in [
            ("api.txt", api_content),
            ("directives.txt", directives_content),
            ("index.txt", index_content),
        ]:
            path = pathlib.Path(app.srcdir) / "_build" / "text" / filename
            actual_content = normalize(path.read_text())
>           assert actual_content == expected_content
E           assert ('Fake Docs\n'\n '*********\n'\n '\n'\n '   >>> print("hello, world!");\n'\n '   hello, world!\n'\n '\n'\n '   >>> print("foo bar baz!");\n'\n '   foo bar baz!\n'\n '\n'\n '   >>> print("i\'m on my own line too!");\n'\n "   i'm on my own line too!\n"\n '\n'\n '   >>> import uqbar.graphs\n'\n '\n'\n '   >>> g = uqbar.graphs.Graph()\n'\n '   >>> n1 = uqbar.graphs.Node()\n'\n '   >>> g.append(n1)\n'\n '\n'\n '   >>> for i in range(3):\n'\n '   ...     n2 = uqbar.graphs.Node()\n'\n '   ...     g.append(n2)\n'\n '   ...     e = n1.attach(n2)\n'\n '   ...     uqbar.graphs.Grapher(g)()\n'\n '   ...     print(i)\n'\n '   ...     n1 = n2\n'\n '   ...\n'\n '\n'\n '   digraph G {\n'\n '       node_0;\n'\n '       node_1;\n'\n '       node_0 -> node_1;\n'\n '   }\n'\n '\n'\n '   0\n'\n '\n'\n '   digraph G {\n'\n '       node_0;\n'\n '       node_1;\n'\n '       node_2;\n'\n '       node_0 -> node_1;\n'\n '       node_1 -> node_2;\n'\n '   }\n'\n '\n'\n '   1\n'\n '\n'\n '   digraph G {\n'\n '       node_0;\n'\n '       node_1;\n'\n '       node_2;\n'\n '       node_3;\n'\n '       node_0 -> node_1;\n'\n '       node_1 -> node_2;\n'\n '       node_2 -> node_3;\n'\n '   }\n'\n '\n'\n '   2\n'\n '\n'\n '   >>> print(format(g, "graphviz"))\n'\n '   digraph G {\n'\n '       node_0;\n'\n '       node_1;\n'\n '       node_2;\n'\n '       node_3;\n'\n '       node_0 -> node_1;\n'\n '       node_1 -> node_2;\n'\n '       node_2 -> node_3;\n'\n '   }\n'\n '\n'\n '* API\n'\n '\n'\n '* Directives') == ('Fake Docs\n'\n '*********\n'\n '\n'\n '   >>> print("hello, world!");\n'\n '   hello, world!\n'\n '\n'\n '   >>> print("foo bar baz!");\n'\n '   foo bar baz!\n'\n '\n'\n '   >>> print("i\'m on my own line too!");\n'\n "   i'm on my own line too!\n"\n '\n'\n '   >>> import uqbar.graphs\n'\n '\n'\n '   >>> g = uqbar.graphs.Graph()\n'\n '   >>> n1 = uqbar.graphs.Node()\n'\n '   >>> g.append(n1)\n'\n '\n'\n '   >>> for i in range(3):\n'\n '   ...     n2 = uqbar.graphs.Node()\n'\n '   ...     g.append(n2)\n'\n '   ...     e = n1.attach(n2)\n'\n '   ...     uqbar.graphs.Grapher(g)()\n'\n '   ...     print(i)\n'\n '   ...     n1 = n2\n'\n '   ...\n'\n '\n'\n '   digraph G {\n'\n '       node_0;\n'\n '       node_1;\n'\n '       node_0 -> node_1;\n'\n '   }\n'\n '\n'\n '   0\n'\n '\n'\n '   digraph G {\n'\n '       node_0;\n'\n '       node_1;\n'\n '       node_2;\n'\n '       node_0 -> node_1;\n'\n '       node_1 -> node_2;\n'\n '   }\n'\n '\n'\n '   1\n'\n '\n'\n '   digraph G {\n'\n '       node_0;\n'\n '       node_1;\n'\n '       node_2;\n'\n '       node_3;\n'\n '       node_0 -> node_1;\n'\n '       node_1 -> node_2;\n'\n '       node_2 -> node_3;\n'\n '   }\n'\n '\n'\n '   2\n'\n '\n'\n '   >>> print(format(g, "graphviz"))\n'\n '   digraph G {\n'\n '       node_0;\n'\n '       node_1;\n'\n '       node_2;\n'\n '       node_3;\n'\n '       node_0 -> node_1;\n'\n '       node_1 -> node_2;\n'\n '       node_2 -> node_3;\n'\n '   }\n'\n '\n'\n '* API\n'\n '\n'\n '  * "just_a_function()"\n'\n '\n'\n '  * "GrandParent"\n'\n '\n'\n '    * "GrandParent.one()"\n'\n '\n'\n '    * "GrandParent.three()"\n'\n '\n'\n '    * "GrandParent.two()"\n'\n '\n'\n '  * "Parent"\n'\n '\n'\n '    * "Parent.one()"\n'\n '\n'\n '    * "Parent.three()"\n'\n '\n'\n '    * "Parent.two()"\n'\n '\n'\n '  * "Uncle"\n'\n '\n'\n '    * "Uncle.one()"\n'\n '\n'\n '    * "Uncle.three()"\n'\n '\n'\n '    * "Uncle.two()"\n'\n '\n'\n '  * "Child"\n'\n '\n'\n '    * "Child.one()"\n'\n '\n'\n '    * "Child.three()"\n'\n '\n'\n '    * "Child.two()"\n'\n '\n'\n '  * "Outer"\n'\n '\n'\n '    * "Outer.Inner"\n'\n '\n'\n '      * "Outer.Inner.inner_method()"\n'\n '\n'\n '    * "Outer.outer_method()"\n'\n '\n'\n '* Directives')
E               Fake Docs
E               *********
E               
E                  >>> print("hello, world!");
E                  hello, world!
E               
E                  >>> print("foo bar baz!");
E                  foo bar baz!
E               
E                  >>> print("i'm on my own line too!");
E                  i'm on my own line too!
E               
E                  >>> import uqbar.graphs
E               
E                  >>> g = uqbar.graphs.Graph()
E                  >>> n1 = uqbar.graphs.Node()
E                  >>> g.append(n1)
E               
E                  >>> for i in range(3):
E                  ...     n2 = uqbar.graphs.Node()
E                  ...     g.append(n2)
E                  ...     e = n1.attach(n2)
E                  ...     uqbar.graphs.Grapher(g)()
E                  ...     print(i)
E                  ...     n1 = n2
E                  ...
E               
E                  digraph G {
E                      node_0;
E                      node_1;
E                      node_0 -> node_1;
E                  }
E               
E                  0
E               
E                  digraph G {
E                      node_0;
E                      node_1;
E                      node_2;
E                      node_0 -> node_1;
E                      node_1 -> node_2;
E                  }
E               
E                  1
E               
E                  digraph G {
E                      node_0;
E                      node_1;
E                      node_2;
E                      node_3;
E                      node_0 -> node_1;
E                      node_1 -> node_2;
E                      node_2 -> node_3;
E                  }
E               
E                  2
E               
E                  >>> print(format(g, "graphviz"))
E                  digraph G {
E                      node_0;
E                      node_1;
E                      node_2;
E                      node_3;
E                      node_0 -> node_1;
E                      node_1 -> node_2;
E                      node_2 -> node_3;
E                  }
E               
E               * API
E               
E             -   * "just_a_function()"
E             - 
E             -   * "GrandParent"
E             - 
E             -     * "GrandParent.one()"
E             - 
E             -     * "GrandParent.three()"
E             - 
E             -     * "GrandParent.two()"
E             - 
E             -   * "Parent"
E             - 
E             -     * "Parent.one()"
E             - 
E             -     * "Parent.three()"
E             - 
E             -     * "Parent.two()"
E             - 
E             -   * "Uncle"
E             - 
E             -     * "Uncle.one()"
E             - 
E             -     * "Uncle.three()"
E             - 
E             -     * "Uncle.two()"
E             - 
E             -   * "Child"
E             - 
E             -     * "Child.one()"
E             - 
E             -     * "Child.three()"
E             - 
E             -     * "Child.two()"
E             - 
E             -   * "Outer"
E             - 
E             -     * "Outer.Inner"
E             - 
E             -       * "Outer.Inner.inner_method()"
E             - 
E             -     * "Outer.outer_method()"
E             - 
E               * Directives

tests/test_sphinx_book.py:555: AssertionError
--------------------------- Captured stdout teardown ---------------------------
# testroot: root
# builder: text
# srcdir: /tmp/guix-build-python-uqbar-0.6.4.drv-0/pytest-of-nixbld/pytest-0/uqbar-sphinx-book
# outdir: /tmp/guix-build-python-uqbar-0.6.4.drv-0/pytest-of-nixbld/pytest-0/uqbar-sphinx-book/_build/text
# status: 
Running Sphinx v5.1.1
loading pickled environment... done
building [mo]: targets for 0 po files that are out of date
building [text]: targets for 0 source files that are out of date
updating environment: [config changed ('uqbar_book_use_cache')] 3 added, 0 changed, 0 removed
reading sources... [ 33%] api                                                  
reading sources... [ 66%] directives                                           
reading sources... [100%] index                                                
looking for now-outdated files... none found
pickling environment... done
checking consistency... done
preparing documents... done
writing output... [ 33%] api                                                   
writing output... [ 66%] directives                                            
writing output... [100%] index                                                 
build succeeded.

The text files are in ../pytest-of-nixbld/pytest-0/uqbar-sphinx-book/_build/text.

# warning: 

=========================== short test summary info ============================
FAILED tests/test_sphinx_api.py::test_sphinx_api_1 - assert ('API\n'\n '***\n...
FAILED tests/test_sphinx_book.py::test_sphinx_book_text_cached - assert ('Fak...
FAILED tests/test_sphinx_book.py::test_sphinx_book_text_uncached - assert ('F...
======================== 3 failed, 101 passed in 6.75s =========================
error: in phase 'check': uncaught exception:
%exception #<&invoke-error program: "python" arguments: ("-m" "pytest" "tests") exit-status: 1 term-signal: #f stop-signal: #f> 
phase `check' failed after 7.6 seconds
command "python" "-m" "pytest" "tests" failed with status 1
builder for `/gnu/store/kkz9yv6rf5ypbgshyar1zq8cd8wpj434-python-uqbar-0.6.4.drv' failed with exit code 1
build of /gnu/store/kkz9yv6rf5ypbgshyar1zq8cd8wpj434-python-uqbar-0.6.4.drv failed
View build log at '/var/log/guix/drvs/kk/z9yv6rf5ypbgshyar1zq8cd8wpj434-python-uqbar-0.6.4.drv.gz'.
guix build: error: build of `/gnu/store/kkz9yv6rf5ypbgshyar1zq8cd8wpj434-python-uqbar-0.6.4.drv' failed
josiah-wolf-oberholtzer commented 1 year ago

What version of Sphinx are you on?

jgarte commented 1 year ago

What version of Sphinx are you on?

5.1.1 😄

https://github.com/josiah-wolf-oberholtzer/uqbar/blob/1ff1e785c2ed66ba6f4ec410ffd77c746524d656/pyproject.toml#L22

josiah-wolf-oberholtzer commented 1 year ago

You didn't need to close the issue.

FWIW, I'm seeing failures under Sphinx 5.3.0 in GitHub Actions. Will look into fixing next week.

The v0.6.4 tests passed with Sphinx 5.3.0, so I'm not sure what's going on. That's the latest version on PyPI. See https://github.com/josiah-wolf-oberholtzer/uqbar/actions/runs/3309433792/jobs/5462614991

josiah-wolf-oberholtzer commented 1 year ago

Requirements installed in the v0.6.4 passing GHA (https://github.com/josiah-wolf-oberholtzer/uqbar/actions/runs/3309433792/jobs/5462614991):

Jinja2-3.1.2
MarkupSafe-2.1.1
Pygments-2.13.0
Sphinx-5.3.0
Unidecode-1.3.6
alabaster-0.7.12
attrs-22.1.0
babel-2.10.3
black-22.10.0
certifi-2022.9.24
charset-normalizer-2.1.1
click-8.1.3
coverage-6.5.0
docutils-0.19
flake8-5.0.4
idna-3.4
imagesize-1.4.1
iniconfig-1.1.1
isort-5.10.1
mccabe-0.7.0
mypy-0.982
mypy-extensions-0.4.3
packaging-21.3
pathspec-0.10.1
platformdirs-2.5.2
pluggy-1.0.0
py-1.11.0
pycodestyle-2.9.1
pyflakes-2.5.0
pyparsing-3.0.9
pytest-7.1.3
pytest-cov-4.0.0
pytz-2022.5
requests-2.28.1
snowballstemmer-2.2.0
sphinxcontrib-applehelp-1.0.2
sphinxcontrib-devhelp-1.0.2
sphinxcontrib-htmlhelp-2.0.0
sphinxcontrib-jsmath-1.0.1
sphinxcontrib-qthelp-1.0.3
sphinxcontrib-serializinghtml-1.1.5
tomli-2.0.1
types-PyYAML-6.0.12
types-docutils-0.19.1.1
typing-extensions-4.4.0
uqbar-0.6.4
urllib3-1.26.12

Requirements installed in the failing GHA (https://github.com/josiah-wolf-oberholtzer/uqbar/actions/runs/3642179788/jobs/6148988835):

Jinja2-3.1.2
MarkupSafe-2.1.1
Pygments-2.13.0
Sphinx-5.3.0
Unidecode-1.3.6
alabaster-0.7.12
attrs-22.1.0
babel-2.11.0
black-22.10.0
certifi-2022.9.24
charset-normalizer-2.1.1
click-8.1.3
coverage-6.5.0
docutils-0.19
exceptiongroup-1.0.4
flake8-3.9.2
idna-3.4
imagesize-1.4.1
importlib-metadata-5.1.0
iniconfig-1.1.1
isort-5.10.1
mccabe-0.6.1
mypy-0.991
mypy-extensions-0.4.3
packaging-21.3
pathspec-0.10.2
platformdirs-2.6.0
pluggy-1.0.0
pycodestyle-2.7.0
pyflakes-2.3.1
pyparsing-3.0.9
pytest-7.2.0
pytest-cov-4.0.0
pytz-2022.6
requests-2.28.1
snowballstemmer-2.2.0
sphinxcontrib-applehelp-1.0.2
sphinxcontrib-devhelp-1.0.2
sphinxcontrib-htmlhelp-2.0.0
sphinxcontrib-jsmath-1.0.1
sphinxcontrib-qthelp-1.0.3
sphinxcontrib-serializinghtml-1.1.5
tomli-2.0.1
typed-ast-1.5.4
types-PyYAML-6.0.12.2
types-docutils-0.19.1.1
typing-extensions-4.4.0
uqbar-0.6.4
urllib3-1.26.13
zipp-3.11.0

And the diff of the two requirements:

--- a/v0.6.4.txt
+++ b/v0.6.5.txt
@@ -5,32 +5,33 @@ Sphinx-5.3.0
 Unidecode-1.3.6
 alabaster-0.7.12
 attrs-22.1.0
-babel-2.10.3
+babel-2.11.0
 black-22.10.0
 certifi-2022.9.24
 charset-normalizer-2.1.1
 click-8.1.3
 coverage-6.5.0
 docutils-0.19
-flake8-5.0.4
+exceptiongroup-1.0.4
+flake8-3.9.2
 idna-3.4
 imagesize-1.4.1
+importlib-metadata-5.1.0
 iniconfig-1.1.1
 isort-5.10.1
-mccabe-0.7.0
-mypy-0.982
+mccabe-0.6.1
+mypy-0.991
 mypy-extensions-0.4.3
 packaging-21.3
-pathspec-0.10.1
-platformdirs-2.5.2
+pathspec-0.10.2
+platformdirs-2.6.0
 pluggy-1.0.0
-py-1.11.0
-pycodestyle-2.9.1
-pyflakes-2.5.0
+pycodestyle-2.7.0
+pyflakes-2.3.1
 pyparsing-3.0.9
-pytest-7.1.3
+pytest-7.2.0
 pytest-cov-4.0.0
-pytz-2022.5
+pytz-2022.6
 requests-2.28.1
 snowballstemmer-2.2.0
 sphinxcontrib-applehelp-1.0.2
@@ -40,8 +41,10 @@ sphinxcontrib-jsmath-1.0.1
 sphinxcontrib-qthelp-1.0.3
 sphinxcontrib-serializinghtml-1.1.5
 tomli-2.0.1
-types-PyYAML-6.0.12
+typed-ast-1.5.4
+types-PyYAML-6.0.12.2
 types-docutils-0.19.1.1
 typing-extensions-4.4.0
 uqbar-0.6.4
-urllib3-1.26.12
+urllib3-1.26.13
+zipp-3.11.0
jgarte commented 1 year ago

@josiah-wolf-oberholtzer

The reason it failed is because I was using sphinx installed via Guix which is at 5.1.1 versus PyPi:

https://packages.guix.gnu.org/packages/python-sphinx/5.1.1/

I have to update the sphinx package in Guix 😄

josiah-wolf-oberholtzer commented 1 year ago

We might be talking past each other.

The tests are failing without any Python code or requirements changes between October and now. See my comment just before yours. Uqbar with Sphinx 5.3.0 worked in October and now it doesn't, probably due to transitive dependencies being updated.

jgarte commented 1 year ago

Got it. Thanks for clarifying.

I'll wait for you to do more testing on your end.

Keep me posted.

I have a Guix package for uqbar here:

https://packages.guix.gnu.org/packages/python-uqbar/0.5.6/

josiah-wolf-oberholtzer commented 1 year ago

Have to admit I still don't understand the appeal of repackaging Python packages for (insert Linux distro / package manager here).

jgarte commented 1 year ago

I think it is just yet another tool that people are using to provide reproducibility of your dev environment for a Python project.

Guix System is the other killer feature that lets you automate services in Guile Scheme and deploy them similarly to Ansible:

https://github.com/genenetwork/genenetwork3/blob/main/guix-system.scm#L68

The above declarative Operating System configuration deploys a python REST API running on gunicorn called genenetwork3. All the Python dependencies that are required by genenetwork3 are also managed by Guix.

Guix has a ton of powerful features that pip/poetry/etc/ doesn't provide or are out of scope for pip/poetry/etc.

It is also just fun hacking on this sort of stuff with Scheme for the sake of hacking the great hack.

Here's a distro based on Guix that configures a ton of interesting stuff:

https://trop.in/rde

jgarte commented 1 year ago

Have to admit I still don't understand the appeal of repackaging Python packages for (insert Linux distro / package manager here).

I agree that what Guix should provide is powerful tools to generate Guix packages for a given project based on what you need instead of trying to package PyPi and the world.

I think Nix might be doing a better job of this currently:

https://github.com/nix-community/poetry2nix

Speaking of PyPi:

https://github.com/on-nix/python

BTW, Guix is a fork of Nix. Guix even uses the nix daemon still from the time it forked Nix more or less.

josiah-wolf-oberholtzer commented 1 year ago

Honestly, if I never looked at Scheme again, that would be fine with me 😂.

I'm not a poetry user either. Virtualenv and pip work fine for me for local development, and anything deployed uses Docker (again with regular pip for Python applications).

jgarte commented 1 year ago

I use pip and docker also. That's a great combination if you want to actually ship software 😆

Honestly, if I never looked at Scheme again, that would be fine with me joy.

It's a love hate relationship for me with Scheme. It's complicated.

jgarte commented 1 year ago

Awesome! THNX!!