Syntax reference¶
Irrespective of the format chosen (Markdown, Jupyter Notebook, or slides with lecture notes), you would need to get acquainted with the markdown syntax to create effective training materials.
See also
If you are unfamiliar with Markdown read this 60 second cheatsheet first
Overview of directives¶
There are some directives defined in MyST markdown and sphinx-lesson to highlight blocks within the course materials. Some of these are:
core admonitions:
note,hint,important,attention,caution,warning,danger, …sphinx-lesson admonitions:
discussion,demo,exercises,solution,homework,instructor-note,type-along…
The core admonition types are defined in Sphinx and MyST-Parser:
Attention
This is a attention
Caution
This is a caution
Danger
This is a danger
Error
This is a error
Hint
This is a hint
Important
This is a important
Note
This is a note
See also
This is a seealso
Tip
This is a tip
Warning
This is a warning
and these core admonitions take no argument and do not allow custom titles out of the box. More on the core MyST admonitions can be read here.
These directives are extensions on top of the vanilla Markdown syntax. When a markdown cell in a Jupyter notebook contains the following markup for a tip admonition it renders into a rectangle with a green heading:
:::{tip}
Let's give readers a helpful hint!
:::
Tip
Let’s give readers a helpful hint!
Admonitions¶
All supported admonitions are showcased below. They are also classified into 5 groups.
Internal¶
This is meant for the instructor and meant to be ignored by the learner.
Instructor note
This episode includes
20 min lecture
20 min exercises
NOTE: The admonition above is named instructor-note.
Information¶
These are passive directives from the perspective of the learner.
Prerequisites
Knowledge of X
Course on Y
Recommendation
It is recommended to use the CUDA version > 10.0.
Objectives
learning objective 1
learning objective 2
Questions
What does the tool X do?
How can we use tool X in an HPC cluster?
Discussion
How large is the data you are working with?
Are you experiencing performance bottlenecks when you try to analyse it?
Note
Here we emphasize an important point from the section.
Demo
Code for demonstration Due to the faster pace, we do not expect learners to type-along.
See also
Blog by X
Course on Y by Z
Keypoints
summary 1
summary 2
Success¶
These admonitions require active participation from the reader
Important
You should follow the instructions step-by-step.
Hint
In this exercise, you can use A instead of B.
Tip
In this exercise, you can use A instead of B.
Exercise
Description of exercise
Do this
then do this
finally observe what happens when you do this.
Solution
Here is the solution for the above exercise.
Homework
Here are the homework assignments for this episode.
Type-Along
This is a type-along live-coding session. We go at a slower pace to allow learners to follow along.
import this
NOTE: The admonition above is named type-along
Warning¶
Warning
Do not remove the following line.
Caution
Do not remove the following line.
Error¶
Error
Here is an error!
Attention
Here is a crucial detail. Pay attention to this.
Danger
Here is a danger, a potential pitfall!
Extending admontions¶
Custom titles¶
All sphinx-lesson admonitions support custom titles.
:::{discussion} Discussion: Semantic versioning v/s calendar versioning
- Which versioning scheme do you prefer?
- What are the pros and cons of either schemes?
:::
Discussion: Semantic versioning v/s calendar versioning
Which versioning scheme do you prefer?
What are the pros and cons of either schemes?
Making a drop-down admonition¶
In this example, we show how an exercise admonition can be
customized. This is done by adding a :class: dropdown argument
as shown below. This renders as a admonition with a
Click to show button.
:::{exercise} Advanced exercise
:class: dropdown
If you have finished the previous exercise, try to do...
:::
Advanced exercise
If you have finished the previous exercise, try to do…
Nested admonition¶
Nesting admonitions are supported in all directives. In fact, it is
recommended to nest the solution admonition within an exercise
admonition.
::::{exercise}
1. Task A
1. Task B
:::{solution}
1. This is how to do Task A ...
1. This is how to do Task B ...
:::
::::
Exercise
Task A
Task B
Solution
This is how to do Task A …
This is how to do Task B …
Cross-references and Bibliography¶
To include cross-references, markdown links are used. Refer to myst-parser documentation to learn how to acheive this. Here is an example of a link to a section heading in this page:
[Here](#overview-of-directives) are all directives that are currently
supported.
Here are all directives that are currently supported.
For citing publications, webpages, books etc. as bibliography, the
the conf.py file should include the extension sphinxcontrib-bibtex
and the name of a BibTeX file,
extensions = [
# other extensions
"sphinxcontrib.bibtex"
]
bibtex_bibfiles = ["references.bib"]
Then within the module articles be cited inline as follows:
The learnings from the Software Carpentry project were crucial
in developing this style of teaching {cite}`wilson2016`.
The learnings from the Software Carpentry project were crucial in developing this style of teaching [Wil16].
Finally the articles can be listed using the bibliography
directive. Preferably this should be done at the bottom of the
page.
### References
:::{bibliography}
:::
References
G Wilson. Software carpentry: lessons learned [version 2; peer review: 3 approved]. F1000Research, 2016. doi:10.12688/f1000research.3-62.v2.
Badges¶
Here is a badge of a module from Zenodo:
We can design other badges with different colors. See: https://shields.io/badges
Presenting code¶
Sphinx and MyST-parser also adds a number of additional admonition types for presenting code, such as code-block which can be useful.
:::{code-block} python
:emphasize-lines: 3,5
def some_function():
interesting = False
print('This line is highlighted.')
print('This one is not...')
print('...but this one is.')
:::
def some_function():
interesting = False
print('This line is highlighted.')
print('This one is not...')
print('...but this one is.')
All Markdown syntax are also valid MyST markup. Therefore wrapping using three backticks to syntax-highlight code can also work.
```cpp
#include <iostream>
int main() {
std::cout << "Hello world";
return 0;
}
```
#include <iostream>
int main() {
std::cout << "Hello world";
return 0;
}
For including code or code-snippets from other files,
the literalinclude directive
can also be adopted.
Providing system or language-specific course instructions¶
Using tabs and group-tab directives we can allow the learner to focus on a single group of instructions.
Here is an example below[1], starting with the syntax for
### Testing frameworks
::::{tabs}
:::{group-tab} Python
The suggested solutions below use pytest.
:::
:::{group-tab} C++
The suggested solutions below use Catch2.
:::
:::{group-tab} R
The suggested solutions below use testthat.
:::
:::{group-tab} Julia
The suggested solutions below use Test.
:::
:::{group-tab} Fortran
The suggested solutions below use pFUnit.
:::
::::
Testing frameworks
The suggested solutions below use pytest.
The suggested solutions below use Catch2.
The suggested solutions below use testthat.
The suggested solutions below use Test.
The suggested solutions below use pFUnit.
Repeated use tabs and group-tab directives with the same key are synced
Exercise: Design a test for a function that receives a number and returns a number
def factorial(n):
"""
Computes the factorial of n.
"""
if n < 0:
raise ValueError('received negative input')
result = 1
for i in range(1, n + 1):
result *= i
return result
/* Computes the factorial of n recursively. */
constexpr unsigned int factorial(unsigned int n) {
return (n <= 1) ? 1 : (n * factorial(n - 1));
}
#' Computes the factorial of n
#'
#' @param n The number to compute the factorial of.
#' @return The factorial of n
factorial <- function(n) {
if (n < 0)
stop('received negative input')
if (n == 0)
return(1)
result <- 1
for (i in 1:n)
result <- result * i
result
}
"""
factorial(n::Int)
Compute the factorial of n.
"""
function factorial(n::Int)
if n < 0
throw(DomainError("n must be non-negative"))
end
result = 1
for i in 1:n
result *= i
end
return result
end
module factorial_mod
contains
! computes the factorial of n
integer function factorial(n)
implicit none
integer, intent(in) :: n
integer r
integer i
if(n < 0) then
write(*,*) 'Received negative input'
stop
end if
r = 1
do i = 1,n
r = r*i
end do
factorial=r
end function factorial
end module factorial_mod
Discussion
The factorial grows very rapidly. What happens if you pass a large number as argument to the function?
Solution
This is a pure function so is easy to test: inputs go to outputs. For example, start with the below, then think of some what extreme cases/boundary cases there might be. This example shows all of the tests as one function, but you might want to make each test function more fine-grained and test only one concept.
import pytest
def test_factorial():
assert factorial(0) == 1
assert factorial(1) == 1
assert factorial(2) == 2
#include <catch2/catch.hpp>
#include "factorial.hpp"
TEST_CASE("Compute the factorial", "[factorial]") {
REQUIRE(factorial(0) == 1);
REQUIRE(factorial(1) == 1);
REQUIRE(factorial(2) == 2);
REQUIRE(factorial(3) == 6);
}
test_that("Test factorial", {
expect_equal(factorial(0), 1)
expect_equal(factorial(1), 1)
expect_equal(factorial(2), 2)
expect_equal(factorial(3), 6)
# also try negatives (check that it raises an error), non-integers, etc.
# Raise an error if factorial does *not* raise an error:
expect_error(factorial(-1))
})
@testset "Test factorial function" begin
@test_throws DomainError factorial(-1)
@test factorial(3) == 6
end
@test
subroutine test_factorial()
use factorial_mod
use funit
@assertEqual(120, factorial(5), 'factorial(5)')
end subroutine test_factorial
Embedding PDF slides¶
The pdfembed directive can be used to embed slides as follows:
:::{pdfembed} ../_static/slides/efficient-array-computing.pdf
:::
NOTE: the slides need to be placed under the content/_static directory