Skip to content

Commit

Permalink
0.3
Browse files Browse the repository at this point in the history
- Added some more documentation and fixed some false path warnings
  • Loading branch information
spacemanspiff2007 committed Sep 24, 2021
1 parent 66e6c97 commit 1b84552
Show file tree
Hide file tree
Showing 6 changed files with 135 additions and 38 deletions.
69 changes: 60 additions & 9 deletions doc/description.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,22 @@ Usage

Without options
------------------------------
.. code-block:: rst
.. code-block:: python
.. exec_code::
print('Easy!')
Generated view:
Generated view

----

.. exec_code::

print('Easy!')

----

Options
------------------------------
It's possible to further configure both the code block and the output block with the following options:
Expand All @@ -34,7 +38,7 @@ language/language_output:

Example:

.. code-block:: rst
.. code-block:: python
.. exec_code::
:linenos:
Expand All @@ -43,7 +47,9 @@ Example:
print('Easy!')
Generated view:
Generated view

----

.. exec_code::
:linenos:
Expand All @@ -52,12 +58,15 @@ Generated view:

print('Easy!')

----


Hide code parts
Code Markers
------------------------------
It's possible to hide parts of the code (e.g. to setup a working example)
and it's possible to skip part of the code execution. This is possible with the
``#hide:[start|stop|toggle]`` or ``#skip:[start|stop|toggle]`` marker in the code.
Empty lines after a disabling marker will be ignored.

Spaces and dashes are ignored for the case insensitive marker detection so these are all the same:

Expand All @@ -69,33 +78,75 @@ Spaces and dashes are ignored for the case insensitive marker detection so these
# ----- hide: start -----
Example:

.. code-block:: rst
Hiding code parts
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. code-block:: python
.. exec_code::
# --- hide: start ---
print('Setup!')
#hide:toggle
print('Easy!')
# --- hide: start ---
print('Hidden!')
# --- hide: stop ---
# Note the missing entries!
print('Visible!')
Generated view:
Generated view (note the skipped empty lines after the stop and disabling toggle marker)

----

.. exec_code::

# --- hide: start ---
print('Setup!')
#hide:toggle

print('Easy!')

# --- hide: start ---
print('Hidden!')
# --- hide: stop ---

# Note the missing entries!
print('Visible!')

----

Skipping code parts
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. code-block:: python
.. exec_code::
# --- skip: start ---
print(f'1 / 0 = {1 / 0}')
# --- skip: stop ---
# --- hide: start ---
print('1 / 0 = 0')
# --- hide: stop ---
Generated view

----

.. exec_code::

# --- skip: start ---
print(f'1 / 0 = {1 / 0}')
# --- skip: stop ---

# --- hide: start ---
print('1 / 0 = 0')
# --- hide: stop ---

----

With the combination of ``skip`` and ``hide`` it's possible to "simulate" every code.
3 changes: 3 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,8 @@ This code will be executed
```

# Changelog
#### 0.3 (24.09.2021)
- Added some more documentation and fixed some false path warnings

#### 0.2 (21.09.2021)
- Initial Release
2 changes: 1 addition & 1 deletion src/sphinx_exec_code/__version__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = '0.2'
__version__ = '0.3'
82 changes: 57 additions & 25 deletions src/sphinx_exec_code/code_format.py
Original file line number Diff line number Diff line change
@@ -1,41 +1,73 @@
from typing import Iterable, List, Tuple
from typing import Iterable, Tuple


class VisibilityMarkerError(Exception):
pass


def _process_code(code_lines: Iterable[str], marker: str) -> List[str]:
class CodeMarker:
MARKERS = ('hide', 'skip')

marker_start = f'#{marker}:start'
marker_stop = f'#{marker}:stop'
marker_toggle = f'#{marker}:toggle'
def __init__(self, marker: str):
assert marker in CodeMarker.MARKERS
self.start = f'#{marker}:start'
self.stop = f'#{marker}:stop'
self.toggle = f'#{marker}:toggle'

self.do_add = True
self.skip_empty = False
self.lines = []

def is_marker(self, line: str) -> bool:
if line == self.start:
if not self.do_add:
raise VisibilityMarkerError(f'{self.start[1:]} already called! '
f'Use {self.stop[1:]} or {self.toggle[1:]}!')
self.do_add = False
return True

if line == self.stop:
if self.do_add:
raise VisibilityMarkerError(f'{self.stop[1:]} already called! '
f'Use {self.start[1:]} or {self.toggle[1:]}!')
self.do_add = True
self.skip_empty = True
return True

if line == self.toggle:
self.do_add = not self.do_add
return True

return False

def add_line(self, line: str):
if not self.do_add:
return None

if self.skip_empty:
if not line.strip():
return None
self.skip_empty = False

self.lines.append(line)


def get_show_exec_code(code_lines: Iterable[str]) -> Tuple[str, str]:
hide = CodeMarker('hide')
skip = CodeMarker('skip')

lines = []
do_add = True
for org_line in code_lines:
line = org_line.replace(' ', '').replace('-', '').lower()
if line == marker_start:
if not do_add:
raise VisibilityMarkerError(f'{marker}:start already called! Use {marker}:stop or {marker}:toggle!')
do_add = False
continue
elif line == marker_stop:
if do_add:
raise VisibilityMarkerError(f'{marker}:stop already called! Use {marker}:start or {marker}:toggle!')
do_add = True

if hide.is_marker(line):
continue
elif line == marker_toggle:
do_add = not do_add
if skip.is_marker(line):
continue

if do_add:
lines.append(org_line)
return lines

hide.add_line(org_line)
skip.add_line(org_line)

def get_show_exec_code(code_lines: Iterable[str]) -> Tuple[str, str]:
shown_code = '\n'.join(_process_code(code_lines, 'hide'))
executed_code = '\n'.join(_process_code(code_lines, 'skip'))
shown_code = '\n'.join(hide.lines)
executed_code = '\n'.join(skip.lines)

return shown_code.strip(), executed_code.strip()
7 changes: 5 additions & 2 deletions src/sphinx_exec_code/sphinx_exec.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,14 +57,17 @@ def _run(self) -> list:
:return:
"""
output = []
file, line = self.get_source_info()

# format the code
code_show, code_exec = get_show_exec_code(self.content)
try:
code_show, code_exec = get_show_exec_code(self.content)
except Exception as e:
raise ExtensionError(f'Could not parse code markers at {self.get_location()}', orig_exc=e)

# Show the code from the user
create_literal_block(output, code_show, spec=SpecCode.from_options(self.options))

file, line = self.get_source_info()
try:
code_results = execute_code(code_exec, file, line)
except CodeException as e:
Expand Down
10 changes: 9 additions & 1 deletion tests/test_code_format.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,17 @@


def test_format_hide():
code = 'print("1")\n# - hide: start - \nprint("2")\n #hide:stop\nprint("3")'
code = 'print("1")\n# - hide: start - \nprint("2")\n #hide:stop\n \n \nprint("3")'
show, run = get_show_exec_code(code.splitlines())
assert show == 'print("1")\nprint("3")'
assert run == 'print("1")\nprint("2")\n \n \nprint("3")'


def test_format_skip():
code = 'print("1")\n# - skip: start - \nprint("2")\n #skip:stop\nprint("3")'
show, run = get_show_exec_code(code.splitlines())
assert show == 'print("1")\nprint("2")\nprint("3")'
assert run == 'print("1")\nprint("3")'


def test_marker_err():
Expand Down

0 comments on commit 1b84552

Please sign in to comment.