pax_global_header00006660000000000000000000000064145016502720014514gustar00rootroot0000000000000052 comment=d0ca7e22b8e4d0c2d8807a9cf9e1f8ca7ef20442 pytest-codeblocks-0.17.0/000077500000000000000000000000001450165027200152375ustar00rootroot00000000000000pytest-codeblocks-0.17.0/.codecov.yml000066400000000000000000000000141450165027200174550ustar00rootroot00000000000000comment: no pytest-codeblocks-0.17.0/.flake8000066400000000000000000000001671450165027200164160ustar00rootroot00000000000000[flake8] ignore = E203, E266, E501, W503, F401, C901 max-line-length = 80 max-complexity = 18 select = B,C,E,F,W,T4,B9 pytest-codeblocks-0.17.0/.github/000077500000000000000000000000001450165027200165775ustar00rootroot00000000000000pytest-codeblocks-0.17.0/.github/renovate.json000066400000000000000000000000411450165027200213100ustar00rootroot00000000000000{ "extends": ["config:base"] } pytest-codeblocks-0.17.0/.github/workflows/000077500000000000000000000000001450165027200206345ustar00rootroot00000000000000pytest-codeblocks-0.17.0/.github/workflows/tests.yml000066400000000000000000000017161450165027200225260ustar00rootroot00000000000000name: tests on: push: branches: - main pull_request: branches: - main jobs: lint: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: pre-commit/action@v3.0.0 build: needs: [lint] strategy: matrix: platform: [ubuntu-latest] python-version: ["3.7", "3.11"] include: - platform: macos-latest python-version: "3.11" - platform: windows-latest python-version: "3.11" runs-on: ${{ matrix.platform }} steps: - uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - uses: actions/checkout@v4 - name: Test with tox run: | pip install tox tox -- --cov pytest_codeblocks --cov-report xml --cov-report term - uses: codecov/codecov-action@v4-beta if: ${{ matrix.python-version == '3.11' && matrix.os == 'ubuntu-latest' }} pytest-codeblocks-0.17.0/.gitignore000066400000000000000000000001231450165027200172230ustar00rootroot00000000000000.cache/ build/ doc/_build/ doc/build/ *.egg-info/ dist/ *.png .pytest_cache/ .tox/ pytest-codeblocks-0.17.0/.pre-commit-config.yaml000066400000000000000000000005211450165027200215160ustar00rootroot00000000000000repos: - repo: https://github.com/charliermarsh/ruff-pre-commit rev: v0.0.290 hooks: - id: ruff - repo: https://github.com/psf/black rev: 23.9.1 hooks: - id: black language_version: python3 - repo: https://github.com/pre-commit/mirrors-prettier rev: v3.0.3 hooks: - id: prettier pytest-codeblocks-0.17.0/LICENSE.txt000066400000000000000000000021011450165027200170540ustar00rootroot00000000000000The MIT License (MIT) Copyright (c) 2020-present Nico Schlömer Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. pytest-codeblocks-0.17.0/MANIFEST.in000066400000000000000000000000461450165027200167750ustar00rootroot00000000000000include tests/*.md include tests/*.py pytest-codeblocks-0.17.0/README.md000066400000000000000000000102771450165027200165250ustar00rootroot00000000000000

pytest-codeblocks

Test code blocks in your READMEs.

[![PyPi Version](https://img.shields.io/pypi/v/pytest-codeblocks.svg?style=flat-square)](https://pypi.org/project/pytest_codeblocks/) [![Anaconda Cloud](https://anaconda.org/conda-forge/pytest-codeblocks/badges/version.svg?=style=flat-square)](https://anaconda.org/conda-forge/pytest-codeblocks/) [![PyPI pyversions](https://img.shields.io/pypi/pyversions/pytest-codeblocks.svg?style=flat-square)](https://pypi.org/project/pytest_codeblocks/) [![GitHub stars](https://img.shields.io/github/stars/nschloe/pytest-codeblocks.svg?style=flat-square&logo=github&label=Stars&logoColor=white)](https://github.com/nschloe/pytest-codeblocks) [![Downloads](https://static.pepy.tech/badge/pytest-codeblocks/month?style=flat-square)](https://www.pepy.tech/projects/pytest-codeblocks) [![gh-actions](https://img.shields.io/github/actions/workflow/status/nschloe/pytest-codeblocks/tests?style=flat-square)](https://github.com/nschloe/pytest-codeblocks/actions?query=workflow%3Atests) [![codecov](https://img.shields.io/codecov/c/github/nschloe/pytest-codeblocks.svg?style=flat-square)](https://app.codecov.io/gh/nschloe/pytest-codeblocks) [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg?style=flat-square)](https://github.com/psf/black) This is pytest-codeblocks, a [pytest](https://pytest.org/) plugin for testing code blocks from README files. It supports Python and shell code. Install with ```sh pip install pytest-codeblocks ``` and run pytest with ```sh pytest --codeblocks ``` ```sh ================================= test session starts ================================= platform linux -- Python 3.9.4, pytest-6.2.4, py-1.10.0, pluggy-0.13.1 rootdir: /path/to/directory plugins: codeblocks-0.11.0 collected 56 items example.md ....................... [ 50%] README.md ....................... [100%] ================================= 56 passed in 0.08s ================================== ``` pytest-codeblocks will only pick up code blocks with `python` and `sh`/`bash`/`zsh` syntax highlighting. #### Marking code blocks It is possible to use `pytest.mark` for marking code blocks. For example, to skip a code block use `pytest.mark.skip` or `pytest.mark.skipif`: ````markdown Lorem ipsum ```python foo + bar # not working ``` dolor sit amet. ```` ```markdown ``` You can skip code blocks on import errors with ```markdown ``` Skip the entire file by putting ```markdown ``` in the first line. For expected errors, use `pytest.mark.xfail`: ````markdown The following gives an error: ```python 1 / 0 ``` ```` #### Merging code blocks Broken-up code blocks can be merged into one with the `pytest-codeblocks:cont` prefix ````markdown Lorem ipsum ```python a = 1 ``` dolor sit amet ```python # this would otherwise fail since `a` is not defined a + 1 ``` ```` If you'd like to prepend code that you don't want to show, you can just comment it out; pytest-codeblocks will pick it up anyway: ````markdown Lorem ipsum dolor sit amet ```python # this would otherwise fail since `a` is not defined a + 1 ``` ```` #### Expected output You can also define the expected output of a code block: ````markdown This ```sh print(1 + 3) ``` gives ``` 4 ``` ```` Use `expected-output-ignore-whitespace` if you'd like whitespace differences to be ignored. (Conditionally) Skipping the output verfication works by prepending the first block with `skip`/`skipif` (see [above](#skipping-code-blocks)). pytest-codeblocks-0.17.0/justfile000066400000000000000000000007521450165027200170130ustar00rootroot00000000000000version := `python3 -c "from src.pytest_codeblocks.__about__ import __version__; print(__version__)"` default: @echo "\"just publish\"?" publish: @if [ "$(git rev-parse --abbrev-ref HEAD)" != "main" ]; then exit 1; fi gh release create "v{{version}}" flit publish clean: @find . | grep -E "(__pycache__|\.pyc|\.pyo$)" | xargs rm -rf @rm -rf src/*.egg-info/ build/ dist/ .tox/ format: ruff src/ tests/ --fix black src/ tests/ blacken-docs README.md lint: pre-commit run --all pytest-codeblocks-0.17.0/pyproject.toml000066400000000000000000000024731450165027200201610ustar00rootroot00000000000000[build-system] requires = ["setuptools>=61"] build-backend = "setuptools.build_meta" [project] name = "pytest_codeblocks" authors = [{name = "Nico Schlömer", email = "nico.schloemer@gmail.com"}] description = "Test code blocks in your READMEs" readme = "README.md" license = {file = "LICENSE.txt"} classifiers = [ "Development Status :: 5 - Production/Stable", "Framework :: Pytest", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", ] dynamic = ["version"] requires-python = ">=3.7" dependencies = [ "pytest >= 7.0.0" ] [tool.setuptools.dynamic] version = {attr = "pytest_codeblocks.__about__.__version__"} [project.urls] Homepage = "https://github.com/nschloe/pytest-codeblocks" Code = "https://github.com/nschloe/pytest-codeblocks" Issues = "https://github.com/nschloe/pytest-codeblocks/issues" Funding = "https://github.com/sponsors/nschloe" [project.entry-points.pytest11] codeblocks = "pytest_codeblocks.plugin" pytest-codeblocks-0.17.0/src/000077500000000000000000000000001450165027200160265ustar00rootroot00000000000000pytest-codeblocks-0.17.0/src/pytest_codeblocks/000077500000000000000000000000001450165027200215465ustar00rootroot00000000000000pytest-codeblocks-0.17.0/src/pytest_codeblocks/__about__.py000066400000000000000000000000271450165027200240250ustar00rootroot00000000000000__version__ = "0.17.0" pytest-codeblocks-0.17.0/src/pytest_codeblocks/__init__.py000066400000000000000000000003611450165027200236570ustar00rootroot00000000000000from . import plugin from .__about__ import __version__ from .main import CodeBlock, extract_from_buffer, extract_from_file __all__ = [ "CodeBlock", "extract_from_buffer", "extract_from_file", "plugin", "__version__", ] pytest-codeblocks-0.17.0/src/pytest_codeblocks/main.py000066400000000000000000000146461450165027200230570ustar00rootroot00000000000000from __future__ import annotations import contextlib import re import sys import warnings # namedtuple with default arguments # from dataclasses import dataclass, field from io import StringIO from pathlib import Path @dataclass class CodeBlock: code: str lineno: int syntax: str | None = None expected_output: str | None = None expected_output_ignore_whitespace: bool = False importorskip: str | None = None marks: list[str] = field(default_factory=lambda: []) def extract_from_file( f: str | bytes | Path, encoding: str | None = "utf-8", *args, **kwargs ): with open(f, encoding=encoding) as handle: return extract_from_buffer(handle, *args, **kwargs) def extract_from_buffer(f, max_num_lines: int = 10000) -> list[CodeBlock]: out = [] marks = [] continued_block = None expected_output_block = None expected_output_ignore_whitespace = False importorskip = None k = 1 while True: line = f.readline() if k == 1 and line.strip() == "": return [] k += 1 if not line: # EOF break if line.strip() == "": continue m = re.match( r"", line.strip(), ) if m is not None: keyword = m.group(1).strip("- ") # handle special tags if keyword in {"expected-output", "expected-output-ignore-whitespace"}: if len(out) == 0: raise RuntimeError( f"Found " + "but no previous code block." ) if out[-1].expected_output is not None: raise RuntimeError( f"Found " + "but block already has expected_output." ) expected_output_block = out[-1] if keyword == "expected-output-ignore-whitespace": # \s: regex matches all whitespace characters expected_output_ignore_whitespace = True elif keyword == "cont": if len(out) == 0: msg = ( "Found " "but no previous code block." ) raise RuntimeError(msg) continued_block = out[-1] elif keyword == "skip": warnings.warn( "pytest-codeblocks:skip is deprecated. Use pytest.mark.skip", DeprecationWarning, ) marks.append("pytest.mark.skip") elif keyword.startswith("skipif"): warnings.warn( "pytest-codeblocks:skipif is deprecated. Use pytest.mark.skipif", DeprecationWarning, ) m = re.match(r"skipif\((.*)\)", keyword) if m is None: raise RuntimeError( "pytest-codeblocks: Expected skipif(some-condition)" ) marks.append(f"pytest.mark.skipif({m.group(1)}, reason='')") elif keyword.startswith("importorskip"): m = re.match(r"importorskip\((.*)\)", keyword) if m is None: raise RuntimeError( "pytest-codeblocks: Expected importorskip(some-module)" ) importorskip = m.group(1) elif keyword in ["expect-exception", "expect-error"]: warnings.warn( f"pytest-codeblocks:{keyword} is deprecated. Use pytest.mark.xfail", DeprecationWarning, ) marks.append("pytest.mark.xfail") else: raise RuntimeError(f'Unknown pytest-codeblocks keyword "{keyword}"') continue m = re.match( r"", line.strip(), ) if m is not None: marks.append(m.group(1)) continue lsline = line.lstrip() if lsline.startswith("```"): # normally 3, but can be more: num_leading_backticks = len(lsline) - len(lsline.lstrip("`")) syntax = line.strip()[num_leading_backticks:] num_leading_spaces = len(line) - len(lsline) lineno = k - 1 # read the block code_block = [] while True: line = f.readline() lsline = line.lstrip() k += 1 if not line: raise RuntimeError("Hit end-of-file prematurely. Syntax error?") if k > max_num_lines: raise RuntimeError( f"File too large (> {max_num_lines} lines). Set max_num_lines." ) # check if end of block if lsline[:num_leading_backticks] == "`" * num_leading_backticks: break # Cut (at most) num_leading_spaces leading spaces nls = min(num_leading_spaces, len(line) - len(lsline)) line = line[nls:] code_block.append(line) code = "".join(code_block) if continued_block: continued_block.code += code continued_block = None elif expected_output_block: expected_output_block.expected_output = code expected_output_block.expected_output_ignore_whitespace = ( expected_output_ignore_whitespace ) expected_output_block = None else: out.append( CodeBlock( code, lineno, syntax, marks=marks, importorskip=importorskip, ) ) marks = [] importorskip = None return out # https://stackoverflow.com/a/3906390/353337 @contextlib.contextmanager def stdout_io(stdout=None): old = sys.stdout if stdout is None: stdout = StringIO() sys.stdout = stdout yield stdout sys.stdout = old pytest-codeblocks-0.17.0/src/pytest_codeblocks/plugin.py000066400000000000000000000100631450165027200234160ustar00rootroot00000000000000# # Take a look at the example # https://docs.pytest.org/en/stable/example/nonpython.html # import subprocess from pathlib import Path import re import pytest from .main import extract_from_file, stdout_io def pytest_addoption(parser): group = parser.getgroup("general") group.addoption( "--codeblocks", action="store_true", help="enable testing of code blocks", ) def pytest_collect_file(path, parent): config = parent.config path = Path(path) if config.option.codeblocks and path.suffix == ".md": return MarkdownFile.from_parent(parent, path=path) class MarkdownFile(pytest.File): def __init__(self, **kwargs): super().__init__(**kwargs) def collect(self): for block in extract_from_file(self.path): if block.syntax not in ["python", "sh", "bash"]: continue # https://docs.pytest.org/en/stable/deprecations.html#node-construction-changed-to-node-from-parent # The name makes sure that tests appear as # ``` # README.md::line 56 # ``` out = TestBlock.from_parent(parent=self, name=f"line {block.lineno}") out.obj = block for mark in block.marks: # A common thing is # # pytest.mark.skipif(sys.version_info < (3, 10), reason="...") # # which needs sys. Import it here. import sys # noqa: F401 out.add_marker(eval(mark)) yield out class TestBlock(pytest.Item): def __init__(self, name, parent, obj=None): super().__init__(name, parent=parent) self.obj = obj def runtest(self): assert self.obj is not None output = None if self.obj.importorskip is not None: try: __import__(self.obj.importorskip) except (ImportError, ModuleNotFoundError): pytest.skip() if self.obj.syntax == "python": with stdout_io() as s: try: # https://stackoverflow.com/a/62851176/353337 exec(self.obj.code, {"__MODULE__": "__main__"}) except Exception as e: raise RuntimeError( f"{self.name}, line {self.obj.lineno}:\n```\n" + self.obj.code + "```\n\n" + f"{e}" ) output = s.getvalue() else: assert self.obj.syntax in ["sh", "bash"] executable = { "sh": None, "bash": "/bin/bash", "zsh": "/bin/zsh", }[self.obj.syntax] # TODO for python 3.7+, stdout=subprocess.PIPE can be replaced # by capture_output=True ret = subprocess.run( self.obj.code, shell=True, check=True, stdout=subprocess.PIPE, executable=executable, ) output = ret.stdout.decode() if output is not None and self.obj.expected_output is not None: str0 = self.obj.expected_output str1 = output if self.obj.expected_output_ignore_whitespace: str0 = re.sub(r"\s+", "", str0) str1 = re.sub(r"\s+", "", str1) if str0 != str1: raise RuntimeError( f"{self.name}, line {self.obj.lineno}:\n```\n" + f"Expected output\n```\n{self.obj.expected_output}```\n" + f"but got\n```\n{output}```" ) def repr_failure(self, excinfo): """Called when self.runtest() raises an exception.""" # if isinstance(excinfo.value, CodeblockException): return excinfo.value.args[0] # if excinfo.errisinstance(RuntimeError): # return excinfo.value.args[0].stdout # return super().repr_failure(excinfo) def reportinfo(self): return (self.path, -1, "code block check") pytest-codeblocks-0.17.0/tests/000077500000000000000000000000001450165027200164015ustar00rootroot00000000000000pytest-codeblocks-0.17.0/tests/example.md000066400000000000000000000010371450165027200203570ustar00rootroot00000000000000```python 1 + 1 ``` Lorem ipsum ```python 1 + 2 + 3 2 + 5 ``` dolor sit amet. ```python import pytest_codeblocks pytest_codeblocks.extract_from_buffer ``` Something that should be skipped because of the language: ```ruby foobar ``` A shell script should be exectuted: ```sh echo abc ``` Again with an explicit skip: ```python bar ``` Something that contains triple fences ````python # ```import math``` ```` Indented code blocks: ```python 1 + 1 == 2 ``` "Wrong" indentation: ```python 1 + 1 == 2 ``` pytest-codeblocks-0.17.0/tests/test_comment_styles.py000066400000000000000000000010211450165027200230510ustar00rootroot00000000000000import pytest @pytest.mark.parametrize( "comment", [ "", "", "", "", ], ) def test_cont(testdir, comment): string = """ Lorem ipsum ```python a = 1 ``` dolor sit amet {comment} ``` a + 1 ``` """ testdir.makefile(".md", string) result = testdir.runpytest("--codeblocks") result.assert_outcomes(passed=1) pytest-codeblocks-0.17.0/tests/test_cont.py000066400000000000000000000015351450165027200207610ustar00rootroot00000000000000def test_cont(testdir): string = """ Lorem ipsum ```python a = 1 ``` dolor sit amet ``` a + 1 ``` """ testdir.makefile(".md", string) result = testdir.runpytest("--codeblocks") result.assert_outcomes(passed=1) def test_hidden_cont(testdir): string = """ Lorem ipsum dolor sit amet ``` a + 1 ``` """ testdir.makefile(".md", string) result = testdir.runpytest("--codeblocks") result.assert_outcomes(passed=1) def test_nocont(testdir): string = """ ```python 1 + 2 + 3 ``` """ testdir.makefile(".md", string) result = testdir.runpytest("--codeblocks") result.assert_outcomes(errors=1) pytest-codeblocks-0.17.0/tests/test_errors.py000066400000000000000000000007361450165027200213340ustar00rootroot00000000000000import io import pytest import pytest_codeblocks def test_unclosed(testdir): string = """ ```python 1 + 2 + 3 """ testdir.makefile(".md", string) result = testdir.runpytest("--codeblocks") result.assert_outcomes(errors=1) def test_maxlines(): unclosed = io.StringIO( """ ```python 1 + 2 + 3 ``` """ ) with pytest.raises(RuntimeError): pytest_codeblocks.extract_from_buffer(unclosed, max_num_lines=1) pytest-codeblocks-0.17.0/tests/test_expect_error.py000066400000000000000000000021051450165027200225110ustar00rootroot00000000000000def test_expect_error(testdir): string = """ ```python raise RuntimeError() ``` """ testdir.makefile(".md", string) result = testdir.runpytest("--codeblocks") result.assert_outcomes(xfailed=1) def test_expect_error_runtimeerror(testdir): string = """ ```python raise RuntimeError() ``` """ testdir.makefile(".md", string) result = testdir.runpytest("--codeblocks") result.assert_outcomes(xfailed=1) def test_expect_error_indexerror(testdir): string = """ ```python raise RuntimeError() ``` """ testdir.makefile(".md", string) result = testdir.runpytest("--codeblocks") result.assert_outcomes(failed=1) def test_expect_error_fail(testdir): string1 = """ Lorem ipsum ```python 1 + 1 ``` """ testdir.makefile(".md", string1) result = testdir.runpytest("--codeblocks") result.assert_outcomes(xpassed=1) pytest-codeblocks-0.17.0/tests/test_expected_output.py000066400000000000000000000026011450165027200232320ustar00rootroot00000000000000def test_expected_output(testdir): string = """ Lorem ipsum ```python print(1 + 3) print(1 - 3) print(1 * 3) ``` dolor sit amet ``` 4 -2 3 ``` """ testdir.makefile(".md", string) result = testdir.runpytest("--codeblocks") result.assert_outcomes(passed=1) def test_expected_output_fail(testdir): string = """ Lorem ipsum ```python print(1 + 3) ``` dolor sit amet ``` 5 ``` """ testdir.makefile(".md", string) result = testdir.runpytest("--codeblocks") result.assert_outcomes(failed=1) def test_expected_output_ignore_whitespace(testdir): string = """ Lorem ipsum ```python print(1 + 3) print(1 - 3) print(1 * 3) ``` dolor sit amet ``` 4 -2 3 ``` """ testdir.makefile(".md", string) result = testdir.runpytest("--codeblocks") result.assert_outcomes(passed=1) def test_expected_output_ignore_whitespace_fail(testdir): string = """ Lorem ipsum ```python print(1 + 3) print(1 - 3) print(1 * 3) ``` dolor sit amet ``` 4 -2 5 ``` """ testdir.makefile(".md", string) result = testdir.runpytest("--codeblocks") result.assert_outcomes(failed=1) pytest-codeblocks-0.17.0/tests/test_general.py000066400000000000000000000032631450165027200214330ustar00rootroot00000000000000import pathlib import pytest_codeblocks def test_basic(testdir): string1 = """ Lorem ipsum ```python 1 + 2 + 3 ``` dolor sit amet """ testdir.makefile(".md", string1) result = testdir.runpytest("--codeblocks") result.assert_outcomes(passed=1) def test_skip(testdir): string1 = """ Lorem ipsum ```python 1 + 2 + 3 ``` dolor sit amet Some newlines: ```python 1 + 2 + 3 ``` """ testdir.makefile(".md", string1) result = testdir.runpytest("--codeblocks") result.assert_outcomes(skipped=2) # example.md against reference strings test against def test_reference(): ref = [ pytest_codeblocks.CodeBlock("1 + 1\n", 1, "python"), pytest_codeblocks.CodeBlock("1 + 2 + 3\n2 + 5\n", 7, "python"), pytest_codeblocks.CodeBlock( "import pytest_codeblocks\n\npytest_codeblocks.extract_from_buffer\n", 14, "python", ), pytest_codeblocks.CodeBlock("foobar\n", 22, "ruby"), pytest_codeblocks.CodeBlock("echo abc\n", 28, "sh"), pytest_codeblocks.CodeBlock("bar\n", 36, "python", marks=["pytest.mark.skip"]), pytest_codeblocks.CodeBlock("# ```import math```\n", 42, "python"), pytest_codeblocks.CodeBlock("1 + 1 == 2\n", 48, "python"), pytest_codeblocks.CodeBlock("1 + 1 == 2\n", 54, "python"), ] this_dir = pathlib.Path(__file__).resolve().parent lst = pytest_codeblocks.extract_from_file(this_dir / "example.md") print(lst) for r, obj in zip(ref, lst): print("\n\nr ", r) print("\nobj", obj) assert r == obj pytest-codeblocks-0.17.0/tests/test_shell.py000066400000000000000000000036721450165027200211310ustar00rootroot00000000000000import sys import pytest if sys.platform.startswith("win"): pytest.skip("skipping shell tests", allow_module_level=True) def test_shell(testdir): string = """ Lorem ipsum ```sh ls ``` dolor sit amet ```sh cd ``` """ testdir.makefile(".md", string) result = testdir.runpytest("--codeblocks") result.assert_outcomes(passed=2) def test_shell_fail(testdir): string = """ ```sh cdc ``` """ testdir.makefile(".md", string) result = testdir.runpytest("--codeblocks") result.assert_outcomes(failed=1) def test_shell_expect_fail(testdir): string = """ ```sh cdc ``` """ testdir.makefile(".md", string) result = testdir.runpytest("--codeblocks") result.assert_outcomes(xfailed=1) def test_shell_expect_fail_passed(testdir): string = """ ```sh cd ``` """ testdir.makefile(".md", string) result = testdir.runpytest("--codeblocks") result.assert_outcomes(xpassed=1) def test_shell_expect_output(testdir): string = """ ```sh echo abc ``` ```sh abc ``` """ testdir.makefile(".md", string) result = testdir.runpytest("--codeblocks") result.assert_outcomes(passed=1) def test_shell_expect_output_fail(testdir): string = """ ```sh echo abc ``` ```sh ac ``` """ testdir.makefile(".md", string) result = testdir.runpytest("--codeblocks") result.assert_outcomes(failed=1) def test_bash(testdir): string = """ ```bash foo=1 if [[ $foo == 1 ]]; then echo abc fi ``` ```sh abc ``` """ testdir.makefile(".md", string) result = testdir.runpytest("--codeblocks") result.assert_outcomes(passed=1) pytest-codeblocks-0.17.0/tests/test_skipif.py000066400000000000000000000046621450165027200213070ustar00rootroot00000000000000def test_skip(testdir): string = """ Lorem ipsum ```python print(1 + 3) ``` """ testdir.makefile(".md", string) result = testdir.runpytest("--codeblocks") result.assert_outcomes(skipped=1) def test_skip_expected_output(testdir): string = """ Lorem ipsum ```python print(1 + 3) ``` ``` 25abc ``` """ testdir.makefile(".md", string) result = testdir.runpytest("--codeblocks") result.assert_outcomes(skipped=1) def test_skipif(testdir): string = """ Lorem ipsum ```python print(1 + 3) ``` """ testdir.makefile(".md", string) result = testdir.runpytest("--codeblocks") result.assert_outcomes(skipped=1) def test_skipif2(testdir): string = """ Lorem ipsum ```python print(1 + 3) ``` """ testdir.makefile(".md", string) result = testdir.runpytest("--codeblocks") result.assert_outcomes(passed=1) def test_skipif_expected_output(testdir): string = """ Lorem ipsum ```python print(1 + 3) ``` ``` 25abc ``` """ testdir.makefile(".md", string) result = testdir.runpytest("--codeblocks") result.assert_outcomes(skipped=1) def test_skipif_expected_output2(testdir): string = """ Lorem ipsum ```python print(1 + 3) ``` ``` 4 ``` """ testdir.makefile(".md", string) result = testdir.runpytest("--codeblocks") result.assert_outcomes(passed=1) def test_importorskip(testdir): string = """ Lorem ipsum ```python print(1 + 3) ``` """ testdir.makefile(".md", string) result = testdir.runpytest("--codeblocks") result.assert_outcomes(skipped=1) def test_importorskip2(testdir): string = """ Lorem ipsum ```python print(1 + 3) ``` """ testdir.makefile(".md", string) result = testdir.runpytest("--codeblocks") result.assert_outcomes(passed=1) pytest-codeblocks-0.17.0/tests/test_unicode.py000066400000000000000000000006731450165027200214460ustar00rootroot00000000000000def test_unicode(testdir): # Unicode identifyers are in fact legal Python code string = """ ```python # Α α, Β β, Γ γ, Δ δ, Ε ε, Ζ ζ, Η η, Θ θ, Ι ι, Κ κ, Λ λ, Μ μ, Ν ν, Ξ ξ, Ο ο, Π π, # Ρ ρ, Σ σ/ς, Τ τ, Υ υ, Φ φ, Χ χ, Ψ ψ, Ω ω α = 1 ``` """ testdir.makefile(".md", string) result = testdir.runpytest("--codeblocks") result.assert_outcomes(passed=1) pytest-codeblocks-0.17.0/tox.ini000066400000000000000000000002021450165027200165440ustar00rootroot00000000000000[tox] envlist = py3 isolated_build = True [testenv] deps = pytest pytest-cov commands = pytest {posargs} -p pytester