"
@@ -438,9 +442,9 @@ def _repr_html_(self) -> str:
formatter = HtmlFormatter(style="friendly", wrapcode=True)
out.append(f"")
- out.append(highlight(self.format(), PythonLexer(), formatter))
+ out.append(highlight(self.render_and_format(), PythonLexer(), formatter))
except ModuleNotFoundError:
- out.append(f"{self.format()}
")
+ out.append(f"{self.render_and_format()}
")
return "\n".join(out)
@@ -505,10 +509,10 @@ def reprex(
# Don't screw up output file or lexing for HTML and RTF with terminal syntax highlighting
terminal = False
r = Reprex.from_input(input, config=config)
- output = r.format(terminal=terminal)
+ output = r.render_and_format(terminal=terminal)
if outfile is not None:
with Path(outfile).open("w") as fp:
- fp.write(r.format(terminal=False))
+ fp.write(r.render_and_format(terminal=False))
if print_:
print(output)
return r
diff --git a/reprexlite/session_info.py b/reprexlite/session_info.py
index 8fcc91e..6b09583 100644
--- a/reprexlite/session_info.py
+++ b/reprexlite/session_info.py
@@ -1,12 +1,7 @@
+import importlib.metadata
import platform
-import sys
from typing import List, Tuple
-if sys.version_info[:2] >= (3, 8):
- import importlib.metadata as importlib_metadata
-else:
- import importlib_metadata
-
class SessionInfo:
"""Class for pretty-formatting Python session info. Includes details about your Python version,
@@ -25,7 +20,7 @@ def __init__(self) -> None:
self.os: str = platform.platform()
self.packages: List[Package] = [
- Package(distr) for distr in importlib_metadata.Distribution.discover()
+ Package(distr) for distr in importlib.metadata.Distribution.discover()
]
def __str__(self) -> str:
@@ -46,7 +41,7 @@ class Package:
instances for introspection by [`SessionInfo`][reprexlite.session_info.SessionInfo].
""" # noqa: E501
- def __init__(self, distribution: importlib_metadata.Distribution):
+ def __init__(self, distribution: importlib.metadata.Distribution):
self.distribution = distribution
@property
diff --git a/reprexlite/version.py b/reprexlite/version.py
index 5519be3..1ea1a68 100644
--- a/reprexlite/version.py
+++ b/reprexlite/version.py
@@ -1,9 +1,3 @@
-import sys
+import importlib.metadata
-if sys.version_info[:2] >= (3, 8):
- import importlib.metadata as importlib_metadata
-else:
- import importlib_metadata
-
-
-__version__ = importlib_metadata.version(__name__.split(".", 1)[0])
+__version__ = importlib.metadata.version(__name__.split(".", 1)[0])
diff --git a/tests/test_cli.py b/tests/test_cli.py
index 166ef27..2721dd8 100644
--- a/tests/test_cli.py
+++ b/tests/test_cli.py
@@ -3,17 +3,15 @@
import sys
from textwrap import dedent
+import platformdirs
import pytest
-import typer
-from typer.testing import CliRunner
-from reprexlite.cli import app
+import reprexlite.cli
+from reprexlite.cli import app, user_reprexlite_toml_loader
from reprexlite.exceptions import IPythonNotFoundError
from reprexlite.version import __version__
from tests.utils import remove_ansi_escape
-runner = CliRunner()
-
INPUT = dedent(
"""\
x = 2
@@ -36,11 +34,12 @@ def __init__(self):
self.input = INPUT
def mock_edit(self, *args, **kwargs):
+ sys.stderr.write("Mocking editor\n")
return self.input
patch = EditPatch()
- monkeypatch.setattr(typer, "edit", patch.mock_edit)
- return patch
+ monkeypatch.setattr(reprexlite.cli, "handle_editor", patch.mock_edit)
+ yield patch
@pytest.fixture
@@ -55,32 +54,56 @@ def mocked_import(name, *args):
monkeypatch.setattr(builtins, "__import__", mocked_import)
-def test_reprex(patch_edit):
- result = runner.invoke(app)
- print(result.stdout)
- assert result.exit_code == 0
- assert EXPECTED in remove_ansi_escape(result.stdout)
+@pytest.fixture
+def project_dir(tmp_path, monkeypatch):
+ project_dir = tmp_path / "project_dir"
+ project_dir.mkdir()
+ monkeypatch.chdir(project_dir)
+ yield project_dir
+
+
+@pytest.fixture
+def user_config_dir(tmp_path, monkeypatch):
+ user_config_dir = tmp_path / "user_config_dir"
+ user_config_dir.mkdir()
+
+ def _mock_get_user_config_dir(*args, **kwargs):
+ return user_config_dir
+
+ monkeypatch.setattr(platformdirs, "user_config_dir", _mock_get_user_config_dir)
+ yield user_config_dir
+
+
+def test_reprex(project_dir, user_config_dir, patch_edit, capsys):
+ assert reprexlite.cli.handle_editor == patch_edit.mock_edit
+ capsys.readouterr()
+ app([])
+ stdout = capsys.readouterr().out
+ print(stdout)
+ assert EXPECTED in remove_ansi_escape(stdout)
-def test_reprex_infile(tmp_path):
+def test_reprex_infile(project_dir, user_config_dir, tmp_path, capsys):
infile = tmp_path / "infile.py"
with infile.open("w") as fp:
fp.write(INPUT)
- result = runner.invoke(app, ["-i", str(infile)])
- assert result.exit_code == 0
- assert EXPECTED in remove_ansi_escape(result.stdout)
+ app(["-i", str(infile)])
+ stdout = capsys.readouterr().out
+ print(stdout)
+ assert EXPECTED in remove_ansi_escape(stdout)
-def test_reprex_outfile(patch_edit, tmp_path):
+def test_reprex_outfile(project_dir, user_config_dir, patch_edit, tmp_path, capsys):
outfile = tmp_path / "outfile.md"
- result = runner.invoke(app, ["-o", str(outfile)])
- assert result.exit_code == 0
+ app(["-o", str(outfile)])
with outfile.open("r") as fp:
assert EXPECTED in fp.read()
- assert str(outfile) in result.stdout
+ stdout = capsys.readouterr().out
+ print(stdout)
+ assert str(outfile) in stdout
-def test_old_results(patch_edit):
+def test_old_results(project_dir, user_config_dir, patch_edit, capsys):
patch_edit.input = dedent(
"""\
arr = [1, 2, 3, 4, 5]
@@ -90,51 +113,61 @@ def test_old_results(patch_edit):
)
# no --old-results (default)
- result = runner.invoke(app)
- print(result.stdout)
- assert result.exit_code == 0
- assert "#> old line" not in result.stdout
- assert "#> [2, 3, 4, 5, 6]" in result.stdout
+ capsys.readouterr()
+ app([])
+ stdout = capsys.readouterr().out
+ print(stdout)
+ assert "#> old line" not in stdout
+ assert "#> [2, 3, 4, 5, 6]" in stdout
# with --old-results
- result = runner.invoke(app, ["--keep-old-results"])
- print(result.stdout)
- assert result.exit_code == 0
- assert "#> old line" in result.stdout
- assert "#> [2, 3, 4, 5, 6]" in result.stdout
+ app(["--keep-old-results"])
+ stdout = capsys.readouterr().out
+ print(stdout)
+ assert "#> old line" in stdout
+ assert "#> [2, 3, 4, 5, 6]" in stdout
-def test_ipython_editor():
- """Test that IPython interactive editor opens as expected. Not testing a reprex. Not sure how
- to inject input into the IPython shell."""
- result = runner.invoke(app, ["-e", "ipython"])
- assert result.exit_code == 0
- assert "Interactive reprex editor via IPython" in result.stdout # text from banner
+# def test_ipython_editor(project_dir, user_config_dir):
+# """Test that IPython interactive editor opens as expected. Not testing a reprex."""
+# result = subprocess.run(
+# [sys.executable, "-I", "-m", "reprexlite", "-e", "ipython"],
+# stdout=subprocess.PIPE,
+# stderr=subprocess.PIPE,
+# universal_newlines=True,
+# text=True,
+# input="exit",
+# )
+# assert result.returncode == 0
+# assert "Interactive reprex editor via IPython" in result.stdout # text from banner
-def test_ipython_editor_not_installed(no_ipython):
+
+def test_ipython_editor_not_installed(project_dir, user_config_dir, no_ipython, capsys):
"""Test for expected error when opening the IPython interactive editor without IPython
installed"""
- result = runner.invoke(app, ["-e", "ipython"])
- assert result.exit_code == 1
- assert "ipython is required" in result.stdout
+ with pytest.raises(SystemExit) as excinfo:
+ app(["-e", "ipython"])
+ assert excinfo.value.code == 1
+ stdout = capsys.readouterr().out
+ assert "ipython is required" in stdout
-def test_help():
+def test_help(project_dir, user_config_dir, capsys):
"""Test the CLI with --help flag."""
- result = runner.invoke(app, ["--help"])
- assert result.exit_code == 0
- assert "Render reproducible examples of Python code for sharing." in result.output
+ app(["--help"])
+ stdout = capsys.readouterr().out
+ assert "Render reproducible examples of Python code for sharing." in stdout
-def test_version():
+def test_version(project_dir, user_config_dir, capsys):
"""Test the CLI with --version flag."""
- result = runner.invoke(app, ["--version"])
- assert result.exit_code == 0
- assert result.output.strip() == __version__
+ app(["--version"])
+ stdout = capsys.readouterr().out
+ assert stdout.strip() == __version__
-def test_python_m_version():
+def test_python_m_version(project_dir, user_config_dir):
"""Test the CLI with python -m and --version flag."""
result = subprocess.run(
[sys.executable, "-I", "-m", "reprexlite", "--version"],
@@ -144,3 +177,47 @@ def test_python_m_version():
)
assert result.returncode == 0
assert result.stdout.strip() == __version__
+
+
+def test_pyproject_toml(project_dir, user_config_dir):
+ pyproject_toml = project_dir / "pyproject.toml"
+ with pyproject_toml.open("w") as fp:
+ fp.write(
+ dedent(
+ """\
+ [tool.reprexlite]
+ editor = "test_editor"
+ """
+ )
+ )
+ params = app(["--debug"])
+ assert params["config"]["editor"] == "test_editor"
+
+
+@pytest.mark.parametrize("filename", [".reprexlite.toml", "reprexlite.toml"])
+def test_reprexlite_toml(project_dir, user_config_dir, filename):
+ reprexlite_toml = project_dir / filename
+ with reprexlite_toml.open("w") as fp:
+ fp.write(
+ dedent(
+ """\
+ editor = "test_editor"
+ """
+ )
+ )
+ params = app(["--debug"])
+ assert params["config"]["editor"] == "test_editor"
+
+
+def test_user_config_dir(project_dir, user_config_dir, monkeypatch):
+ with (user_config_dir / "config.toml").open("w") as fp:
+ fp.write(
+ dedent(
+ """\
+ editor = "test_editor"
+ """
+ )
+ )
+ monkeypatch.setattr(user_reprexlite_toml_loader, "path", user_config_dir / "config.toml")
+ params = app(["--debug"])
+ assert params["config"]["editor"] == "test_editor"
diff --git a/tests/test_formatting.py b/tests/test_formatting.py
index 8bd02b1..3ceb46b 100644
--- a/tests/test_formatting.py
+++ b/tests/test_formatting.py
@@ -4,9 +4,9 @@
import pytest
-from reprexlite.config import ReprexConfig
-from reprexlite.exceptions import NotAFormatterError, PygmentsNotFoundError
-from reprexlite.formatting import register_formatter
+from reprexlite.config import ReprexConfig, Venue
+from reprexlite.exceptions import PygmentsNotFoundError
+from reprexlite.formatting import formatter_registry
from reprexlite.reprexes import Reprex
from tests.expected_formatted import (
ASSETS_DIR,
@@ -37,7 +37,7 @@ def patch_session_info(monkeypatch):
@pytest.mark.parametrize("ereprex", expected_reprexes, ids=[e.filename for e in expected_reprexes])
def test_reprex(ereprex, patch_datetime, patch_session_info, patch_version):
r = Reprex.from_input(INPUT, ReprexConfig(**ereprex.kwargs))
- actual = r.format()
+ actual = r.render_and_format()
with (ASSETS_DIR / ereprex.filename).open("r") as fp:
assert str(actual) == fp.read()
assert str(actual).endswith("\n")
@@ -55,9 +55,15 @@ def mocked_import(name, *args):
monkeypatch.setattr(builtins, "__import__", mocked_import)
+def test_all_venues_have_formatters():
+ for venue in Venue:
+ print(venue)
+ assert venue in formatter_registry
+
+
def test_html_no_pygments(patch_datetime, patch_version, no_pygments):
r = Reprex.from_input(INPUT, ReprexConfig(venue="html"))
- actual = r.format()
+ actual = r.render_and_format()
expected = dedent(
"""\
x = 2
@@ -73,7 +79,7 @@ def test_html_no_pygments(patch_datetime, patch_version, no_pygments):
def test_rtf_no_pygments(patch_datetime, patch_version, no_pygments):
with pytest.raises(PygmentsNotFoundError):
r = Reprex.from_input(INPUT, ReprexConfig(venue="rtf"))
- r.format()
+ r.render_and_format()
@pytest.fixture
@@ -95,15 +101,7 @@ def test_rtf_pygments_bad_dependency(patch_datetime, patch_version, pygments_bad
"""Test that a bad import inside pygments does not trigger PygmentsNotFoundError"""
with pytest.raises(ModuleNotFoundError) as exc_info:
r = Reprex.from_input(INPUT, ReprexConfig(venue="rtf"))
- r.format()
+ r.render_and_format()
assert not isinstance(exc_info.type, PygmentsNotFoundError)
assert exc_info.value.name != "pygments"
assert exc_info.value.name == pygments_bad_dependency
-
-
-def test_not_a_formatter_error():
- with pytest.raises(NotAFormatterError):
-
- @register_formatter("l33t", label="l33t")
- class F0rm4tt3r:
- pass
diff --git a/tests/test_ipython_editor.py b/tests/test_ipython_editor.py
index 7048e01..aafc50c 100644
--- a/tests/test_ipython_editor.py
+++ b/tests/test_ipython_editor.py
@@ -58,7 +58,7 @@ def test_ipython_editor(reprexlite_ipython, capsys):
reprexlite_ipython.run_cell(input)
captured = capsys.readouterr()
r = Reprex.from_input(input)
- expected = r.format()
+ expected = r.render_and_format()
print("\n---EXPECTED---\n")
print(expected)
diff --git a/tests/test_ipython_magics.py b/tests/test_ipython_magics.py
index e1cfc19..df56856 100644
--- a/tests/test_ipython_magics.py
+++ b/tests/test_ipython_magics.py
@@ -51,7 +51,7 @@ def test_cell_magic(ipython, capsys):
captured = capsys.readouterr()
r = Reprex.from_input(input, config=ReprexConfig(advertise=False, session_info=True))
- expected = r.format(terminal=True)
+ expected = r.render_and_format(terminal=True)
print("\n---EXPECTED---\n")
print(expected)
diff --git a/tests/test_reprexes.py b/tests/test_reprexes.py
index 59ea3a2..4ae192b 100644
--- a/tests/test_reprexes.py
+++ b/tests/test_reprexes.py
@@ -697,7 +697,7 @@ def mocked_import(name, *args):
def test_no_black(no_black):
with pytest.raises(BlackNotFoundError):
reprex = Reprex.from_input("2+2", config=ReprexConfig(style=True))
- reprex.format()
+ reprex.render_and_format()
@pytest.fixture
@@ -718,7 +718,7 @@ def mocked_import(name, *args):
def test_black_bad_dependency(black_bad_dependency, monkeypatch):
with pytest.raises(ModuleNotFoundError) as exc_info:
reprex = Reprex.from_input("2+2", config=ReprexConfig(style=True))
- reprex.format()
+ reprex.render_and_format()
assert not isinstance(exc_info.type, BlackNotFoundError)
assert exc_info.value.name != "black"
assert exc_info.value.name == black_bad_dependency
@@ -739,7 +739,7 @@ def mocked_import(name, *args):
def test_no_pygments_terminal(no_pygments):
"""Test that format for terminal works even if pygments is not installed."""
r = Reprex.from_input("2+2")
- assert_str_equals(r.format(terminal=False), r.format(terminal=True))
+ assert_str_equals(r.render_and_format(terminal=False), r.render_and_format(terminal=True))
def test_repr_html():
@@ -776,4 +776,4 @@ def test_reprex_function(tmp_path):
# Test writing to file
with (tmp_path / "rendered.txt").open("r") as fp:
- assert expected.format() == fp.read()
+ assert expected.render_and_format() == fp.read()