Add optional tweaking of the .gv output

Solves #174 intermediately by allowing low level .gv tweaking.
This commit is contained in:
KV 2021-02-11 19:25:41 +01:00
parent 92354e6852
commit 723235759b
4 changed files with 75 additions and 2 deletions

View File

@ -35,6 +35,8 @@ additional_bom_items: # custom items to add to BOM
- <bom-item> # BOM item (see below) - <bom-item> # BOM item (see below)
... ...
tweak: # optional tweaking of .gv output
...
``` ```
## Metadata entries ## Metadata entries
@ -327,6 +329,30 @@ Alternatively items can be added to just the BOM by putting them in the section
manufacturer: <str> # manufacturer name manufacturer: <str> # manufacturer name
``` ```
## Tweak entries
```yaml
# Optional tweaking of the .gv output.
# This feature is experimental and might change
# or be removed in future versions.
override: # dict of .gv entries to override
# Each entry is identified by its leading string
# in lines beginning with a TAB character.
# The leading string might be in "quotes" in
# the .gv output. This leading string must be
# followed by attributes in [square brackets].
# Entries containing HTML in an attribute are
# not supported.
<str>: # leading string of .gv entry
<str> : <str> # attribute and its new value
# Any number of attributes can be overridden
# for each entry
append: # single or list of .gv entries to append
<str> # strings to append might have multiple lines
```
## Colors ## Colors
Colors are defined via uppercase, two character strings. Colors are defined via uppercase, two character strings.
@ -403,6 +429,7 @@ The following attributes accept multiline strings:
- `manufacturer` - `manufacturer`
- `mpn` - `mpn`
- `image.caption` - `image.caption`
- `tweak.append`
### Method 1 ### Method 1

View File

@ -59,6 +59,12 @@ class Options:
self.bgcolor_bundle = self.bgcolor_cable self.bgcolor_bundle = self.bgcolor_cable
@dataclass
class Tweak:
override: Optional[Dict[Designator, Dict[str, str]]] = None
append: Union[str, List[str], None] = None
@dataclass @dataclass
class Image: class Image:
gv_dir: InitVar[Path] # Directory of .gv file injected as context during parsing gv_dir: InitVar[Path] # Directory of .gv file injected as context during parsing

View File

@ -10,7 +10,7 @@ from itertools import zip_longest
import re import re
from wireviz import wv_colors, __version__, APP_NAME, APP_URL from wireviz import wv_colors, __version__, APP_NAME, APP_URL
from wireviz.DataClasses import Metadata, Options, Connector, Cable from wireviz.DataClasses import Metadata, Options, Tweak, Connector, Cable
from wireviz.wv_colors import get_color_hex, translate_color from wireviz.wv_colors import get_color_hex, translate_color
from wireviz.wv_gv_html import nested_html_table, html_colorbar, html_image, \ from wireviz.wv_gv_html import nested_html_table, html_colorbar, html_image, \
html_caption, remove_links, html_line_breaks html_caption, remove_links, html_line_breaks
@ -25,6 +25,7 @@ from wireviz.wv_helper import awg_equiv, mm2_equiv, tuplelist2tsv, flatten2d, \
class Harness: class Harness:
metadata: Metadata metadata: Metadata
options: Options options: Options
tweak: Tweak
def __post_init__(self): def __post_init__(self):
self.connectors = {} self.connectors = {}
@ -344,6 +345,44 @@ class Harness:
dot.node(cable.name, label=f'<\n{html}\n>', shape='box', dot.node(cable.name, label=f'<\n{html}\n>', shape='box',
style=style, fillcolor=translate_color(bgcolor, "HEX")) style=style, fillcolor=translate_color(bgcolor, "HEX"))
def typecheck(name: str, var, type) -> None:
if not isinstance(var, type):
raise Exception(f'Unexpected value type of {name}: {var}')
# TODO?: Differ between override attributes and HTML?
if self.tweak.override is not None:
typecheck('tweak.override', self.tweak.override, dict)
for k, d in self.tweak.override.items():
typecheck(f'tweak.override.{k} key', k, str)
typecheck(f'tweak.override.{k} value', d, dict)
for a, v in d.items():
typecheck(f'tweak.override.{k}.{a} key', a, str)
typecheck(f'tweak.override.{k}.{a} value', v, str)
# Override generated attributes of selected entries matching tweak.override.
for i, entry in enumerate(dot.body):
if isinstance(entry, str):
# Find a possibly quoted keyword after leading TAB(s) and followed by [ ].
match = re.match(r'^\t*(")?((?(1)[^"]|[^ "])+)(?(1)") \[.*\]$', entry, re.S)
keyword = match and match[2]
if keyword in self.tweak.override.keys():
for attr, value in self.tweak.override[keyword].items():
if len(value) == 0 or ' ' in value:
value = value.replace('"', r'\"')
value = f'"{value}"'
# TODO?: If value is None: delete attr, and if attr not found: append it?
entry = re.sub(f'{attr}=("[^"]*"|[^] ]*)', f'{attr}={value}', entry)
dot.body[i] = entry
if self.tweak.append is not None:
if isinstance(self.tweak.append, list):
for i, element in enumerate(self.tweak.append, 1):
typecheck(f'tweak.append[{i}]', element, str)
dot.body.extend(self.tweak.append)
else:
typecheck(f'tweak.append', self.tweak.append, str)
dot.body.append(self.tweak.append)
return dot return dot
@property @property

View File

@ -13,7 +13,7 @@ if __name__ == '__main__':
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..')) sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))
from wireviz import __version__ from wireviz import __version__
from wireviz.DataClasses import Metadata, Options from wireviz.DataClasses import Metadata, Options, Tweak
from wireviz.Harness import Harness from wireviz.Harness import Harness
from wireviz.wv_helper import expand, open_file_read from wireviz.wv_helper import expand, open_file_read
@ -38,6 +38,7 @@ def parse(yaml_input: str, file_out: (str, Path) = None, return_types: (None, st
harness = Harness( harness = Harness(
metadata = Metadata(**yaml_data.get('metadata', {})), metadata = Metadata(**yaml_data.get('metadata', {})),
options = Options(**yaml_data.get('options', {})), options = Options(**yaml_data.get('options', {})),
tweak = Tweak(**yaml_data.get('tweak', {})),
) )
if 'title' not in harness.metadata: if 'title' not in harness.metadata:
harness.metadata['title'] = Path(file_out).stem harness.metadata['title'] = Path(file_out).stem