mdq 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- mdq-0.1.0/LICENSE +21 -0
- mdq-0.1.0/PKG-INFO +168 -0
- mdq-0.1.0/README.md +148 -0
- mdq-0.1.0/mdq/__init__.py +19 -0
- mdq-0.1.0/mdq/__main__.py +4 -0
- mdq-0.1.0/mdq/_diagnostics.py +40 -0
- mdq-0.1.0/mdq/cli.py +327 -0
- mdq-0.1.0/mdq/convert/__init__.py +14 -0
- mdq-0.1.0/mdq/convert/aiken.py +151 -0
- mdq-0.1.0/mdq/convert/base.py +106 -0
- mdq-0.1.0/mdq/convert/gift.py +876 -0
- mdq-0.1.0/mdq/convert/moodle_xml.py +922 -0
- mdq-0.1.0/mdq/convert/parser.py +161 -0
- mdq-0.1.0/mdq/errors.py +114 -0
- mdq-0.1.0/mdq/grading.py +87 -0
- mdq-0.1.0/mdq/hypothesis/__init__.py +14 -0
- mdq-0.1.0/mdq/hypothesis/aiken.py +59 -0
- mdq-0.1.0/mdq/hypothesis/documents.py +625 -0
- mdq-0.1.0/mdq/hypothesis/frontmatter.py +88 -0
- mdq-0.1.0/mdq/hypothesis/gift.py +140 -0
- mdq-0.1.0/mdq/hypothesis/moodle_xml.py +234 -0
- mdq-0.1.0/mdq/hypothesis/schedule.py +236 -0
- mdq-0.1.0/mdq/hypothesis/slugs.py +247 -0
- mdq-0.1.0/mdq/linter.py +905 -0
- mdq-0.1.0/mdq/loaders.py +113 -0
- mdq-0.1.0/mdq/loading.py +520 -0
- mdq-0.1.0/mdq/mdit/__init__.py +0 -0
- mdq-0.1.0/mdq/mdit/plugins/__init__.py +0 -0
- mdq-0.1.0/mdq/mdit/plugins/choices.py +170 -0
- mdq-0.1.0/mdq/mdq.schema.json +1172 -0
- mdq-0.1.0/mdq/models.py +1836 -0
- mdq-0.1.0/mdq/parser.py +2101 -0
- mdq-0.1.0/mdq/py.typed +0 -0
- mdq-0.1.0/mdq/regex.py +238 -0
- mdq-0.1.0/mdq/render.py +167 -0
- mdq-0.1.0/mdq/scaffold.py +438 -0
- mdq-0.1.0/mdq/schedule.py +188 -0
- mdq-0.1.0/mdq/scripts/__init__.py +0 -0
- mdq-0.1.0/mdq/scripts/lint_snapshot.py +159 -0
- mdq-0.1.0/mdq/show.py +534 -0
- mdq-0.1.0/mdq/slugify.py +221 -0
- mdq-0.1.0/mdq/testing.py +129 -0
- mdq-0.1.0/mdq/types.py +403 -0
- mdq-0.1.0/pyproject.toml +72 -0
- mdq-0.1.0/pyproject.toml.orig +73 -0
mdq-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Fábio Macêdo Mendes
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
mdq-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: mdq
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Reference schemas and validation CLI for the MDQ question file format.
|
|
5
|
+
Author: Fábio Macêdo Mendes
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
License-File: LICENSE
|
|
8
|
+
Requires-Dist: pyyaml>=6.0
|
|
9
|
+
Requires-Dist: typer>=0.12
|
|
10
|
+
Requires-Dist: rich>=15.0.0
|
|
11
|
+
Requires-Dist: markdown-it-py>=4.2.0
|
|
12
|
+
Requires-Dist: pydantic>=2.9
|
|
13
|
+
Requires-Dist: optionz>=0.2.0
|
|
14
|
+
Requires-Dist: linkify-it-py>=2.2.0
|
|
15
|
+
Requires-Dist: python-slugify>=8.0.4
|
|
16
|
+
Requires-Dist: pytest>=7 ; extra == 'test'
|
|
17
|
+
Requires-Python: >=3.13
|
|
18
|
+
Provides-Extra: test
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
|
|
21
|
+
# mdq-py
|
|
22
|
+
|
|
23
|
+
[](https://github.com/fabiommendes/mdq-spec/actions/workflows/ci.yml)
|
|
24
|
+
[](LICENSE)
|
|
25
|
+
|
|
26
|
+
> [!WARNING]
|
|
27
|
+
> This is a work in progress. The MDQ specification is not stable yet, and the
|
|
28
|
+
> API and the CLI may change.
|
|
29
|
+
|
|
30
|
+
Python reference implementation of [MDQ](https://github.com/fabiommendes/mdq-spec),
|
|
31
|
+
a file format to write questions and exams in plain Markdown:
|
|
32
|
+
|
|
33
|
+
```md
|
|
34
|
+
What is the capital of Brazil?
|
|
35
|
+
|
|
36
|
+
* [ ] Rio de Janeiro
|
|
37
|
+
> It was the capital until 1960.
|
|
38
|
+
* [*] Brasília
|
|
39
|
+
* [ ] São Paulo
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
`mdq-py` provides:
|
|
43
|
+
|
|
44
|
+
* A parser from MDQ Markdown (and from YAML/JSON) to Pydantic models.
|
|
45
|
+
* A linter that reports problems the schema cannot express.
|
|
46
|
+
* Scoring of student responses.
|
|
47
|
+
* Converters to and from GIFT, Aiken and Moodle XML.
|
|
48
|
+
* The `mdq` command line tool.
|
|
49
|
+
|
|
50
|
+
The syntax of each question type is in the
|
|
51
|
+
[specification](https://github.com/fabiommendes/mdq-spec/tree/main/docs).
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
## Installation
|
|
55
|
+
|
|
56
|
+
Requires Python 3.13 or later. The package is not on PyPI yet. Install it from
|
|
57
|
+
the repository:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
# CLI only
|
|
61
|
+
uv tool install "git+https://github.com/fabiommendes/mdq-py"
|
|
62
|
+
|
|
63
|
+
# As a library
|
|
64
|
+
uv add "git+https://github.com/fabiommendes/mdq-py"
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
## Command line
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
mdq new multiple-choice # scaffold multiple-choice.mdq.md
|
|
72
|
+
mdq new numeric --complete # scaffold with every feature of the type
|
|
73
|
+
mdq validate question.mdq.md # print errors and warnings
|
|
74
|
+
mdq validate question.mdq.md --level strict # also print info diagnostics
|
|
75
|
+
mdq show exam.mdq.md # render the parsed document
|
|
76
|
+
mdq show exam.mdq.md --no-answer-key # preview it as a student sees it
|
|
77
|
+
mdq export question.mdq.md --format gift
|
|
78
|
+
mdq import question.gift -o question.mdq.md
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
`mdq validate` exits with a non-zero code if the document has errors:
|
|
82
|
+
|
|
83
|
+
```
|
|
84
|
+
$ mdq validate capital.mdq.md
|
|
85
|
+
OK capital.mdq.md
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
`import` and `export` support `aiken`, `gift` and `moodle-xml`. The format is
|
|
89
|
+
inferred from the file extension if `--format` is not given. Run `mdq --help`
|
|
90
|
+
or `mdq <command> --help` for all options.
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
## Library
|
|
94
|
+
|
|
95
|
+
`mdq.parse()` returns a validated model, or raises `InvalidDocument`:
|
|
96
|
+
|
|
97
|
+
```python
|
|
98
|
+
from pathlib import Path
|
|
99
|
+
|
|
100
|
+
import mdq
|
|
101
|
+
|
|
102
|
+
question = mdq.parse("""
|
|
103
|
+
What is the capital of Brazil?
|
|
104
|
+
|
|
105
|
+
* [ ] Rio de Janeiro
|
|
106
|
+
* [*] Brasília
|
|
107
|
+
""")
|
|
108
|
+
|
|
109
|
+
print(type(question).__name__) # MultipleChoiceQuestion
|
|
110
|
+
print(question.to_dict())
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
A `str` is read as MDQ source. Pass a `Path` to read a file, or a mapping to
|
|
114
|
+
load an already parsed document. The `format` argument selects `"mdq"`,
|
|
115
|
+
`"yaml"` or `"json"` explicitly.
|
|
116
|
+
|
|
117
|
+
`mdq.load()` never raises for a problem in the document. It returns the
|
|
118
|
+
document together with every diagnostic, which is useful for editors and
|
|
119
|
+
linters:
|
|
120
|
+
|
|
121
|
+
```python
|
|
122
|
+
loaded = mdq.load(Path("exam.mdq.md"))
|
|
123
|
+
for diagnostic in loaded.diagnostics:
|
|
124
|
+
print(diagnostic.severity, diagnostic.code, diagnostic.message)
|
|
125
|
+
|
|
126
|
+
exam = loaded.validate(raise_on="warning")
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Other useful parts of the API:
|
|
130
|
+
|
|
131
|
+
* `ids="fill"` in `parse()`/`load()`, or `document.with_ids()`, derives the
|
|
132
|
+
missing ids of questions and choices.
|
|
133
|
+
* `question.score_response(response)` scores a student response.
|
|
134
|
+
* `question.render()` serializes a model back to MDQ Markdown.
|
|
135
|
+
* `Exam.resolve()` replaces the `include` blocks of an exam with the questions
|
|
136
|
+
they refer to.
|
|
137
|
+
* `mdq.convert.import_question()` and `mdq.convert.export_question()` convert
|
|
138
|
+
from and to other formats.
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
## Development
|
|
142
|
+
|
|
143
|
+
The test suite reads the specification, the schema and the shared examples from
|
|
144
|
+
the parent [mdq-spec](https://github.com/fabiommendes/mdq-spec) repository, where
|
|
145
|
+
this package lives in the `mdq-py/` directory. Clone that repository to run the
|
|
146
|
+
tests; a standalone clone of `mdq-py` cannot run them.
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
git clone https://github.com/fabiommendes/mdq-spec
|
|
150
|
+
cd mdq-spec/mdq-py
|
|
151
|
+
uv sync
|
|
152
|
+
uv run pytest # tests
|
|
153
|
+
uv run mypy mdq # type check
|
|
154
|
+
uv run ruff check # lint
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
This is the reference implementation: new features are specified in
|
|
158
|
+
`mdq-spec`, implemented here, and then ported to
|
|
159
|
+
[mdq-js](https://github.com/fabiommendes/mdq-js). See [AGENTS.md](AGENTS.md) for
|
|
160
|
+
the coding conventions.
|
|
161
|
+
|
|
162
|
+
See the [changelog](CHANGELOG.md) and the
|
|
163
|
+
[contributing guide](https://github.com/fabiommendes/mdq-spec/blob/main/CONTRIBUTING.md).
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
## License
|
|
167
|
+
|
|
168
|
+
[MIT](LICENSE)
|
mdq-0.1.0/README.md
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
# mdq-py
|
|
2
|
+
|
|
3
|
+
[](https://github.com/fabiommendes/mdq-spec/actions/workflows/ci.yml)
|
|
4
|
+
[](LICENSE)
|
|
5
|
+
|
|
6
|
+
> [!WARNING]
|
|
7
|
+
> This is a work in progress. The MDQ specification is not stable yet, and the
|
|
8
|
+
> API and the CLI may change.
|
|
9
|
+
|
|
10
|
+
Python reference implementation of [MDQ](https://github.com/fabiommendes/mdq-spec),
|
|
11
|
+
a file format to write questions and exams in plain Markdown:
|
|
12
|
+
|
|
13
|
+
```md
|
|
14
|
+
What is the capital of Brazil?
|
|
15
|
+
|
|
16
|
+
* [ ] Rio de Janeiro
|
|
17
|
+
> It was the capital until 1960.
|
|
18
|
+
* [*] Brasília
|
|
19
|
+
* [ ] São Paulo
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
`mdq-py` provides:
|
|
23
|
+
|
|
24
|
+
* A parser from MDQ Markdown (and from YAML/JSON) to Pydantic models.
|
|
25
|
+
* A linter that reports problems the schema cannot express.
|
|
26
|
+
* Scoring of student responses.
|
|
27
|
+
* Converters to and from GIFT, Aiken and Moodle XML.
|
|
28
|
+
* The `mdq` command line tool.
|
|
29
|
+
|
|
30
|
+
The syntax of each question type is in the
|
|
31
|
+
[specification](https://github.com/fabiommendes/mdq-spec/tree/main/docs).
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
## Installation
|
|
35
|
+
|
|
36
|
+
Requires Python 3.13 or later. The package is not on PyPI yet. Install it from
|
|
37
|
+
the repository:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
# CLI only
|
|
41
|
+
uv tool install "git+https://github.com/fabiommendes/mdq-py"
|
|
42
|
+
|
|
43
|
+
# As a library
|
|
44
|
+
uv add "git+https://github.com/fabiommendes/mdq-py"
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
## Command line
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
mdq new multiple-choice # scaffold multiple-choice.mdq.md
|
|
52
|
+
mdq new numeric --complete # scaffold with every feature of the type
|
|
53
|
+
mdq validate question.mdq.md # print errors and warnings
|
|
54
|
+
mdq validate question.mdq.md --level strict # also print info diagnostics
|
|
55
|
+
mdq show exam.mdq.md # render the parsed document
|
|
56
|
+
mdq show exam.mdq.md --no-answer-key # preview it as a student sees it
|
|
57
|
+
mdq export question.mdq.md --format gift
|
|
58
|
+
mdq import question.gift -o question.mdq.md
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
`mdq validate` exits with a non-zero code if the document has errors:
|
|
62
|
+
|
|
63
|
+
```
|
|
64
|
+
$ mdq validate capital.mdq.md
|
|
65
|
+
OK capital.mdq.md
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
`import` and `export` support `aiken`, `gift` and `moodle-xml`. The format is
|
|
69
|
+
inferred from the file extension if `--format` is not given. Run `mdq --help`
|
|
70
|
+
or `mdq <command> --help` for all options.
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
## Library
|
|
74
|
+
|
|
75
|
+
`mdq.parse()` returns a validated model, or raises `InvalidDocument`:
|
|
76
|
+
|
|
77
|
+
```python
|
|
78
|
+
from pathlib import Path
|
|
79
|
+
|
|
80
|
+
import mdq
|
|
81
|
+
|
|
82
|
+
question = mdq.parse("""
|
|
83
|
+
What is the capital of Brazil?
|
|
84
|
+
|
|
85
|
+
* [ ] Rio de Janeiro
|
|
86
|
+
* [*] Brasília
|
|
87
|
+
""")
|
|
88
|
+
|
|
89
|
+
print(type(question).__name__) # MultipleChoiceQuestion
|
|
90
|
+
print(question.to_dict())
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
A `str` is read as MDQ source. Pass a `Path` to read a file, or a mapping to
|
|
94
|
+
load an already parsed document. The `format` argument selects `"mdq"`,
|
|
95
|
+
`"yaml"` or `"json"` explicitly.
|
|
96
|
+
|
|
97
|
+
`mdq.load()` never raises for a problem in the document. It returns the
|
|
98
|
+
document together with every diagnostic, which is useful for editors and
|
|
99
|
+
linters:
|
|
100
|
+
|
|
101
|
+
```python
|
|
102
|
+
loaded = mdq.load(Path("exam.mdq.md"))
|
|
103
|
+
for diagnostic in loaded.diagnostics:
|
|
104
|
+
print(diagnostic.severity, diagnostic.code, diagnostic.message)
|
|
105
|
+
|
|
106
|
+
exam = loaded.validate(raise_on="warning")
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Other useful parts of the API:
|
|
110
|
+
|
|
111
|
+
* `ids="fill"` in `parse()`/`load()`, or `document.with_ids()`, derives the
|
|
112
|
+
missing ids of questions and choices.
|
|
113
|
+
* `question.score_response(response)` scores a student response.
|
|
114
|
+
* `question.render()` serializes a model back to MDQ Markdown.
|
|
115
|
+
* `Exam.resolve()` replaces the `include` blocks of an exam with the questions
|
|
116
|
+
they refer to.
|
|
117
|
+
* `mdq.convert.import_question()` and `mdq.convert.export_question()` convert
|
|
118
|
+
from and to other formats.
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
## Development
|
|
122
|
+
|
|
123
|
+
The test suite reads the specification, the schema and the shared examples from
|
|
124
|
+
the parent [mdq-spec](https://github.com/fabiommendes/mdq-spec) repository, where
|
|
125
|
+
this package lives in the `mdq-py/` directory. Clone that repository to run the
|
|
126
|
+
tests; a standalone clone of `mdq-py` cannot run them.
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
git clone https://github.com/fabiommendes/mdq-spec
|
|
130
|
+
cd mdq-spec/mdq-py
|
|
131
|
+
uv sync
|
|
132
|
+
uv run pytest # tests
|
|
133
|
+
uv run mypy mdq # type check
|
|
134
|
+
uv run ruff check # lint
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
This is the reference implementation: new features are specified in
|
|
138
|
+
`mdq-spec`, implemented here, and then ported to
|
|
139
|
+
[mdq-js](https://github.com/fabiommendes/mdq-js). See [AGENTS.md](AGENTS.md) for
|
|
140
|
+
the coding conventions.
|
|
141
|
+
|
|
142
|
+
See the [changelog](CHANGELOG.md) and the
|
|
143
|
+
[contributing guide](https://github.com/fabiommendes/mdq-spec/blob/main/CONTRIBUTING.md).
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
## License
|
|
147
|
+
|
|
148
|
+
[MIT](LICENSE)
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"""mdq: tools for the MDQ (Markdown Questions) file format."""
|
|
2
|
+
|
|
3
|
+
from .errors import ParseError
|
|
4
|
+
from .loading import Diagnostic, InvalidDocument, Loaded, Severity, load, parse
|
|
5
|
+
from .models import Exam, Question
|
|
6
|
+
|
|
7
|
+
__version__ = "0.1.0"
|
|
8
|
+
__all__ = [
|
|
9
|
+
"Question",
|
|
10
|
+
"Exam",
|
|
11
|
+
"ParseError",
|
|
12
|
+
#: Loading
|
|
13
|
+
"load",
|
|
14
|
+
"parse",
|
|
15
|
+
"Loaded",
|
|
16
|
+
"Diagnostic",
|
|
17
|
+
"Severity",
|
|
18
|
+
"InvalidDocument",
|
|
19
|
+
]
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"""
|
|
2
|
+
`Diagnostic`, the one problem shape every stage of `mdq.loading`'s
|
|
3
|
+
pipeline reports through -- a parse failure, a pydantic error, a lint
|
|
4
|
+
warning, an unknown frontmatter key.
|
|
5
|
+
|
|
6
|
+
Split out from `mdq.loading` (which owns and re-exports it) so that
|
|
7
|
+
`mdq.linter` and `mdq.parser` -- both upstream of `mdq.loading` in the
|
|
8
|
+
pipeline -- can report `Diagnostic`s of their own without importing back
|
|
9
|
+
into the module that orchestrates them.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
from dataclasses import dataclass
|
|
15
|
+
from typing import Literal
|
|
16
|
+
|
|
17
|
+
Severity = Literal["error", "warning", "info"]
|
|
18
|
+
|
|
19
|
+
#: Severity, ranked so "at or above" (as `Loaded.validate` uses it) is a
|
|
20
|
+
#: plain integer comparison. Higher is more severe.
|
|
21
|
+
RANK: dict[Severity, int] = {"info": 1, "warning": 2, "error": 3}
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@dataclass(frozen=True)
|
|
25
|
+
class Diagnostic:
|
|
26
|
+
"""
|
|
27
|
+
One problem found while loading a document.
|
|
28
|
+
|
|
29
|
+
`path` locates the offending value the way a `jsonschema`
|
|
30
|
+
`ValidationError.path` or a pydantic error's `loc` does: a tuple of
|
|
31
|
+
keys/indices from the document's root. `line` is set only for a
|
|
32
|
+
parse failure tied to a source node, and only when that node's
|
|
33
|
+
position in the source is known.
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
severity: Severity
|
|
37
|
+
code: str
|
|
38
|
+
message: str
|
|
39
|
+
path: tuple[str | int, ...] = ()
|
|
40
|
+
line: int | None = None
|