11# -*- coding: utf-8 -*-
22
33import re
4+ import sys
45from collections import Counter
56from dataclasses import dataclass
67from itertools import zip_longest
78from pathlib import Path
8- from typing import Any , List , Union
9+ from typing import Any , List , Union , Optional
910
1011from graphviz import Graph
1112
2021 Tweak ,
2122 Side ,
2223)
23- from wireviz .svgembed import embed_svg_images_file
24+ from wireviz .svgembed import embed_svg_images
2425from wireviz .wv_bom import (
2526 HEADER_MPN ,
2627 HEADER_PN ,
2728 HEADER_SPN ,
2829 bom_list ,
29- component_table_entry ,
3030 generate_bom ,
3131 get_additional_component_table ,
3232 pn_info_string ,
@@ -543,11 +543,11 @@ def typecheck(name: str, value: Any, expect: type) -> None:
543543 f'( +)?{ attr } =("[^"]*"|[^] ]*)(?(1)| *)' , "" , entry
544544 )
545545 if n_subs < 1 :
546- print (
546+ sys . stderr . write (
547547 f"Harness.create_graph() warning: { attr } not found in { keyword } !"
548548 )
549549 elif n_subs > 1 :
550- print (
550+ sys . stderr . write (
551551 f"Harness.create_graph() warning: { attr } removed { n_subs } times in { keyword } !"
552552 )
553553 continue
@@ -562,7 +562,7 @@ def typecheck(name: str, value: Any, expect: type) -> None:
562562 # If attr not found, then append it
563563 entry = re .sub (r"\]$" , f" { attr } ={ value } ]" , entry )
564564 elif n_subs > 1 :
565- print (
565+ sys . stderr . write (
566566 f"Harness.create_graph() warning: { attr } overridden { n_subs } times in { keyword } !"
567567 )
568568
@@ -650,55 +650,58 @@ def svg(self):
650650 graph = self .graph
651651 return embed_svg_images (graph .pipe (format = "svg" ).decode ("utf-8" ), Path .cwd ())
652652
653-
654653 def output (
655- self ,
656- filename : (str , Path ),
657- view : bool = False ,
658- cleanup : bool = True ,
659- fmt : tuple = ("html" , "png" , "svg" , "tsv" ),
654+ self ,
655+ output_dir : Optional [Union [str , Path ]],
656+ output_name : Optional [Union [str , Path ]],
657+ formats : List [str ] | tuple [str ]
660658 ) -> None :
661659 # graphical output
662660 graph = self .graph
663- svg_already_exists = Path (
664- f"{ filename } .svg"
665- ).exists () # if SVG already exists, do not delete later
666- # graphical output
667- for f in fmt :
668- if f in ("png" , "svg" , "html" ):
669- if f == "html" : # if HTML format is specified,
670- f = "svg" # generate SVG for embedding into HTML
671- # SVG file will be renamed/deleted later
672- _filename = f"{ filename } .tmp" if f == "svg" else filename
673- # TODO: prevent rendering SVG twice when both SVG and HTML are specified
674- graph .format = f
675- graph .render (filename = _filename , view = view , cleanup = cleanup )
676- # embed images into SVG output
677- if "svg" in fmt or "html" in fmt :
678- embed_svg_images_file (f"{ filename } .tmp.svg" )
679- # GraphViz output
680- if "gv" in fmt :
681- graph .save (filename = f"{ filename } .gv" )
682- # BOM output
683- bomlist = bom_list (self .bom ())
684- if "tsv" in fmt :
685- open_file_write (f"{ filename } .bom.tsv" ).write (tuplelist2tsv (bomlist ))
686- if "csv" in fmt :
687- # TODO: implement CSV output (preferrably using CSV library)
688- print ("CSV output is not yet supported" )
689- # HTML output
690- if "html" in fmt :
691- generate_html_output (filename , bomlist , self .metadata , self .options )
692- # PDF output
693- if "pdf" in fmt :
661+
662+ if "csv" in formats :
663+ # TODO: implement CSV output (preferably using CSV library)
664+ sys .stderr .write ("CSV output is not yet supported" )
665+ if "pdf" in formats :
694666 # TODO: implement PDF output
695- print ("PDF output is not yet supported" )
696- # delete SVG if not needed
697- if "html" in fmt and not "svg" in fmt :
698- # SVG file was just needed to generate HTML
699- Path (f"{ filename } .tmp.svg" ).unlink ()
700- elif "svg" in fmt :
701- Path (f"{ filename } .tmp.svg" ).replace (f"{ filename } .svg" )
667+ sys .stderr .write ("PDF output is not yet supported" )
668+
669+ outputs = {}
670+ if "svg" in formats or "html" in formats :
671+ # embed images into SVG output
672+ outputs ["svg" ] = embed_svg_images (graph .pipe (format = "svg" , encoding = "utf8" ))
673+
674+ if "png" in formats :
675+ outputs ["png" ] = graph .pipe (format = "png" )
676+
677+ # GraphViz output
678+ if "gv" in formats :
679+ outputs ["gv" ] = graph .pipe (format = "gv" )
680+
681+ if "tsv" in formats or "html" in formats :
682+ bomlist = bom_list (self .bom ())
683+ # BOM output
684+ if "tsv" in formats :
685+ outputs ["tsv" ] = tuplelist2tsv (bomlist )
686+
687+ # HTML output
688+ if "html" in formats and "svg" in outputs :
689+ outputs ["html" ] = generate_html_output (outputs ["svg" ], output_dir , bomlist , self .metadata , self .options )
690+
691+ # print to stdout or write files in order
692+ for f in formats :
693+ if f in outputs :
694+ output = outputs [f ]
695+ if output_dir is None or output_name is None :
696+ sys .stdout .write (output )
697+ else :
698+ file = f"{ output_dir } /{ output_name } .{ f } "
699+ if isinstance (output , (bytes , bytearray )):
700+ with open (file , "wb" ) as binary_file :
701+ binary_file .write (output )
702+ else :
703+ with open (file , "w" ) as binary_file :
704+ binary_file .write (output )
702705
703706 def bom (self ):
704707 if not self ._bom :
0 commit comments