diff --git a/pyvis/network.py b/pyvis/network.py index 8deb915..9094226 100644 --- a/pyvis/network.py +++ b/pyvis/network.py @@ -4,6 +4,8 @@ import tempfile import webbrowser from collections import defaultdict +from io import TextIOBase +from pathlib import Path import jsonpickle import networkx as nx @@ -497,41 +499,51 @@ def generate_html(self, name="index.html", local=True, notebook=False): ) return self.html - def write_html(self, name, local=True, notebook=False,open_browser=False): + def write_html(self, html_file, local=True, notebook=False, open_browser=False): """ This method gets the data structures supporting the nodes, edges, and options and updates the template to write the HTML holding the visualization. To work with the old local methods local is being depricated, but not removed. - :type name_html: str - @param name: name of the file to save the graph as. + :type html_file: Union[PathLike, TextIOBase] + @param html_file: path to or file object of the file to save the graph as. @param local: Depricated parameter. Used to be used to determine how the graph needs deploy. Has been removed in favor of using the class cdn_resources instead. @param notebook: If true, this object will return the iframe document for use in juptyer notebook. @param open_browser: If true, will open a web browser with the generated graph. """ - getcwd_name = name - check_html(getcwd_name) + if self.cdn_resources not in ['in_line','remote','local']: + raise ValueError("cdn_resources should be 'local', 'in_line', or 'remote'") + + if isinstance(html_file, TextIOBase): + # the filename of this file object + filename = Path(html_file.name).resolve() + else: + filename = Path(html_file).resolve() + + check_html(filename) self.html = self.generate_html(notebook=notebook) if self.cdn_resources == "local": - if not os.path.exists("lib"): - os.makedirs("lib") - if not os.path.exists("lib/bindings"): - shutil.copytree(f"{os.path.dirname(__file__)}/templates/lib/bindings", "lib/bindings") - if not os.path.exists(os.getcwd()+"/lib/tom-select"): - shutil.copytree(f"{os.path.dirname(__file__)}/templates/lib/tom-select", "lib/tom-select") - if not os.path.exists(os.getcwd()+"/lib/vis-9.1.2"): - shutil.copytree(f"{os.path.dirname(__file__)}/templates/lib/vis-9.1.2", "lib/vis-9.1.2") - with open(getcwd_name, "w+") as out: - out.write(self.html) - elif self.cdn_resources == "in_line" or self.cdn_resources == "remote": - with open(getcwd_name, "w+") as out: - out.write(self.html) + # copy local cdn resources to lib_dir lib_dir will always be a sibling of filename + lib_dir = filename.parent / "lib" + if not lib_dir.exists(): + lib_dir.mkdir(parents=True, exist_ok=True) + if not (lib_dir/"bindings").exists(): + shutil.copytree(Path(__file__)/"templates/lib/bindings", lib_dir/"bindings") + if not (lib_dir/"tom-select").exists(): + shutil.copytree(Path(__file__)/"templates/lib/tom-select", lib_dir/"tom-select") + if not (lib_dir/"vis-9.1.2").exists(): + shutil.copytree(Path(__file__)/"templates/lib/vis-9.1.2", lib_dir/"vis-9.1.2") + + if isinstance(html_file, TextIOBase): + html_file.write(self.html) else: - assert "cdn_resources is not in ['in_line','remote','local']." + with open(filename, "w+") as out: + out.write(self.html) + if open_browser: # open the saved file in a new browser window. - webbrowser.open(getcwd_name) + webbrowser.open(str(filename)) def show(self, name, local=True,notebook=True): diff --git a/pyvis/utils.py b/pyvis/utils.py index 9e394c6..2539985 100644 --- a/pyvis/utils.py +++ b/pyvis/utils.py @@ -1,13 +1,17 @@ # utility and helper functions for use in pyvis +from os import PathLike +from pathlib import Path - -def check_html(name): +def check_html(name: PathLike): """ Given a name of graph to save or write, check if it is of valid syntax :param: name: the name to check - :type name: str + :type name: PathLike """ - assert len(name.split(".")) >= 2, "invalid file type for %s" % name - assert name.split( - ".")[-1] == "html", "%s is not a valid html file" % name + name = Path(name) + if (name.suffix != ".html") or (name.suffixes[-1] != ".html"): + raise ValueError(f"{name} is not a valid html file") + if not name.parent.exists(): + # ensures that the parent folder exists and creates it if it doesn't exist + name.parent.mkdir(parents=True, exist_ok=True)