diff --git a/pyproject.toml b/pyproject.toml
index 199bd25..2932d77 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -63,6 +63,10 @@ warn_redundant_casts = true
warn_unreachable = true
files = ["src", "tests"]
+[[tool.mypy.overrides]]
+module = "tabulate"
+ignore_missing_imports = true
+
[tool.pylint.message_control]
enable = ["c-extension-no-member", "no-else-return"]
disable = ["missing-module-docstring", "missing-class-docstring", "invalid-name", "R0801"]
diff --git a/setup.cfg b/setup.cfg
index 05a611d..eacffba 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -23,11 +23,11 @@ zip_safe = False
package_dir=
=src
packages = find:
-install_requires=
- funcy>=1.17
- tabulate>=0.8.7
+
[options.extras_require]
+table =
+ tabulate>=0.8.7
docs =
mkdocs==1.3.0
mkdocs-gen-files==0.3.4
@@ -35,6 +35,8 @@ docs =
mkdocs-section-index==0.3.4
mkdocstrings-python==0.7.0
tests =
+ %(table)s
+ funcy>=1.17
pytest==7.1.2
pytest-sugar==0.9.4
pytest-cov==3.0.0
@@ -43,6 +45,7 @@ tests =
mypy==0.961
pytest-test-utils>=0.0.6
dev =
+ %(table)s
%(tests)s
%(docs)s
diff --git a/src/dvc_render/base.py b/src/dvc_render/base.py
index b299fd4..4cb26af 100644
--- a/src/dvc_render/base.py
+++ b/src/dvc_render/base.py
@@ -57,7 +57,6 @@ def generate_html(self, html_path=None) -> str:
if partial:
div_id = self.remove_special_chars(self.name)
- div_id = f"plot_{div_id}"
return self.DIV.format(id=div_id, partial=partial)
return ""
diff --git a/src/dvc_render/html.py b/src/dvc_render/html.py
index f55aed1..7ae1ac2 100644
--- a/src/dvc_render/html.py
+++ b/src/dvc_render/html.py
@@ -1,8 +1,6 @@
from pathlib import Path
from typing import TYPE_CHECKING, Dict, List, Optional
-import tabulate # type: ignore
-
from .exceptions import DvcRenderException
if TYPE_CHECKING:
@@ -15,6 +13,11 @@
{refresh_tag}
DVC Plot
{scripts}
+
{plot_divs}
@@ -50,21 +53,6 @@ def __init__(
if refresh_seconds is not None:
self.refresh_tag = self.REFRESH_TAG.format(refresh_seconds)
- def with_metrics(self, metrics: Dict[str, Dict]) -> "HTML":
- "Adds metrics element."
- header: List[str] = []
- rows: List[List[str]] = []
-
- for _, rev_data in metrics.items():
- for _, data in rev_data.items():
- if not header:
- header.extend(sorted(data.keys()))
-
- rows.append([data[key] for key in header])
-
- self.elements.append(tabulate.tabulate(rows, header, tablefmt="html"))
- return self
-
def with_scripts(self, scripts: str) -> "HTML":
"Extend scripts element."
if scripts not in self.scripts:
@@ -108,7 +96,6 @@ def render_html(
document = HTML(page_html, refresh_seconds=refresh_seconds)
if metrics:
- document.with_metrics(metrics)
document.with_element("
")
for renderer in renderers:
diff --git a/src/dvc_render/table.py b/src/dvc_render/table.py
new file mode 100644
index 0000000..3177104
--- /dev/null
+++ b/src/dvc_render/table.py
@@ -0,0 +1,33 @@
+from .base import Renderer
+
+try:
+ from tabulate import tabulate
+except ImportError:
+ tabulate = None
+
+
+class TableRenderer(Renderer):
+ """Renderer for tables."""
+
+ TYPE = "table"
+ DIV = """
+ """
+
+ SCRIPTS = ""
+
+ EXTENSIONS = {".yml", ".yaml", ".json"}
+
+ def partial_html(self, **kwargs) -> str:
+ # From list of dicts to dict of lists
+ data = {
+ k: [datapoint[k] for datapoint in self.datapoints]
+ for k in self.datapoints[0]
+ }
+ if tabulate is None:
+ raise ImportError(f"{self.__class__} requires `tabulate`.")
+ return tabulate(data, headers="keys", tablefmt="html")
diff --git a/src/dvc_render/vega.py b/src/dvc_render/vega.py
index 66da47c..a57b13f 100644
--- a/src/dvc_render/vega.py
+++ b/src/dvc_render/vega.py
@@ -33,6 +33,8 @@ class VegaRenderer(Renderer):
EXTENSIONS = {".yml", ".yaml", ".json", ".csv", ".tsv"}
def __init__(self, datapoints: List, name: str, **properties):
+ if name and not name.startswith("plot_"):
+ name = f"plot_{name}"
super().__init__(datapoints, name, **properties)
self.template = get_template(
self.properties.get("template", None),
diff --git a/tests/test_html.py b/tests/test_html.py
index 2e4aa18..c5ff59e 100644
--- a/tests/test_html.py
+++ b/tests/test_html.py
@@ -43,7 +43,9 @@
(
None,
["content"],
- PAGE_HTML.format(plot_divs="content", refresh_tag="", scripts=""),
+ PAGE_HTML.replace("{plot_divs}", "content")
+ .replace("{scripts}", "")
+ .replace("{refresh_tag}", ""),
),
(
CUSTOM_PAGE_HTML,
diff --git a/tests/test_parallel_coordinates.py b/tests/test_parallel_coordinates.py
index 3b8d8e2..423b734 100644
--- a/tests/test_parallel_coordinates.py
+++ b/tests/test_parallel_coordinates.py
@@ -144,7 +144,7 @@ def test_write_parallel_coordinates(tmp_dir):
assert ParallelCoordinatesRenderer.SCRIPTS in html_text
div = ParallelCoordinatesRenderer.DIV.format(
- id="plot_pcp", partial=renderer.partial_html()
+ id="pcp", partial=renderer.partial_html()
)
assert div in html_text
diff --git a/tests/test_table.py b/tests/test_table.py
new file mode 100644
index 0000000..c0ab785
--- /dev/null
+++ b/tests/test_table.py
@@ -0,0 +1,15 @@
+from dvc_render.table import TableRenderer
+
+# pylint: disable=missing-function-docstring
+
+
+def test_render():
+ datapoints = [
+ {"foo": 1, "bar": 2},
+ ]
+ html = TableRenderer(datapoints, "metrics.json").generate_html()
+ assert "metrics_json
" in html
+ assert '| foo | ' in html
+ assert ' bar |
' in html
+ assert ' 1 | ' in html
+ assert ' 2 | ' in html