Skip to content

Add functionality to raise error if block or include_block is not found in file #31

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ Note that:
* Every line in the source file will be searched for an instance of the token (e.g. `doFoo`). If more than one line
includes that token, then potentially more than one block could be targeted for inclusion. It is advisable to use a
specific, unique token to avoid unexpected behaviour.
* If the specified block is not found, behavior depends on the `block_throw` config value (see [Configuration](#configuration))

When we wish to include a section of code that does not naturally appear within braces, we can simply insert our token,
with matching braces, in a comment.
Expand Down Expand Up @@ -127,6 +128,16 @@ will be rendered as:
doTheThingThatWeActuallyWantToShow();
```

## Configuration

This plugin takes two config values, specified in `mkdocs.yml`.

| Name | Description | Values | Default |
|---------------|---------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------|-------------------|
| `title_mode` | Controls how titles are generated for included blocks | `none`, `legacy_pymdownx.superfences`, `pymdownx.tabbed` | `pymdownx.tabbed` |
| `block_throw` | Controls whether to include entire file (`false`) or raise an error (`true`) if included block is not found in file | `true`, `false` | `false` |


## Building the Project

Install the dependencies:
Expand Down
6 changes: 5 additions & 1 deletion codeinclude/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ class CodeIncludePlugin(BasePlugin):
default="pymdownx.tabbed",
),
),
(
"block_throw",
mkdocs.config.config_options.Type(bool, default=False)
)
)

def on_page_markdown(self, markdown, page, config, site_navigation=None, **kwargs):
Expand Down Expand Up @@ -147,7 +151,7 @@ def get_substitute(self, page, title, filename, lines, block, inside_block):
content = f.read()

selected_content = select(
content, lines=lines, block=block, inside_block=inside_block
content, filename=filename, lines=lines, block=block, inside_block=inside_block, block_throw=self.config["block_throw"]
)

dedented = textwrap.dedent(selected_content)
Expand Down
13 changes: 13 additions & 0 deletions codeinclude/resolver.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@

def select(
text,
filename=None,
lines=None,
from_token=None,
to_token=None,
block=None,
inside_block=None,
lang=None,
block_throw=False
):

selected_lines = []
Expand All @@ -27,10 +29,12 @@ def select(
if block:
i = 0
delim_count = 0
found_block = False
for line in text.splitlines():
first_line_of_block = False
i = i + 1
if block in line and delim_count <= 0:
found_block = True
delim_count = 0
first_line_of_block = True
delim_count += line.count("{")
Expand All @@ -42,13 +46,19 @@ def select(

delim_count -= line.count("}")

if block_throw and not found_block:
raise ValueError(f"Block {block} not found to inject from {filename}")

if inside_block:
delim_count = 0
inside_matching = False
found_block = False
for line_number, line in enumerate(text.splitlines(), start=1):
first_line_of_block = False

# Detect the block beginning
if inside_block in line and delim_count <= 0:
found_block = True
delim_count = 0
first_line_of_block = True
inside_matching = True
Expand All @@ -68,6 +78,9 @@ def select(
# Append the lines inside the matching block, skipping the first matching
if inside_matching and not first_line_of_block:
selected_lines.append(line_number)

if block_throw and not found_block:
raise ValueError(f"Block {inside_block} not found to inject from {filename}")

if from_token and to_token:
i = 0
Expand Down
18 changes: 18 additions & 0 deletions tests/codeinclude/test_resolver.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,24 @@ def test_whole_block(self):
result = select(CODE_BLOCK_EXAMPLE, block="blockstarter")
self.assertEquals(("blockstarter {\n" " block content\n" "}\n"), result)

def test_block_throw(self):
# Test that entire file is returned for nonexistent block where `block_throw`=False
result = select(CODE_BLOCK_EXAMPLE, "test_file", block="nonexistent_block", block_throw=False)
self.assertEquals(CODE_BLOCK_EXAMPLE, result)

# ...as well as for inside_block
result = select(CODE_BLOCK_EXAMPLE, "test_file", inside_block="nonexistent_block", block_throw=False)
self.assertEquals(CODE_BLOCK_EXAMPLE, result)

# Test that throw occurs for nonexistent block
with self.assertRaises(ValueError):
result = select(CODE_BLOCK_EXAMPLE, "test_file", block="nonexistent_block", block_throw=True)

# ...as well as for inside_block
with self.assertRaises(ValueError):
result = select(CODE_BLOCK_EXAMPLE, "test_file", inside_block="nonexistent_block", block_throw=True)


def test_block_curly_on_same_line(self):
result = select(
textwrap.dedent(
Expand Down