Skip to content

Commit 9d48390

Browse files
committed
Add DataSet.to_html() method for HTML export
1 parent 8cc8b31 commit 9d48390

4 files changed

Lines changed: 542 additions & 1 deletion

File tree

CHANGELOG.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,32 @@
5959
* Makes it immediately clear which fields you can edit and which are display-only
6060
* Validation errors are still highlighted with orange background when they occur
6161

62+
* **DataSet HTML Export**: Added HTML representation method for datasets:
63+
* New `to_html()` method on `DataSet` class generates HTML representation similar to Sigima's TableResult format
64+
* Features blue-styled title and comment section derived from the dataset's docstring
65+
* Two-column table layout with right-aligned item names and left-aligned values
66+
* Special handling for `BoolItem` with checkbox characters (☑ for True, ☐ for False)
67+
* Monospace font styling for consistent alignment and professional appearance
68+
* Proper handling of None values (displayed as "-") and nested ObjectItem datasets
69+
* Example usage:
70+
71+
```python
72+
class PersonDataSet(DataSet):
73+
"""Personal Information Dataset
74+
75+
This dataset collects basic personal information.
76+
"""
77+
name = StringItem("Full Name", default="John Doe")
78+
age = IntItem("Age", default=30)
79+
active = BoolItem("Account Active", default=True)
80+
81+
dataset = PersonDataSet()
82+
html_output = dataset.to_html() # Generate HTML representation
83+
```
84+
85+
* Ideal for reports, documentation, and web-based dataset visualization
86+
* Comprehensive unit test coverage ensures reliability across all item types
87+
6288
* `guidata.configtools.get_icon`:
6389
* This function retrieves a QIcon from the specified image file.
6490
* Now supports Qt standard icons (e.g. "MessageBoxInformation" or "DialogApplyButton").

guidata/dataset/dataitems.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -632,6 +632,15 @@ def __init__(
632632
)
633633
self.set_prop("display", text=text)
634634

635+
def get_string_value(self, instance: DataSet) -> str:
636+
"""Override DataItem method"""
637+
value_str = "☑" if self.get_value(instance) else "☐"
638+
label = self.get_prop_value("display", self, "label")
639+
text = self.get_prop_value("display", instance, "text", "")
640+
if label and text:
641+
value_str += " " + text
642+
return value_str
643+
635644
def get_value_from_reader(
636645
self, reader: HDF5Reader | JSONReader | INIReader
637646
) -> bool:

guidata/dataset/datatypes.py

Lines changed: 81 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -580,7 +580,7 @@ def get_string_value(self, instance: DataSet) -> str:
580580
if value is not None:
581581
text = self.format_string(instance, value, fmt, func)
582582
else:
583-
text = ""
583+
text = "-"
584584
return text
585585

586586
def get_name(self) -> str:
@@ -1675,6 +1675,86 @@ def accept(self, vis: object) -> None:
16751675
for item in self._items:
16761676
item.accept(vis)
16771677

1678+
def to_html(self) -> str:
1679+
"""Return HTML representation of the dataset.
1680+
1681+
Similar to Sigima's TableResult transpose format with:
1682+
1683+
- Title and comment in blue
1684+
- Two-column table: item names (right-aligned) and values (left-aligned)
1685+
- For BoolItem: checkbox in first column with label:text formatting
1686+
1687+
Returns:
1688+
HTML representation
1689+
"""
1690+
# Create the title with comment
1691+
html = f'<u><b style="color: blue">{self.__title}</b></u>'
1692+
1693+
if self.__comment:
1694+
# Add comment on new line, also in blue
1695+
html += f'<br><span style="color: blue">{self.__comment}</span>'
1696+
1697+
html += ":"
1698+
1699+
# Get items for representation (excluding trailing separators)
1700+
filtered_items = self._get_items_for_text_representation()
1701+
1702+
if not filtered_items:
1703+
html += "<br><em>No items to display</em>"
1704+
return html
1705+
1706+
# Start table with monospace font
1707+
html += '<table border="0" style="font-family: monospace;">'
1708+
1709+
for item in filtered_items:
1710+
# Skip group items and separators for HTML representation
1711+
if isinstance(item, (BeginGroup, EndGroup, SeparatorItem)):
1712+
continue
1713+
1714+
# Skip hidden items
1715+
try:
1716+
hide = item.get_prop_value("display", self, "hide")
1717+
if hide is True:
1718+
continue
1719+
except KeyError:
1720+
pass
1721+
1722+
# Handle ObjectItem (nested datasets)
1723+
if isinstance(item, ObjectItem):
1724+
composite_dataset = item.get_value(self)
1725+
if hasattr(composite_dataset, "to_html"):
1726+
item_label = item.get_prop_value("display", self, "label")
1727+
html += (
1728+
f'<tr><td style="text-align: right; vertical-align: top;">'
1729+
f"{item_label}:</td>"
1730+
)
1731+
nested_html = composite_dataset.to_html(transpose=False)
1732+
html += (
1733+
f'<td style="text-align: left; padding-left: 10px;">'
1734+
f"{nested_html}</td></tr>"
1735+
)
1736+
continue
1737+
1738+
# Get item label and value
1739+
label = item.get_prop_value("display", self, "label")
1740+
if not label:
1741+
# For BoolItem without label, use name:text formatting
1742+
label = item.get_prop_value("display", self, "text", "")
1743+
1744+
# Get string representation of value
1745+
value_str = item.get_string_value(self)
1746+
1747+
html += (
1748+
f'<tr><td style="text-align: right; vertical-align: top;">{label}:</td>'
1749+
)
1750+
html += (
1751+
f'<td style="text-align: left; padding-left: 10px;">'
1752+
f"{value_str}</td></tr>"
1753+
)
1754+
1755+
html += "</table>"
1756+
return html
1757+
16781758
def serialize(self, writer: HDF5Writer | JSONWriter | INIWriter) -> None:
16791759
"""Serialize the dataset
16801760

0 commit comments

Comments
 (0)