diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 6245853..1ad1c9c 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -4,6 +4,7 @@ on: push: branches: - main + - dev paths: - 'LICENSE' - 'CHANGELOG.md' @@ -52,7 +53,7 @@ jobs: - name: Install dependencies run: | uv pip install -e . - uv pip install --group docs + uv pip install --group docs --group lint - name: Deploy to GitHub Pages run: uv run mkdocs gh-deploy --force diff --git a/.gitignore b/.gitignore index 15e5312..891876a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1,135 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +pip-wheel-metadata/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +.python-version -/.venv -/build -/src/flet_data_table_2.egg-info -/examples/datatable2_example/build/ -/examples/datatable2_example/src/__pycache__ -/examples/datatable2_example/src/flet_datatable2_example.egg-info -/examples/flet_data_table_example/build +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock +uv.lock + +# celery beat schedule file +celerybeat-schedule + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation /site -/src/flet_datatable2.egg-info + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# VS Code +.vscode/ + +# PDM +.pdm.toml +__pypackages__/ + .DS_Store -uv.lock -__pycache__/ diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..8f2d1ab --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,20 @@ +repos: + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.12.5 + hooks: + # Run the linter. + - id: ruff + args: [ --fix ] + # Run the formatter. + - id: ruff-format + + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v5.0.0 + hooks: + - id: end-of-file-fixer + - id: trailing-whitespace + + - repo: https://github.com/aio-libs/sort-all + rev: v1.3.0 + hooks: + - id: sort-all diff --git a/examples/datatable2_example/src/example-1.py b/examples/datatable2_example/src/example-1.py index cc85687..fab6b8d 100644 --- a/examples/datatable2_example/src/example-1.py +++ b/examples/datatable2_example/src/example-1.py @@ -8,9 +8,9 @@ def main(page: ft.Page): fdt.DataTable2( empty=ft.Text("This table is empty."), columns=[ - fdt.DataColumn2(ft.Text("First name")), - fdt.DataColumn2(ft.Text("Last name")), - fdt.DataColumn2(ft.Text("Age"), numeric=True), + fdt.DataColumn2(label=ft.Text("First name")), + fdt.DataColumn2(label=ft.Text("Last name")), + fdt.DataColumn2(label=ft.Text("Age"), numeric=True), ], ), ) diff --git a/examples/datatable2_example/src/example-2.py b/examples/datatable2_example/src/example-2.py index c3c6287..3060871 100644 --- a/examples/datatable2_example/src/example-2.py +++ b/examples/datatable2_example/src/example-2.py @@ -22,44 +22,44 @@ def all_selected(e: ft.ControlEvent): def get_data_columns(): data_columns = [ ftd.DataColumn2( - ft.Text("Name"), + label=ft.Text("Name"), size=ftd.DataColumnSize.L, on_sort=sort_column, heading_row_alignment=ft.MainAxisAlignment.START, ), ftd.DataColumn2( - ft.Text("Calories"), + label=ft.Text("Calories"), on_sort=sort_column, numeric=True, heading_row_alignment=ft.MainAxisAlignment.END, ), ftd.DataColumn2( - ft.Text("Fat"), + label=ft.Text("Fat"), on_sort=sort_column, numeric=True, ), ftd.DataColumn2( - ft.Text("Carbs"), + label=ft.Text("Carbs"), on_sort=sort_column, numeric=True, ), ftd.DataColumn2( - ft.Text("Protein"), + label=ft.Text("Protein"), on_sort=sort_column, numeric=True, ), ftd.DataColumn2( - ft.Text("Sodium"), + label=ft.Text("Sodium"), on_sort=sort_column, numeric=True, ), ftd.DataColumn2( - ft.Text("Calcium"), + label=ft.Text("Calcium"), on_sort=sort_column, numeric=True, ), ftd.DataColumn2( - ft.Text("Iron"), + label=ft.Text("Iron"), on_sort=sort_column, numeric=True, ), diff --git a/mkdocs.yml b/mkdocs.yml index 94acc53..635495a 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -95,13 +95,17 @@ validation: # Watch watch: - docs - - src + - src/flet_datatable2 + - CHANGELOG.md + - LICENSE + - README.md # Plugins plugins: # - footnotes - search: lang: en + - open-in-new-tab - mike: alias_type: symlink - glightbox @@ -131,17 +135,12 @@ plugins: preload_modules: [ flet ] filters: - "!^_" # Exclude private members starting with only one underscore - - "!before_update" - - "!before_event" - - "!clean" - - "!did_mount" - - "!init" - - "!is_isolated" - - "!update" - - "!will_unmount" + - "!get_event_field_type" extensions: - griffe_modernized_annotations + - griffe_warnings_deprecated inventories: + - url: https://docs.flet.dev/objects.inv - url: https://docs.python.org/3/objects.inv domains: [ py, std ] - url: https://typing-extensions.readthedocs.io/en/latest/objects.inv diff --git a/pyproject.toml b/pyproject.toml index da269c7..6a01523 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -20,22 +20,43 @@ Issues = "https://github.com/flet-dev/flet-datatable2/issues" "flutter.flet_datatable2" = ["**/*"] [dependency-groups] +test = [ + "pytest >=7.2.0", +] +lint = [ + "ruff >=0.11.7", +] dev = [ - "pre-commit>=4.2.0", - "ruff>=0.11.7", + "pre-commit >=4.2.0", + { include-group = 'lint' }, + { include-group = 'test' }, +] +docs-coverage = [ + "docstr-coverage >=2.3.2", ] docs = [ - "mkdocs", - "mkdocs-material", - "mkdocstrings[python]", - "mkdocstrings-python-xref", - "mike", - "markdown>=3.6", - "pymdown-extensions", - "mkdocs-glightbox", - "mkdocs-section-index", - "griffe-modernized-annotations", - "pygments>=2.16", + "mkdocs >=1.6.1", + "mkdocs-material >=9.6.15", + "mkdocstrings-python >=1.16.12", + "mkdocstrings-python-xref >=1.16.3", + "mike >=2.1.3", + "markdown >=3.6", + "pymdown-extensions >=10.16", + "mkdocs-exclude >=1.0.2", + "mkdocs-glightbox >=0.4.0", + "mkdocs-open-in-new-tab >=1.0.8", + "mkdocs-section-index >=0.3.10", + "griffe-modernized-annotations >=1.0.8", + "griffe-warnings-deprecated >=1.1.0", + "pygments >=2.16", + "markdown-exec[ansi] >=1.11.0", + "pydocstyle >=6.3.0", + "linkcheckmd >=1.4.0", + { include-group = 'docs-coverage' }, +] +all = [ + { include-group = 'dev' }, + { include-group = 'docs' }, ] [build-system] @@ -64,8 +85,9 @@ select = [ "I" ] preview = true +pydocstyle = { convention = 'google' } [tool.ruff.format] quote-style = "double" indent-style = "space" -line-ending = "auto" \ No newline at end of file +line-ending = "auto" diff --git a/src/flet_datatable2/__init__.py b/src/flet_datatable2/__init__.py index 9f767c1..b26b9d5 100644 --- a/src/flet_datatable2/__init__.py +++ b/src/flet_datatable2/__init__.py @@ -2,3 +2,10 @@ from .datarow2 import DataRow2 from .datatable2 import DataTable2 from .types import DataColumnSize + +__all__ = [ + "DataColumn2", + "DataColumnSize", + "DataRow2", + "DataTable2", +] diff --git a/src/flet_datatable2/datacolumn2.py b/src/flet_datatable2/datacolumn2.py index 6b5d4b3..00140bf 100644 --- a/src/flet_datatable2/datacolumn2.py +++ b/src/flet_datatable2/datacolumn2.py @@ -1,12 +1,13 @@ from typing import Optional import flet as ft + from .types import DataColumnSize __all__ = ["DataColumn2"] -@ft.control("DataColumn2") +@ft.control("DataColumn2", kw_only=True) class DataColumn2(ft.DataColumn): """ Extends [`flet.DataColumn`][flet.DataColumn], @@ -17,12 +18,12 @@ class DataColumn2(ft.DataColumn): fixed_width: Optional[ft.Number] = None """ - Defines absolute width of the column in pixels + Defines absolute width of the column in pixels (as opposed to relative [`size`][..] used by default). """ size: Optional[DataColumnSize] = DataColumnSize.S """ - Column sizes are determined based on available width by distributing - it to individual columns accounting for their relative sizes. + Column sizes are determined based on available width by distributing + it to individual columns accounting for their relative sizes. """ diff --git a/src/flet_datatable2/datatable2.py b/src/flet_datatable2/datatable2.py index 7f49052..ad9ba78 100644 --- a/src/flet_datatable2/datatable2.py +++ b/src/flet_datatable2/datatable2.py @@ -132,9 +132,13 @@ class DataTable2(ft.DataTable): data_row_height: Optional[ft.Number] = None """ - Height of each data row. + Height of each data row. """ # present in parent (DataTable) but of no use in DataTable2 - data_row_min_height: None = field(init=False, repr=False, compare=False, metadata={"skip": True}) - data_row_max_height: None = field(init=False, repr=False, compare=False, metadata={"skip": True}) + data_row_min_height: None = field( + init=False, repr=False, compare=False, metadata={"skip": True} + ) + data_row_max_height: None = field( + init=False, repr=False, compare=False, metadata={"skip": True} + ) diff --git a/tests/basic_test.py b/tests/basic_test.py index cc85687..fab6b8d 100644 --- a/tests/basic_test.py +++ b/tests/basic_test.py @@ -8,9 +8,9 @@ def main(page: ft.Page): fdt.DataTable2( empty=ft.Text("This table is empty."), columns=[ - fdt.DataColumn2(ft.Text("First name")), - fdt.DataColumn2(ft.Text("Last name")), - fdt.DataColumn2(ft.Text("Age"), numeric=True), + fdt.DataColumn2(label=ft.Text("First name")), + fdt.DataColumn2(label=ft.Text("Last name")), + fdt.DataColumn2(label=ft.Text("Age"), numeric=True), ], ), ) diff --git a/tests/sorting_test.py b/tests/sorting_test.py index 280da34..02b393a 100644 --- a/tests/sorting_test.py +++ b/tests/sorting_test.py @@ -8,7 +8,7 @@ def main(page: ft.Page): page.vertical_alignment = ft.MainAxisAlignment.CENTER page.horizontal_alignment = ft.CrossAxisAlignment.CENTER - def select_row(e: ft.ControlEvent): + def select_row(e: ft.Event[ftd.DataRow2]): print("on_select_row") e.control.selected = not e.control.selected # e.control.update() @@ -31,44 +31,44 @@ def all_selected(e: ft.ControlEvent): def get_data_columns(): data_columns = [ ftd.DataColumn2( - ft.Text("Name"), + label=ft.Text("Name"), size=ftd.DataColumnSize.L, on_sort=sort_column, heading_row_alignment=ft.MainAxisAlignment.START, ), ftd.DataColumn2( - ft.Text("Calories"), + label=ft.Text("Calories"), on_sort=sort_column, numeric=True, heading_row_alignment=ft.MainAxisAlignment.END, ), ftd.DataColumn2( - ft.Text("Fat"), + label=ft.Text("Fat"), on_sort=sort_column, numeric=True, ), ftd.DataColumn2( - ft.Text("Carbs"), + label=ft.Text("Carbs"), on_sort=sort_column, numeric=True, ), ftd.DataColumn2( - ft.Text("Protein"), + label=ft.Text("Protein"), on_sort=sort_column, numeric=True, ), ftd.DataColumn2( - ft.Text("Sodium"), + label=ft.Text("Sodium"), on_sort=sort_column, numeric=True, ), ftd.DataColumn2( - ft.Text("Calcium"), + label=ft.Text("Calcium"), on_sort=sort_column, numeric=True, ), ftd.DataColumn2( - ft.Text("Iron"), + label=ft.Text("Iron"), on_sort=sort_column, numeric=True, ), @@ -81,7 +81,7 @@ def get_data_rows(desserts): data_rows.append( ftd.DataRow2( specific_row_height=50, - on_select_changed=select_row, + on_select_change=select_row, cells=[ ft.DataCell(content=ft.Text(dessert.name)), ft.DataCell(content=ft.Text(dessert.calories)),