Niharmahesh's picture
Upload folder using huggingface_hub
d015b2a verified
raw
history blame
6.18 kB
"""Save DOT code objects, render with Graphviz dot, and open in viewer."""
import locale
import logging
import os
import typing
from .encoding import DEFAULT_ENCODING
from . import _tools
from . import saving
from . import jupyter_integration
from . import piping
from . import rendering
from . import unflattening
__all__ = ['Source']
log = logging.getLogger(__name__)
class Source(rendering.Render, saving.Save,
jupyter_integration.JupyterIntegration, piping.Pipe,
unflattening.Unflatten):
"""Verbatim DOT source code string to be rendered by Graphviz.
Args:
source: The verbatim DOT source code string.
filename: Filename for saving the source (defaults to ``'Source.gv'``).
directory: (Sub)directory for source saving and rendering.
format: Rendering output format (``'pdf'``, ``'png'``, ...).
engine: Layout engine used (``'dot'``, ``'neato'``, ...).
encoding: Encoding for saving the source.
Note:
All parameters except ``source`` are optional. All of them
can be changed under their corresponding attribute name
after instance creation.
"""
@classmethod
@_tools.deprecate_positional_args(supported_number=2)
def from_file(cls, filename: typing.Union[os.PathLike, str],
directory: typing.Union[os.PathLike, str, None] = None,
format: typing.Optional[str] = None,
engine: typing.Optional[str] = None,
encoding: typing.Optional[str] = DEFAULT_ENCODING,
renderer: typing.Optional[str] = None,
formatter: typing.Optional[str] = None) -> 'Source':
"""Return an instance with the source string read from the given file.
Args:
filename: Filename for loading/saving the source.
directory: (Sub)directory for source loading/saving and rendering.
format: Rendering output format (``'pdf'``, ``'png'``, ...).
engine: Layout command used (``'dot'``, ``'neato'``, ...).
encoding: Encoding for loading/saving the source.
"""
directory = _tools.promote_pathlike_directory(directory)
filepath = (os.path.join(directory, filename) if directory.parts
else os.fspath(filename))
if encoding is None:
encoding = locale.getpreferredencoding()
log.debug('read %r with encoding %r', filepath, encoding)
with open(filepath, encoding=encoding) as fd:
source = fd.read()
return cls(source,
filename=filename, directory=directory,
format=format, engine=engine, encoding=encoding,
renderer=renderer, formatter=formatter,
loaded_from_path=filepath)
@_tools.deprecate_positional_args(supported_number=2)
def __init__(self, source: str,
filename: typing.Union[os.PathLike, str, None] = None,
directory: typing.Union[os.PathLike, str, None] = None,
format: typing.Optional[str] = None,
engine: typing.Optional[str] = None,
encoding: typing.Optional[str] = DEFAULT_ENCODING, *,
renderer: typing.Optional[str] = None,
formatter: typing.Optional[str] = None,
loaded_from_path: typing.Optional[os.PathLike] = None) -> None:
super().__init__(filename=filename, directory=directory,
format=format, engine=engine,
renderer=renderer, formatter=formatter,
encoding=encoding)
self._loaded_from_path = loaded_from_path
self._source = source
# work around pytype false alarm
_source: str
_loaded_from_path: typing.Optional[os.PathLike]
def _copy_kwargs(self, **kwargs):
"""Return the kwargs to create a copy of the instance."""
return super()._copy_kwargs(source=self._source,
loaded_from_path=self._loaded_from_path,
**kwargs)
def __iter__(self) -> typing.Iterator[str]:
r"""Yield the DOT source code read from file line by line.
Yields: Line ending with a newline (``'\n'``).
"""
lines = self._source.splitlines(keepends=True)
yield from lines[:-1]
for line in lines[-1:]:
suffix = '\n' if not line.endswith('\n') else ''
yield line + suffix
@property
def source(self) -> str:
"""The DOT source code as string.
Normalizes so that the string always ends in a final newline.
"""
source = self._source
if not source.endswith('\n'):
source += '\n'
return source
@_tools.deprecate_positional_args(supported_number=2)
def save(self, filename: typing.Union[os.PathLike, str, None] = None,
directory: typing.Union[os.PathLike, str, None] = None, *,
skip_existing: typing.Optional[bool] = None) -> str:
"""Save the DOT source to file. Ensure the file ends with a newline.
Args:
filename: Filename for saving the source (defaults to ``name`` + ``'.gv'``)
directory: (Sub)directory for source saving and rendering.
skip_existing: Skip write if file exists (default: ``None``).
By default skips if instance was loaded from the target path:
``.from_file(self.filepath)``.
Returns:
The (possibly relative) path of the saved source file.
"""
skip = (skip_existing is None and self._loaded_from_path
and os.path.samefile(self._loaded_from_path, self.filepath))
if skip:
log.debug('.save(skip_existing=None) skip writing Source.from_file(%r)',
self.filepath)
return super().save(filename=filename, directory=directory,
skip_existing=skip)