Closed mmcky closed 2 years ago
Merging #45 (a16787b) into master (92b9614) will increase coverage by
1.12%
. The diff coverage is96.82%
.
@@ Coverage Diff @@
## master #45 +/- ##
==========================================
+ Coverage 92.98% 94.10% +1.12%
==========================================
Files 6 7 +1
Lines 442 628 +186
==========================================
+ Hits 411 591 +180
- Misses 31 37 +6
Flag | Coverage Δ | |
---|---|---|
pytests | 94.10% <96.82%> (+1.12%) |
:arrow_up: |
Flags with carried forward coverage won't be shown. Click here to find out more.
Impacted Files | Coverage Δ | |
---|---|---|
sphinx_exercise/directive.py | 97.14% <94.73%> (-1.18%) |
:arrow_down: |
sphinx_exercise/transforms.py | 97.32% <97.32%> (ø) |
|
sphinx_exercise/__init__.py | 95.06% <100.00%> (+0.77%) |
:arrow_up: |
sphinx_exercise/nodes.py | 90.32% <100.00%> (+0.78%) |
:arrow_up: |
Continue to review full report at Codecov.
Legend - Click here to learn more
Δ = absolute <relative> (impact)
,ø = not affected
,? = missing data
Powered by Codecov. Last update 92b9614...a16787b. Read the comment docs.
This definitely works for me @mmcky . Fits my simple uses cases and the syntax is clean and simple enough to easily remember. Fully in favor :+1:
Oops, hit wrong button :grimacing: -- reopened.
Thanks for comments @jstac @choldgraf (@chrisjsewell via slack). Appreciate it.
Next Steps:
robustness
and write a more general tree parsing function for collecting relevant nodes between -start
and -end
. developer
documentationThere is the possibility to make this more general to extend any directives using {{directive}}-start
and {{directive}}-end
but won't put development time into this at the present time. Perhaps we could revisit that for an admonition factory
type of project. I will document the general approach if others want to use this pattern in an extension.
@AakashGfude I just pushed some additional test cases error.md
but with the current test setup using app.build()
I don't see a way to save the errors
and warnings
to pass to an assert statement. Any ideas on this?
Also the way the transform
works currently is:
solution-start
nodesexception
is raised if no matching solution-end
is raised when finding nodes to merge into a base solution
nodeI don't really see a reason to do any further structural testing on the document. This condition seems to be the main issue -- and I think an exception
(vs. a warning) is required so users can fix the issue in the md
.
OK I think the only way to integrate proper error checking is to:
CheckGatedDirectives
to run through the full structure of the document and build a registry to ensure the structure of gated directives is complete (i.e. matching -start
and -end
), non-nestedness etc. and raise Errors if the required structure is not adhered to. Alternatively,
directives
are parsed.I will try the alternative first as it would be more efficient to check an already formed registry (as part of the parsing step)
The current transform
then doesn't have to know the structure of the document and can focus on migrating the appropriate nodes into a unified solution
note in the sphinx.ast
.
In a simple exercise solution, the dropdown
class can be added to the solution to hide it.
For compound solutions between gated sections, it would be useful if the whole section could be collapsible, perhaps by the following:
```{solution-start} solution1
:class: dropdown
More generally, can a class be set in the `solution-start` block, eg `:class: orange` for custom styling, that is then automatically removed (by default, at least) by the matching `solution-end` block.
Regarding supporting code in exercise
directives, this can be useful where some set up or initialisation code is required as part of the exercise set-up.
Generalising support for gated directives would seem to be a good way of doing this, not least because it then opens up a route for other extension developers to easily support high level blocks defined across multiple heterogenous cells.
Naively, I'm assuming that at some point the gated directives essentially gives you a <div> </div>
block to put things in; as such, it would also be useful to allow the user to optionally set a CSS id for the block.
In a simple exercise solution, the
dropdown
class can be added to the solution to hide it.For compound solutions between gated sections, it would be useful if the whole section could be collapsible, perhaps by the following:
```{solution-start} solution1 :class: dropdown
More generally, can a class be set in the `solution-start` block, eg `:class: orange` for custom styling, that is then automatically removed (by default, at least) by the matching `solution-end` block.
Thanks @psychemedia I think this is a good idea. The way solution-start
is setup at the moment is it inherits the solution
directive so all options available to solution
nodes should transfer over to solution-start
. Maybe I need to add a test case as I work through the gated nodes.
Regarding supporting code in exercise directives, this can be useful where some set up or initialisation code is required as part of the exercise set-up.
Support for exercise
nodes will be next.
@chrisjsewell @AakashGfude I have setup the extension to make use of a CheckGatedDirectives
transform before merging them in the sphinx.AST
to check for various structural issues. I am not sure how to get this setup working in the test framework though -- Is it possible to catch a sphinx ExtensionError
and keep executing the document.
I want sphinx
to stop executing if any of these malformed
gated directive conditions exist:
-end
-start
-start
and -end
coupled with a useful error message.
Currently the make html
presents a nice diagnostic message for tests/books/test-gateddirective/
(ebp) ➜ test-gateddirective git:(gated-directive) make html
Running Sphinx v4.4.0
myst v0.15.2: MdParserConfig(renderer='sphinx', commonmark_only=False, enable_extensions=['dollarmath'], dmath_allow_labels=True, dmath_allow_space=True, dmath_allow_digits=True, dmath_double_inline=False, update_mathjax=True, mathjax_classes='tex2jax_process|mathjax_process|math|output_area', disable_syntax=[], url_schemes=['http', 'https', 'mailto', 'ftp'], heading_anchors=None, heading_slug_func=None, html_meta=[], footnote_transition=True, substitutions=[], sub_delimiters=['{', '}'], words_per_minute=200)
building [mo]: targets for 0 po files that are out of date
building [html]: targets for 6 source files that are out of date
updating environment: [new config] 6 added, 0 changed, 0 removed
Executing: errors_1 in: /Users/mmcky/work/executablebooks/sphinx-exercise/tests/books/test-gateddirective
ERROR: The document (errors_1) is missing a solution-end directive
solution-start at line: 20
Extension error:
[sphinx-exercise] An error has occured when parsing gated directives.
Please check warning messages above
make: *** [html] Error 2
but only for error_1
and I am not sure how to test against this condition and keep executing for errors_2
and errors_3
documents.
Should I run a sphinx.build()
for each of the error pages individually and catch the exception?
OK I have just found https://github.com/executablebooks/sphinx-external-toc/blob/96c80db479b9cd926f2d4dad9cc43ee3c007fcb7/sphinx_external_toc/events.py#L69 so maybe that is tested in sphinx-external-toc
. I'll look there.
I'm trying this from Mangled Jupytext header code breaking code display.pip3 install --upgrade git+https://github.com/executablebooks/sphinx-exercise.git@gated-directive
but I don't see the code cells being displayed? Is code cell inclusion between the gateposts supported yet?
Should the solution content blocks all be inside a solution-content
div, which would then allow for collapsing the solution content?
Should the solution content blocks all be inside a
solution-content
div, which would then allow for collapsing the solution content?![]()
thanks @psychemedia -- I will double check the html
. Is this just for gated
solutions?
Is this just for
gated
solutions?
Yes, that's where I spotted it. Inside a gated solution. I was expecting the content between the gateposts to be in the solution-content
div
. Also, looking at it now, is the id="solution-content"
guaranteed unique? It looks more like a class than an id
to me.
nicely spotted thanks @psychemedia the test fixture shows the same -- will fix that.
<div class="solution admonition" id="solution-gated-1">
<p class="admonition-title"><a class="reference internal" href="exercise.html#exercise-1">Solution to Exercise 1</a></p>
<div class="section" id="solution-content">
</div>
<p>This is a solution to Exercise 1</p>
solution
div in the translator
phaseid="solution-content"
should be added to class="section solution-content"
The sphinx.ast
is looking properly nested so this suggests it is the translation
phase rather than transforms
<solution_node classes="solution" docname="solution" hidden="False" ids="solution-gated-1" label="solution-gated-1" names="solution-gated-1" serial_number="0" target_label="exercise-1" title="Solution to" type="solution">
<solution_title>
Solution to
<section ids="solution-content">
<paragraph>
This is a solution to Exercise 1
<CellNode cell_type="code" classes="cell">
<CellInputNode classes="cell_input">
<literal_block language="ipython3" xml:space="preserve">
Presumably, the gated solutions will not be useful in JupyterLab / JupyerLab-MyST contest because of the inability to propagate metadata up the DOM / select parent HTML blocks that define cells; or, at least, not without some sort of extension support, or the availability of CSS has()
selectors?
How easy is it to be able to parse a :class: dropdown
on entering the gated section, and then add the dropdown button to the solution div
?
More generally, can the recipe for gated sections be used to easily create other admonition types that also employ gated sections? Eg could gated blocks be easily added to exercise definitions, or other custom defined admonition blocks based on a similar pattern?
Presumably, the gated solutions will not be useful in JupyterLab / JupyerLab-MyST contest because of the inability to propagate metadata up the DOM / select parent HTML blocks that define cells; or, at least, not without some sort of extension support, or the availability of CSS
has()
selectors?
Sadly no - to my knowledge this will need extension support. There is some work going on at mystjs to bring rendering of MyST
support for jupyter/jupyterlab.
OK so it looks like the xml
tree is incorrect and the solution-content
section should nest the content and it should be:
<section ids="solution-content">
<paragraph>
This is a solution to Exercise 1
<CellNode cell_type="code" classes="cell">
<CellInputNode classes="cell_input">
<literal_block language="ipython3" xml:space="preserve">
error_1
, error_2
and error_3
tests@chrisjsewell @AakashGfude I think I figure out a reasonable solution in 701a398 for testing the Exception cases and checking warning messages
@choldgraf @psychemedia @AakashGfude this is working nicely for me now.
I'll plan to merge this soon and start work on exercise
directives.
@choldgraf this extension to the syntax is quite convenient (vs. nesting structures) -- it might be a nice enhancement proposal for any directive down the track.
A real world example can be seen here:
https://6226e59b74051d4c841f8092--epic-agnesi-957267.netlify.app/functions.html#solutions
which uses sphinx-togglebutton
to collapse the blocks (thanks @choldgraf)
I have now converted one of the QuantEcon lectures sites to use sphinx-exercise
that makes use of both gated exercise
and solution
directives https://github.com/QuantEcon/lecture-python-programming.myst/pull/176
The preview is available here: https://6228365c7ce7b477e5575a73--epic-agnesi-957267.netlify.app/intro.html
@AakashGfude would you mind to take a quick look and let me know what you think.
This PR adds support for
gated
exercise and solution directives, which enables:code-cell
in myst-nb) to be used. As thecode-cell
is at the root level of the document it is executed byjupyter-cache
and follows withjupyter-book
methodology of supportingcode-cell
directives at the root level of the document in a linear fashion (which is 1-to-1 withjupyter
)[exercise,solution]-start
and a[exercise,solution]-end
directive by transforming the AST which can be a convenient way to add nested directives without needing to increase the back-tick depthBasic Syntax
paired with
paired with
This is a solution to Exercise 1
With some follow up text to the solution