Skip to content

Commit b85b8bf

Browse files
geel9Joshua Coffey
andauthored
Add functionality to raise error if block or include_block is not found in file (#31)
* Raise error when block not found * Don't use `better-setuptools-git-version` This is broken on Python 3.10 as `collections.Mapping` no longer exists. * Fix error message * Add filename to error message * Add config value to control whether or not `select()` throws for blocks which are not found * Add documentation for config values * Add tests for `block_throws` * Revert "Don't use `better-setuptools-git-version`" This reverts commit 147d84a. --------- Co-authored-by: Joshua Coffey <[email protected]>
1 parent ea54d28 commit b85b8bf

File tree

4 files changed

+47
-1
lines changed

4 files changed

+47
-1
lines changed

README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ Note that:
100100
* Every line in the source file will be searched for an instance of the token (e.g. `doFoo`). If more than one line
101101
includes that token, then potentially more than one block could be targeted for inclusion. It is advisable to use a
102102
specific, unique token to avoid unexpected behaviour.
103+
* If the specified block is not found, behavior depends on the `block_throw` config value (see [Configuration](#configuration))
103104

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

131+
## Configuration
132+
133+
This plugin takes two config values, specified in `mkdocs.yml`.
134+
135+
| Name | Description | Values | Default |
136+
|---------------|---------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------|-------------------|
137+
| `title_mode` | Controls how titles are generated for included blocks | `none`, `legacy_pymdownx.superfences`, `pymdownx.tabbed` | `pymdownx.tabbed` |
138+
| `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` |
139+
140+
130141
## Building the Project
131142

132143
Install the dependencies:

codeinclude/plugin.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,10 @@ class CodeIncludePlugin(BasePlugin):
6161
default="pymdownx.tabbed",
6262
),
6363
),
64+
(
65+
"block_throw",
66+
mkdocs.config.config_options.Type(bool, default=False)
67+
)
6468
)
6569

6670
def on_page_markdown(self, markdown, page, config, site_navigation=None, **kwargs):
@@ -146,7 +150,7 @@ def get_substitute(self, page, title, filename, lines, block, inside_block):
146150
content = f.read()
147151

148152
selected_content = select(
149-
content, lines=lines, block=block, inside_block=inside_block
153+
content, filename=filename, lines=lines, block=block, inside_block=inside_block, block_throw=self.config["block_throw"]
150154
)
151155

152156
dedented = textwrap.dedent(selected_content)

codeinclude/resolver.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,14 @@
33

44
def select(
55
text,
6+
filename=None,
67
lines=None,
78
from_token=None,
89
to_token=None,
910
block=None,
1011
inside_block=None,
1112
lang=None,
13+
block_throw=False
1214
):
1315

1416
selected_lines = []
@@ -27,10 +29,12 @@ def select(
2729
if block:
2830
i = 0
2931
delim_count = 0
32+
found_block = False
3033
for line in text.splitlines():
3134
first_line_of_block = False
3235
i = i + 1
3336
if block in line and delim_count <= 0:
37+
found_block = True
3438
delim_count = 0
3539
first_line_of_block = True
3640
delim_count += line.count("{")
@@ -42,13 +46,19 @@ def select(
4246

4347
delim_count -= line.count("}")
4448

49+
if block_throw and not found_block:
50+
raise ValueError(f"Block {block} not found to inject from {filename}")
51+
4552
if inside_block:
4653
delim_count = 0
4754
inside_matching = False
55+
found_block = False
4856
for line_number, line in enumerate(text.splitlines(), start=1):
4957
first_line_of_block = False
58+
5059
# Detect the block beginning
5160
if inside_block in line and delim_count <= 0:
61+
found_block = True
5262
delim_count = 0
5363
first_line_of_block = True
5464
inside_matching = True
@@ -68,6 +78,9 @@ def select(
6878
# Append the lines inside the matching block, skipping the first matching
6979
if inside_matching and not first_line_of_block:
7080
selected_lines.append(line_number)
81+
82+
if block_throw and not found_block:
83+
raise ValueError(f"Block {inside_block} not found to inject from {filename}")
7184

7285
if from_token and to_token:
7386
i = 0

tests/codeinclude/test_resolver.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,24 @@ def test_whole_block(self):
2828
result = select(CODE_BLOCK_EXAMPLE, block="blockstarter")
2929
self.assertEquals(("blockstarter {\n" " block content\n" "}\n"), result)
3030

31+
def test_block_throw(self):
32+
# Test that entire file is returned for nonexistent block where `block_throw`=False
33+
result = select(CODE_BLOCK_EXAMPLE, "test_file", block="nonexistent_block", block_throw=False)
34+
self.assertEquals(CODE_BLOCK_EXAMPLE, result)
35+
36+
# ...as well as for inside_block
37+
result = select(CODE_BLOCK_EXAMPLE, "test_file", inside_block="nonexistent_block", block_throw=False)
38+
self.assertEquals(CODE_BLOCK_EXAMPLE, result)
39+
40+
# Test that throw occurs for nonexistent block
41+
with self.assertRaises(ValueError):
42+
result = select(CODE_BLOCK_EXAMPLE, "test_file", block="nonexistent_block", block_throw=True)
43+
44+
# ...as well as for inside_block
45+
with self.assertRaises(ValueError):
46+
result = select(CODE_BLOCK_EXAMPLE, "test_file", inside_block="nonexistent_block", block_throw=True)
47+
48+
3149
def test_block_curly_on_same_line(self):
3250
result = select(
3351
textwrap.dedent(

0 commit comments

Comments
 (0)