├── tests ├── __init__.py ├── test_basic.py ├── utils.py └── test_functions.py ├── setup.py ├── docs ├── requirements.txt └── _src │ ├── index.rst │ ├── api.rst │ ├── _templates │ ├── custom-class-template.rst │ └── custom-module-template.rst │ └── conf.py ├── html2dash ├── __init__.py └── html2dash.py ├── .vscode └── settings.json ├── examples ├── pandas_table.py ├── tabler.py ├── markdown_to_dash.py └── tabler.html ├── .github └── workflows │ ├── python-publish.yml │ └── python-pytest.yml ├── pyproject.toml ├── LICENSE ├── .gitignore └── README.md /tests/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | 3 | setup() 4 | -------------------------------------------------------------------------------- /docs/requirements.txt: -------------------------------------------------------------------------------- 1 | html2dash 2 | sphinx-click==4.4.0 3 | furo==2023.3.27 -------------------------------------------------------------------------------- /html2dash/__init__.py: -------------------------------------------------------------------------------- 1 | from .html2dash import html2dash 2 | 3 | __version__ = "0.2.4" 4 | -------------------------------------------------------------------------------- /docs/_src/index.rst: -------------------------------------------------------------------------------- 1 | .. html2dash documentation master file 2 | 3 | html2dash 4 | ========= 5 | -------------------------------------------------------------------------------- /docs/_src/api.rst: -------------------------------------------------------------------------------- 1 | html2dash API 2 | ================ 3 | 4 | .. autosummary:: 5 | :toctree: _autosummary 6 | :template: custom-module-template.rst 7 | 8 | html2dash -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "python.testing.pytestArgs": [ 3 | "tests" 4 | ], 5 | "python.testing.unittestEnabled": false, 6 | "python.testing.pytestEnabled": true 7 | } -------------------------------------------------------------------------------- /tests/test_basic.py: -------------------------------------------------------------------------------- 1 | from dash import html 2 | from html2dash import html2dash 3 | 4 | 5 | def test_html2dash_empty(): 6 | assert html2dash("").to_plotly_json() == html.Div([]).to_plotly_json() 7 | 8 | 9 | -------------------------------------------------------------------------------- /examples/pandas_table.py: -------------------------------------------------------------------------------- 1 | from dash import Dash 2 | from html2dash import html2dash 3 | import dash_mantine_components as dmc 4 | import pandas as pd 5 | 6 | element_map = { 7 | "table": dmc.Table, 8 | } 9 | 10 | df = pd.read_csv("https://raw.githubusercontent.com/datasciencedojo/datasets/master/titanic.csv") 11 | app = Dash() 12 | 13 | pandas_table = html2dash(df.head(50).to_html(index=False), element_map=element_map) 14 | pandas_table.children[0].striped = True 15 | pandas_table.children[0].withBorder = True 16 | app.layout = dmc.Container(pandas_table) 17 | 18 | if __name__ == "__main__": 19 | app.run_server(debug=True) 20 | -------------------------------------------------------------------------------- /tests/utils.py: -------------------------------------------------------------------------------- 1 | from dash.development.base_component import Component 2 | 3 | 4 | def dash_to_dict(dash_component: Component) -> dict: 5 | """function to recursively convert dash components to dicts""" 6 | if isinstance(dash_component, Component): 7 | return_dict = {} 8 | for k, v in dash_component.to_plotly_json().items(): 9 | if k == "props": 10 | return_dict[k] = {k: dash_to_dict(v) for k, v in v.items()} 11 | elif k == "children": 12 | return_dict[k] = [dash_to_dict(child) for child in v] 13 | else: 14 | return_dict[k] = v 15 | return return_dict 16 | elif isinstance(dash_component, list): 17 | return [dash_to_dict(child) for child in dash_component] 18 | return dash_component 19 | -------------------------------------------------------------------------------- /.github/workflows/python-publish.yml: -------------------------------------------------------------------------------- 1 | name: Upload Python Package 2 | 3 | on: 4 | release: 5 | types: [published] 6 | 7 | permissions: 8 | contents: read 9 | 10 | jobs: 11 | pypi-publish: 12 | name: upload release to PyPI 13 | runs-on: ubuntu-latest 14 | permissions: 15 | id-token: write 16 | steps: 17 | - uses: actions/checkout@v3 18 | - name: Set up Python 19 | uses: actions/setup-python@v3 20 | with: 21 | python-version: '3.x' 22 | - name: Install dependencies 23 | run: | 24 | python -m pip install --upgrade pip 25 | pip install build 26 | - name: Build package 27 | run: python -m build 28 | 29 | - name: Publish package distributions to PyPI 30 | uses: pypa/gh-action-pypi-publish@release/v1 -------------------------------------------------------------------------------- /docs/_src/_templates/custom-class-template.rst: -------------------------------------------------------------------------------- 1 | {{ fullname | escape | underline}} 2 | 3 | .. currentmodule:: {{ module }} 4 | 5 | .. autoclass:: {{ objname }} 6 | :members: 7 | :show-inheritance: 8 | :inherited-members: 9 | :special-members: __call__, __add__, __mul__ 10 | 11 | {% block methods %} 12 | {% if methods %} 13 | .. rubric:: {{ _('Methods') }} 14 | 15 | .. autosummary:: 16 | :nosignatures: 17 | {% for item in methods %} 18 | {%- if not item.startswith('_') %} 19 | ~{{ name }}.{{ item }} 20 | {%- endif -%} 21 | {%- endfor %} 22 | {% endif %} 23 | {% endblock %} 24 | 25 | {% block attributes %} 26 | {% if attributes %} 27 | .. rubric:: {{ _('Attributes') }} 28 | 29 | .. autosummary:: 30 | {% for item in attributes %} 31 | ~{{ name }}.{{ item }} 32 | {%- endfor %} 33 | {% endif %} 34 | {% endblock %} 35 | -------------------------------------------------------------------------------- /examples/tabler.py: -------------------------------------------------------------------------------- 1 | from pathlib import Path 2 | from dash import Dash, html, dcc 3 | from html2dash import html2dash 4 | import dash_mantine_components as dmc 5 | from dash_iconify import DashIconify 6 | 7 | modules = [html, dcc, dmc] 8 | element_map = {} 9 | element_map["icon"] = DashIconify 10 | element_map["rprogress"] = dmc.RingProgress 11 | element_map["lprogress"] = dmc.Progress 12 | 13 | app = Dash( 14 | __name__, 15 | external_scripts=[ 16 | "https://cdn.jsdelivr.net/npm/@tabler/core@1.0.0-beta17/dist/js/tabler.min.js" 17 | ], 18 | external_stylesheets=[ 19 | "https://cdn.jsdelivr.net/npm/@tabler/core@1.0.0-beta17/dist/css/tabler.min.css", 20 | "https://rsms.me/inter/inter.css", 21 | ], 22 | ) 23 | 24 | app.layout = html2dash( 25 | Path("tabler.html").read_text(), module_list=modules, element_map=element_map 26 | ) 27 | 28 | if __name__ == "__main__": 29 | app.run_server(debug=True) 30 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["setuptools>=61.0"] 3 | build-backend = "setuptools.build_meta" 4 | 5 | [project] 6 | name = "html2dash" 7 | dynamic = ["version"] 8 | description = "Convert an HTML layout to a plotly dash layout" 9 | authors = [{ name = "Najeem Muhammed", email = "najeem@gmail.com" }] 10 | readme = "README.md" 11 | requires-python = ">=3.7" 12 | license = { file = "LICENSE" } 13 | keywords = ["dash", "plotly", "html"] 14 | dependencies = ["dash", "beautifulsoup4", "lxml"] 15 | classifiers = [ 16 | "Programming Language :: Python :: 3", 17 | "License :: OSI Approved :: MIT License", 18 | "Operating System :: OS Independent", 19 | ] 20 | 21 | [project.optional-dependencies] 22 | test = ["pytest", "coverage"] 23 | 24 | [project.urls] 25 | "Homepage" = "https://github.com/idling-mind/html2dash" 26 | "Bug Tracker" = "https://github.com/idling-mind/html2dash/issues" 27 | 28 | [tool.setuptools.dynamic] 29 | version = { attr = "html2dash.__version__" } 30 | -------------------------------------------------------------------------------- /tests/test_functions.py: -------------------------------------------------------------------------------- 1 | from bs4 import BeautifulSoup 2 | from dash import html 3 | from dash.development.base_component import Component 4 | from html2dash import ( 5 | html2dash, 6 | ) 7 | from html2dash.html2dash import ( 8 | parse_element, 9 | fix_hyphenated_attr, 10 | ) 11 | from .utils import dash_to_dict 12 | 13 | 14 | def test_is_dash_component(): 15 | assert isinstance(html.Div(), Component) 16 | 17 | 18 | def test_fix_hyphenated_attr(): 19 | assert fix_hyphenated_attr("foo-bar") == "fooBar" 20 | assert fix_hyphenated_attr("baz-qux-quux") == "bazQuxQuux" 21 | 22 | 23 | def test_parse_element_none(): 24 | assert parse_element(None) is None 25 | 26 | 27 | def test_parse_element_comment(): 28 | assert ( 29 | parse_element(BeautifulSoup("", "xml").comment) is None 30 | ) 31 | 32 | 33 | def test_html2dash_empty(): 34 | assert html2dash("").to_plotly_json() == html.Div([]).to_plotly_json() 35 | 36 | 37 | def test_html2dash_simple(): 38 | a = dash_to_dict(html2dash("
This is a paragraph
41 |Another paragraph
44 |This is a paragraph
59 |Another paragraph
62 |This is a paragraph
97 | 98 |This is a paragraph
124 |This is my component
170 |This is my component 2
175 || User | 1078 |Commit | 1079 |Date | 1080 |
|---|---|---|
| 1085 | 1089 | | 1090 |
1091 |
1092 | Fix dart Sass compatibility (#29755)
1093 |
1094 | |
1095 | 28 Nov 2019 | 1096 |
| 1099 | JL 1100 | | 1101 |
1102 |
1103 | Change deprecated html tags to text decoration classes
1104 | (#29604)
1105 |
1106 | |
1107 | 27 Nov 2019 | 1108 |
| 1111 | 1115 | | 1116 |
1117 |
1118 | justify-content:between ⇒ justify-content:space-between
1119 | (#29734)
1120 |
1121 | |
1122 | 26 Nov 2019 | 1123 |
| 1126 | 1130 | | 1131 |
1132 |
1133 | Update change-version.js (#29736)
1134 |
1135 | |
1136 | 26 Nov 2019 | 1137 |
| 1140 | 1144 | | 1145 |
1146 |
1147 | Regenerate package-lock.json (#29730)
1148 |
1149 | |
1150 | 25 Nov 2019 | 1151 |
| Page name | 1202 |Visitors | 1203 |Unique | 1204 |Bounce rate | 1205 ||
|---|---|---|---|---|
| 1210 | / 1211 | 1212 | 1213 | | 1214 |4,896 | 1215 |3,654 | 1216 |82.54% | 1217 |
1218 |
1223 |
1230 |
1228 |
1229 | |
1231 |
| 1234 | /form-elements.html 1235 | 1236 | 1237 | | 1238 |3,652 | 1239 |3,215 | 1240 |76.29% | 1241 |
1242 |
1247 |
1254 |
1252 |
1253 | |
1255 |
| 1258 | /index.html 1259 | 1260 | 1261 | | 1262 |3,256 | 1263 |2,865 | 1264 |72.65% | 1265 |
1266 |
1271 |
1278 |
1276 |
1277 | |
1279 |
| 1282 | /icons.html 1283 | 1284 | 1285 | | 1286 |986 | 1287 |865 | 1288 |44.89% | 1289 |
1290 |
1295 |
1302 |
1300 |
1301 | |
1303 |
| 1306 | /docs/ 1307 | 1308 | 1309 | | 1310 |912 | 1311 |822 | 1312 |41.12% | 1313 |
1314 |
1319 |
1326 |
1324 |
1325 | |
1327 |
| 1330 | /accordion.html 1331 | 1332 | 1333 | | 1334 |855 | 1335 |798 | 1336 |32.65% | 1337 |
1338 |
1343 |
1350 |
1348 |
1349 | |
1351 |
| Network | 1378 |Visitors | 1379 ||
|---|---|---|
| 3,550 | 1385 |
1386 |
1387 |
1391 |
1392 | |
1393 | |
| 1,798 | 1397 |
1398 |
1399 |
1403 |
1404 | |
1405 | |
| 1,245 | 1409 |
1410 |
1411 |
1415 |
1416 | |
1417 | |
| TikTok | 1420 |986 | 1421 |
1422 |
1423 |
1427 |
1428 | |
1429 |
| 854 | 1433 |
1434 |
1435 |
1439 |
1440 | |
1441 | |
| VK | 1444 |650 | 1445 |
1446 |
1447 |
1451 |
1452 | |
1453 |
| 420 | 1457 |
1458 |
1459 |
1463 |
1464 | |
1465 | |
|
1480 | |
1484 | 1485 | Extend the data model. 1486 | | 1487 |1488 | August 05, 2021 1489 | | 1490 |1491 | 1492 | 2/7 1493 | 1494 | | 1495 |1496 | 1497 | 3 1499 | | 1500 |1501 | 1505 | | 1506 |
|
1509 | |
1513 | 1514 | Verify the event flow. 1515 | | 1516 |1517 | January 01, 2019 1518 | | 1519 |1520 | 1521 | 3/10 1522 | 1523 | | 1524 |1525 | 1526 | 6 1528 | | 1529 |1530 | JL 1531 | | 1532 |
|
1535 | |
1539 | 1540 | Database backup and maintenance 1543 | | 1544 |1545 | December 28, 2018 1546 | | 1547 |1548 | 1549 | 0/6 1550 | 1551 | | 1552 |1553 | 1554 | 1 1556 | | 1557 |1558 | 1562 | | 1563 |
|
1566 | |
1570 | 1571 | Identify the implementation team. 1574 | | 1575 |1576 | November 11, 2020 1577 | | 1578 |1579 | 1580 | 6/10 1581 | 1582 | | 1583 |1584 | 1585 | 12 1587 | | 1588 |1589 | 1593 | | 1594 |
|
1597 | |
1601 | 1602 | Define users and workflow 1605 | | 1606 |1607 | November 14, 2021 1608 | | 1609 |1610 | 1611 | 3/7 1612 | 1613 | | 1614 |1615 | 1616 | 5 1618 | | 1619 |1620 | 1624 | | 1625 |
|
1628 | |
1632 | 1633 | Check Pull Requests 1634 | | 1635 |1636 | February 11, 2021 1637 | | 1638 |1639 | 1640 | 2/9 1641 | 1642 | | 1643 |1644 | 1645 | 3 1647 | | 1648 |1649 | 1653 | | 1654 |
|
1697 | |
1701 | 1702 | No. 1703 | | 1704 |Invoice Subject | 1705 |Client | 1706 |VAT No. | 1707 |Created | 1708 |Status | 1709 |Price | 1710 |1711 | |
|---|---|---|---|---|---|---|---|---|
|
1716 | |
1720 | 001401 | 1721 |1722 | Design Works 1725 | | 1726 |1727 | 1728 | Carlson Limited 1729 | | 1730 |87956621 | 1731 |15 Dec 2017 | 1732 |Paid | 1733 |$887 | 1734 |1735 | 1736 | 1741 | 1745 | 1746 | | 1747 |
|
1750 | |
1754 | 001402 | 1755 |1756 | UX Wireframes 1759 | | 1760 |1761 | 1762 | Adobe 1763 | | 1764 |87956421 | 1765 |12 Apr 2017 | 1766 |Pending | 1767 |$1200 | 1768 |1769 | 1770 | 1775 | 1779 | 1780 | | 1781 |
|
1784 | |
1788 | 001403 | 1789 |1790 | New Dashboard 1793 | | 1794 |1795 | 1796 | Bluewolf 1797 | | 1798 |87952621 | 1799 |23 Oct 2017 | 1800 |Pending | 1801 |$534 | 1802 |1803 | 1804 | 1809 | 1813 | 1814 | | 1815 |
|
1818 | |
1822 | 001404 | 1823 |1824 | Landing Page 1827 | | 1828 |1829 | 1830 | Salesforce 1831 | | 1832 |87953421 | 1833 |2 Sep 2017 | 1834 |1835 | Due in 2 1836 | Weeks 1837 | | 1838 |$1500 | 1839 |1840 | 1841 | 1846 | 1850 | 1851 | | 1852 |
|
1855 | |
1859 | 001405 | 1860 |1861 | Marketing Templates 1864 | | 1865 |1866 | 1867 | Printic 1868 | | 1869 |87956621 | 1870 |29 Jan 2018 | 1871 |1872 | Paid Today 1873 | | 1874 |$648 | 1875 |1876 | 1877 | 1882 | 1886 | 1887 | | 1888 |
|
1891 | |
1895 | 001406 | 1896 |1897 | Sales Presentation 1900 | | 1901 |1902 | 1903 | Tabdaq 1904 | | 1905 |87956621 | 1906 |4 Feb 2018 | 1907 |1908 | Due in 3 1909 | Weeks 1910 | | 1911 |$300 | 1912 |1913 | 1914 | 1919 | 1923 | 1924 | | 1925 |
|
1928 | |
1932 | 001407 | 1933 |1934 | Logo & Print 1937 | | 1938 |1939 | 1940 | Apple 1941 | | 1942 |87956621 | 1943 |22 Mar 2018 | 1944 |1945 | Paid Today 1946 | | 1947 |$2500 | 1948 |1949 | 1950 | 1955 | 1959 | 1960 | | 1961 |
|
1964 | |
1968 | 001408 | 1969 |1970 | Icons 1973 | | 1974 |1975 | 1976 | Tookapic 1977 | | 1978 |87956621 | 1979 |13 May 2018 | 1980 |1981 | Paid Today 1982 | | 1983 |$940 | 1984 |1985 | 1986 | 1991 | 1995 | 1996 | | 1997 |