mktestdocs 0.2.1__tar.gz → 0.2.5__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.
- mktestdocs-0.2.5/PKG-INFO +191 -0
- {mktestdocs-0.2.1 → mktestdocs-0.2.5}/README.md +1 -1
- mktestdocs-0.2.5/pyproject.toml +18 -0
- {mktestdocs-0.2.1 → mktestdocs-0.2.5/src}/mktestdocs/__init__.py +3 -2
- {mktestdocs-0.2.1 → mktestdocs-0.2.5/src}/mktestdocs/__main__.py +14 -7
- mktestdocs-0.2.5/src/mktestdocs.egg-info/PKG-INFO +191 -0
- mktestdocs-0.2.5/src/mktestdocs.egg-info/SOURCES.txt +16 -0
- mktestdocs-0.2.5/src/mktestdocs.egg-info/requires.txt +3 -0
- mktestdocs-0.2.5/tests/test_actual_docstrings.py +74 -0
- {mktestdocs-0.2.1 → mktestdocs-0.2.5}/tests/test_class.py +16 -1
- mktestdocs-0.2.5/tests/test_format_docstring.py +61 -0
- {mktestdocs-0.2.1 → mktestdocs-0.2.5}/tests/test_mktestdocs.py +2 -1
- mktestdocs-0.2.1/PKG-INFO +0 -5
- mktestdocs-0.2.1/mktestdocs.egg-info/PKG-INFO +0 -5
- mktestdocs-0.2.1/mktestdocs.egg-info/SOURCES.txt +0 -15
- mktestdocs-0.2.1/mktestdocs.egg-info/requires.txt +0 -3
- mktestdocs-0.2.1/setup.py +0 -14
- mktestdocs-0.2.1/tests/test_actual_docstrings.py +0 -60
- {mktestdocs-0.2.1 → mktestdocs-0.2.5}/LICENSE +0 -0
- {mktestdocs-0.2.1 → mktestdocs-0.2.5}/setup.cfg +0 -0
- {mktestdocs-0.2.1 → mktestdocs-0.2.5/src}/mktestdocs.egg-info/dependency_links.txt +0 -0
- {mktestdocs-0.2.1 → mktestdocs-0.2.5/src}/mktestdocs.egg-info/top_level.txt +0 -0
- {mktestdocs-0.2.1 → mktestdocs-0.2.5}/tests/test_codeblock.py +0 -0
- {mktestdocs-0.2.1 → mktestdocs-0.2.5}/tests/test_markdown.py +0 -0
@@ -0,0 +1,191 @@
|
|
1
|
+
Metadata-Version: 2.4
|
2
|
+
Name: mktestdocs
|
3
|
+
Version: 0.2.5
|
4
|
+
Summary: A tool for testing markdown documentation
|
5
|
+
License: MIT
|
6
|
+
Requires-Python: >=3.8
|
7
|
+
Description-Content-Type: text/markdown
|
8
|
+
License-File: LICENSE
|
9
|
+
Provides-Extra: test
|
10
|
+
Requires-Dist: pytest; extra == "test"
|
11
|
+
Dynamic: license-file
|
12
|
+
|
13
|
+
<img src="icon.png" width=125 height=125 align="right">
|
14
|
+
|
15
|
+
### mktestdocs
|
16
|
+
|
17
|
+
Run pytest against markdown files/docstrings.
|
18
|
+
|
19
|
+
# Installation
|
20
|
+
|
21
|
+
```
|
22
|
+
pip install mktestdocs
|
23
|
+
```
|
24
|
+
|
25
|
+
## Usage
|
26
|
+
|
27
|
+
Let's say that you're using [mkdocs](https://squidfunk.github.io/mkdocs-material/getting-started/)
|
28
|
+
for your documentation. Then you're writing down markdown to explain how your Python packages work.
|
29
|
+
It'd be a shame if a codeblock had an error in it, so it'd be
|
30
|
+
great if you could run your unit tests against them.
|
31
|
+
|
32
|
+
This package allows you to do _just that_. Here's an example:
|
33
|
+
|
34
|
+
```python
|
35
|
+
import pathlib
|
36
|
+
import pytest
|
37
|
+
|
38
|
+
from mktestdocs import check_md_file
|
39
|
+
|
40
|
+
# Note the use of `str`, makes for pretty output
|
41
|
+
@pytest.mark.parametrize('fpath', pathlib.Path("docs").glob("**/*.md"), ids=str)
|
42
|
+
def test_files_good(fpath):
|
43
|
+
check_md_file(fpath=fpath)
|
44
|
+
```
|
45
|
+
|
46
|
+
This will take any codeblock that starts with *\`\`\`python* and run it, checking
|
47
|
+
for any errors that might happen. This means that if your docs contain asserts, that
|
48
|
+
you get some unit-tests for free!
|
49
|
+
|
50
|
+
## Multiple Code Blocks
|
51
|
+
|
52
|
+
Let's suppose that you have the following markdown file:
|
53
|
+
|
54
|
+
This is a code block
|
55
|
+
|
56
|
+
```python
|
57
|
+
from operator import add
|
58
|
+
a = 1
|
59
|
+
b = 2
|
60
|
+
```
|
61
|
+
|
62
|
+
This code-block should run fine.
|
63
|
+
|
64
|
+
```python
|
65
|
+
assert add(1, 2) == 3
|
66
|
+
```
|
67
|
+
|
68
|
+
Then in this case the second code-block depends on the first code-block. The standard settings of `check_md_file` assume that each code-block needs to run independently. If you'd like to test markdown files with these sequential code-blocks be sure to set `memory=True`.
|
69
|
+
|
70
|
+
```python
|
71
|
+
import pathlib
|
72
|
+
|
73
|
+
from mktestdocs import check_md_file
|
74
|
+
|
75
|
+
fpath = pathlib.Path("docs") / "multiple-code-blocks.md"
|
76
|
+
|
77
|
+
try:
|
78
|
+
# Assume that cell-blocks are independent.
|
79
|
+
check_md_file(fpath=fpath)
|
80
|
+
except NameError:
|
81
|
+
# But they weren't
|
82
|
+
pass
|
83
|
+
|
84
|
+
# Assumes that cell-blocks depend on each other.
|
85
|
+
check_md_file(fpath=fpath, memory=True)
|
86
|
+
```
|
87
|
+
|
88
|
+
## Markdown in Docstrings
|
89
|
+
|
90
|
+
You might also have docstrings written in markdown. Those can be easily checked
|
91
|
+
as well.
|
92
|
+
|
93
|
+
```python
|
94
|
+
# I'm assuming that we've got a library called dinosaur
|
95
|
+
from dinosaur import roar, super_roar
|
96
|
+
|
97
|
+
import pytest
|
98
|
+
from mktestdocs import check_docstring
|
99
|
+
|
100
|
+
# Note the use of `__name__`, makes for pretty output
|
101
|
+
@pytest.mark.parametrize('func', [roar, super_roar], ids=lambda d: d.__name__)
|
102
|
+
def test_docstring(func):
|
103
|
+
check_docstring(obj=func)
|
104
|
+
```
|
105
|
+
|
106
|
+
There's even some utilities for grab all the docstrings from classes that you've defined.
|
107
|
+
|
108
|
+
```python
|
109
|
+
# I'm assuming that we've got a library called dinosaur
|
110
|
+
from dinosaur import Dinosaur
|
111
|
+
|
112
|
+
import pytest
|
113
|
+
from mktestdocs import check_docstring, get_codeblock_members
|
114
|
+
|
115
|
+
# This retrieves all methods/properties that have a docstring.
|
116
|
+
members = get_codeblock_members(Dinosaur)
|
117
|
+
|
118
|
+
# Note the use of `__qualname__`, makes for pretty output
|
119
|
+
@pytest.mark.parametrize("obj", members, ids=lambda d: d.__qualname__)
|
120
|
+
def test_member(obj):
|
121
|
+
check_docstring(obj)
|
122
|
+
```
|
123
|
+
|
124
|
+
When you run these commands via `pytest --verbose` you should see informative test info being run.
|
125
|
+
|
126
|
+
If you're wondering why you'd want to write markdown in a docstring feel free to check out [mkdocstrings](https://github.com/mkdocstrings/mkdocstrings).
|
127
|
+
|
128
|
+
## Bash Support
|
129
|
+
|
130
|
+
Be default, bash code blocks are also supported. A markdown file that contains
|
131
|
+
both python and bash code blocks can have each executed separately.
|
132
|
+
|
133
|
+
This will print the python version to the terminal
|
134
|
+
|
135
|
+
```bash
|
136
|
+
python --version
|
137
|
+
```
|
138
|
+
|
139
|
+
This will print the exact same version string
|
140
|
+
|
141
|
+
```python
|
142
|
+
import sys
|
143
|
+
|
144
|
+
print(f"Python {sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}")
|
145
|
+
```
|
146
|
+
|
147
|
+
This markdown could be fully tested like this
|
148
|
+
|
149
|
+
```python
|
150
|
+
import pathlib
|
151
|
+
|
152
|
+
from mktestdocs import check_md_file
|
153
|
+
|
154
|
+
fpath = pathlib.Path("docs") / "bash-support.md"
|
155
|
+
|
156
|
+
check_md_file(fpath=fpath, lang="python")
|
157
|
+
check_md_file(fpath=fpath, lang="bash")
|
158
|
+
```
|
159
|
+
|
160
|
+
## Additional Language Support
|
161
|
+
|
162
|
+
You can add support for languages other than python and bash by first
|
163
|
+
registering a new executor for that language. The `register_executor` function
|
164
|
+
takes a tag to specify the code block type supported, and a function that will
|
165
|
+
be passed any code blocks found in markdown files.
|
166
|
+
|
167
|
+
For example if you have a markdown file like this
|
168
|
+
|
169
|
+
````markdown
|
170
|
+
This is an example REST response
|
171
|
+
|
172
|
+
```json
|
173
|
+
{"body": {"results": ["spam", "eggs"]}, "errors": []}
|
174
|
+
```
|
175
|
+
````
|
176
|
+
|
177
|
+
You could create a json validator that tested the example was always valid json like this
|
178
|
+
|
179
|
+
```python
|
180
|
+
import json
|
181
|
+
import pathlib
|
182
|
+
|
183
|
+
from mktestdocs import check_md_file, register_executor
|
184
|
+
|
185
|
+
def parse_json(json_text):
|
186
|
+
json.loads(json_text)
|
187
|
+
|
188
|
+
register_executor("json", parse_json)
|
189
|
+
|
190
|
+
check_md_file(fpath=pathlib.Path("docs") / "additional-language-support.md", lang="json")
|
191
|
+
```
|
@@ -0,0 +1,18 @@
|
|
1
|
+
[build-system]
|
2
|
+
requires = ["setuptools>=61.0", "wheel"]
|
3
|
+
build-backend = "setuptools.build_meta"
|
4
|
+
|
5
|
+
[project]
|
6
|
+
name = "mktestdocs"
|
7
|
+
version = "0.2.5"
|
8
|
+
description = "A tool for testing markdown documentation"
|
9
|
+
readme = "README.md"
|
10
|
+
license = {text = "MIT"}
|
11
|
+
requires-python = ">=3.8"
|
12
|
+
dependencies = []
|
13
|
+
|
14
|
+
[project.optional-dependencies]
|
15
|
+
test = ["pytest"]
|
16
|
+
|
17
|
+
[tool.setuptools.packages.find]
|
18
|
+
where = ["src"]
|
@@ -1,4 +1,5 @@
|
|
1
|
-
|
1
|
+
import importlib.metadata
|
2
|
+
from .__main__ import (
|
2
3
|
register_executor,
|
3
4
|
check_codeblock,
|
4
5
|
grab_code_blocks,
|
@@ -7,7 +8,7 @@ from mktestdocs.__main__ import (
|
|
7
8
|
get_codeblock_members,
|
8
9
|
)
|
9
10
|
|
10
|
-
__version__ =
|
11
|
+
__version__ = importlib.metadata.version("mktestdocs")
|
11
12
|
|
12
13
|
__all__ = [
|
13
14
|
"__version__",
|
@@ -3,7 +3,6 @@ import pathlib
|
|
3
3
|
import subprocess
|
4
4
|
import textwrap
|
5
5
|
|
6
|
-
|
7
6
|
_executors = {}
|
8
7
|
|
9
8
|
|
@@ -41,7 +40,7 @@ def exec_python(source):
|
|
41
40
|
will propagate out unmodified
|
42
41
|
"""
|
43
42
|
try:
|
44
|
-
exec(source, {"
|
43
|
+
exec(source, {"__name__": "__main__"})
|
45
44
|
except Exception:
|
46
45
|
print(source)
|
47
46
|
raise
|
@@ -51,7 +50,7 @@ register_executor("", exec_python)
|
|
51
50
|
register_executor("python", exec_python)
|
52
51
|
|
53
52
|
|
54
|
-
def get_codeblock_members(*classes):
|
53
|
+
def get_codeblock_members(*classes, lang="python"):
|
55
54
|
"""
|
56
55
|
Grabs the docstrings of any methods of any classes that are passed in.
|
57
56
|
"""
|
@@ -62,7 +61,7 @@ def get_codeblock_members(*classes):
|
|
62
61
|
for name, member in inspect.getmembers(cl):
|
63
62
|
if member.__doc__:
|
64
63
|
results.append(member)
|
65
|
-
return [m for m in results if len(grab_code_blocks(m.__doc__)) > 0]
|
64
|
+
return [m for m in results if len(grab_code_blocks(m.__doc__, lang=lang)) > 0]
|
66
65
|
|
67
66
|
|
68
67
|
def check_codeblock(block, lang="python"):
|
@@ -77,7 +76,7 @@ def check_codeblock(block, lang="python"):
|
|
77
76
|
"""
|
78
77
|
first_line = block.split("\n")[0]
|
79
78
|
if lang:
|
80
|
-
if first_line[3:] != lang:
|
79
|
+
if first_line.lstrip()[3:] != lang:
|
81
80
|
return ""
|
82
81
|
return "\n".join(block.split("\n")[1:])
|
83
82
|
|
@@ -90,19 +89,27 @@ def grab_code_blocks(docstring, lang="python"):
|
|
90
89
|
docstring: the docstring to analyse
|
91
90
|
lang: if not None, the language that is assigned to the codeblock
|
92
91
|
"""
|
92
|
+
docstring = format_docstring(docstring)
|
93
93
|
docstring = textwrap.dedent(docstring)
|
94
94
|
in_block = False
|
95
95
|
block = ""
|
96
96
|
codeblocks = []
|
97
97
|
for idx, line in enumerate(docstring.split("\n")):
|
98
|
-
if
|
98
|
+
if "```" in line:
|
99
99
|
if in_block:
|
100
100
|
codeblocks.append(check_codeblock(block, lang=lang))
|
101
101
|
block = ""
|
102
102
|
in_block = not in_block
|
103
103
|
if in_block:
|
104
104
|
block += line + "\n"
|
105
|
-
return [c for c in codeblocks if c != ""]
|
105
|
+
return [textwrap.dedent(c) for c in codeblocks if c != ""]
|
106
|
+
|
107
|
+
|
108
|
+
def format_docstring(docstring):
|
109
|
+
"""Formats docstring to be able to successfully go through dedent."""
|
110
|
+
if docstring[:1] != "\n":
|
111
|
+
return f"\n {docstring}"
|
112
|
+
return docstring
|
106
113
|
|
107
114
|
|
108
115
|
def check_docstring(obj, lang=""):
|
@@ -0,0 +1,191 @@
|
|
1
|
+
Metadata-Version: 2.4
|
2
|
+
Name: mktestdocs
|
3
|
+
Version: 0.2.5
|
4
|
+
Summary: A tool for testing markdown documentation
|
5
|
+
License: MIT
|
6
|
+
Requires-Python: >=3.8
|
7
|
+
Description-Content-Type: text/markdown
|
8
|
+
License-File: LICENSE
|
9
|
+
Provides-Extra: test
|
10
|
+
Requires-Dist: pytest; extra == "test"
|
11
|
+
Dynamic: license-file
|
12
|
+
|
13
|
+
<img src="icon.png" width=125 height=125 align="right">
|
14
|
+
|
15
|
+
### mktestdocs
|
16
|
+
|
17
|
+
Run pytest against markdown files/docstrings.
|
18
|
+
|
19
|
+
# Installation
|
20
|
+
|
21
|
+
```
|
22
|
+
pip install mktestdocs
|
23
|
+
```
|
24
|
+
|
25
|
+
## Usage
|
26
|
+
|
27
|
+
Let's say that you're using [mkdocs](https://squidfunk.github.io/mkdocs-material/getting-started/)
|
28
|
+
for your documentation. Then you're writing down markdown to explain how your Python packages work.
|
29
|
+
It'd be a shame if a codeblock had an error in it, so it'd be
|
30
|
+
great if you could run your unit tests against them.
|
31
|
+
|
32
|
+
This package allows you to do _just that_. Here's an example:
|
33
|
+
|
34
|
+
```python
|
35
|
+
import pathlib
|
36
|
+
import pytest
|
37
|
+
|
38
|
+
from mktestdocs import check_md_file
|
39
|
+
|
40
|
+
# Note the use of `str`, makes for pretty output
|
41
|
+
@pytest.mark.parametrize('fpath', pathlib.Path("docs").glob("**/*.md"), ids=str)
|
42
|
+
def test_files_good(fpath):
|
43
|
+
check_md_file(fpath=fpath)
|
44
|
+
```
|
45
|
+
|
46
|
+
This will take any codeblock that starts with *\`\`\`python* and run it, checking
|
47
|
+
for any errors that might happen. This means that if your docs contain asserts, that
|
48
|
+
you get some unit-tests for free!
|
49
|
+
|
50
|
+
## Multiple Code Blocks
|
51
|
+
|
52
|
+
Let's suppose that you have the following markdown file:
|
53
|
+
|
54
|
+
This is a code block
|
55
|
+
|
56
|
+
```python
|
57
|
+
from operator import add
|
58
|
+
a = 1
|
59
|
+
b = 2
|
60
|
+
```
|
61
|
+
|
62
|
+
This code-block should run fine.
|
63
|
+
|
64
|
+
```python
|
65
|
+
assert add(1, 2) == 3
|
66
|
+
```
|
67
|
+
|
68
|
+
Then in this case the second code-block depends on the first code-block. The standard settings of `check_md_file` assume that each code-block needs to run independently. If you'd like to test markdown files with these sequential code-blocks be sure to set `memory=True`.
|
69
|
+
|
70
|
+
```python
|
71
|
+
import pathlib
|
72
|
+
|
73
|
+
from mktestdocs import check_md_file
|
74
|
+
|
75
|
+
fpath = pathlib.Path("docs") / "multiple-code-blocks.md"
|
76
|
+
|
77
|
+
try:
|
78
|
+
# Assume that cell-blocks are independent.
|
79
|
+
check_md_file(fpath=fpath)
|
80
|
+
except NameError:
|
81
|
+
# But they weren't
|
82
|
+
pass
|
83
|
+
|
84
|
+
# Assumes that cell-blocks depend on each other.
|
85
|
+
check_md_file(fpath=fpath, memory=True)
|
86
|
+
```
|
87
|
+
|
88
|
+
## Markdown in Docstrings
|
89
|
+
|
90
|
+
You might also have docstrings written in markdown. Those can be easily checked
|
91
|
+
as well.
|
92
|
+
|
93
|
+
```python
|
94
|
+
# I'm assuming that we've got a library called dinosaur
|
95
|
+
from dinosaur import roar, super_roar
|
96
|
+
|
97
|
+
import pytest
|
98
|
+
from mktestdocs import check_docstring
|
99
|
+
|
100
|
+
# Note the use of `__name__`, makes for pretty output
|
101
|
+
@pytest.mark.parametrize('func', [roar, super_roar], ids=lambda d: d.__name__)
|
102
|
+
def test_docstring(func):
|
103
|
+
check_docstring(obj=func)
|
104
|
+
```
|
105
|
+
|
106
|
+
There's even some utilities for grab all the docstrings from classes that you've defined.
|
107
|
+
|
108
|
+
```python
|
109
|
+
# I'm assuming that we've got a library called dinosaur
|
110
|
+
from dinosaur import Dinosaur
|
111
|
+
|
112
|
+
import pytest
|
113
|
+
from mktestdocs import check_docstring, get_codeblock_members
|
114
|
+
|
115
|
+
# This retrieves all methods/properties that have a docstring.
|
116
|
+
members = get_codeblock_members(Dinosaur)
|
117
|
+
|
118
|
+
# Note the use of `__qualname__`, makes for pretty output
|
119
|
+
@pytest.mark.parametrize("obj", members, ids=lambda d: d.__qualname__)
|
120
|
+
def test_member(obj):
|
121
|
+
check_docstring(obj)
|
122
|
+
```
|
123
|
+
|
124
|
+
When you run these commands via `pytest --verbose` you should see informative test info being run.
|
125
|
+
|
126
|
+
If you're wondering why you'd want to write markdown in a docstring feel free to check out [mkdocstrings](https://github.com/mkdocstrings/mkdocstrings).
|
127
|
+
|
128
|
+
## Bash Support
|
129
|
+
|
130
|
+
Be default, bash code blocks are also supported. A markdown file that contains
|
131
|
+
both python and bash code blocks can have each executed separately.
|
132
|
+
|
133
|
+
This will print the python version to the terminal
|
134
|
+
|
135
|
+
```bash
|
136
|
+
python --version
|
137
|
+
```
|
138
|
+
|
139
|
+
This will print the exact same version string
|
140
|
+
|
141
|
+
```python
|
142
|
+
import sys
|
143
|
+
|
144
|
+
print(f"Python {sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}")
|
145
|
+
```
|
146
|
+
|
147
|
+
This markdown could be fully tested like this
|
148
|
+
|
149
|
+
```python
|
150
|
+
import pathlib
|
151
|
+
|
152
|
+
from mktestdocs import check_md_file
|
153
|
+
|
154
|
+
fpath = pathlib.Path("docs") / "bash-support.md"
|
155
|
+
|
156
|
+
check_md_file(fpath=fpath, lang="python")
|
157
|
+
check_md_file(fpath=fpath, lang="bash")
|
158
|
+
```
|
159
|
+
|
160
|
+
## Additional Language Support
|
161
|
+
|
162
|
+
You can add support for languages other than python and bash by first
|
163
|
+
registering a new executor for that language. The `register_executor` function
|
164
|
+
takes a tag to specify the code block type supported, and a function that will
|
165
|
+
be passed any code blocks found in markdown files.
|
166
|
+
|
167
|
+
For example if you have a markdown file like this
|
168
|
+
|
169
|
+
````markdown
|
170
|
+
This is an example REST response
|
171
|
+
|
172
|
+
```json
|
173
|
+
{"body": {"results": ["spam", "eggs"]}, "errors": []}
|
174
|
+
```
|
175
|
+
````
|
176
|
+
|
177
|
+
You could create a json validator that tested the example was always valid json like this
|
178
|
+
|
179
|
+
```python
|
180
|
+
import json
|
181
|
+
import pathlib
|
182
|
+
|
183
|
+
from mktestdocs import check_md_file, register_executor
|
184
|
+
|
185
|
+
def parse_json(json_text):
|
186
|
+
json.loads(json_text)
|
187
|
+
|
188
|
+
register_executor("json", parse_json)
|
189
|
+
|
190
|
+
check_md_file(fpath=pathlib.Path("docs") / "additional-language-support.md", lang="json")
|
191
|
+
```
|
@@ -0,0 +1,16 @@
|
|
1
|
+
LICENSE
|
2
|
+
README.md
|
3
|
+
pyproject.toml
|
4
|
+
src/mktestdocs/__init__.py
|
5
|
+
src/mktestdocs/__main__.py
|
6
|
+
src/mktestdocs.egg-info/PKG-INFO
|
7
|
+
src/mktestdocs.egg-info/SOURCES.txt
|
8
|
+
src/mktestdocs.egg-info/dependency_links.txt
|
9
|
+
src/mktestdocs.egg-info/requires.txt
|
10
|
+
src/mktestdocs.egg-info/top_level.txt
|
11
|
+
tests/test_actual_docstrings.py
|
12
|
+
tests/test_class.py
|
13
|
+
tests/test_codeblock.py
|
14
|
+
tests/test_format_docstring.py
|
15
|
+
tests/test_markdown.py
|
16
|
+
tests/test_mktestdocs.py
|
@@ -0,0 +1,74 @@
|
|
1
|
+
import pytest
|
2
|
+
from mktestdocs import check_docstring
|
3
|
+
|
4
|
+
|
5
|
+
def foobar_good(a, b):
|
6
|
+
"""
|
7
|
+
Returns a + b.
|
8
|
+
|
9
|
+
Examples:
|
10
|
+
|
11
|
+
```python
|
12
|
+
import random
|
13
|
+
|
14
|
+
random.random()
|
15
|
+
assert 'a' + 'b' == 'ab'
|
16
|
+
assert 1 + 2 == 3
|
17
|
+
```
|
18
|
+
"""
|
19
|
+
pass
|
20
|
+
|
21
|
+
|
22
|
+
def foobar_also_good(a, b):
|
23
|
+
"""
|
24
|
+
```python
|
25
|
+
import random
|
26
|
+
|
27
|
+
assert random.random() < 10
|
28
|
+
```
|
29
|
+
"""
|
30
|
+
pass
|
31
|
+
|
32
|
+
|
33
|
+
def foobar_bad(a, b):
|
34
|
+
"""
|
35
|
+
```python
|
36
|
+
assert foobar(1, 2) == 4
|
37
|
+
```
|
38
|
+
"""
|
39
|
+
pass
|
40
|
+
|
41
|
+
|
42
|
+
def admonition_edge_cases():
|
43
|
+
"""
|
44
|
+
!!! note
|
45
|
+
|
46
|
+
All cells of a table are initialized with an empty string. Therefore, to delete the content of a cell,
|
47
|
+
you need to assign an empty string, i.e. `''`. For instance, to delete the first row after the header:
|
48
|
+
|
49
|
+
```python
|
50
|
+
assert 1 + 2 == 3
|
51
|
+
```"""
|
52
|
+
pass
|
53
|
+
|
54
|
+
def adminition_edge_case_bad():
|
55
|
+
"""Test that we can handle the edge cases of admonitions."""
|
56
|
+
example = """!!! note
|
57
|
+
|
58
|
+
Another one.
|
59
|
+
```python
|
60
|
+
assert 1 + 2 == 4
|
61
|
+
```"""
|
62
|
+
pass
|
63
|
+
|
64
|
+
@pytest.mark.parametrize("func", [foobar_good, foobar_also_good, admonition_edge_cases])
|
65
|
+
def test_base_docstrings(func):
|
66
|
+
check_docstring(func)
|
67
|
+
|
68
|
+
|
69
|
+
@pytest.mark.parametrize("func", [foobar_bad, adminition_edge_case_bad])
|
70
|
+
def test_base_docstrings_bad(func, capsys):
|
71
|
+
with pytest.raises(Exception):
|
72
|
+
check_docstring(func)
|
73
|
+
capsys.readouterr()
|
74
|
+
assert func.__name__ in capsys.readouterr().out
|
@@ -60,12 +60,27 @@ class Dinosaur:
|
|
60
60
|
"""
|
61
61
|
return self.name
|
62
62
|
|
63
|
+
def hfdocs_style(self, value):
|
64
|
+
"""
|
65
|
+
Returns value
|
66
|
+
|
67
|
+
Example:
|
68
|
+
|
69
|
+
```python
|
70
|
+
from dinosaur import Dinosaur
|
71
|
+
|
72
|
+
dino = Dinosaur()
|
73
|
+
assert dino.a(1) == 1
|
74
|
+
```
|
75
|
+
"""
|
76
|
+
return value
|
77
|
+
|
63
78
|
|
64
79
|
members = get_codeblock_members(Dinosaur)
|
65
80
|
|
66
81
|
|
67
82
|
def test_grab_methods():
|
68
|
-
assert len(get_codeblock_members(Dinosaur)) ==
|
83
|
+
assert len(get_codeblock_members(Dinosaur)) == 5
|
69
84
|
|
70
85
|
|
71
86
|
@pytest.mark.parametrize("obj", members, ids=lambda d: d.__qualname__)
|
@@ -0,0 +1,61 @@
|
|
1
|
+
import pytest
|
2
|
+
|
3
|
+
from mktestdocs import get_codeblock_members
|
4
|
+
from mktestdocs.__main__ import format_docstring
|
5
|
+
|
6
|
+
|
7
|
+
def test_docstring_formatted():
|
8
|
+
# given (a docstring not prepared for dedent)
|
9
|
+
docstring = "Some class with a header and a code block"
|
10
|
+
# when (we go through the format_docstring function)
|
11
|
+
formatted = format_docstring(docstring)
|
12
|
+
# then (a new line and tab are added to the docstring)
|
13
|
+
assert formatted == "\n Some class with a header and a code block"
|
14
|
+
|
15
|
+
def test_docstring_not_formatted():
|
16
|
+
# given (a docstring prepared for dedent)
|
17
|
+
docstring = "\n Some class with a header and a code block"
|
18
|
+
# when (we go through the format_docstring function)
|
19
|
+
formatted = format_docstring(docstring)
|
20
|
+
# then (the docstring doesn't change)
|
21
|
+
assert formatted == docstring
|
22
|
+
|
23
|
+
|
24
|
+
|
25
|
+
# The docstring of the first class starts like
|
26
|
+
# """Some class ...
|
27
|
+
# The docstring of the second class starts like
|
28
|
+
# """
|
29
|
+
# Some class ...
|
30
|
+
# The tests are checking that regardless of how the class docstring starts we should always be able to read the tests
|
31
|
+
class BadClass:
|
32
|
+
"""Some class with a header and a code block.
|
33
|
+
|
34
|
+
```python
|
35
|
+
assert False, "this should fail."
|
36
|
+
```
|
37
|
+
|
38
|
+
"""
|
39
|
+
def __init__(self):
|
40
|
+
pass
|
41
|
+
|
42
|
+
class BadClassNewLine:
|
43
|
+
"""
|
44
|
+
Some class with a header and a code block.
|
45
|
+
|
46
|
+
```python
|
47
|
+
assert False, "this should fail."
|
48
|
+
```
|
49
|
+
|
50
|
+
"""
|
51
|
+
def __init__(self):
|
52
|
+
pass
|
53
|
+
|
54
|
+
|
55
|
+
|
56
|
+
@pytest.mark.parametrize("cls", [BadClass, BadClassNewLine], ids=lambda d: d.__qualname__)
|
57
|
+
def test_grab_bad_methods(cls):
|
58
|
+
bad_members = get_codeblock_members(cls)
|
59
|
+
assert len(bad_members) == 1
|
60
|
+
|
61
|
+
|
@@ -2,9 +2,10 @@ import pathlib
|
|
2
2
|
|
3
3
|
from mktestdocs import check_md_file
|
4
4
|
|
5
|
+
|
5
6
|
def test_readme(monkeypatch):
|
6
7
|
test_dir = pathlib.Path(__file__).parent
|
7
8
|
fpath = test_dir.parent / "README.md"
|
8
9
|
monkeypatch.chdir(test_dir)
|
9
10
|
|
10
|
-
check_md_file(fpath=fpath)
|
11
|
+
check_md_file(fpath=fpath, memory=True)
|
mktestdocs-0.2.1/PKG-INFO
DELETED
@@ -1,15 +0,0 @@
|
|
1
|
-
LICENSE
|
2
|
-
README.md
|
3
|
-
setup.py
|
4
|
-
mktestdocs/__init__.py
|
5
|
-
mktestdocs/__main__.py
|
6
|
-
mktestdocs.egg-info/PKG-INFO
|
7
|
-
mktestdocs.egg-info/SOURCES.txt
|
8
|
-
mktestdocs.egg-info/dependency_links.txt
|
9
|
-
mktestdocs.egg-info/requires.txt
|
10
|
-
mktestdocs.egg-info/top_level.txt
|
11
|
-
tests/test_actual_docstrings.py
|
12
|
-
tests/test_class.py
|
13
|
-
tests/test_codeblock.py
|
14
|
-
tests/test_markdown.py
|
15
|
-
tests/test_mktestdocs.py
|
mktestdocs-0.2.1/setup.py
DELETED
@@ -1,14 +0,0 @@
|
|
1
|
-
from mktestdocs import __version__
|
2
|
-
from setuptools import setup, find_packages
|
3
|
-
|
4
|
-
test_packages = ["pytest>=4.0.2"]
|
5
|
-
|
6
|
-
setup(
|
7
|
-
name="mktestdocs",
|
8
|
-
version=__version__,
|
9
|
-
packages=find_packages(exclude=["tests"]),
|
10
|
-
install_requires=[],
|
11
|
-
extras_require={
|
12
|
-
"test": test_packages,
|
13
|
-
},
|
14
|
-
)
|
@@ -1,60 +0,0 @@
|
|
1
|
-
import pytest
|
2
|
-
from mktestdocs import check_docstring
|
3
|
-
|
4
|
-
|
5
|
-
def foobar_good(a, b):
|
6
|
-
"""
|
7
|
-
Returns a + b.
|
8
|
-
|
9
|
-
Examples:
|
10
|
-
|
11
|
-
```python
|
12
|
-
import random
|
13
|
-
|
14
|
-
random.random()
|
15
|
-
assert 'a' + 'b' == 'ab'
|
16
|
-
assert 1 + 2 == 3
|
17
|
-
```
|
18
|
-
"""
|
19
|
-
return a + b
|
20
|
-
|
21
|
-
|
22
|
-
def foobar_also_good(a, b):
|
23
|
-
"""
|
24
|
-
Returns a + b.
|
25
|
-
|
26
|
-
Examples:
|
27
|
-
|
28
|
-
```python
|
29
|
-
import random
|
30
|
-
|
31
|
-
assert random.random() < 10
|
32
|
-
```
|
33
|
-
"""
|
34
|
-
return a + b
|
35
|
-
|
36
|
-
|
37
|
-
def foobar_bad(a, b):
|
38
|
-
"""
|
39
|
-
Returns a + b.
|
40
|
-
|
41
|
-
Examples:
|
42
|
-
|
43
|
-
```python
|
44
|
-
assert foobar(1, 2) == 4
|
45
|
-
```
|
46
|
-
"""
|
47
|
-
return a + b
|
48
|
-
|
49
|
-
|
50
|
-
@pytest.mark.parametrize("func", [foobar_good, foobar_also_good])
|
51
|
-
def test_base_docstrings(func):
|
52
|
-
check_docstring(func)
|
53
|
-
|
54
|
-
|
55
|
-
@pytest.mark.parametrize("func", [foobar_bad])
|
56
|
-
def test_base_docstrings_bad(func, capsys):
|
57
|
-
with pytest.raises(Exception):
|
58
|
-
check_docstring(func)
|
59
|
-
capsys.readouterr()
|
60
|
-
assert func.__name__ in capsys.readouterr().out
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|