pytest-markdown-docs 0.6.0__tar.gz → 0.7.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.
- pytest_markdown_docs-0.7.0/Makefile +8 -0
- pytest_markdown_docs-0.6.0/README.md → pytest_markdown_docs-0.7.0/PKG-INFO +27 -1
- pytest_markdown_docs-0.6.0/PKG-INFO → pytest_markdown_docs-0.7.0/README.md +15 -14
- {pytest_markdown_docs-0.6.0 → pytest_markdown_docs-0.7.0}/pyproject.toml +1 -3
- pytest_markdown_docs-0.7.0/pytest-markdown-docs.iml +13 -0
- {pytest_markdown_docs-0.6.0 → pytest_markdown_docs-0.7.0}/src/pytest_markdown_docs/plugin.py +158 -83
- pytest_markdown_docs-0.7.0/tests/conftest.py +10 -0
- {pytest_markdown_docs-0.6.0 → pytest_markdown_docs-0.7.0}/tests/plugin_test.py +84 -3
- pytest_markdown_docs-0.7.0/tests/support/docstring_error_after.py +11 -0
- pytest_markdown_docs-0.7.0/tests/support/docstring_error_before.py +11 -0
- pytest_markdown_docs-0.6.0/poetry.lock +0 -410
- pytest_markdown_docs-0.6.0/poetry.toml +0 -3
- pytest_markdown_docs-0.6.0/tests/conftest.py +0 -1
- {pytest_markdown_docs-0.6.0 → pytest_markdown_docs-0.7.0}/.github/pull_request_template.md +0 -0
- {pytest_markdown_docs-0.6.0 → pytest_markdown_docs-0.7.0}/.github/workflows/check.yml +0 -0
- {pytest_markdown_docs-0.6.0 → pytest_markdown_docs-0.7.0}/.github/workflows/ci.yml +0 -0
- {pytest_markdown_docs-0.6.0 → pytest_markdown_docs-0.7.0}/.github/workflows/codeql.yml +0 -0
- {pytest_markdown_docs-0.6.0 → pytest_markdown_docs-0.7.0}/.gitignore +0 -0
- {pytest_markdown_docs-0.6.0 → pytest_markdown_docs-0.7.0}/.pre-commit-config.yaml +0 -0
- {pytest_markdown_docs-0.6.0 → pytest_markdown_docs-0.7.0}/LICENSE +0 -0
- {pytest_markdown_docs-0.6.0 → pytest_markdown_docs-0.7.0}/src/pytest_markdown_docs/__init__.py +0 -0
- {pytest_markdown_docs-0.6.0 → pytest_markdown_docs-0.7.0}/src/pytest_markdown_docs/hooks.py +0 -0
- {pytest_markdown_docs-0.6.0 → pytest_markdown_docs-0.7.0}/src/pytest_markdown_docs/py.typed +0 -0
- {pytest_markdown_docs-0.6.0 → pytest_markdown_docs-0.7.0}/uv.lock +0 -0
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: pytest-markdown-docs
|
|
3
|
+
Version: 0.7.0
|
|
4
|
+
Summary: Run markdown code fences through pytest
|
|
5
|
+
Author: Modal Labs
|
|
6
|
+
Author-email: Elias Freider <elias@modal.com>
|
|
7
|
+
License: MIT
|
|
8
|
+
Requires-Python: >=3.8
|
|
9
|
+
Requires-Dist: markdown-it-py<4.0,>=2.2.0
|
|
10
|
+
Requires-Dist: pytest>=7.0.0
|
|
11
|
+
Description-Content-Type: text/markdown
|
|
12
|
+
|
|
1
13
|
# Pytest Markdown Docs
|
|
2
14
|
|
|
3
15
|
A plugin for [pytest](https://docs.pytest.org) that uses markdown code snippets from markdown files and docstrings as tests.
|
|
@@ -136,6 +148,20 @@ assert a + " world" == "hello world"
|
|
|
136
148
|
```
|
|
137
149
|
````
|
|
138
150
|
|
|
151
|
+
### Compatibility with Material for MkDocs
|
|
152
|
+
|
|
153
|
+
Material for Mkdocs is not compatible with the default syntax.
|
|
154
|
+
|
|
155
|
+
But if the extension `pymdownx.superfences` is configured for mkdocs, the brace format can be used:
|
|
156
|
+
````markdown
|
|
157
|
+
```{.python continuation}
|
|
158
|
+
````
|
|
159
|
+
|
|
160
|
+
You will need to call pytest with the `--markdown-docs-syntax` option:
|
|
161
|
+
```shell
|
|
162
|
+
pytest --markdown-docs --markdown-docs-syntax=superfences
|
|
163
|
+
```
|
|
164
|
+
|
|
139
165
|
## MDX Comments for Metadata Options
|
|
140
166
|
In .mdx files, you can use MDX comments to provide additional options for code blocks. These comments should be placed immediately before the code block and take the following form:
|
|
141
167
|
|
|
@@ -175,4 +201,4 @@ Or for fun, you can use this plugin to include testing of the validity of snippe
|
|
|
175
201
|
* Line numbers are "wrong" for docstring-inlined snippets (since we don't know where in the file the docstring starts)
|
|
176
202
|
* Line numbers are "wrong" for continuation blocks even in pure markdown files (can be worked out with some refactoring)
|
|
177
203
|
* There are probably more appropriate ways to use pytest internal APIs to get more features "for free" - current state of the code is a bit "patch it til' it works".
|
|
178
|
-
* Assertions are not rewritten w/ pretty data structure inspection like they are with regular pytest tests by default
|
|
204
|
+
* Assertions are not rewritten w/ pretty data structure inspection like they are with regular pytest tests by default
|
|
@@ -1,16 +1,3 @@
|
|
|
1
|
-
Metadata-Version: 2.3
|
|
2
|
-
Name: pytest-markdown-docs
|
|
3
|
-
Version: 0.6.0
|
|
4
|
-
Summary: Run markdown code fences through pytest
|
|
5
|
-
Author: Modal Labs
|
|
6
|
-
Author-email: Elias Freider <elias@modal.com>
|
|
7
|
-
License-Expression: MIT
|
|
8
|
-
License-File: LICENSE
|
|
9
|
-
Requires-Python: >=3.8
|
|
10
|
-
Requires-Dist: markdown-it-py<4.0,>=2.2.0
|
|
11
|
-
Requires-Dist: pytest>=7.0.0
|
|
12
|
-
Description-Content-Type: text/markdown
|
|
13
|
-
|
|
14
1
|
# Pytest Markdown Docs
|
|
15
2
|
|
|
16
3
|
A plugin for [pytest](https://docs.pytest.org) that uses markdown code snippets from markdown files and docstrings as tests.
|
|
@@ -149,6 +136,20 @@ assert a + " world" == "hello world"
|
|
|
149
136
|
```
|
|
150
137
|
````
|
|
151
138
|
|
|
139
|
+
### Compatibility with Material for MkDocs
|
|
140
|
+
|
|
141
|
+
Material for Mkdocs is not compatible with the default syntax.
|
|
142
|
+
|
|
143
|
+
But if the extension `pymdownx.superfences` is configured for mkdocs, the brace format can be used:
|
|
144
|
+
````markdown
|
|
145
|
+
```{.python continuation}
|
|
146
|
+
````
|
|
147
|
+
|
|
148
|
+
You will need to call pytest with the `--markdown-docs-syntax` option:
|
|
149
|
+
```shell
|
|
150
|
+
pytest --markdown-docs --markdown-docs-syntax=superfences
|
|
151
|
+
```
|
|
152
|
+
|
|
152
153
|
## MDX Comments for Metadata Options
|
|
153
154
|
In .mdx files, you can use MDX comments to provide additional options for code blocks. These comments should be placed immediately before the code block and take the following form:
|
|
154
155
|
|
|
@@ -188,4 +189,4 @@ Or for fun, you can use this plugin to include testing of the validity of snippe
|
|
|
188
189
|
* Line numbers are "wrong" for docstring-inlined snippets (since we don't know where in the file the docstring starts)
|
|
189
190
|
* Line numbers are "wrong" for continuation blocks even in pure markdown files (can be worked out with some refactoring)
|
|
190
191
|
* There are probably more appropriate ways to use pytest internal APIs to get more features "for free" - current state of the code is a bit "patch it til' it works".
|
|
191
|
-
* Assertions are not rewritten w/ pretty data structure inspection like they are with regular pytest tests by default
|
|
192
|
+
* Assertions are not rewritten w/ pretty data structure inspection like they are with regular pytest tests by default
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "pytest-markdown-docs"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.7.0"
|
|
4
4
|
description = "Run markdown code fences through pytest"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
authors = [
|
|
@@ -30,5 +30,3 @@ dev-dependencies = [
|
|
|
30
30
|
"pytest~=8.1.0",
|
|
31
31
|
"ruff>=0.7.0",
|
|
32
32
|
]
|
|
33
|
-
|
|
34
|
-
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<module type="WEB_MODULE" version="4">
|
|
3
|
+
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
|
4
|
+
<exclude-output />
|
|
5
|
+
<content url="file://$MODULE_DIR$">
|
|
6
|
+
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
|
7
|
+
<sourceFolder url="file://$MODULE_DIR$/tests" isTestSource="true" />
|
|
8
|
+
<excludeFolder url="file://$MODULE_DIR$/dist" />
|
|
9
|
+
</content>
|
|
10
|
+
<orderEntry type="inheritedJdk" />
|
|
11
|
+
<orderEntry type="sourceFolder" forTests="false" />
|
|
12
|
+
</component>
|
|
13
|
+
</module>
|
{pytest_markdown_docs-0.6.0 → pytest_markdown_docs-0.7.0}/src/pytest_markdown_docs/plugin.py
RENAMED
|
@@ -3,12 +3,17 @@ import inspect
|
|
|
3
3
|
import traceback
|
|
4
4
|
import types
|
|
5
5
|
import pathlib
|
|
6
|
+
from dataclasses import dataclass
|
|
7
|
+
|
|
6
8
|
import pytest
|
|
7
9
|
import typing
|
|
10
|
+
from enum import Enum
|
|
8
11
|
|
|
9
12
|
from _pytest._code import ExceptionInfo
|
|
10
13
|
from _pytest.config.argparsing import Parser
|
|
11
14
|
from _pytest.pathlib import import_path
|
|
15
|
+
import logging
|
|
16
|
+
|
|
12
17
|
from pytest_markdown_docs import hooks
|
|
13
18
|
|
|
14
19
|
|
|
@@ -22,9 +27,43 @@ else:
|
|
|
22
27
|
if typing.TYPE_CHECKING:
|
|
23
28
|
from markdown_it.token import Token
|
|
24
29
|
|
|
30
|
+
logger = logging.getLogger("pytest-markdown-docs")
|
|
31
|
+
|
|
25
32
|
MARKER_NAME = "markdown-docs"
|
|
26
33
|
|
|
27
34
|
|
|
35
|
+
class FenceSyntax(Enum):
|
|
36
|
+
default = "default"
|
|
37
|
+
superfences = "superfences"
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@dataclass
|
|
41
|
+
class FenceTest:
|
|
42
|
+
source: str
|
|
43
|
+
fixture_names: typing.List[str]
|
|
44
|
+
start_line: int
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
@dataclass
|
|
48
|
+
class ObjectTest:
|
|
49
|
+
intra_object_index: int
|
|
50
|
+
object_name: str
|
|
51
|
+
fence_test: FenceTest
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def get_docstring_start_line(obj) -> typing.Optional[int]:
|
|
55
|
+
# Get the source lines and the starting line number of the object
|
|
56
|
+
source_lines, start_line = inspect.getsourcelines(obj)
|
|
57
|
+
|
|
58
|
+
# Find the line in the source code that starts with triple quotes (""" or ''')
|
|
59
|
+
for idx, line in enumerate(source_lines):
|
|
60
|
+
line = line.strip()
|
|
61
|
+
if line.startswith(('"""', "'''")):
|
|
62
|
+
return start_line + idx # Return the starting line number
|
|
63
|
+
|
|
64
|
+
return None # Docstring not found in source
|
|
65
|
+
|
|
66
|
+
|
|
28
67
|
class MarkdownInlinePythonItem(pytest.Item):
|
|
29
68
|
def __init__(
|
|
30
69
|
self,
|
|
@@ -33,7 +72,6 @@ class MarkdownInlinePythonItem(pytest.Item):
|
|
|
33
72
|
code: str,
|
|
34
73
|
fixture_names: typing.List[str],
|
|
35
74
|
start_line: int,
|
|
36
|
-
fake_line_numbers: bool,
|
|
37
75
|
) -> None:
|
|
38
76
|
super().__init__(name, parent)
|
|
39
77
|
self.add_marker(MARKER_NAME)
|
|
@@ -41,7 +79,6 @@ class MarkdownInlinePythonItem(pytest.Item):
|
|
|
41
79
|
self.obj = None
|
|
42
80
|
self.user_properties.append(("code", code))
|
|
43
81
|
self.start_line = start_line
|
|
44
|
-
self.fake_line_numbers = fake_line_numbers
|
|
45
82
|
self.fixturenames = fixture_names
|
|
46
83
|
self.nofuncargs = True
|
|
47
84
|
|
|
@@ -93,58 +130,47 @@ class MarkdownInlinePythonItem(pytest.Item):
|
|
|
93
130
|
excinfo: ExceptionInfo[BaseException],
|
|
94
131
|
style=None,
|
|
95
132
|
):
|
|
96
|
-
rawlines = self.code.split("\n")
|
|
133
|
+
rawlines = self.code.rstrip("\n").split("\n")
|
|
97
134
|
|
|
98
135
|
# custom formatted traceback to translate line numbers and markdown files
|
|
99
136
|
traceback_lines = []
|
|
100
137
|
stack_summary = traceback.StackSummary.extract(traceback.walk_tb(excinfo.tb))
|
|
101
138
|
start_capture = False
|
|
102
139
|
|
|
103
|
-
start_line =
|
|
140
|
+
start_line = self.start_line
|
|
104
141
|
|
|
105
142
|
for frame_summary in stack_summary:
|
|
106
143
|
if frame_summary.filename == str(self.path):
|
|
107
|
-
|
|
108
|
-
start_capture =
|
|
109
|
-
True # start capturing frames the first time we enter user code
|
|
110
|
-
)
|
|
111
|
-
line = (
|
|
112
|
-
rawlines[frame_summary.lineno - 1] if frame_summary.lineno else ""
|
|
113
|
-
)
|
|
114
|
-
else:
|
|
115
|
-
lineno = frame_summary.lineno or 0
|
|
116
|
-
line = frame_summary.line or ""
|
|
144
|
+
# start capturing frames the first time we enter user code
|
|
145
|
+
start_capture = True
|
|
117
146
|
|
|
118
147
|
if start_capture:
|
|
148
|
+
lineno = frame_summary.lineno
|
|
149
|
+
line = frame_summary.line or ""
|
|
119
150
|
linespec = f"line {lineno}"
|
|
120
|
-
if self.fake_line_numbers:
|
|
121
|
-
linespec = f"code block line {lineno}*"
|
|
122
|
-
|
|
123
151
|
traceback_lines.append(
|
|
124
152
|
f""" File "{frame_summary.filename}", {linespec}, in {frame_summary.name}"""
|
|
125
153
|
)
|
|
126
154
|
traceback_lines.append(f" {line.lstrip()}")
|
|
127
155
|
|
|
128
|
-
|
|
156
|
+
maxdigits = len(str(len(rawlines)))
|
|
157
|
+
code_margin = " "
|
|
129
158
|
numbered_code = "\n".join(
|
|
130
159
|
[
|
|
131
|
-
f"{i:>{
|
|
132
|
-
for i, line in enumerate(rawlines, start_line + 1)
|
|
160
|
+
f"{i:>{maxdigits}}{code_margin}{line}"
|
|
161
|
+
for i, line in enumerate(rawlines[start_line:], start_line + 1)
|
|
133
162
|
]
|
|
134
163
|
)
|
|
135
164
|
|
|
136
165
|
pretty_traceback = "\n".join(traceback_lines)
|
|
137
|
-
|
|
138
|
-
if self.fake_line_numbers:
|
|
139
|
-
note = ", *-denoted line numbers refer to code block"
|
|
140
|
-
pt = f"""Traceback (most recent call last{note}):
|
|
166
|
+
pt = f"""Traceback (most recent call last):
|
|
141
167
|
{pretty_traceback}
|
|
142
168
|
{excinfo.exconly()}"""
|
|
143
169
|
|
|
144
170
|
return f"""Error in code block:
|
|
145
|
-
```
|
|
171
|
+
{maxdigits * " "}{code_margin}```
|
|
146
172
|
{numbered_code}
|
|
147
|
-
```
|
|
173
|
+
{maxdigits * " "}{code_margin}```
|
|
148
174
|
{pt}
|
|
149
175
|
"""
|
|
150
176
|
|
|
@@ -152,10 +178,12 @@ class MarkdownInlinePythonItem(pytest.Item):
|
|
|
152
178
|
return self.name, 0, self.nodeid
|
|
153
179
|
|
|
154
180
|
|
|
155
|
-
def
|
|
181
|
+
def extract_fence_tests(
|
|
156
182
|
markdown_string: str,
|
|
183
|
+
start_line_offset: int,
|
|
157
184
|
markdown_type: str = "md",
|
|
158
|
-
|
|
185
|
+
fence_syntax: FenceSyntax = FenceSyntax.default,
|
|
186
|
+
) -> typing.Generator[FenceTest, None, None]:
|
|
159
187
|
import markdown_it
|
|
160
188
|
|
|
161
189
|
mi = markdown_it.MarkdownIt(config="commonmark")
|
|
@@ -166,8 +194,10 @@ def extract_code_blocks(
|
|
|
166
194
|
if block.type != "fence" or not block.map:
|
|
167
195
|
continue
|
|
168
196
|
|
|
169
|
-
|
|
170
|
-
|
|
197
|
+
if fence_syntax == FenceSyntax.superfences:
|
|
198
|
+
code_info = parse_superfences_block_info(block.info)
|
|
199
|
+
else:
|
|
200
|
+
code_info = block.info.split()
|
|
171
201
|
|
|
172
202
|
lang = code_info[0] if code_info else None
|
|
173
203
|
code_options = set(code_info) - {lang}
|
|
@@ -187,19 +217,50 @@ def extract_code_blocks(
|
|
|
187
217
|
code_options |= extract_options_from_mdx_comment(tokens[i - 2].content)
|
|
188
218
|
|
|
189
219
|
if lang in ("py", "python", "python3") and "notest" not in code_options:
|
|
190
|
-
|
|
220
|
+
start_line = (
|
|
221
|
+
start_line_offset + block.map[0] + 1
|
|
222
|
+
) # actual code starts on +1 from the "info" line
|
|
223
|
+
if "continuation" not in code_options:
|
|
224
|
+
prev = ""
|
|
191
225
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
startline = -1 # this disables proper line numbers, TODO: adjust line numbers *per snippet*
|
|
226
|
+
add_blank_lines = start_line - prev.count("\n")
|
|
227
|
+
code_block = prev + ("\n" * add_blank_lines) + block.content
|
|
195
228
|
|
|
196
229
|
fixture_names = [
|
|
197
230
|
f[len("fixture:") :] for f in code_options if f.startswith("fixture:")
|
|
198
231
|
]
|
|
199
|
-
yield code_block, fixture_names,
|
|
232
|
+
yield FenceTest(code_block, fixture_names, start_line)
|
|
200
233
|
prev = code_block
|
|
201
234
|
|
|
202
235
|
|
|
236
|
+
def parse_superfences_block_info(block_info: str) -> typing.List[str]:
|
|
237
|
+
"""Parse PyMdown Superfences block info syntax.
|
|
238
|
+
|
|
239
|
+
The default `python continuation` format is not compatible with Material for Mkdocs.
|
|
240
|
+
But, PyMdown Superfences has a special brace format to add options to code fence blocks: `{.<lang> <option1> <option2>}`.
|
|
241
|
+
|
|
242
|
+
This function also works if the default syntax is used to allow for mixed usage.
|
|
243
|
+
"""
|
|
244
|
+
block_info = block_info.strip()
|
|
245
|
+
|
|
246
|
+
if not block_info.startswith("{"):
|
|
247
|
+
# default syntax
|
|
248
|
+
return block_info.split()
|
|
249
|
+
|
|
250
|
+
block_info = block_info.strip("{}")
|
|
251
|
+
code_info = block_info.split()
|
|
252
|
+
# Lang may not be the first but is always the first element that starts with a dot.
|
|
253
|
+
# (https://facelessuser.github.io/pymdown-extensions/extensions/superfences/#injecting-classes-ids-and-attributes)
|
|
254
|
+
dot_lang = next(
|
|
255
|
+
(info_part for info_part in code_info if info_part.startswith(".")), None
|
|
256
|
+
)
|
|
257
|
+
if dot_lang:
|
|
258
|
+
code_info.remove(dot_lang)
|
|
259
|
+
lang = dot_lang[1:]
|
|
260
|
+
code_info.insert(0, lang)
|
|
261
|
+
return code_info
|
|
262
|
+
|
|
263
|
+
|
|
203
264
|
def is_mdx_comment(block: "Token") -> bool:
|
|
204
265
|
return (
|
|
205
266
|
block.type == "inline"
|
|
@@ -219,29 +280,6 @@ def extract_options_from_mdx_comment(comment: str) -> typing.Set[str]:
|
|
|
219
280
|
return set(option.strip() for option in comment.split(" ") if option)
|
|
220
281
|
|
|
221
282
|
|
|
222
|
-
def find_object_tests_recursive(
|
|
223
|
-
module_name: str, object: typing.Any
|
|
224
|
-
) -> typing.Generator[
|
|
225
|
-
typing.Tuple[int, typing.Any, typing.Tuple[str, typing.List[str], int]], None, None
|
|
226
|
-
]:
|
|
227
|
-
docstr = inspect.getdoc(object)
|
|
228
|
-
|
|
229
|
-
if docstr:
|
|
230
|
-
for i, code_block in enumerate(extract_code_blocks(docstr)):
|
|
231
|
-
yield i, object, code_block
|
|
232
|
-
|
|
233
|
-
for member_name, member in inspect.getmembers(object):
|
|
234
|
-
if member_name.startswith("_"):
|
|
235
|
-
continue
|
|
236
|
-
|
|
237
|
-
if (
|
|
238
|
-
inspect.isclass(member)
|
|
239
|
-
or inspect.isfunction(member)
|
|
240
|
-
or inspect.ismethod(member)
|
|
241
|
-
) and member.__module__ == module_name:
|
|
242
|
-
yield from find_object_tests_recursive(module_name, member)
|
|
243
|
-
|
|
244
|
-
|
|
245
283
|
class MarkdownDocstringCodeModule(pytest.Module):
|
|
246
284
|
def collect(self):
|
|
247
285
|
if pytest.version_tuple >= (8, 1, 0):
|
|
@@ -250,45 +288,74 @@ class MarkdownDocstringCodeModule(pytest.Module):
|
|
|
250
288
|
self.path, root=self.config.rootpath, consider_namespace_packages=True
|
|
251
289
|
)
|
|
252
290
|
else:
|
|
253
|
-
# but unsupported before 8.1...
|
|
291
|
+
# but unsupported before pytest 8.1...
|
|
254
292
|
module = import_path(self.path, root=self.config.rootpath)
|
|
255
293
|
|
|
256
|
-
for
|
|
257
|
-
|
|
258
|
-
fixture_names,
|
|
259
|
-
start_line,
|
|
260
|
-
) in find_object_tests_recursive(module.__name__, module):
|
|
261
|
-
obj_name = (
|
|
262
|
-
getattr(obj, "__qualname__", None)
|
|
263
|
-
or getattr(obj, "__name__", None)
|
|
264
|
-
or "<Unnamed obj>"
|
|
265
|
-
)
|
|
294
|
+
for object_test in self.find_object_tests_recursive(module.__name__, module):
|
|
295
|
+
fence_test = object_test.fence_test
|
|
266
296
|
yield MarkdownInlinePythonItem.from_parent(
|
|
267
297
|
self,
|
|
268
|
-
name=f"{
|
|
269
|
-
code=
|
|
270
|
-
fixture_names=fixture_names,
|
|
271
|
-
start_line=start_line,
|
|
272
|
-
fake_line_numbers=True, # TODO: figure out where docstrings are in file to offset line numbers properly
|
|
298
|
+
name=f"{object_test.object_name}[CodeFence#{object_test.intra_object_index+1}][line:{fence_test.start_line}]",
|
|
299
|
+
code=fence_test.source,
|
|
300
|
+
fixture_names=fence_test.fixture_names,
|
|
301
|
+
start_line=fence_test.start_line,
|
|
273
302
|
)
|
|
274
303
|
|
|
304
|
+
def find_object_tests_recursive(
|
|
305
|
+
self, module_name: str, object: typing.Any
|
|
306
|
+
) -> typing.Generator[ObjectTest, None, None]:
|
|
307
|
+
docstr = inspect.getdoc(object)
|
|
308
|
+
|
|
309
|
+
if docstr:
|
|
310
|
+
docstring_offset = get_docstring_start_line(object)
|
|
311
|
+
if docstring_offset is None:
|
|
312
|
+
logger.warning(
|
|
313
|
+
"Could not find line number offset for docstring: {docstr}"
|
|
314
|
+
)
|
|
315
|
+
docstring_offset = 0
|
|
316
|
+
|
|
317
|
+
obj_name = (
|
|
318
|
+
getattr(object, "__qualname__", None)
|
|
319
|
+
or getattr(object, "__name__", None)
|
|
320
|
+
or "<Unnamed obj>"
|
|
321
|
+
)
|
|
322
|
+
fence_syntax = FenceSyntax(self.config.option.markdowndocs_syntax)
|
|
323
|
+
for i, fence_test in enumerate(
|
|
324
|
+
extract_fence_tests(docstr, docstring_offset, fence_syntax=fence_syntax)
|
|
325
|
+
):
|
|
326
|
+
yield ObjectTest(i, obj_name, fence_test)
|
|
327
|
+
|
|
328
|
+
for member_name, member in inspect.getmembers(object):
|
|
329
|
+
if member_name.startswith("_"):
|
|
330
|
+
continue
|
|
331
|
+
|
|
332
|
+
if (
|
|
333
|
+
inspect.isclass(member)
|
|
334
|
+
or inspect.isfunction(member)
|
|
335
|
+
or inspect.ismethod(member)
|
|
336
|
+
) and member.__module__ == module_name:
|
|
337
|
+
yield from self.find_object_tests_recursive(module_name, member)
|
|
338
|
+
|
|
275
339
|
|
|
276
340
|
class MarkdownTextFile(pytest.File):
|
|
277
341
|
def collect(self):
|
|
278
342
|
markdown_content = self.path.read_text("utf8")
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
343
|
+
fence_syntax = FenceSyntax(self.config.option.markdowndocs_syntax)
|
|
344
|
+
|
|
345
|
+
for i, fence_test in enumerate(
|
|
346
|
+
extract_fence_tests(
|
|
347
|
+
markdown_content,
|
|
348
|
+
start_line_offset=0,
|
|
349
|
+
markdown_type=self.path.suffix.replace(".", ""),
|
|
350
|
+
fence_syntax=fence_syntax,
|
|
283
351
|
)
|
|
284
352
|
):
|
|
285
353
|
yield MarkdownInlinePythonItem.from_parent(
|
|
286
354
|
self,
|
|
287
|
-
name=f"[
|
|
288
|
-
code=
|
|
289
|
-
fixture_names=fixture_names,
|
|
290
|
-
start_line=start_line,
|
|
291
|
-
fake_line_numbers=start_line == -1,
|
|
355
|
+
name=f"[CodeFence#{i+1}][line:{fence_test.start_line}]",
|
|
356
|
+
code=fence_test.source,
|
|
357
|
+
fixture_names=fence_test.fixture_names,
|
|
358
|
+
start_line=fence_test.start_line,
|
|
292
359
|
)
|
|
293
360
|
|
|
294
361
|
|
|
@@ -321,6 +388,14 @@ def pytest_addoption(parser: Parser) -> None:
|
|
|
321
388
|
help="run ",
|
|
322
389
|
dest="markdowndocs",
|
|
323
390
|
)
|
|
391
|
+
group.addoption(
|
|
392
|
+
"--markdown-docs-syntax",
|
|
393
|
+
action="store",
|
|
394
|
+
choices=[choice.value for choice in FenceSyntax],
|
|
395
|
+
default="default",
|
|
396
|
+
help="Choose an alternative fences syntax",
|
|
397
|
+
dest="markdowndocs_syntax",
|
|
398
|
+
)
|
|
324
399
|
|
|
325
400
|
|
|
326
401
|
def pytest_addhooks(pluginmanager):
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import re
|
|
2
|
+
|
|
3
|
+
from _pytest.pytester import LineMatcher
|
|
4
|
+
|
|
2
5
|
import pytest_markdown_docs # hack: used for storing a side effect in one of the tests
|
|
3
6
|
|
|
4
7
|
|
|
@@ -122,7 +125,7 @@ def test_traceback(testdir):
|
|
|
122
125
|
# we check the traceback vs a regex pattern since the file paths can change
|
|
123
126
|
expected_output_pattern = r"""
|
|
124
127
|
Error in code block:
|
|
125
|
-
```
|
|
128
|
+
```
|
|
126
129
|
4 def foo\(\):
|
|
127
130
|
5 raise Exception\("doh"\)
|
|
128
131
|
6
|
|
@@ -130,8 +133,7 @@ Error in code block:
|
|
|
130
133
|
8 foo\(\)
|
|
131
134
|
9
|
|
132
135
|
10 foo\(\)
|
|
133
|
-
|
|
134
|
-
```
|
|
136
|
+
```
|
|
135
137
|
Traceback \(most recent call last\):
|
|
136
138
|
File ".*/test_traceback.md", line 10, in <module>
|
|
137
139
|
foo\(\)
|
|
@@ -350,3 +352,82 @@ def test_notest_mdx_comment(testdir):
|
|
|
350
352
|
)
|
|
351
353
|
result = testdir.runpytest("--markdown-docs")
|
|
352
354
|
result.assert_outcomes(passed=0)
|
|
355
|
+
|
|
356
|
+
|
|
357
|
+
def test_superfences_format_markdown(testdir):
|
|
358
|
+
testdir.makefile(
|
|
359
|
+
".md",
|
|
360
|
+
"""
|
|
361
|
+
```python
|
|
362
|
+
b = "hello"
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
```{.python continuation}
|
|
366
|
+
assert b + " world" == "hello world"
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
# the lang may not be the first element
|
|
370
|
+
```{other_option .python .other-class continuation}
|
|
371
|
+
assert b + " world" == "hello world"
|
|
372
|
+
```
|
|
373
|
+
""",
|
|
374
|
+
)
|
|
375
|
+
result = testdir.runpytest("--markdown-docs", "--markdown-docs-syntax=superfences")
|
|
376
|
+
result.assert_outcomes(passed=3)
|
|
377
|
+
|
|
378
|
+
|
|
379
|
+
def test_superfences_format_docstring(testdir):
|
|
380
|
+
testdir.makepyfile(
|
|
381
|
+
"""
|
|
382
|
+
def simple():
|
|
383
|
+
\"\"\"
|
|
384
|
+
```python
|
|
385
|
+
b = "hello"
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
```{.python continuation}
|
|
389
|
+
assert b + " world" == "hello world"
|
|
390
|
+
```
|
|
391
|
+
\"\"\"
|
|
392
|
+
"""
|
|
393
|
+
)
|
|
394
|
+
result = testdir.runpytest("--markdown-docs", "--markdown-docs-syntax=superfences")
|
|
395
|
+
result.assert_outcomes(passed=2)
|
|
396
|
+
|
|
397
|
+
|
|
398
|
+
def test_error_origin_after_docstring_traceback(testdir, support_dir):
|
|
399
|
+
sample_file = support_dir / "docstring_error_after.py"
|
|
400
|
+
testdir.makepyfile(**{sample_file.stem: sample_file.read_text()})
|
|
401
|
+
result = testdir.runpytest("-v", "--markdown-docs")
|
|
402
|
+
|
|
403
|
+
data: LineMatcher = result.stdout
|
|
404
|
+
data.re_match_lines(
|
|
405
|
+
[
|
|
406
|
+
r"Traceback \(most recent call last\):",
|
|
407
|
+
r'\s*File ".*/docstring_error_after.py", line 5, in <module>',
|
|
408
|
+
r"\s*docstring_error_after.error_after\(\)",
|
|
409
|
+
r'\s*File ".*/docstring_error_after.py", line 11, in error_after',
|
|
410
|
+
r'\s*raise Exception\("bar"\)',
|
|
411
|
+
r"\s*Exception: bar",
|
|
412
|
+
],
|
|
413
|
+
consecutive=True,
|
|
414
|
+
)
|
|
415
|
+
|
|
416
|
+
|
|
417
|
+
def test_error_origin_before_docstring_traceback(testdir, support_dir):
|
|
418
|
+
sample_file = support_dir / "docstring_error_before.py"
|
|
419
|
+
testdir.makepyfile(**{sample_file.stem: sample_file.read_text()})
|
|
420
|
+
result = testdir.runpytest("-v", "--markdown-docs")
|
|
421
|
+
|
|
422
|
+
data: LineMatcher = result.stdout
|
|
423
|
+
data.re_match_lines(
|
|
424
|
+
[
|
|
425
|
+
r"Traceback \(most recent call last\):",
|
|
426
|
+
r'\s*File ".*/docstring_error_before.py", line 9, in <module>',
|
|
427
|
+
r"\s*docstring_error_before.error_before\(\)",
|
|
428
|
+
r'\s*File ".*/docstring_error_before.py", line 2, in error_before',
|
|
429
|
+
r'\s*raise Exception\("foo"\)',
|
|
430
|
+
r"\s*Exception: foo",
|
|
431
|
+
],
|
|
432
|
+
consecutive=True,
|
|
433
|
+
)
|
|
@@ -1,410 +0,0 @@
|
|
|
1
|
-
# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand.
|
|
2
|
-
|
|
3
|
-
[[package]]
|
|
4
|
-
name = "cfgv"
|
|
5
|
-
version = "3.4.0"
|
|
6
|
-
description = "Validate configuration and produce human readable error messages."
|
|
7
|
-
optional = false
|
|
8
|
-
python-versions = ">=3.8"
|
|
9
|
-
files = [
|
|
10
|
-
{file = "cfgv-3.4.0-py2.py3-none-any.whl", hash = "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9"},
|
|
11
|
-
{file = "cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560"},
|
|
12
|
-
]
|
|
13
|
-
|
|
14
|
-
[[package]]
|
|
15
|
-
name = "colorama"
|
|
16
|
-
version = "0.4.6"
|
|
17
|
-
description = "Cross-platform colored terminal text."
|
|
18
|
-
optional = false
|
|
19
|
-
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
|
|
20
|
-
files = [
|
|
21
|
-
{file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"},
|
|
22
|
-
{file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
|
|
23
|
-
]
|
|
24
|
-
|
|
25
|
-
[[package]]
|
|
26
|
-
name = "distlib"
|
|
27
|
-
version = "0.3.8"
|
|
28
|
-
description = "Distribution utilities"
|
|
29
|
-
optional = false
|
|
30
|
-
python-versions = "*"
|
|
31
|
-
files = [
|
|
32
|
-
{file = "distlib-0.3.8-py2.py3-none-any.whl", hash = "sha256:034db59a0b96f8ca18035f36290806a9a6e6bd9d1ff91e45a7f172eb17e51784"},
|
|
33
|
-
{file = "distlib-0.3.8.tar.gz", hash = "sha256:1530ea13e350031b6312d8580ddb6b27a104275a31106523b8f123787f494f64"},
|
|
34
|
-
]
|
|
35
|
-
|
|
36
|
-
[[package]]
|
|
37
|
-
name = "exceptiongroup"
|
|
38
|
-
version = "1.2.2"
|
|
39
|
-
description = "Backport of PEP 654 (exception groups)"
|
|
40
|
-
optional = false
|
|
41
|
-
python-versions = ">=3.7"
|
|
42
|
-
files = [
|
|
43
|
-
{file = "exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b"},
|
|
44
|
-
{file = "exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc"},
|
|
45
|
-
]
|
|
46
|
-
|
|
47
|
-
[package.extras]
|
|
48
|
-
test = ["pytest (>=6)"]
|
|
49
|
-
|
|
50
|
-
[[package]]
|
|
51
|
-
name = "filelock"
|
|
52
|
-
version = "3.16.1"
|
|
53
|
-
description = "A platform independent file lock."
|
|
54
|
-
optional = false
|
|
55
|
-
python-versions = ">=3.8"
|
|
56
|
-
files = [
|
|
57
|
-
{file = "filelock-3.16.1-py3-none-any.whl", hash = "sha256:2082e5703d51fbf98ea75855d9d5527e33d8ff23099bec374a134febee6946b0"},
|
|
58
|
-
{file = "filelock-3.16.1.tar.gz", hash = "sha256:c249fbfcd5db47e5e2d6d62198e565475ee65e4831e2561c8e313fa7eb961435"},
|
|
59
|
-
]
|
|
60
|
-
|
|
61
|
-
[package.extras]
|
|
62
|
-
docs = ["furo (>=2024.8.6)", "sphinx (>=8.0.2)", "sphinx-autodoc-typehints (>=2.4.1)"]
|
|
63
|
-
testing = ["covdefaults (>=2.3)", "coverage (>=7.6.1)", "diff-cover (>=9.2)", "pytest (>=8.3.3)", "pytest-asyncio (>=0.24)", "pytest-cov (>=5)", "pytest-mock (>=3.14)", "pytest-timeout (>=2.3.1)", "virtualenv (>=20.26.4)"]
|
|
64
|
-
typing = ["typing-extensions (>=4.12.2)"]
|
|
65
|
-
|
|
66
|
-
[[package]]
|
|
67
|
-
name = "identify"
|
|
68
|
-
version = "2.6.1"
|
|
69
|
-
description = "File identification library for Python"
|
|
70
|
-
optional = false
|
|
71
|
-
python-versions = ">=3.8"
|
|
72
|
-
files = [
|
|
73
|
-
{file = "identify-2.6.1-py2.py3-none-any.whl", hash = "sha256:53863bcac7caf8d2ed85bd20312ea5dcfc22226800f6d6881f232d861db5a8f0"},
|
|
74
|
-
{file = "identify-2.6.1.tar.gz", hash = "sha256:91478c5fb7c3aac5ff7bf9b4344f803843dc586832d5f110d672b19aa1984c98"},
|
|
75
|
-
]
|
|
76
|
-
|
|
77
|
-
[package.extras]
|
|
78
|
-
license = ["ukkonen"]
|
|
79
|
-
|
|
80
|
-
[[package]]
|
|
81
|
-
name = "iniconfig"
|
|
82
|
-
version = "2.0.0"
|
|
83
|
-
description = "brain-dead simple config-ini parsing"
|
|
84
|
-
optional = false
|
|
85
|
-
python-versions = ">=3.7"
|
|
86
|
-
files = [
|
|
87
|
-
{file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"},
|
|
88
|
-
{file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"},
|
|
89
|
-
]
|
|
90
|
-
|
|
91
|
-
[[package]]
|
|
92
|
-
name = "markdown-it-py"
|
|
93
|
-
version = "3.0.0"
|
|
94
|
-
description = "Python port of markdown-it. Markdown parsing, done right!"
|
|
95
|
-
optional = false
|
|
96
|
-
python-versions = ">=3.8"
|
|
97
|
-
files = [
|
|
98
|
-
{file = "markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb"},
|
|
99
|
-
{file = "markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1"},
|
|
100
|
-
]
|
|
101
|
-
|
|
102
|
-
[package.dependencies]
|
|
103
|
-
mdurl = ">=0.1,<1.0"
|
|
104
|
-
|
|
105
|
-
[package.extras]
|
|
106
|
-
benchmarking = ["psutil", "pytest", "pytest-benchmark"]
|
|
107
|
-
code-style = ["pre-commit (>=3.0,<4.0)"]
|
|
108
|
-
compare = ["commonmark (>=0.9,<1.0)", "markdown (>=3.4,<4.0)", "mistletoe (>=1.0,<2.0)", "mistune (>=2.0,<3.0)", "panflute (>=2.3,<3.0)"]
|
|
109
|
-
linkify = ["linkify-it-py (>=1,<3)"]
|
|
110
|
-
plugins = ["mdit-py-plugins"]
|
|
111
|
-
profiling = ["gprof2dot"]
|
|
112
|
-
rtd = ["jupyter_sphinx", "mdit-py-plugins", "myst-parser", "pyyaml", "sphinx", "sphinx-copybutton", "sphinx-design", "sphinx_book_theme"]
|
|
113
|
-
testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"]
|
|
114
|
-
|
|
115
|
-
[[package]]
|
|
116
|
-
name = "mdurl"
|
|
117
|
-
version = "0.1.2"
|
|
118
|
-
description = "Markdown URL utilities"
|
|
119
|
-
optional = false
|
|
120
|
-
python-versions = ">=3.7"
|
|
121
|
-
files = [
|
|
122
|
-
{file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"},
|
|
123
|
-
{file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"},
|
|
124
|
-
]
|
|
125
|
-
|
|
126
|
-
[[package]]
|
|
127
|
-
name = "mypy"
|
|
128
|
-
version = "1.11.2"
|
|
129
|
-
description = "Optional static typing for Python"
|
|
130
|
-
optional = false
|
|
131
|
-
python-versions = ">=3.8"
|
|
132
|
-
files = [
|
|
133
|
-
{file = "mypy-1.11.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d42a6dd818ffce7be66cce644f1dff482f1d97c53ca70908dff0b9ddc120b77a"},
|
|
134
|
-
{file = "mypy-1.11.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:801780c56d1cdb896eacd5619a83e427ce436d86a3bdf9112527f24a66618fef"},
|
|
135
|
-
{file = "mypy-1.11.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:41ea707d036a5307ac674ea172875f40c9d55c5394f888b168033177fce47383"},
|
|
136
|
-
{file = "mypy-1.11.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6e658bd2d20565ea86da7d91331b0eed6d2eee22dc031579e6297f3e12c758c8"},
|
|
137
|
-
{file = "mypy-1.11.2-cp310-cp310-win_amd64.whl", hash = "sha256:478db5f5036817fe45adb7332d927daa62417159d49783041338921dcf646fc7"},
|
|
138
|
-
{file = "mypy-1.11.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:75746e06d5fa1e91bfd5432448d00d34593b52e7e91a187d981d08d1f33d4385"},
|
|
139
|
-
{file = "mypy-1.11.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a976775ab2256aadc6add633d44f100a2517d2388906ec4f13231fafbb0eccca"},
|
|
140
|
-
{file = "mypy-1.11.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cd953f221ac1379050a8a646585a29574488974f79d8082cedef62744f0a0104"},
|
|
141
|
-
{file = "mypy-1.11.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:57555a7715c0a34421013144a33d280e73c08df70f3a18a552938587ce9274f4"},
|
|
142
|
-
{file = "mypy-1.11.2-cp311-cp311-win_amd64.whl", hash = "sha256:36383a4fcbad95f2657642a07ba22ff797de26277158f1cc7bd234821468b1b6"},
|
|
143
|
-
{file = "mypy-1.11.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:e8960dbbbf36906c5c0b7f4fbf2f0c7ffb20f4898e6a879fcf56a41a08b0d318"},
|
|
144
|
-
{file = "mypy-1.11.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:06d26c277962f3fb50e13044674aa10553981ae514288cb7d0a738f495550b36"},
|
|
145
|
-
{file = "mypy-1.11.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6e7184632d89d677973a14d00ae4d03214c8bc301ceefcdaf5c474866814c987"},
|
|
146
|
-
{file = "mypy-1.11.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:3a66169b92452f72117e2da3a576087025449018afc2d8e9bfe5ffab865709ca"},
|
|
147
|
-
{file = "mypy-1.11.2-cp312-cp312-win_amd64.whl", hash = "sha256:969ea3ef09617aff826885a22ece0ddef69d95852cdad2f60c8bb06bf1f71f70"},
|
|
148
|
-
{file = "mypy-1.11.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:37c7fa6121c1cdfcaac97ce3d3b5588e847aa79b580c1e922bb5d5d2902df19b"},
|
|
149
|
-
{file = "mypy-1.11.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4a8a53bc3ffbd161b5b2a4fff2f0f1e23a33b0168f1c0778ec70e1a3d66deb86"},
|
|
150
|
-
{file = "mypy-1.11.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2ff93107f01968ed834f4256bc1fc4475e2fecf6c661260066a985b52741ddce"},
|
|
151
|
-
{file = "mypy-1.11.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:edb91dded4df17eae4537668b23f0ff6baf3707683734b6a818d5b9d0c0c31a1"},
|
|
152
|
-
{file = "mypy-1.11.2-cp38-cp38-win_amd64.whl", hash = "sha256:ee23de8530d99b6db0573c4ef4bd8f39a2a6f9b60655bf7a1357e585a3486f2b"},
|
|
153
|
-
{file = "mypy-1.11.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:801ca29f43d5acce85f8e999b1e431fb479cb02d0e11deb7d2abb56bdaf24fd6"},
|
|
154
|
-
{file = "mypy-1.11.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:af8d155170fcf87a2afb55b35dc1a0ac21df4431e7d96717621962e4b9192e70"},
|
|
155
|
-
{file = "mypy-1.11.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f7821776e5c4286b6a13138cc935e2e9b6fde05e081bdebf5cdb2bb97c9df81d"},
|
|
156
|
-
{file = "mypy-1.11.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:539c570477a96a4e6fb718b8d5c3e0c0eba1f485df13f86d2970c91f0673148d"},
|
|
157
|
-
{file = "mypy-1.11.2-cp39-cp39-win_amd64.whl", hash = "sha256:3f14cd3d386ac4d05c5a39a51b84387403dadbd936e17cb35882134d4f8f0d24"},
|
|
158
|
-
{file = "mypy-1.11.2-py3-none-any.whl", hash = "sha256:b499bc07dbdcd3de92b0a8b29fdf592c111276f6a12fe29c30f6c417dd546d12"},
|
|
159
|
-
{file = "mypy-1.11.2.tar.gz", hash = "sha256:7f9993ad3e0ffdc95c2a14b66dee63729f021968bff8ad911867579c65d13a79"},
|
|
160
|
-
]
|
|
161
|
-
|
|
162
|
-
[package.dependencies]
|
|
163
|
-
mypy-extensions = ">=1.0.0"
|
|
164
|
-
tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""}
|
|
165
|
-
typing-extensions = ">=4.6.0"
|
|
166
|
-
|
|
167
|
-
[package.extras]
|
|
168
|
-
dmypy = ["psutil (>=4.0)"]
|
|
169
|
-
install-types = ["pip"]
|
|
170
|
-
mypyc = ["setuptools (>=50)"]
|
|
171
|
-
reports = ["lxml"]
|
|
172
|
-
|
|
173
|
-
[[package]]
|
|
174
|
-
name = "mypy-extensions"
|
|
175
|
-
version = "1.0.0"
|
|
176
|
-
description = "Type system extensions for programs checked with the mypy type checker."
|
|
177
|
-
optional = false
|
|
178
|
-
python-versions = ">=3.5"
|
|
179
|
-
files = [
|
|
180
|
-
{file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"},
|
|
181
|
-
{file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"},
|
|
182
|
-
]
|
|
183
|
-
|
|
184
|
-
[[package]]
|
|
185
|
-
name = "nodeenv"
|
|
186
|
-
version = "1.9.1"
|
|
187
|
-
description = "Node.js virtual environment builder"
|
|
188
|
-
optional = false
|
|
189
|
-
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
|
|
190
|
-
files = [
|
|
191
|
-
{file = "nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9"},
|
|
192
|
-
{file = "nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f"},
|
|
193
|
-
]
|
|
194
|
-
|
|
195
|
-
[[package]]
|
|
196
|
-
name = "packaging"
|
|
197
|
-
version = "24.1"
|
|
198
|
-
description = "Core utilities for Python packages"
|
|
199
|
-
optional = false
|
|
200
|
-
python-versions = ">=3.8"
|
|
201
|
-
files = [
|
|
202
|
-
{file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"},
|
|
203
|
-
{file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"},
|
|
204
|
-
]
|
|
205
|
-
|
|
206
|
-
[[package]]
|
|
207
|
-
name = "platformdirs"
|
|
208
|
-
version = "4.3.6"
|
|
209
|
-
description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`."
|
|
210
|
-
optional = false
|
|
211
|
-
python-versions = ">=3.8"
|
|
212
|
-
files = [
|
|
213
|
-
{file = "platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb"},
|
|
214
|
-
{file = "platformdirs-4.3.6.tar.gz", hash = "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907"},
|
|
215
|
-
]
|
|
216
|
-
|
|
217
|
-
[package.extras]
|
|
218
|
-
docs = ["furo (>=2024.8.6)", "proselint (>=0.14)", "sphinx (>=8.0.2)", "sphinx-autodoc-typehints (>=2.4)"]
|
|
219
|
-
test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=8.3.2)", "pytest-cov (>=5)", "pytest-mock (>=3.14)"]
|
|
220
|
-
type = ["mypy (>=1.11.2)"]
|
|
221
|
-
|
|
222
|
-
[[package]]
|
|
223
|
-
name = "pluggy"
|
|
224
|
-
version = "1.5.0"
|
|
225
|
-
description = "plugin and hook calling mechanisms for python"
|
|
226
|
-
optional = false
|
|
227
|
-
python-versions = ">=3.8"
|
|
228
|
-
files = [
|
|
229
|
-
{file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"},
|
|
230
|
-
{file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"},
|
|
231
|
-
]
|
|
232
|
-
|
|
233
|
-
[package.extras]
|
|
234
|
-
dev = ["pre-commit", "tox"]
|
|
235
|
-
testing = ["pytest", "pytest-benchmark"]
|
|
236
|
-
|
|
237
|
-
[[package]]
|
|
238
|
-
name = "pre-commit"
|
|
239
|
-
version = "3.8.0"
|
|
240
|
-
description = "A framework for managing and maintaining multi-language pre-commit hooks."
|
|
241
|
-
optional = false
|
|
242
|
-
python-versions = ">=3.9"
|
|
243
|
-
files = [
|
|
244
|
-
{file = "pre_commit-3.8.0-py2.py3-none-any.whl", hash = "sha256:9a90a53bf82fdd8778d58085faf8d83df56e40dfe18f45b19446e26bf1b3a63f"},
|
|
245
|
-
{file = "pre_commit-3.8.0.tar.gz", hash = "sha256:8bb6494d4a20423842e198980c9ecf9f96607a07ea29549e180eef9ae80fe7af"},
|
|
246
|
-
]
|
|
247
|
-
|
|
248
|
-
[package.dependencies]
|
|
249
|
-
cfgv = ">=2.0.0"
|
|
250
|
-
identify = ">=1.0.0"
|
|
251
|
-
nodeenv = ">=0.11.1"
|
|
252
|
-
pyyaml = ">=5.1"
|
|
253
|
-
virtualenv = ">=20.10.0"
|
|
254
|
-
|
|
255
|
-
[[package]]
|
|
256
|
-
name = "pytest"
|
|
257
|
-
version = "8.3.3"
|
|
258
|
-
description = "pytest: simple powerful testing with Python"
|
|
259
|
-
optional = false
|
|
260
|
-
python-versions = ">=3.8"
|
|
261
|
-
files = [
|
|
262
|
-
{file = "pytest-8.3.3-py3-none-any.whl", hash = "sha256:a6853c7375b2663155079443d2e45de913a911a11d669df02a50814944db57b2"},
|
|
263
|
-
{file = "pytest-8.3.3.tar.gz", hash = "sha256:70b98107bd648308a7952b06e6ca9a50bc660be218d53c257cc1fc94fda10181"},
|
|
264
|
-
]
|
|
265
|
-
|
|
266
|
-
[package.dependencies]
|
|
267
|
-
colorama = {version = "*", markers = "sys_platform == \"win32\""}
|
|
268
|
-
exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""}
|
|
269
|
-
iniconfig = "*"
|
|
270
|
-
packaging = "*"
|
|
271
|
-
pluggy = ">=1.5,<2"
|
|
272
|
-
tomli = {version = ">=1", markers = "python_version < \"3.11\""}
|
|
273
|
-
|
|
274
|
-
[package.extras]
|
|
275
|
-
dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"]
|
|
276
|
-
|
|
277
|
-
[[package]]
|
|
278
|
-
name = "pyyaml"
|
|
279
|
-
version = "6.0.2"
|
|
280
|
-
description = "YAML parser and emitter for Python"
|
|
281
|
-
optional = false
|
|
282
|
-
python-versions = ">=3.8"
|
|
283
|
-
files = [
|
|
284
|
-
{file = "PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086"},
|
|
285
|
-
{file = "PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf"},
|
|
286
|
-
{file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237"},
|
|
287
|
-
{file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b"},
|
|
288
|
-
{file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed"},
|
|
289
|
-
{file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180"},
|
|
290
|
-
{file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68"},
|
|
291
|
-
{file = "PyYAML-6.0.2-cp310-cp310-win32.whl", hash = "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99"},
|
|
292
|
-
{file = "PyYAML-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e"},
|
|
293
|
-
{file = "PyYAML-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774"},
|
|
294
|
-
{file = "PyYAML-6.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee"},
|
|
295
|
-
{file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c"},
|
|
296
|
-
{file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317"},
|
|
297
|
-
{file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85"},
|
|
298
|
-
{file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4"},
|
|
299
|
-
{file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e"},
|
|
300
|
-
{file = "PyYAML-6.0.2-cp311-cp311-win32.whl", hash = "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5"},
|
|
301
|
-
{file = "PyYAML-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44"},
|
|
302
|
-
{file = "PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab"},
|
|
303
|
-
{file = "PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725"},
|
|
304
|
-
{file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5"},
|
|
305
|
-
{file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425"},
|
|
306
|
-
{file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476"},
|
|
307
|
-
{file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48"},
|
|
308
|
-
{file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b"},
|
|
309
|
-
{file = "PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4"},
|
|
310
|
-
{file = "PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8"},
|
|
311
|
-
{file = "PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba"},
|
|
312
|
-
{file = "PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1"},
|
|
313
|
-
{file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133"},
|
|
314
|
-
{file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484"},
|
|
315
|
-
{file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5"},
|
|
316
|
-
{file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc"},
|
|
317
|
-
{file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652"},
|
|
318
|
-
{file = "PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183"},
|
|
319
|
-
{file = "PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563"},
|
|
320
|
-
{file = "PyYAML-6.0.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a"},
|
|
321
|
-
{file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5"},
|
|
322
|
-
{file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d"},
|
|
323
|
-
{file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083"},
|
|
324
|
-
{file = "PyYAML-6.0.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706"},
|
|
325
|
-
{file = "PyYAML-6.0.2-cp38-cp38-win32.whl", hash = "sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a"},
|
|
326
|
-
{file = "PyYAML-6.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff"},
|
|
327
|
-
{file = "PyYAML-6.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d"},
|
|
328
|
-
{file = "PyYAML-6.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f"},
|
|
329
|
-
{file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290"},
|
|
330
|
-
{file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12"},
|
|
331
|
-
{file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19"},
|
|
332
|
-
{file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e"},
|
|
333
|
-
{file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725"},
|
|
334
|
-
{file = "PyYAML-6.0.2-cp39-cp39-win32.whl", hash = "sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631"},
|
|
335
|
-
{file = "PyYAML-6.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8"},
|
|
336
|
-
{file = "pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e"},
|
|
337
|
-
]
|
|
338
|
-
|
|
339
|
-
[[package]]
|
|
340
|
-
name = "ruff"
|
|
341
|
-
version = "0.2.2"
|
|
342
|
-
description = "An extremely fast Python linter and code formatter, written in Rust."
|
|
343
|
-
optional = false
|
|
344
|
-
python-versions = ">=3.7"
|
|
345
|
-
files = [
|
|
346
|
-
{file = "ruff-0.2.2-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:0a9efb032855ffb3c21f6405751d5e147b0c6b631e3ca3f6b20f917572b97eb6"},
|
|
347
|
-
{file = "ruff-0.2.2-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:d450b7fbff85913f866a5384d8912710936e2b96da74541c82c1b458472ddb39"},
|
|
348
|
-
{file = "ruff-0.2.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ecd46e3106850a5c26aee114e562c329f9a1fbe9e4821b008c4404f64ff9ce73"},
|
|
349
|
-
{file = "ruff-0.2.2-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5e22676a5b875bd72acd3d11d5fa9075d3a5f53b877fe7b4793e4673499318ba"},
|
|
350
|
-
{file = "ruff-0.2.2-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1695700d1e25a99d28f7a1636d85bafcc5030bba9d0578c0781ba1790dbcf51c"},
|
|
351
|
-
{file = "ruff-0.2.2-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:b0c232af3d0bd8f521806223723456ffebf8e323bd1e4e82b0befb20ba18388e"},
|
|
352
|
-
{file = "ruff-0.2.2-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f63d96494eeec2fc70d909393bcd76c69f35334cdbd9e20d089fb3f0640216ca"},
|
|
353
|
-
{file = "ruff-0.2.2-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6a61ea0ff048e06de273b2e45bd72629f470f5da8f71daf09fe481278b175001"},
|
|
354
|
-
{file = "ruff-0.2.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5e1439c8f407e4f356470e54cdecdca1bd5439a0673792dbe34a2b0a551a2fe3"},
|
|
355
|
-
{file = "ruff-0.2.2-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:940de32dc8853eba0f67f7198b3e79bc6ba95c2edbfdfac2144c8235114d6726"},
|
|
356
|
-
{file = "ruff-0.2.2-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:0c126da55c38dd917621552ab430213bdb3273bb10ddb67bc4b761989210eb6e"},
|
|
357
|
-
{file = "ruff-0.2.2-py3-none-musllinux_1_2_i686.whl", hash = "sha256:3b65494f7e4bed2e74110dac1f0d17dc8e1f42faaa784e7c58a98e335ec83d7e"},
|
|
358
|
-
{file = "ruff-0.2.2-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:1ec49be4fe6ddac0503833f3ed8930528e26d1e60ad35c2446da372d16651ce9"},
|
|
359
|
-
{file = "ruff-0.2.2-py3-none-win32.whl", hash = "sha256:d920499b576f6c68295bc04e7b17b6544d9d05f196bb3aac4358792ef6f34325"},
|
|
360
|
-
{file = "ruff-0.2.2-py3-none-win_amd64.whl", hash = "sha256:cc9a91ae137d687f43a44c900e5d95e9617cb37d4c989e462980ba27039d239d"},
|
|
361
|
-
{file = "ruff-0.2.2-py3-none-win_arm64.whl", hash = "sha256:c9d15fc41e6054bfc7200478720570078f0b41c9ae4f010bcc16bd6f4d1aacdd"},
|
|
362
|
-
{file = "ruff-0.2.2.tar.gz", hash = "sha256:e62ed7f36b3068a30ba39193a14274cd706bc486fad521276458022f7bccb31d"},
|
|
363
|
-
]
|
|
364
|
-
|
|
365
|
-
[[package]]
|
|
366
|
-
name = "tomli"
|
|
367
|
-
version = "2.0.1"
|
|
368
|
-
description = "A lil' TOML parser"
|
|
369
|
-
optional = false
|
|
370
|
-
python-versions = ">=3.7"
|
|
371
|
-
files = [
|
|
372
|
-
{file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"},
|
|
373
|
-
{file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"},
|
|
374
|
-
]
|
|
375
|
-
|
|
376
|
-
[[package]]
|
|
377
|
-
name = "typing-extensions"
|
|
378
|
-
version = "4.12.2"
|
|
379
|
-
description = "Backported and Experimental Type Hints for Python 3.8+"
|
|
380
|
-
optional = false
|
|
381
|
-
python-versions = ">=3.8"
|
|
382
|
-
files = [
|
|
383
|
-
{file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"},
|
|
384
|
-
{file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"},
|
|
385
|
-
]
|
|
386
|
-
|
|
387
|
-
[[package]]
|
|
388
|
-
name = "virtualenv"
|
|
389
|
-
version = "20.26.5"
|
|
390
|
-
description = "Virtual Python Environment builder"
|
|
391
|
-
optional = false
|
|
392
|
-
python-versions = ">=3.7"
|
|
393
|
-
files = [
|
|
394
|
-
{file = "virtualenv-20.26.5-py3-none-any.whl", hash = "sha256:4f3ac17b81fba3ce3bd6f4ead2749a72da5929c01774948e243db9ba41df4ff6"},
|
|
395
|
-
{file = "virtualenv-20.26.5.tar.gz", hash = "sha256:ce489cac131aa58f4b25e321d6d186171f78e6cb13fafbf32a840cee67733ff4"},
|
|
396
|
-
]
|
|
397
|
-
|
|
398
|
-
[package.dependencies]
|
|
399
|
-
distlib = ">=0.3.7,<1"
|
|
400
|
-
filelock = ">=3.12.2,<4"
|
|
401
|
-
platformdirs = ">=3.9.1,<5"
|
|
402
|
-
|
|
403
|
-
[package.extras]
|
|
404
|
-
docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2,!=7.3)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"]
|
|
405
|
-
test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8)", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10)"]
|
|
406
|
-
|
|
407
|
-
[metadata]
|
|
408
|
-
lock-version = "2.0"
|
|
409
|
-
python-versions = "^3.8"
|
|
410
|
-
content-hash = "555416233d534c92e9fd0327b7024f9185a43aeb4c96ba51d1b3b84c9f7633f9"
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
pytest_plugins = ["pytester"]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pytest_markdown_docs-0.6.0 → pytest_markdown_docs-0.7.0}/src/pytest_markdown_docs/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|