Skip to content

Commit

Permalink
Add optional tweaking of the .gv output
Browse files Browse the repository at this point in the history
Solves wireviz#174 intermediately by allowing low level .gv tweaking.
  • Loading branch information
kvid committed Sep 6, 2021
1 parent 92354e6 commit 7232357
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 2 deletions.
27 changes: 27 additions & 0 deletions docs/syntax.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ additional_bom_items: # custom items to add to BOM
- <bom-item> # BOM item (see below)
...

tweak: # optional tweaking of .gv output
...
```
## Metadata entries
Expand Down Expand Up @@ -327,6 +329,30 @@ Alternatively items can be added to just the BOM by putting them in the section
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 are defined via uppercase, two character strings.
Expand Down Expand Up @@ -403,6 +429,7 @@ The following attributes accept multiline strings:
- `manufacturer`
- `mpn`
- `image.caption`
- `tweak.append`

### Method 1

Expand Down
6 changes: 6 additions & 0 deletions src/wireviz/DataClasses.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,12 @@ def __post_init__(self):
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
class Image:
gv_dir: InitVar[Path] # Directory of .gv file injected as context during parsing
Expand Down
41 changes: 40 additions & 1 deletion src/wireviz/Harness.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import re

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_gv_html import nested_html_table, html_colorbar, html_image, \
html_caption, remove_links, html_line_breaks
Expand All @@ -25,6 +25,7 @@
class Harness:
metadata: Metadata
options: Options
tweak: Tweak

def __post_init__(self):
self.connectors = {}
Expand Down Expand Up @@ -344,6 +345,44 @@ def create_graph(self) -> Graph:
dot.node(cable.name, label=f'<\n{html}\n>', shape='box',
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

@property
Expand Down
3 changes: 2 additions & 1 deletion src/wireviz/wireviz.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))

from wireviz import __version__
from wireviz.DataClasses import Metadata, Options
from wireviz.DataClasses import Metadata, Options, Tweak
from wireviz.Harness import Harness
from wireviz.wv_helper import expand, open_file_read

Expand All @@ -38,6 +38,7 @@ def parse(yaml_input: str, file_out: (str, Path) = None, return_types: (None, st
harness = Harness(
metadata = Metadata(**yaml_data.get('metadata', {})),
options = Options(**yaml_data.get('options', {})),
tweak = Tweak(**yaml_data.get('tweak', {})),
)
if 'title' not in harness.metadata:
harness.metadata['title'] = Path(file_out).stem
Expand Down

0 comments on commit 7232357

Please sign in to comment.