pytest-markdown-docs 0.9.1__tar.gz → 0.9.2__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.9.1/README.md → pytest_markdown_docs-0.9.2/PKG-INFO +39 -0
- pytest_markdown_docs-0.9.1/PKG-INFO → pytest_markdown_docs-0.9.2/README.md +23 -13
- {pytest_markdown_docs-0.9.1 → pytest_markdown_docs-0.9.2}/pyproject.toml +16 -9
- {pytest_markdown_docs-0.9.1 → pytest_markdown_docs-0.9.2}/src/pytest_markdown_docs/_runners.py +18 -10
- {pytest_markdown_docs-0.9.1 → pytest_markdown_docs-0.9.2}/src/pytest_markdown_docs/plugin.py +47 -1
- pytest_markdown_docs-0.9.1/.github/pull_request_template.md +0 -5
- pytest_markdown_docs-0.9.1/.github/workflows/check.yml +0 -27
- pytest_markdown_docs-0.9.1/.github/workflows/ci.yml +0 -31
- pytest_markdown_docs-0.9.1/.github/workflows/codeql.yml +0 -74
- pytest_markdown_docs-0.9.1/.gitignore +0 -129
- pytest_markdown_docs-0.9.1/.pre-commit-config.yaml +0 -8
- pytest_markdown_docs-0.9.1/Makefile +0 -8
- pytest_markdown_docs-0.9.1/tests/conftest.py +0 -10
- pytest_markdown_docs-0.9.1/tests/plugin_test.py +0 -723
- pytest_markdown_docs-0.9.1/tests/support/docstring_error_after.py +0 -11
- pytest_markdown_docs-0.9.1/tests/support/docstring_error_before.py +0 -11
- {pytest_markdown_docs-0.9.1 → pytest_markdown_docs-0.9.2}/LICENSE +0 -0
- {pytest_markdown_docs-0.9.1 → pytest_markdown_docs-0.9.2}/src/pytest_markdown_docs/__init__.py +0 -0
- {pytest_markdown_docs-0.9.1 → pytest_markdown_docs-0.9.2}/src/pytest_markdown_docs/definitions.py +0 -0
- {pytest_markdown_docs-0.9.1 → pytest_markdown_docs-0.9.2}/src/pytest_markdown_docs/hooks.py +0 -0
- {pytest_markdown_docs-0.9.1 → pytest_markdown_docs-0.9.2}/src/pytest_markdown_docs/py.typed +0 -0
|
@@ -1,3 +1,19 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pytest-markdown-docs
|
|
3
|
+
Version: 0.9.2
|
|
4
|
+
Summary: Run markdown code fences through pytest
|
|
5
|
+
Author: Modal Labs, Elias Freider
|
|
6
|
+
Author-email: Elias Freider <elias@modal.com>
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
Requires-Dist: markdown-it-py>=2.2.0,<4.0
|
|
10
|
+
Requires-Dist: pytest>=7.0.0
|
|
11
|
+
Requires-Python: >=3.9
|
|
12
|
+
Project-URL: Homepage, https://github.com/modal-labs/pytest-markdown-docs
|
|
13
|
+
Project-URL: Repository, https://github.com/modal-labs/pytest-markdown-docs
|
|
14
|
+
Project-URL: Issue Tracker, https://github.com/modal-labs/pytest-markdown-docs/issues
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
|
|
1
17
|
# Pytest Markdown Docs
|
|
2
18
|
|
|
3
19
|
A plugin for [pytest](https://docs.pytest.org) that uses markdown code snippets from markdown files and docstrings as tests.
|
|
@@ -120,6 +136,29 @@ assert captured.out == "hello\n"
|
|
|
120
136
|
|
|
121
137
|
As you can see above, the fixture value will be injected as a global. For `autouse=True` fixtures, the value is only injected as a global if it's explicitly added using a `fixture:<name>` marker.
|
|
122
138
|
|
|
139
|
+
### Async Fixtures (pytest-asyncio)
|
|
140
|
+
|
|
141
|
+
If you have [pytest-asyncio](https://pypi.org/project/pytest-asyncio/) installed, you can use async fixtures with your markdown tests. The async fixture will be executed and its resolved value will be injected into the test code:
|
|
142
|
+
|
|
143
|
+
```python
|
|
144
|
+
# conftest.py
|
|
145
|
+
import pytest_asyncio
|
|
146
|
+
|
|
147
|
+
@pytest_asyncio.fixture
|
|
148
|
+
async def async_data():
|
|
149
|
+
# Simulate async data fetching
|
|
150
|
+
return {"status": "ok", "value": 42}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
````markdown
|
|
154
|
+
```python fixture:async_data
|
|
155
|
+
assert async_data["status"] == "ok"
|
|
156
|
+
assert async_data["value"] == 42
|
|
157
|
+
```
|
|
158
|
+
````
|
|
159
|
+
|
|
160
|
+
Async fixtures can depend on other async fixtures, sync fixtures, or a mix of both. The fixture values are fully resolved before being passed to your markdown test code.
|
|
161
|
+
|
|
123
162
|
### Depending on previous snippets
|
|
124
163
|
|
|
125
164
|
If you have multiple snippets following each other and want to keep the side
|
|
@@ -1,16 +1,3 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: pytest-markdown-docs
|
|
3
|
-
Version: 0.9.1
|
|
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.9
|
|
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.
|
|
@@ -133,6 +120,29 @@ assert captured.out == "hello\n"
|
|
|
133
120
|
|
|
134
121
|
As you can see above, the fixture value will be injected as a global. For `autouse=True` fixtures, the value is only injected as a global if it's explicitly added using a `fixture:<name>` marker.
|
|
135
122
|
|
|
123
|
+
### Async Fixtures (pytest-asyncio)
|
|
124
|
+
|
|
125
|
+
If you have [pytest-asyncio](https://pypi.org/project/pytest-asyncio/) installed, you can use async fixtures with your markdown tests. The async fixture will be executed and its resolved value will be injected into the test code:
|
|
126
|
+
|
|
127
|
+
```python
|
|
128
|
+
# conftest.py
|
|
129
|
+
import pytest_asyncio
|
|
130
|
+
|
|
131
|
+
@pytest_asyncio.fixture
|
|
132
|
+
async def async_data():
|
|
133
|
+
# Simulate async data fetching
|
|
134
|
+
return {"status": "ok", "value": 42}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
````markdown
|
|
138
|
+
```python fixture:async_data
|
|
139
|
+
assert async_data["status"] == "ok"
|
|
140
|
+
assert async_data["value"] == 42
|
|
141
|
+
```
|
|
142
|
+
````
|
|
143
|
+
|
|
144
|
+
Async fixtures can depend on other async fixtures, sync fixtures, or a mix of both. The fixture values are fully resolved before being passed to your markdown test code.
|
|
145
|
+
|
|
136
146
|
### Depending on previous snippets
|
|
137
147
|
|
|
138
148
|
If you have multiple snippets following each other and want to keep the side
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "pytest-markdown-docs"
|
|
3
|
-
version = "0.9.
|
|
3
|
+
version = "0.9.2"
|
|
4
4
|
description = "Run markdown code fences through pytest"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
authors = [
|
|
@@ -8,26 +8,33 @@ authors = [
|
|
|
8
8
|
{ name = "Elias Freider", email = "elias@modal.com" }
|
|
9
9
|
]
|
|
10
10
|
license = "MIT"
|
|
11
|
+
license-files = ["LICENSE"]
|
|
11
12
|
requires-python = ">=3.9"
|
|
12
13
|
dependencies = [
|
|
13
14
|
"markdown-it-py>=2.2.0,<4.0",
|
|
14
15
|
"pytest>=7.0.0",
|
|
15
16
|
]
|
|
16
|
-
|
|
17
|
+
|
|
18
|
+
[project.urls]
|
|
19
|
+
Homepage = "https://github.com/modal-labs/pytest-markdown-docs"
|
|
20
|
+
Repository = "https://github.com/modal-labs/pytest-markdown-docs"
|
|
21
|
+
"Issue Tracker" = "https://github.com/modal-labs/pytest-markdown-docs/issues"
|
|
22
|
+
|
|
17
23
|
|
|
18
24
|
[project.entry-points.pytest11]
|
|
19
25
|
pytest_markdown_docs = "pytest_markdown_docs.plugin"
|
|
20
26
|
|
|
21
27
|
[build-system]
|
|
22
|
-
requires = ["
|
|
23
|
-
build-backend = "
|
|
28
|
+
requires = ["uv_build>=0.10.9,<0.11.0"]
|
|
29
|
+
build-backend = "uv_build"
|
|
30
|
+
|
|
24
31
|
|
|
25
|
-
[
|
|
26
|
-
|
|
27
|
-
dev-dependencies = [
|
|
32
|
+
[dependency-groups]
|
|
33
|
+
dev = [
|
|
28
34
|
"mypy>=1.12.1",
|
|
29
35
|
"pre-commit>=3.5.0",
|
|
30
|
-
"pytest
|
|
36
|
+
"pytest>=8.1.0",
|
|
37
|
+
"pytest-asyncio>=0.23.0",
|
|
31
38
|
"ruff~=0.9.10",
|
|
32
|
-
"mdit-py-plugins~=0.4.2"
|
|
39
|
+
"mdit-py-plugins~=0.4.2",
|
|
33
40
|
]
|
{pytest_markdown_docs-0.9.1 → pytest_markdown_docs-0.9.2}/src/pytest_markdown_docs/_runners.py
RENAMED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import abc
|
|
2
2
|
import ast
|
|
3
|
+
import inspect
|
|
3
4
|
import traceback
|
|
4
5
|
import typing
|
|
5
6
|
from abc import abstractmethod
|
|
@@ -50,22 +51,29 @@ def register_runner(*, default: bool = False):
|
|
|
50
51
|
|
|
51
52
|
@register_runner(default=True)
|
|
52
53
|
class DefaultRunner(_Runner):
|
|
53
|
-
def runtest(self, test: FenceTestDefinition, args):
|
|
54
|
+
def runtest(self, test: FenceTestDefinition, args, *, asyncio_runner=None):
|
|
54
55
|
try:
|
|
55
|
-
tree = ast.parse(test.source, filename=test.source_path)
|
|
56
|
-
except SyntaxError:
|
|
57
|
-
raise
|
|
58
|
-
|
|
59
|
-
try:
|
|
60
|
-
# if we don't compile the code, it seems we get name lookup errors
|
|
61
|
-
# for functions etc. when doing cross-calls across inline functions
|
|
62
56
|
compiled = compile(
|
|
63
|
-
|
|
57
|
+
test.source,
|
|
58
|
+
filename=test.source_path,
|
|
59
|
+
mode="exec",
|
|
60
|
+
flags=ast.PyCF_ALLOW_TOP_LEVEL_AWAIT,
|
|
61
|
+
dont_inherit=True,
|
|
64
62
|
)
|
|
65
63
|
except SyntaxError:
|
|
66
64
|
raise
|
|
67
65
|
|
|
68
|
-
|
|
66
|
+
if compiled.co_flags & inspect.CO_COROUTINE:
|
|
67
|
+
if asyncio_runner is None:
|
|
68
|
+
raise RuntimeError(
|
|
69
|
+
"Top-level async code in markdown code blocks is not natively supported.\n"
|
|
70
|
+
"You need pytest-asyncio>=1.1.0 to run async code blocks:\n"
|
|
71
|
+
" pip install 'pytest-asyncio>=1.1.0'"
|
|
72
|
+
)
|
|
73
|
+
coro = eval(compiled, args)
|
|
74
|
+
asyncio_runner.run(coro)
|
|
75
|
+
else:
|
|
76
|
+
exec(compiled, args)
|
|
69
77
|
|
|
70
78
|
def repr_failure(
|
|
71
79
|
self,
|
{pytest_markdown_docs-0.9.1 → pytest_markdown_docs-0.9.2}/src/pytest_markdown_docs/plugin.py
RENAMED
|
@@ -52,6 +52,14 @@ def get_docstring_start_line(obj) -> typing.Optional[int]:
|
|
|
52
52
|
return None # Docstring not found in source
|
|
53
53
|
|
|
54
54
|
|
|
55
|
+
def _get_asyncio_runner(fixture_request):
|
|
56
|
+
"""Try to fetch pytest-asyncio's event loop runner for shared-loop execution."""
|
|
57
|
+
try:
|
|
58
|
+
return fixture_request.getfixturevalue("_function_scoped_runner")
|
|
59
|
+
except Exception:
|
|
60
|
+
return None
|
|
61
|
+
|
|
62
|
+
|
|
55
63
|
class MarkdownInlinePythonItem(pytest.Item):
|
|
56
64
|
def __init__(
|
|
57
65
|
self,
|
|
@@ -109,8 +117,17 @@ class MarkdownInlinePythonItem(pytest.Item):
|
|
|
109
117
|
try:
|
|
110
118
|
# this ensures that pytest's stdout/stderr capture works during the test:
|
|
111
119
|
capman = self.config.pluginmanager.getplugin("capturemanager")
|
|
120
|
+
asyncio_runner = _get_asyncio_runner(self.fixture_request)
|
|
112
121
|
with capman.global_and_fixture_disabled():
|
|
113
|
-
|
|
122
|
+
try:
|
|
123
|
+
self.runner.runtest(
|
|
124
|
+
self.test_definition,
|
|
125
|
+
all_globals,
|
|
126
|
+
asyncio_runner=asyncio_runner,
|
|
127
|
+
)
|
|
128
|
+
except TypeError:
|
|
129
|
+
# Custom runner doesn't accept asyncio_runner kwarg
|
|
130
|
+
self.runner.runtest(self.test_definition, all_globals)
|
|
114
131
|
|
|
115
132
|
# Success - test passed
|
|
116
133
|
if attempt > 0:
|
|
@@ -282,8 +299,33 @@ def extract_options_from_mdx_comment(comment: str) -> typing.Set[str]:
|
|
|
282
299
|
return set(option.strip() for option in comment.split(" ") if option)
|
|
283
300
|
|
|
284
301
|
|
|
302
|
+
def _preprocess_async_fixtures_if_available(collector: pytest.Collector) -> None:
|
|
303
|
+
"""
|
|
304
|
+
If pytest-asyncio is installed, trigger its async fixture preprocessing.
|
|
305
|
+
|
|
306
|
+
pytest-asyncio preprocesses async fixtures during collection, but only for
|
|
307
|
+
pytest.Module and pytest.Class collectors. We need to trigger this manually
|
|
308
|
+
for our markdown collectors so that async fixtures work correctly.
|
|
309
|
+
"""
|
|
310
|
+
try:
|
|
311
|
+
from pytest_asyncio.plugin import ( # type: ignore
|
|
312
|
+
_preprocess_async_fixtures,
|
|
313
|
+
_HOLDER,
|
|
314
|
+
)
|
|
315
|
+
|
|
316
|
+
_preprocess_async_fixtures(collector, _HOLDER)
|
|
317
|
+
except ImportError:
|
|
318
|
+
# pytest-asyncio is not installed, or using a newer version that
|
|
319
|
+
# doesn't require these imports
|
|
320
|
+
pass
|
|
321
|
+
|
|
322
|
+
|
|
285
323
|
class MarkdownDocstringCodeModule(pytest.Module):
|
|
286
324
|
def collect(self):
|
|
325
|
+
# Trigger pytest-asyncio's async fixture preprocessing if available
|
|
326
|
+
# (needed for pytest-asyncio 0.23.x; 1.x uses pytest_fixture_setup hook instead)
|
|
327
|
+
_preprocess_async_fixtures_if_available(self)
|
|
328
|
+
|
|
287
329
|
if pytest.version_tuple >= (8, 1, 0):
|
|
288
330
|
# consider_namespace_packages is a required keyword argument in pytest 8.1.0
|
|
289
331
|
module = import_path(
|
|
@@ -361,6 +403,10 @@ class MarkdownDocstringCodeModule(pytest.Module):
|
|
|
361
403
|
|
|
362
404
|
class MarkdownTextFile(pytest.File):
|
|
363
405
|
def collect(self):
|
|
406
|
+
# Trigger pytest-asyncio's async fixture preprocessing if available
|
|
407
|
+
# (needed for pytest-asyncio 0.23.x; 1.x uses pytest_fixture_setup hook instead)
|
|
408
|
+
_preprocess_async_fixtures_if_available(self)
|
|
409
|
+
|
|
364
410
|
markdown_content = self.path.read_text("utf8")
|
|
365
411
|
fence_syntax = FenceSyntax(self.config.option.markdowndocs_syntax)
|
|
366
412
|
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
name: ruff & mypy
|
|
2
|
-
on: push
|
|
3
|
-
|
|
4
|
-
jobs:
|
|
5
|
-
build:
|
|
6
|
-
runs-on: ubuntu-latest
|
|
7
|
-
steps:
|
|
8
|
-
- uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3
|
|
9
|
-
- name: Install uv
|
|
10
|
-
uses: astral-sh/setup-uv@caf0cab7a618c569241d31dcd442f54681755d39 # v3
|
|
11
|
-
|
|
12
|
-
- name: Install Python (3.11)
|
|
13
|
-
uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55 # v5
|
|
14
|
-
with:
|
|
15
|
-
python-version: 3.11
|
|
16
|
-
|
|
17
|
-
- name: Install the project
|
|
18
|
-
run: uv sync --all-extras --dev --no-install-project
|
|
19
|
-
|
|
20
|
-
- name: Ruff check
|
|
21
|
-
run: uv run ruff check --diff
|
|
22
|
-
|
|
23
|
-
- name: Ruff format
|
|
24
|
-
run: uv run ruff format --diff
|
|
25
|
-
|
|
26
|
-
- name: Mypy
|
|
27
|
-
run: uv run mypy .
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
name: Test
|
|
2
|
-
on: push
|
|
3
|
-
|
|
4
|
-
jobs:
|
|
5
|
-
build:
|
|
6
|
-
runs-on: ubuntu-latest
|
|
7
|
-
strategy:
|
|
8
|
-
matrix:
|
|
9
|
-
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
|
|
10
|
-
steps:
|
|
11
|
-
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
|
12
|
-
|
|
13
|
-
- name: Install uv
|
|
14
|
-
uses: astral-sh/setup-uv@caf0cab7a618c569241d31dcd442f54681755d39 # v3
|
|
15
|
-
|
|
16
|
-
- name: Install Python ${{ matrix.python-version }}
|
|
17
|
-
uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55 # v5
|
|
18
|
-
with:
|
|
19
|
-
python-version: ${{ matrix.python-version }}
|
|
20
|
-
|
|
21
|
-
- name: Install the project
|
|
22
|
-
run: uv sync --all-extras --dev
|
|
23
|
-
|
|
24
|
-
- name: Run tests with pytest
|
|
25
|
-
run: uv run pytest
|
|
26
|
-
|
|
27
|
-
- name: Downgrade to pytest 7
|
|
28
|
-
run: uv pip install "pytest<8"
|
|
29
|
-
|
|
30
|
-
- name: Run tests with pytest 7
|
|
31
|
-
run: uv run pytest
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
# For most projects, this workflow file will not need changing; you simply need
|
|
2
|
-
# to commit it to your repository.
|
|
3
|
-
#
|
|
4
|
-
# You may wish to alter this file to override the set of languages analyzed,
|
|
5
|
-
# or to provide custom queries or build logic.
|
|
6
|
-
#
|
|
7
|
-
# ******** NOTE ********
|
|
8
|
-
# We have attempted to detect the languages in your repository. Please check
|
|
9
|
-
# the `language` matrix defined below to confirm you have the correct set of
|
|
10
|
-
# supported CodeQL languages.
|
|
11
|
-
#
|
|
12
|
-
name: "CodeQL"
|
|
13
|
-
|
|
14
|
-
on:
|
|
15
|
-
push:
|
|
16
|
-
branches: [ "main" ]
|
|
17
|
-
pull_request:
|
|
18
|
-
schedule:
|
|
19
|
-
- cron: '42 12 * * 0'
|
|
20
|
-
|
|
21
|
-
jobs:
|
|
22
|
-
analyze:
|
|
23
|
-
name: Analyze
|
|
24
|
-
runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }}
|
|
25
|
-
permissions:
|
|
26
|
-
actions: read
|
|
27
|
-
contents: read
|
|
28
|
-
security-events: write
|
|
29
|
-
|
|
30
|
-
strategy:
|
|
31
|
-
fail-fast: false
|
|
32
|
-
matrix:
|
|
33
|
-
language: [ 'python' ]
|
|
34
|
-
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
|
|
35
|
-
# Use only 'java' to analyze code written in Java, Kotlin or both
|
|
36
|
-
# Use only 'javascript' to analyze code written in JavaScript, TypeScript or both
|
|
37
|
-
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
|
|
38
|
-
|
|
39
|
-
steps:
|
|
40
|
-
- name: Checkout repository
|
|
41
|
-
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3
|
|
42
|
-
|
|
43
|
-
# Initializes the CodeQL tools for scanning.
|
|
44
|
-
- name: Initialize CodeQL
|
|
45
|
-
uses: github/codeql-action/init@b8d3b6e8af63cde30bdc382c0bc28114f4346c88 # v2
|
|
46
|
-
with:
|
|
47
|
-
languages: ${{ matrix.language }}
|
|
48
|
-
# If you wish to specify custom queries, you can do so here or in a config file.
|
|
49
|
-
# By default, queries listed here will override any specified in a config file.
|
|
50
|
-
# Prefix the list here with "+" to use these queries and those in the config file.
|
|
51
|
-
|
|
52
|
-
# For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
|
|
53
|
-
# queries: security-extended,security-and-quality
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
# Autobuild attempts to build any compiled languages (C/C++, C#, Go, or Java).
|
|
57
|
-
# If this step fails, then you should remove it and run the build manually (see below)
|
|
58
|
-
- name: Autobuild
|
|
59
|
-
uses: github/codeql-action/autobuild@b8d3b6e8af63cde30bdc382c0bc28114f4346c88 # v2
|
|
60
|
-
|
|
61
|
-
# ℹ️ Command-line programs to run using the OS shell.
|
|
62
|
-
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
|
|
63
|
-
|
|
64
|
-
# If the Autobuild fails above, remove it and uncomment the following three lines.
|
|
65
|
-
# modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.
|
|
66
|
-
|
|
67
|
-
# - run: |
|
|
68
|
-
# echo "Run, Build Application using script"
|
|
69
|
-
# ./location_of_script_within_repo/buildscript.sh
|
|
70
|
-
|
|
71
|
-
- name: Perform CodeQL Analysis
|
|
72
|
-
uses: github/codeql-action/analyze@b8d3b6e8af63cde30bdc382c0bc28114f4346c88 # v2
|
|
73
|
-
with:
|
|
74
|
-
category: "/language:${{matrix.language}}"
|
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
# Byte-compiled / optimized / DLL files
|
|
2
|
-
__pycache__/
|
|
3
|
-
*.py[cod]
|
|
4
|
-
*$py.class
|
|
5
|
-
|
|
6
|
-
# C extensions
|
|
7
|
-
*.so
|
|
8
|
-
|
|
9
|
-
# Distribution / packaging
|
|
10
|
-
.Python
|
|
11
|
-
build/
|
|
12
|
-
develop-eggs/
|
|
13
|
-
dist/
|
|
14
|
-
downloads/
|
|
15
|
-
eggs/
|
|
16
|
-
.eggs/
|
|
17
|
-
lib/
|
|
18
|
-
lib64/
|
|
19
|
-
parts/
|
|
20
|
-
sdist/
|
|
21
|
-
var/
|
|
22
|
-
wheels/
|
|
23
|
-
pip-wheel-metadata/
|
|
24
|
-
share/python-wheels/
|
|
25
|
-
*.egg-info/
|
|
26
|
-
.installed.cfg
|
|
27
|
-
*.egg
|
|
28
|
-
MANIFEST
|
|
29
|
-
|
|
30
|
-
# PyInstaller
|
|
31
|
-
# Usually these files are written by a python script from a template
|
|
32
|
-
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
33
|
-
*.manifest
|
|
34
|
-
*.spec
|
|
35
|
-
|
|
36
|
-
# Installer logs
|
|
37
|
-
pip-log.txt
|
|
38
|
-
pip-delete-this-directory.txt
|
|
39
|
-
|
|
40
|
-
# Unit test / coverage reports
|
|
41
|
-
htmlcov/
|
|
42
|
-
.tox/
|
|
43
|
-
.nox/
|
|
44
|
-
.coverage
|
|
45
|
-
.coverage.*
|
|
46
|
-
.cache
|
|
47
|
-
nosetests.xml
|
|
48
|
-
coverage.xml
|
|
49
|
-
*.cover
|
|
50
|
-
*.py,cover
|
|
51
|
-
.hypothesis/
|
|
52
|
-
.pytest_cache/
|
|
53
|
-
|
|
54
|
-
# Translations
|
|
55
|
-
*.mo
|
|
56
|
-
*.pot
|
|
57
|
-
|
|
58
|
-
# Django stuff:
|
|
59
|
-
*.log
|
|
60
|
-
local_settings.py
|
|
61
|
-
db.sqlite3
|
|
62
|
-
db.sqlite3-journal
|
|
63
|
-
|
|
64
|
-
# Flask stuff:
|
|
65
|
-
instance/
|
|
66
|
-
.webassets-cache
|
|
67
|
-
|
|
68
|
-
# Scrapy stuff:
|
|
69
|
-
.scrapy
|
|
70
|
-
|
|
71
|
-
# Sphinx documentation
|
|
72
|
-
docs/_build/
|
|
73
|
-
|
|
74
|
-
# PyBuilder
|
|
75
|
-
target/
|
|
76
|
-
|
|
77
|
-
# Jupyter Notebook
|
|
78
|
-
.ipynb_checkpoints
|
|
79
|
-
|
|
80
|
-
# IPython
|
|
81
|
-
profile_default/
|
|
82
|
-
ipython_config.py
|
|
83
|
-
|
|
84
|
-
# pyenv
|
|
85
|
-
.python-version
|
|
86
|
-
|
|
87
|
-
# pipenv
|
|
88
|
-
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
|
89
|
-
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
|
90
|
-
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
|
91
|
-
# install all needed dependencies.
|
|
92
|
-
#Pipfile.lock
|
|
93
|
-
|
|
94
|
-
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
|
|
95
|
-
__pypackages__/
|
|
96
|
-
|
|
97
|
-
# Celery stuff
|
|
98
|
-
celerybeat-schedule
|
|
99
|
-
celerybeat.pid
|
|
100
|
-
|
|
101
|
-
# SageMath parsed files
|
|
102
|
-
*.sage.py
|
|
103
|
-
|
|
104
|
-
# Environments
|
|
105
|
-
.env
|
|
106
|
-
.venv
|
|
107
|
-
env/
|
|
108
|
-
venv/
|
|
109
|
-
ENV/
|
|
110
|
-
env.bak/
|
|
111
|
-
venv.bak/
|
|
112
|
-
|
|
113
|
-
# Spyder project settings
|
|
114
|
-
.spyderproject
|
|
115
|
-
.spyproject
|
|
116
|
-
|
|
117
|
-
# Rope project settings
|
|
118
|
-
.ropeproject
|
|
119
|
-
|
|
120
|
-
# mkdocs documentation
|
|
121
|
-
/site
|
|
122
|
-
|
|
123
|
-
# mypy
|
|
124
|
-
.mypy_cache/
|
|
125
|
-
.dmypy.json
|
|
126
|
-
dmypy.json
|
|
127
|
-
|
|
128
|
-
# Pyre type checker
|
|
129
|
-
.pyre/
|
|
@@ -1,723 +0,0 @@
|
|
|
1
|
-
import re
|
|
2
|
-
|
|
3
|
-
from _pytest.pytester import LineMatcher
|
|
4
|
-
|
|
5
|
-
import pytest_markdown_docs # hack: used for storing a side effect in one of the tests
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
def test_docstring_markdown(testdir):
|
|
9
|
-
testdir.makeconftest(
|
|
10
|
-
"""
|
|
11
|
-
def pytest_markdown_docs_globals():
|
|
12
|
-
return {"a": "hello"}
|
|
13
|
-
"""
|
|
14
|
-
)
|
|
15
|
-
testdir.makepyfile(
|
|
16
|
-
"""
|
|
17
|
-
def simple():
|
|
18
|
-
\"\"\"
|
|
19
|
-
```python
|
|
20
|
-
import pytest_markdown_docs
|
|
21
|
-
pytest_markdown_docs.side_effect = "hello"
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
```
|
|
25
|
-
not a python block
|
|
26
|
-
```
|
|
27
|
-
\"\"\"
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
class Parent:
|
|
31
|
-
def using_global(self):
|
|
32
|
-
\"\"\"
|
|
33
|
-
```python
|
|
34
|
-
assert a + " world" == "hello world"
|
|
35
|
-
```
|
|
36
|
-
\"\"\"
|
|
37
|
-
|
|
38
|
-
def failing():
|
|
39
|
-
\"\"\"
|
|
40
|
-
```python
|
|
41
|
-
assert False
|
|
42
|
-
```
|
|
43
|
-
\"\"\"
|
|
44
|
-
|
|
45
|
-
def error():
|
|
46
|
-
\"\"\"
|
|
47
|
-
```python
|
|
48
|
-
raise Exception("oops")
|
|
49
|
-
```
|
|
50
|
-
\"\"\"
|
|
51
|
-
"""
|
|
52
|
-
)
|
|
53
|
-
result = testdir.runpytest("--markdown-docs")
|
|
54
|
-
result.assert_outcomes(passed=2, failed=2)
|
|
55
|
-
assert (
|
|
56
|
-
getattr(pytest_markdown_docs, "side_effect", None) == "hello"
|
|
57
|
-
) # hack to make sure the test actually does something
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
def test_markdown_text_file(testdir):
|
|
61
|
-
testdir.makeconftest(
|
|
62
|
-
"""
|
|
63
|
-
def pytest_markdown_docs_globals():
|
|
64
|
-
return {"a": "hello"}
|
|
65
|
-
"""
|
|
66
|
-
)
|
|
67
|
-
|
|
68
|
-
testdir.makefile(
|
|
69
|
-
".md",
|
|
70
|
-
"""
|
|
71
|
-
```python
|
|
72
|
-
assert a + " world" == "hello world"
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
```python
|
|
76
|
-
assert False
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
```python
|
|
80
|
-
**@ # this is a syntax error
|
|
81
|
-
```
|
|
82
|
-
""",
|
|
83
|
-
)
|
|
84
|
-
result = testdir.runpytest("--markdown-docs")
|
|
85
|
-
result.assert_outcomes(passed=1, failed=2)
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
def test_continuation(testdir):
|
|
89
|
-
testdir.makefile(
|
|
90
|
-
".md",
|
|
91
|
-
"""
|
|
92
|
-
```python
|
|
93
|
-
b = "hello"
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
```python continuation
|
|
97
|
-
assert b + " world" == "hello world"
|
|
98
|
-
```
|
|
99
|
-
""",
|
|
100
|
-
)
|
|
101
|
-
result = testdir.runpytest("--markdown-docs")
|
|
102
|
-
result.assert_outcomes(passed=2)
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
def test_traceback(testdir):
|
|
106
|
-
testdir.makefile(
|
|
107
|
-
".md",
|
|
108
|
-
"""
|
|
109
|
-
yada yada yada
|
|
110
|
-
|
|
111
|
-
```python
|
|
112
|
-
def foo():
|
|
113
|
-
raise Exception("doh")
|
|
114
|
-
|
|
115
|
-
def bar():
|
|
116
|
-
foo()
|
|
117
|
-
|
|
118
|
-
foo()
|
|
119
|
-
```
|
|
120
|
-
""",
|
|
121
|
-
)
|
|
122
|
-
result = testdir.runpytest("--markdown-docs")
|
|
123
|
-
result.assert_outcomes(passed=0, failed=1)
|
|
124
|
-
|
|
125
|
-
# we check the traceback vs a regex pattern since the file paths can change
|
|
126
|
-
expected_output_pattern = r"""
|
|
127
|
-
Error in code block:
|
|
128
|
-
```
|
|
129
|
-
4 def foo\(\):
|
|
130
|
-
5 raise Exception\("doh"\)
|
|
131
|
-
6
|
|
132
|
-
7 def bar\(\):
|
|
133
|
-
8 foo\(\)
|
|
134
|
-
9
|
|
135
|
-
10 foo\(\)
|
|
136
|
-
```
|
|
137
|
-
Traceback \(most recent call last\):
|
|
138
|
-
File ".*/test_traceback.md", line 10, in <module>
|
|
139
|
-
foo\(\)
|
|
140
|
-
File ".*/test_traceback.md", line 5, in foo
|
|
141
|
-
raise Exception\("doh"\)
|
|
142
|
-
Exception: doh
|
|
143
|
-
""".strip()
|
|
144
|
-
pytest_output = "\n".join(line.rstrip() for line in result.outlines).strip()
|
|
145
|
-
assert re.search(expected_output_pattern, pytest_output) is not None, (
|
|
146
|
-
"Output traceback doesn't match expected value"
|
|
147
|
-
)
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
def test_autouse_fixtures(testdir):
|
|
151
|
-
testdir.makeconftest(
|
|
152
|
-
"""
|
|
153
|
-
import pytest
|
|
154
|
-
|
|
155
|
-
@pytest.fixture(autouse=True)
|
|
156
|
-
def initialize():
|
|
157
|
-
import pytest_markdown_docs
|
|
158
|
-
pytest_markdown_docs.bump = getattr(pytest_markdown_docs, "bump", 0) + 1
|
|
159
|
-
yield
|
|
160
|
-
pytest_markdown_docs.bump -= 1
|
|
161
|
-
"""
|
|
162
|
-
)
|
|
163
|
-
|
|
164
|
-
testdir.makefile(
|
|
165
|
-
".md",
|
|
166
|
-
"""
|
|
167
|
-
```python
|
|
168
|
-
import pytest_markdown_docs
|
|
169
|
-
assert pytest_markdown_docs.bump == 1
|
|
170
|
-
```
|
|
171
|
-
""",
|
|
172
|
-
)
|
|
173
|
-
result = testdir.runpytest("--markdown-docs")
|
|
174
|
-
result.assert_outcomes(passed=1)
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
def test_specific_fixtures(testdir):
|
|
178
|
-
testdir.makeconftest(
|
|
179
|
-
"""
|
|
180
|
-
import pytest
|
|
181
|
-
|
|
182
|
-
@pytest.fixture()
|
|
183
|
-
def initialize_specific():
|
|
184
|
-
import pytest_markdown_docs
|
|
185
|
-
pytest_markdown_docs.bump = getattr(pytest_markdown_docs, "bump", 0) + 1
|
|
186
|
-
yield "foobar"
|
|
187
|
-
pytest_markdown_docs.bump -= 1
|
|
188
|
-
"""
|
|
189
|
-
)
|
|
190
|
-
|
|
191
|
-
testdir.makefile(
|
|
192
|
-
".md",
|
|
193
|
-
"""
|
|
194
|
-
\"\"\"
|
|
195
|
-
```python fixture:initialize_specific
|
|
196
|
-
import pytest_markdown_docs
|
|
197
|
-
assert pytest_markdown_docs.bump == 1
|
|
198
|
-
assert initialize_specific == "foobar"
|
|
199
|
-
```
|
|
200
|
-
\"\"\"
|
|
201
|
-
""",
|
|
202
|
-
)
|
|
203
|
-
result = testdir.runpytest("--markdown-docs")
|
|
204
|
-
result.assert_outcomes(passed=1)
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
def test_non_existing_fixture_error(testdir):
|
|
208
|
-
testdir.makeconftest(
|
|
209
|
-
"""
|
|
210
|
-
import pytest
|
|
211
|
-
|
|
212
|
-
@pytest.fixture()
|
|
213
|
-
def foo():
|
|
214
|
-
pass
|
|
215
|
-
"""
|
|
216
|
-
)
|
|
217
|
-
|
|
218
|
-
testdir.makefile(
|
|
219
|
-
".md",
|
|
220
|
-
"""
|
|
221
|
-
\"\"\"
|
|
222
|
-
```python fixture:bar
|
|
223
|
-
```
|
|
224
|
-
\"\"\"
|
|
225
|
-
""",
|
|
226
|
-
)
|
|
227
|
-
result = testdir.runpytest("--markdown-docs")
|
|
228
|
-
assert "fixture 'bar' not found" in result.stdout.str()
|
|
229
|
-
result.assert_outcomes(errors=1)
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
def test_fixture_overriding_global(testdir):
|
|
233
|
-
testdir.makeconftest(
|
|
234
|
-
"""
|
|
235
|
-
import pytest
|
|
236
|
-
|
|
237
|
-
def pytest_markdown_docs_globals():
|
|
238
|
-
return {
|
|
239
|
-
"some_global": "foo"
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
@pytest.fixture()
|
|
243
|
-
def some_global():
|
|
244
|
-
return "bar"
|
|
245
|
-
"""
|
|
246
|
-
)
|
|
247
|
-
|
|
248
|
-
testdir.makefile(
|
|
249
|
-
".md",
|
|
250
|
-
"""
|
|
251
|
-
\"\"\"
|
|
252
|
-
```python
|
|
253
|
-
assert some_global == "foo"
|
|
254
|
-
```
|
|
255
|
-
|
|
256
|
-
```python fixture:some_global
|
|
257
|
-
assert some_global == "bar"
|
|
258
|
-
```
|
|
259
|
-
\"\"\"
|
|
260
|
-
""",
|
|
261
|
-
)
|
|
262
|
-
result = testdir.runpytest("--markdown-docs")
|
|
263
|
-
result.assert_outcomes(passed=2)
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
def test_continuation_mdx_comment(testdir):
|
|
267
|
-
testdir.makefile(
|
|
268
|
-
".mdx",
|
|
269
|
-
"""
|
|
270
|
-
```python
|
|
271
|
-
b = "hello"
|
|
272
|
-
```
|
|
273
|
-
{/* pmd-metadata: continuation */}
|
|
274
|
-
```python
|
|
275
|
-
assert b + " world" == "hello world"
|
|
276
|
-
```
|
|
277
|
-
""",
|
|
278
|
-
)
|
|
279
|
-
result = testdir.runpytest("--markdown-docs")
|
|
280
|
-
result.assert_outcomes(passed=2)
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
def test_specific_fixture_mdx_comment(testdir):
|
|
284
|
-
testdir.makeconftest(
|
|
285
|
-
"""
|
|
286
|
-
import pytest
|
|
287
|
-
@pytest.fixture()
|
|
288
|
-
def initialize_specific():
|
|
289
|
-
import pytest_markdown_docs
|
|
290
|
-
pytest_markdown_docs.bump = getattr(pytest_markdown_docs, "bump", 0) + 1
|
|
291
|
-
yield "foobar"
|
|
292
|
-
pytest_markdown_docs.bump -= 1
|
|
293
|
-
"""
|
|
294
|
-
)
|
|
295
|
-
|
|
296
|
-
testdir.makefile(
|
|
297
|
-
".mdx",
|
|
298
|
-
"""
|
|
299
|
-
{/* pmd-metadata: fixture:initialize_specific */}
|
|
300
|
-
```python
|
|
301
|
-
import pytest_markdown_docs
|
|
302
|
-
assert pytest_markdown_docs.bump == 1
|
|
303
|
-
assert initialize_specific == "foobar"
|
|
304
|
-
```
|
|
305
|
-
""",
|
|
306
|
-
)
|
|
307
|
-
result = testdir.runpytest("--markdown-docs")
|
|
308
|
-
result.assert_outcomes(passed=1)
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
def test_multiple_fixtures_mdx_comment(testdir):
|
|
312
|
-
testdir.makeconftest(
|
|
313
|
-
"""
|
|
314
|
-
import pytest
|
|
315
|
-
@pytest.fixture()
|
|
316
|
-
def initialize_specific():
|
|
317
|
-
import pytest_markdown_docs
|
|
318
|
-
pytest_markdown_docs.bump = getattr(pytest_markdown_docs, "bump", 0) + 1
|
|
319
|
-
yield "foobar"
|
|
320
|
-
pytest_markdown_docs.bump -= 1
|
|
321
|
-
|
|
322
|
-
@pytest.fixture
|
|
323
|
-
def another_fixture():
|
|
324
|
-
return "hello"
|
|
325
|
-
"""
|
|
326
|
-
)
|
|
327
|
-
|
|
328
|
-
testdir.makefile(
|
|
329
|
-
".mdx",
|
|
330
|
-
"""
|
|
331
|
-
{/* pmd-metadata: fixture:initialize_specific fixture:another_fixture */}
|
|
332
|
-
```python
|
|
333
|
-
import pytest_markdown_docs
|
|
334
|
-
assert pytest_markdown_docs.bump == 1
|
|
335
|
-
assert initialize_specific == "foobar"
|
|
336
|
-
```
|
|
337
|
-
""",
|
|
338
|
-
)
|
|
339
|
-
result = testdir.runpytest("--markdown-docs")
|
|
340
|
-
result.assert_outcomes(passed=1)
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
def test_notest_mdx_comment(testdir):
|
|
344
|
-
testdir.makefile(
|
|
345
|
-
".mdx",
|
|
346
|
-
"""
|
|
347
|
-
{/* pmd-metadata: notest */}
|
|
348
|
-
```python
|
|
349
|
-
assert True
|
|
350
|
-
```
|
|
351
|
-
""",
|
|
352
|
-
)
|
|
353
|
-
result = testdir.runpytest("--markdown-docs")
|
|
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
|
-
)
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
def test_custom_runner(testdir):
|
|
437
|
-
testdir.makeconftest(
|
|
438
|
-
"""
|
|
439
|
-
import pytest_markdown_docs._runners
|
|
440
|
-
|
|
441
|
-
@pytest_markdown_docs._runners.register_runner()
|
|
442
|
-
class LinesAreAllFoo(pytest_markdown_docs._runners.DefaultRunner):
|
|
443
|
-
def runtest(self, test, args):
|
|
444
|
-
lines = test.source.strip().split("\\n")
|
|
445
|
-
for line in lines:
|
|
446
|
-
assert line == "foo"
|
|
447
|
-
"""
|
|
448
|
-
)
|
|
449
|
-
testdir.makefile(
|
|
450
|
-
".md",
|
|
451
|
-
"""
|
|
452
|
-
```python runner:LinesAreAllFoo
|
|
453
|
-
foo
|
|
454
|
-
foo
|
|
455
|
-
```
|
|
456
|
-
|
|
457
|
-
```python runner:LinesAreAllFoo
|
|
458
|
-
foo
|
|
459
|
-
bar
|
|
460
|
-
```
|
|
461
|
-
""",
|
|
462
|
-
)
|
|
463
|
-
|
|
464
|
-
result = testdir.runpytest("-v", "--markdown-docs")
|
|
465
|
-
result.assert_outcomes(passed=1, failed=1)
|
|
466
|
-
result.stdout.re_match_lines(
|
|
467
|
-
[
|
|
468
|
-
r".*\[CodeFence#1\]\[line:1\].*PASSED.*",
|
|
469
|
-
r".*\[CodeFence#2\]\[line:6\].*FAILED.*",
|
|
470
|
-
],
|
|
471
|
-
consecutive=True,
|
|
472
|
-
)
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
def test_admonition_markdown_text_file(testdir):
|
|
476
|
-
testdir.makeconftest(
|
|
477
|
-
"""
|
|
478
|
-
def pytest_markdown_docs_globals():
|
|
479
|
-
return {"a": "hello"}
|
|
480
|
-
|
|
481
|
-
def pytest_markdown_docs_markdown_it():
|
|
482
|
-
import markdown_it
|
|
483
|
-
from mdit_py_plugins.admon import admon_plugin
|
|
484
|
-
|
|
485
|
-
mi = markdown_it.MarkdownIt(config="commonmark")
|
|
486
|
-
mi.use(admon_plugin)
|
|
487
|
-
return mi
|
|
488
|
-
"""
|
|
489
|
-
)
|
|
490
|
-
|
|
491
|
-
testdir.makefile(
|
|
492
|
-
".md",
|
|
493
|
-
"""
|
|
494
|
-
??? quote
|
|
495
|
-
|
|
496
|
-
```python
|
|
497
|
-
assert a + " world" == "hello world"
|
|
498
|
-
```
|
|
499
|
-
|
|
500
|
-
!!! info
|
|
501
|
-
```python
|
|
502
|
-
assert False
|
|
503
|
-
```
|
|
504
|
-
|
|
505
|
-
???+ note
|
|
506
|
-
```python
|
|
507
|
-
**@ # this is a syntax error
|
|
508
|
-
```
|
|
509
|
-
""",
|
|
510
|
-
)
|
|
511
|
-
result = testdir.runpytest("--markdown-docs")
|
|
512
|
-
result.assert_outcomes(passed=1, failed=2)
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
def test_retry_eventually_succeeds(testdir):
|
|
516
|
-
"""Test that a flaky test succeeds after retrying."""
|
|
517
|
-
testdir.makepyfile(
|
|
518
|
-
conftest="""
|
|
519
|
-
attempt_counter = {}
|
|
520
|
-
"""
|
|
521
|
-
)
|
|
522
|
-
testdir.makefile(
|
|
523
|
-
".md",
|
|
524
|
-
test_file="""
|
|
525
|
-
```python retry:3
|
|
526
|
-
import conftest
|
|
527
|
-
key = "test_1"
|
|
528
|
-
conftest.attempt_counter[key] = conftest.attempt_counter.get(key, 0) + 1
|
|
529
|
-
assert conftest.attempt_counter[key] >= 2 # Fails first time, passes on retry
|
|
530
|
-
```
|
|
531
|
-
""",
|
|
532
|
-
)
|
|
533
|
-
result = testdir.runpytest("--markdown-docs")
|
|
534
|
-
result.assert_outcomes(passed=1)
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
def test_retry_exhausted(testdir):
|
|
538
|
-
"""Test that a test fails after all retry attempts are exhausted."""
|
|
539
|
-
testdir.makefile(
|
|
540
|
-
".md",
|
|
541
|
-
test_file="""
|
|
542
|
-
```python retry:2
|
|
543
|
-
assert False # Always fails
|
|
544
|
-
```
|
|
545
|
-
""",
|
|
546
|
-
)
|
|
547
|
-
result = testdir.runpytest("--markdown-docs")
|
|
548
|
-
result.assert_outcomes(failed=1)
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
def test_retry_with_fixture(testdir):
|
|
552
|
-
"""Test that fixtures are not re-run between retries."""
|
|
553
|
-
testdir.makepyfile(
|
|
554
|
-
conftest="""
|
|
555
|
-
import pytest
|
|
556
|
-
|
|
557
|
-
fixture_call_count = 0
|
|
558
|
-
|
|
559
|
-
@pytest.fixture
|
|
560
|
-
def counting_fixture():
|
|
561
|
-
global fixture_call_count
|
|
562
|
-
fixture_call_count += 1
|
|
563
|
-
return fixture_call_count
|
|
564
|
-
|
|
565
|
-
attempt_counter = {}
|
|
566
|
-
"""
|
|
567
|
-
)
|
|
568
|
-
testdir.makefile(
|
|
569
|
-
".md",
|
|
570
|
-
test_file="""
|
|
571
|
-
```python retry:3 fixture:counting_fixture
|
|
572
|
-
import conftest
|
|
573
|
-
key = "test_2"
|
|
574
|
-
conftest.attempt_counter[key] = conftest.attempt_counter.get(key, 0) + 1
|
|
575
|
-
|
|
576
|
-
# Fixture should only be called once (value should stay 1)
|
|
577
|
-
assert counting_fixture == 1
|
|
578
|
-
|
|
579
|
-
# Fail on first attempt, pass on second
|
|
580
|
-
assert conftest.attempt_counter[key] >= 2
|
|
581
|
-
```
|
|
582
|
-
""",
|
|
583
|
-
)
|
|
584
|
-
result = testdir.runpytest("--markdown-docs")
|
|
585
|
-
result.assert_outcomes(passed=1)
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
def test_retry_with_continuation(testdir):
|
|
589
|
-
"""Test that retry works with continuation blocks."""
|
|
590
|
-
testdir.makepyfile(
|
|
591
|
-
conftest="""
|
|
592
|
-
attempt_counter = {}
|
|
593
|
-
"""
|
|
594
|
-
)
|
|
595
|
-
testdir.makefile(
|
|
596
|
-
".md",
|
|
597
|
-
test_file="""
|
|
598
|
-
```python
|
|
599
|
-
a = "hello"
|
|
600
|
-
```
|
|
601
|
-
|
|
602
|
-
```python retry:2 continuation
|
|
603
|
-
import conftest
|
|
604
|
-
key = "test_3"
|
|
605
|
-
conftest.attempt_counter[key] = conftest.attempt_counter.get(key, 0) + 1
|
|
606
|
-
|
|
607
|
-
# Variable 'a' from previous block should be available
|
|
608
|
-
assert a + " world" == "hello world"
|
|
609
|
-
|
|
610
|
-
# Fail on first attempt, pass on second
|
|
611
|
-
assert conftest.attempt_counter[key] >= 2
|
|
612
|
-
```
|
|
613
|
-
""",
|
|
614
|
-
)
|
|
615
|
-
result = testdir.runpytest("--markdown-docs")
|
|
616
|
-
result.assert_outcomes(passed=2)
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
def test_retry_invalid_negative(testdir):
|
|
620
|
-
"""Test that negative retry counts raise an error."""
|
|
621
|
-
testdir.makefile(
|
|
622
|
-
".md",
|
|
623
|
-
test_file="""
|
|
624
|
-
```python retry:-1
|
|
625
|
-
assert True
|
|
626
|
-
```
|
|
627
|
-
""",
|
|
628
|
-
)
|
|
629
|
-
result = testdir.runpytest("--markdown-docs")
|
|
630
|
-
result.assert_outcomes(errors=1)
|
|
631
|
-
result.stdout.fnmatch_lines(["*Invalid retry count*non-negative integer*"])
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
def test_retry_invalid_non_numeric(testdir):
|
|
635
|
-
"""Test that non-numeric retry counts raise an error."""
|
|
636
|
-
testdir.makefile(
|
|
637
|
-
".md",
|
|
638
|
-
test_file="""
|
|
639
|
-
```python retry:abc
|
|
640
|
-
assert True
|
|
641
|
-
```
|
|
642
|
-
""",
|
|
643
|
-
)
|
|
644
|
-
result = testdir.runpytest("--markdown-docs")
|
|
645
|
-
result.assert_outcomes(errors=1)
|
|
646
|
-
result.stdout.fnmatch_lines(["*Invalid retry count*non-negative integer*"])
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
def test_retry_multiple_values_error(testdir):
|
|
650
|
-
"""Test that multiple retry values raise an error."""
|
|
651
|
-
testdir.makefile(
|
|
652
|
-
".md",
|
|
653
|
-
test_file="""
|
|
654
|
-
```python retry:2 retry:3
|
|
655
|
-
assert True
|
|
656
|
-
```
|
|
657
|
-
""",
|
|
658
|
-
)
|
|
659
|
-
result = testdir.runpytest("--markdown-docs")
|
|
660
|
-
result.assert_outcomes(errors=1)
|
|
661
|
-
result.stdout.fnmatch_lines(["*Multiple retry counts are not supported*"])
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
def test_retry_zero(testdir):
|
|
665
|
-
"""Test that retry:0 behaves the same as no retry."""
|
|
666
|
-
testdir.makefile(
|
|
667
|
-
".md",
|
|
668
|
-
test_file="""
|
|
669
|
-
```python retry:0
|
|
670
|
-
assert False
|
|
671
|
-
```
|
|
672
|
-
""",
|
|
673
|
-
)
|
|
674
|
-
result = testdir.runpytest("--markdown-docs")
|
|
675
|
-
result.assert_outcomes(failed=1)
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
def test_retry_mdx_comment(testdir):
|
|
679
|
-
"""Test that retry works with MDX comment metadata."""
|
|
680
|
-
testdir.makepyfile(
|
|
681
|
-
conftest="""
|
|
682
|
-
attempt_counter = {}
|
|
683
|
-
"""
|
|
684
|
-
)
|
|
685
|
-
testdir.makefile(
|
|
686
|
-
".mdx",
|
|
687
|
-
test_file="""
|
|
688
|
-
{/* pmd-metadata: retry:3 */}
|
|
689
|
-
```python
|
|
690
|
-
import conftest
|
|
691
|
-
key = "test_4"
|
|
692
|
-
conftest.attempt_counter[key] = conftest.attempt_counter.get(key, 0) + 1
|
|
693
|
-
assert conftest.attempt_counter[key] >= 2
|
|
694
|
-
```
|
|
695
|
-
""",
|
|
696
|
-
)
|
|
697
|
-
result = testdir.runpytest("--markdown-docs")
|
|
698
|
-
result.assert_outcomes(passed=1)
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
def test_retry_with_docstring(testdir):
|
|
702
|
-
"""Test that retry works in Python docstrings."""
|
|
703
|
-
testdir.makepyfile(
|
|
704
|
-
conftest="""
|
|
705
|
-
attempt_counter = {}
|
|
706
|
-
"""
|
|
707
|
-
)
|
|
708
|
-
testdir.makepyfile(
|
|
709
|
-
test_module="""
|
|
710
|
-
def my_function():
|
|
711
|
-
\"\"\"
|
|
712
|
-
```python retry:3
|
|
713
|
-
import conftest
|
|
714
|
-
key = "test_5"
|
|
715
|
-
conftest.attempt_counter[key] = conftest.attempt_counter.get(key, 0) + 1
|
|
716
|
-
assert conftest.attempt_counter[key] >= 2
|
|
717
|
-
```
|
|
718
|
-
\"\"\"
|
|
719
|
-
pass
|
|
720
|
-
"""
|
|
721
|
-
)
|
|
722
|
-
result = testdir.runpytest("--markdown-docs")
|
|
723
|
-
result.assert_outcomes(passed=1)
|
|
File without changes
|
{pytest_markdown_docs-0.9.1 → pytest_markdown_docs-0.9.2}/src/pytest_markdown_docs/__init__.py
RENAMED
|
File without changes
|
{pytest_markdown_docs-0.9.1 → pytest_markdown_docs-0.9.2}/src/pytest_markdown_docs/definitions.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|