Skip to content

Commit 64e69bb

Browse files
committed
verify: Let a spec reach the items nested inside a block (t51)
2 parents 4813294 + f89b528 commit 64e69bb

23 files changed

Lines changed: 1470 additions & 1298 deletions

‎CHANGELOG.md‎

Lines changed: 20 additions & 18 deletions
Large diffs are not rendered by default.

‎docs/source/drafts.md‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,15 @@ The layer and the ranges are left as they were, so the field still names the lin
364364
from, and `edited` says the field no longer holds what those lines say. The wording replaced has
365365
to occur in the field exactly once, and `--regex` reads it as a regular expression.
366366

367+
Where the source does say the wording and the field was quoted from the wrong lines - a spec
368+
matching the label line `Q4` alone writes an empty `q4.text`, which `in2lambda validate` reports -
369+
`in2lambda draft field set q4.text --text b3` quotes block `b3` into the field instead. The field
370+
is written again at layer 3, with the range of the lines quoted and `edited` false, as
371+
`in2lambda draft question add --text` writes one. The lines the field named before are dropped,
372+
and `in2lambda validate` reports them as in no field until `in2lambda draft mark ignore` says they
373+
are nothing to take a question from. `in2lambda draft field set` takes no `--literal`:
374+
`in2lambda draft field replace` is the command for text no line of the source says.
375+
367376
## Replay and check again
368377

369378
```bash

‎docs/source/index.md‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ og:title: in2lambda
2121
:::{grid-item}
2222
\
2323
\
24-
Automagically uploads questions to [Lambda Feedback](https://lambda-feedback.github.io/user-documentation/) so you don't have to.
24+
Converts a document of questions into a question set that [Lambda Feedback](https://lambda-feedback.github.io/user-documentation/) imports.
2525

2626
```{button-ref} quickstart
2727
:ref-type: doc
@@ -39,19 +39,19 @@ Get Started
3939
:::{grid-item-card} {octicon}`tools;1.5em` Highly Configurable
4040
:link: filters/index
4141
:link-type: doc
42-
Can be used to process numerous file formats with a variety of different structures by using [pandoc filters](https://pandoc.org/filters.html).
42+
Reads many file formats, and documents of many structures, through [pandoc filters](https://pandoc.org/filters.html).
4343
:::
4444

4545
:::{grid-item-card} {octicon}`terminal;1.5em` Accessible Command Line Tool
4646
:link: reference/command-line
4747
:link-type: doc
48-
Just provide the question file and select one of the in-built file parsers.
48+
Name the question file and one of the built-in filters.
4949
:::
5050

5151
:::{grid-item-card} {octicon}`gear;1.5em` Powerful API
5252
:link: reference/library
5353
:link-type: doc
54-
A fully type-annotated extensively documented Python library is available for those that need a bit more control.
54+
A type-annotated, documented Python library builds a question set without a source document.
5555
:::
5656

5757
::::

‎docs/source/question-format.md‎

Lines changed: 37 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ describes that JSON, and how to build it from Python without a source document.
88
A {class}`~in2lambda.api.set.Set` holds {class}`~in2lambda.api.question.Question` objects, each
99
holding {class}`~in2lambda.api.part.Part` objects, each holding the
1010
{class}`~in2lambda.api.response_area.ResponseArea` boxes students type into.
11-
{meth}`~in2lambda.api.set.Set.to_json` writes the lot.
11+
{meth}`~in2lambda.api.set.Set.to_json` writes the set as JSON.
1212

1313
```pycon
1414
>>> from in2lambda.api.part import Part
@@ -66,8 +66,8 @@ holding {class}`~in2lambda.api.part.Part` objects, each holding the
6666

6767
```
6868

69-
{meth}`~in2lambda.api.set.Set.to_json` writes a folder named after the set, and a zip of it to
70-
upload:
69+
{meth}`~in2lambda.api.set.Set.to_json` writes a folder named after the set, and a zip of that
70+
folder to upload:
7171

7272
```pycon
7373
>>> import json, os, tempfile
@@ -87,24 +87,23 @@ upload:
8787

8888
```
8989

90-
A few things the example shows in passing:
90+
The example also shows the following:
9191

92-
- **Building parts directly beats the incremental helpers.** [Filters](filters/index)
93-
read a document in order, so they call
92+
- **Pass `Part` objects to `Question` where the script holds the whole question.**
93+
[Filters](filters/index) read a document in order, so they call
9494
{meth}`~in2lambda.api.question.Question.add_part_text` and
9595
{meth}`~in2lambda.api.question.Question.add_solution`, which fill in whichever part comes next.
96-
A script that already knows the whole question should pass `Part` objects to `Question`, as
97-
above; only those give a part a final answer or an answer box.
98-
- **A line holding only `---` (or `***`) splits a worked solution** into the steps students go
99-
through one at a time in the structured tutorial.
100-
- **Unset question settings are left out of the JSON** rather than guessed at, so `skill`,
101-
`guidance` and the two durations only appear when set. `publish` and the four `display_*`
102-
settings always do, defaulting to `True`.
103-
- **Images** go in `Question.images` as paths on disk; they are copied into `media/` under the file
104-
name they already had, and every reference to one in the question's markdown is rewritten to that
105-
name, which is all Lambda Feedback looks an image up by.
96+
A `Part` object gives a part a final answer and an answer box, which those two methods do not.
97+
- **A line holding only `---` (or `***`) splits a worked solution** into the steps the
98+
structured tutorial shows students one at a time.
99+
- **Unset question settings are left out of the JSON**, so `skill`, `guidance` and the two
100+
durations appear only when set. `publish` and the four `display_*` settings always appear, and
101+
default to `True`.
102+
- **Images** are paths on disk listed in `Question.images`. `to_json` copies each image into
103+
`media/` under its own file name, and rewrites every reference to that image in the question's
104+
markdown to the same name. Lambda Feedback looks an image up by that name alone.
106105
- **{meth}`Set.from_json <in2lambda.api.set.Set.from_json>`** reads an existing export, as a folder
107-
or a zip, so an edit to a real set can start from what Lambda Feedback produced.
106+
or a zip, so an edit to a real set starts from the export Lambda Feedback produced.
108107

109108
## The JSON in2lambda writes
110109

@@ -116,12 +115,13 @@ A few things the example shows in passing:
116115
<set name>.zip # the folder, zipped, to upload
117116
```
118117

119-
A question's filename is its title with spaces and the characters Windows and path separators
120-
forbid (`/ \ < > : " | ? *`) each replaced by an underscore. An image keeps the file name it
121-
already had, so `images=["figures/rocket-momentum.png"]` gives `media/rocket-momentum.png`, and the
122-
references to it are rewritten to that name. `media/` is one flat folder for the whole set, so a
123-
file two questions use is copied once, and a second file of a name already taken is named as Lambda
124-
Feedback names one, `question_001_<Title>_0001.png`. Files are written on a single line.
118+
A question's filename is its title, with spaces and the characters Windows and path separators
119+
forbid (`/ \ < > : " | ? *`) each replaced by an underscore. An image keeps its own file name, so
120+
`images=["figures/rocket-momentum.png"]` gives `media/rocket-momentum.png`, and every reference to
121+
that image is rewritten to `rocket-momentum.png`. `media/` is one flat folder for the whole set: a
122+
file two questions use is copied once, and a second file whose name is already taken is named as
123+
Lambda Feedback names an image, `question_001_<Title>_0001.png`. Each JSON file is written on a
124+
single line.
125125

126126
### Set
127127

@@ -154,33 +154,32 @@ The three types in2lambda writes:
154154
| `NUMERIC_UNITS` | `comparePhysicalQuantities` | a number and a unit, e.g. `0.106 kg` | `gradeParams` holds `rtol` (and `strict_syntax`); `config` is null |
155155
| `MULTIPLE_CHOICE` | `arrayEqual` | a list of booleans, one per option | `config` holds `single`, `options` and `randomise`; `gradeParams` is null |
156156

157-
The three lists an area carries, each a dataclass in
157+
A response area holds three lists, each of a dataclass in
158158
{mod}`in2lambda.api.response_area`:
159159

160160
- `inputSymbols` — `{"symbol", "code", "aliases", "isVisible"}` from
161-
{class}`~in2lambda.api.response_area.InputSymbol`. `symbol` is what students see
162-
(e.g. `\(\rho\)`), `code` what the evaluation function reads.
161+
{class}`~in2lambda.api.response_area.InputSymbol`. Lambda Feedback displays `symbol` to students
162+
(e.g. `\(\rho\)`), and the evaluation function reads `code`.
163163
- `tests` — `{"id", "payload", "expectedResponse": {"isCorrect"}}` from
164164
{class}`~in2lambda.api.response_area.Test`: the author's own checks of the marking.
165165
- `cases` — `{"id", "answer", "feedback", "isCorrect", "params"}` from
166166
{class}`~in2lambda.api.response_area.Case`: a response matching `answer` is shown `feedback`,
167167
and may be marked correct.
168168

169-
An `id` left unset is a fresh UUID, which is what import needs.
169+
An `id` left unset is written as a fresh UUID, which import requires.
170170

171171
### Markdown
172172

173-
Maths is `$...$` inline and `$$` on its own lines for display, rendered by
174-
[KaTeX](https://katex.org/): commands KaTeX lacks do not display — degrees, for example, are
175-
written `^\circ`. An image is written `![pictureTag](rocket-momentum.png)`, naming the file as it
176-
sits in `media/`. A filter passes through whatever path the source document used, so
177-
`\includegraphics{figures/rocket-momentum.png}` becomes `![pictureTag](figures/rocket-momentum.png)`
178-
in the set; writing the set out rewrites it to `![pictureTag](rocket-momentum.png)`, which is the
179-
image as `media/` holds it. A reference naming no image of the question is left as written, and
180-
{func}`~in2lambda.validation.validate` reports it.
173+
[KaTeX](https://katex.org/) renders maths written `$...$` inline and `$$` on its own lines for
174+
display. KaTeX does not display the commands it lacks, so a degree is written `^\circ`. An image
175+
is written `![pictureTag](rocket-momentum.png)`, naming the file as `media/` holds it. A filter
176+
passes the source document's path through, so `\includegraphics{figures/rocket-momentum.png}`
177+
becomes `![pictureTag](figures/rocket-momentum.png)` in the set, and writing the set out rewrites
178+
that reference to `![pictureTag](rocket-momentum.png)`. A reference naming no image of the question
179+
is written as it stands, and {func}`~in2lambda.validation.validate` reports that reference.
181180

182181
:::{note}
183-
Lambda Feedback's own exports carry a few keys in2lambda neither reads nor writes, among them
184-
`isSurvey` and `releasedAt` on the set. Diffing a written set against a real export will show
185-
them missing; the platform fills them in on import.
182+
Lambda Feedback's own exports hold a few keys in2lambda neither reads nor writes, among them
183+
`isSurvey` and `releasedAt` on the set. A diff of a written set against a real export shows those
184+
keys missing. Lambda Feedback fills them in on import.
186185
:::

‎docs/source/quickstart.md‎

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
11
# 🚀 Quickstart
22

3-
This page gives a quick overview of how to get started with in2lambda to quickly add documents to Lambda Feedback.
3+
This page describes how to install in2lambda and convert a document into a Lambda Feedback question set.
44

55
## 1. Installation
66

77
### Docker
88

99
[![GitHub Workflow Status (with event)](https://img.shields.io/github/actions/workflow/status/lambda-feedback/in2lambda/docker-publish.yml?style=flat-square&logo=docker&label=Docker)](https://github.com/lambda-feedback/in2lambda/pkgs/container/in2lambda)
1010

11-
The following creates an interactive container which includes in2lambda and mounts the current working directory into `/files`:
11+
The following command starts an interactive container holding in2lambda, with the current working directory mounted at `/files`:
1212

1313
```bash
1414
$ docker run -it --rm -v $(pwd):/files ghcr.io/lambda-feedback/in2lambda sh
1515
```
1616

17-
Within the container, we can access the files and run in2lambda as normal.
17+
Run in2lambda over those files inside the container.
1818

1919
```bash
2020
$ cd files
@@ -23,15 +23,15 @@ $ ...
2323
$ exit
2424
```
2525

26-
The container is stopped and deleted after exiting, although the image remains downloaded for future use.
26+
Docker stops and deletes the container on exit. The image stays on disk for the next run.
2727

2828
### PyPi
2929

3030
[![PyPI - Version](https://img.shields.io/pypi/v/in2lambda?logo=pypi&logoColor=white&color=blue&style=flat-square)](https://pypi.org/project/in2lambda/)
3131
[![PyPI - Python Version](https://img.shields.io/pypi/pyversions/in2lambda?style=flat-square&logo=python&logoColor=white)](https://pypi.org/project/in2lambda/)
3232

3333

34-
in2lambda can be installed via [pip](https://pip.pypa.io/en/stable/). To author questions in Python:
34+
[pip](https://pip.pypa.io/en/stable/) installs in2lambda. To write questions in Python:
3535

3636
```shell
3737
$ pip install in2lambda
@@ -44,50 +44,50 @@ $ pip install 'in2lambda[convert]'
4444
$ in2lambda --help
4545
```
4646

47-
This can also be done through [pipx](https://pypa.github.io/pipx/).
47+
[pipx](https://pypa.github.io/pipx/) installs in2lambda as well.
4848

4949
## 2. Choose a Document
5050

51-
`in2lambda convert` takes in two arguments:
51+
`in2lambda convert` takes two arguments:
5252

5353
- The path to a document.
54-
- A filter describing how to parse it.
54+
- A filter describing how to parse that document.
5555

56-
A list of available filters can be found [here](filters/index).
56+
The [filters page](filters/index) lists every filter.
5757

58-
For instance, the following takes in `questions.tex` and uses a filter that expects [each part to be directly followed by the solution](filters/_autosummary/PartSolPartSol):
58+
The following command reads `questions.tex` with a filter that expects [each part to be followed by its solution](filters/_autosummary/PartSolPartSol):
5959

6060
```bash
6161
$ in2lambda convert questions.tex PartSolPartSol
6262
```
6363

6464
:::{note}
65-
The filter name is case-insensitive. Don't worry about the capital letters.
65+
The filter name is case-insensitive.
6666
:::
6767

68-
Another filter might be used if [the answers are in a separate file](filters/_autosummary/PartsSepSol):
68+
A different filter reads [answers held in a separate file](filters/_autosummary/PartsSepSol):
6969

7070
```bash
7171
$ in2lambda convert questions.tex -a solutions.tex PartsSepSol
7272
```
7373

74-
By default, this generates an `out` directory in the same place that the command was run in. It contains the zipped question files.
74+
`in2lambda convert` writes an `out` directory in the directory the command ran in, holding the zipped question files.
7575

76-
Before writing anything, in2lambda prints the problems it can detect that would stop the set importing or make it render wrongly — an answer that doesn't fit the box marking it, a figure the export won't contain, maths that KaTeX can't display. Each names the question, part and field to go and look at. They are warnings rather than errors: the `out` directory is written either way, since a problem found here may well be deliberate.
76+
Before writing that directory, in2lambda prints the problems that would stop Lambda Feedback importing the set or would render it wrongly: an answer that does not fit the box marking it, a figure the export would not contain, maths KaTeX cannot display. Each problem names the question, the part and the field holding it. Each problem is a warning, and in2lambda writes the `out` directory whatever it finds, because an author may have intended the problem.
7777

78-
The maths is checked by rendering it with KaTeX itself, the way Lambda Feedback will, which needs [Node.js](https://nodejs.org) installed. Without Node.js everything else is still checked and in2lambda says the maths was not.
78+
in2lambda checks the maths by rendering it with KaTeX, as Lambda Feedback renders it, which needs [Node.js](https://nodejs.org). Without Node.js, in2lambda runs the other checks and reports that it did not check the maths.
7979

80-
With [xelatex](https://tug.org/texlive/) installed alongside pandoc, the set is also compiled the way Lambda Feedback makes a PDF of it, and any LaTeX error names the field it is in. Without it, one warning says which packages to install instead.
80+
With [xelatex](https://tug.org/texlive/) installed alongside pandoc, in2lambda also compiles the set as Lambda Feedback compiles a PDF of it, and names the field holding each LaTeX error. Without xelatex, in2lambda prints one warning naming the packages to install.
8181

82-
Check the [command line tool reference](reference/command-line) for more information.
82+
The [command line reference](reference/command-line) describes every command and option.
8383

8484
## 3. Import into Lambda Feedback
8585

86-
Click on a set in teacher mode. The arrow next to the "Add Question" button allows you to import a question from a file.
86+
Open a set in teacher mode. The arrow beside the "Add Question" button imports a question from a file.
8787

88-
Choose the zip file you wish to upload, and the question should appear! 🎉
88+
Choose the zip file to upload, and Lambda Feedback adds the question to the set.
8989

90-
Imported questions arrive published with every display setting on, and the set's own visibility settings still apply. The Python API can set each of these per question — see the
90+
An imported question arrives published, with every display setting on, and the set's own visibility settings apply to it. The Python API sets each of these per question; see the
9191
[question format](question-format).
9292

9393
![Importing Question from file in Teacher Mode](_static/images/import-teacher.png)

0 commit comments

Comments
 (0)