Source code for datasheet.types
from dataclasses import dataclass, InitVar
from typing import Any, ClassVar
from pathlib import Path
def _map_lines(func, s):
return "\n".join(map(func, s.split("\n")))
[docs]@dataclass
class ElementInterface:
"""Base class for all other Interfaces.
To add an interface, 3 steps are neccessary:
1. Define a class for it, which is derived from ElementInterface.
If it has a method named 'save_to_dir' which takes one argument: the
output directory, it will be called by
`datasheet.sheet.Sheet.__lshift__`. This way it
is possible to save files, that can be used in the render-handlers.
2. Optionally define a mapping for a type to be wrapped automatically with
your new interface by
`datasheet.sheet.Sheet.__lshift__` in :code:`Sheet.type_wrap_map`
:param Any content: the actual element
:param Path rel_save_path: the output path in case a file should be stored,
if not set, it can be assigned automatically using
`ElementInterface.get_outfile`
"""
content: Any
rel_save_path: Path = None
_save_counter: ClassVar[int] = 0
[docs] def get_outfile(self, target_dir: Path, ext: str):
"""returns a path for a file, that was not yet used.
:param Path target_dir: The output directory
:param str ext: The file extension"""
if self.rel_save_path is None:
ElementInterface._save_counter += 1
self.rel_save_path = f"{ElementInterface._save_counter}.{ext}"
return target_dir / self.rel_save_path
[docs]@dataclass
class MD(ElementInterface):
"""Markdown
:param offset: the ammount of characters to strip of the left of each line.
Determined automatically if set to -1.
"""
offset: InitVar[int] = -1
def __post_init__(self, offset):
if offset < 0:
offset = min(len(line) - len(line.lstrip())
for line in self.content.split("\n") if len(line.strip()) > 0)
if offset > 0:
self.content = _map_lines(lambda s: s[offset:], self.content)
[docs]@dataclass
class Str(ElementInterface):
"""String. Use this if you want add a string that is not interpreted as Markdown."""
[docs]@dataclass
class Repr(ElementInterface):
"""Adds a repr() of the object"""
[docs]@dataclass
class DF(ElementInterface):
"""Pandas.DataFrame
:param str save_format: supports to either save the dataframe as latex-table
or csv-file. Valid values are "tex" and "csv"
"""
save_format: str = "tex"
def save_to_dir(self, target_dir):
out_file = self.get_outfile(target_dir, self.save_format)
if self.save_format == "tex":
out_file.write_text(self.content.to_latex(index=False))
elif self.save_format == "csv":
self.content.to_csv(str(out_file))
[docs]@dataclass
class Nifti(ElementInterface):
"""nibabel.Nifti1Image"""
def save_to_dir(self, target_dir):
out_file = self.get_outfile(target_dir, "nii")
self.content.to_filename(str(out_file))
[docs]@dataclass
class MultiCell(ElementInterface):
"""Allows to use multiple elements in a Row. Takes a tuple as argument"""
def __post_init__(self):
if type(self.content) != tuple:
raise ValueError("Content must be tuple")