Skip to content

Commit

Permalink
Parse code copied from REPL. Closes #24 (#29)
Browse files Browse the repository at this point in the history
Co-authored-by: Jay Qi <jayqi@users.noreply.github.com>
  • Loading branch information
jayqi and jayqi committed Mar 1, 2021
1 parent 30d41d1 commit eeac9a4
Show file tree
Hide file tree
Showing 6 changed files with 78 additions and 4 deletions.
6 changes: 5 additions & 1 deletion HISTORY.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
# reprexlite Changelog

## v0.4.2 (2021-02-28)

- Added support for parsing code copied from an interactive Python shell (REPL) with `>>>` prompts. ([#29](https://github.com/jayqi/reprexlite/pull/29))

## v0.4.1 (2021-02-27)

- Added missing LICENSE file.

## v0.4.0 (2021-02-27)

- Adds optional IPython extension that enables `%%reprex` cell magic. See [documentation](https://jayqi.github.io/reprexlite/ipython-jupyter-magic/) for usage. ([#21](https://github.com/jayqi/reprexlite/pull/21))
- Added optional IPython extension that enables `%%reprex` cell magic. See [documentation](https://jayqi.github.io/reprexlite/ipython-jupyter-magic/) for usage. ([#21](https://github.com/jayqi/reprexlite/pull/21))

## v0.3.1 (2021-02-26)

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ list(zip(*grid))

Writing a good reprex takes thought and effort (see ["Reprex Do's and Don'ts"](https://jayqi.github.io/reprexlite/dos-and-donts) for tips). The goal of reprexlite is to be a tool that seamlessly handles the mechanical stuff, so you can devote your full attention to the important, creative work of writing the content.

Reprex-style code formatting—namely, with outputs as comments—is also great for documentation. Users can copy and run with no modification. Consider using reprexlite when writing your documentation instead of copying code with `>>>` prompts from an interactive Python shell.
Reprex-style code formatting—namely, with outputs as comments—is also great for documentation. Users can copy and run with no modification. Consider using reprexlite when writing your documentation instead of copying code with `>>>` prompts from an interactive Python shell. In fact, reprexlite can parse code with `>>>` prompts and convert it into a reprex for you instead.

reprexlite is a lightweight alternative to [reprexpy](https://github.com/crew102/reprexpy) and is similarly meant as a port of the R package [reprex](https://github.com/tidyverse/reprex).

Expand Down
2 changes: 2 additions & 0 deletions docs/docs/design-philosophy.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ math.sqrt(4)
#> 2.0
```

If this has convinced you, you can take advantage of reprexlite's ability to parse doctest-style code and easily convert those examples to reprexes instead.

## reprexlite's Design

The primary design goal of reprexlite is that it should be **quick and convenient** to use. That objective drove the emphasis on following the design characteristics:
Expand Down
23 changes: 23 additions & 0 deletions reprexlite/code.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,8 @@ def __init__(
match the `comment` prefix. False means these lines are removed, in effect meaning
an inputted regex will have its results regenerated. Defaults to False.
"""
if any(line.startswith(">>>") for line in input.split("\n")):
input = repl_to_reprex_code(input, comment=comment)
if not old_results and comment in input:
input = "\n".join(line for line in input.split("\n") if not line.startswith(comment))
self.input: str = input
Expand Down Expand Up @@ -177,3 +179,24 @@ def _repr_html_(self):
except ImportError:
out.append(f"<pre><code>{self}</code></pre>")
return "\n".join(out)


def repl_to_reprex_code(input: str, comment: str = "#>") -> str:
"""Reformat a code block copied from a Python REPL to a reprex-style code block.
Args:
input (str): code block
comment (str): Line prefix to use when rendering the evaluated results. Defaults to "#>".
Returns:
Reformatted code block in reprex-style.
"""
out = []
for line in input.split("\n"):
if line.startswith(">>>") or line.startswith("..."):
out.append(line[4:])
elif line.strip() == "":
out.append(line)
else:
out.append(comment + " " + line)
return "\n".join(out)
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,5 +53,5 @@ def load_requirements(path: Path):
"Source Code": "https://github.com/jayqi/reprexlite",
},
url="https://github.com/jayqi/reprexlite",
version="0.4.1",
version="0.4.2",
)
47 changes: 46 additions & 1 deletion tests/test_code.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

import pytest

from reprexlite.code import CodeBlock
from reprexlite.code import CodeBlock, repl_to_reprex_code

REPO_ROOT = Path(__file__).parents[1].resolve()

Expand Down Expand Up @@ -185,6 +185,25 @@ class MyException(Exception): ...
#> caught
""",
),
Case(
id="repl code",
input="""\
>>> def add_one(x: int):
... return x + 1
...
>>> # Now add 1
>>> add_one(1)
2 # old result
""",
expected="""\
def add_one(x: int):
return x + 1
# Now add 1
add_one(1)
#> 2
""",
),
]


Expand Down Expand Up @@ -228,3 +247,29 @@ def test_old_results():
"""
)
assert str(CodeBlock(input, old_results=True)) == expected_true.strip()


def test_repl_to_reprex_code():
input = dedent(
"""\
>>> def add_one(x: int):
... return x + 1
...
>>> # Now add 1
>>> add_one(1)
2
"""
)
expected = dedent(
"""\
def add_one(x: int):
return x + 1
# Now add 1
add_one(1)
#> 2
"""
)

assert repl_to_reprex_code(input) == expected
assert str(CodeBlock(input)) + "\n" == expected

0 comments on commit eeac9a4

Please sign in to comment.