From f2a52c5c3c09d14d46003b80f4402be6e9acfe73 Mon Sep 17 00:00:00 2001 From: Antony Milne <49395058+antonymilne@users.noreply.github.com> Date: Thu, 17 Oct 2024 12:58:39 +0100 Subject: [PATCH] [Feat] Drop Python 3.8 and add Python 3.13 support to Vizro (#813) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .github/workflows/checks-vizro-ai.yml | 2 +- .github/workflows/checks-vizro-core.yml | 4 +- .github/workflows/checks-workflows.yml | 2 +- .github/workflows/lint-vizro-all.yml | 2 +- .github/workflows/release-if-needed.yml | 2 +- .github/workflows/secret-scan.yml | 2 +- .../workflows/test-integration-vizro-ai.yml | 5 ++- .../workflows/test-integration-vizro-core.yml | 6 +-- .github/workflows/test-unit-vizro-ai.yml | 2 +- .github/workflows/test-unit-vizro-core.yml | 6 +-- .vale/styles/Microsoft/ignore.txt | 1 + README.md | 2 +- pyproject.toml | 29 ++++++++---- tools/extract_release_notes.py | 6 +-- vizro-ai/.readthedocs.yaml | 2 +- ...16_133757_antony.milne_bump_python_py39.md | 43 ++++++++++++++++++ vizro-ai/examples/chart_by_vizro_ai.ipynb | 2 +- vizro-ai/examples/dashboard_by_vizro_ai.ipynb | 2 +- vizro-ai/examples/dashboard_ui/components.py | 12 ++--- vizro-ai/hatch.toml | 4 +- vizro-ai/pyproject.toml | 4 +- vizro-ai/snyk/requirements.txt | 11 ----- vizro-ai/src/vizro_ai/_llm_models.py | 4 +- vizro-ai/src/vizro_ai/_vizro_ai.py | 4 +- .../dashboard/_graph/dashboard_creation.py | 28 ++++++------ .../dashboard/_response_models/controls.py | 4 +- .../dashboard/_response_models/dashboard.py | 3 +- .../dashboard/_response_models/df_info.py | 6 +-- .../dashboard/_response_models/layout.py | 8 ++-- .../dashboard/_response_models/page.py | 14 +++--- vizro-ai/src/vizro_ai/dashboard/utils.py | 14 +++--- .../src/vizro_ai/plot/_response_models.py | 6 +-- vizro-ai/src/vizro_ai/utils/helper.py | 4 +- vizro-ai/tests/integration/test_example.py | 4 +- .../dashboard/_response_models/conftest.py | 4 +- .../tests/unit/vizro-ai/dashboard/conftest.py | 4 +- vizro-core/.readthedocs.yaml | 2 +- vizro-core/README.md | 2 +- ...16_133749_antony.milne_bump_python_py39.md | 45 +++++++++++++++++++ vizro-core/docs/pages/user-guides/actions.md | 2 +- .../pages/user-guides/custom-components.md | 12 ++--- .../docs/pages/user-guides/custom-tables.md | 8 +--- vizro-core/docs/pages/user-guides/install.md | 2 +- vizro-core/docs/pages/user-guides/layouts.md | 2 +- vizro-core/examples/dev/app.py | 4 +- .../examples/dev/jupyter_version/app.ipynb | 4 +- vizro-core/examples/visual-vocabulary/app.py | 4 +- .../visual-vocabulary/chart_groups.py | 5 +-- .../visual-vocabulary/custom_charts.py | 10 ++--- .../pages/examples/sankey.py | 4 +- .../pages/examples/waterfall.py | 4 +- vizro-core/hatch.toml | 25 +++++------ vizro-core/pyproject.toml | 16 +++---- vizro-core/schemas/0.1.26.dev0.json | 40 ++++++++--------- vizro-core/snyk/requirements.txt | 17 ------- vizro-core/src/vizro/_vizro.py | 3 +- vizro-core/src/vizro/actions/__init__.py | 1 - .../actions/_action_loop/_action_loop.py | 4 +- .../_action_loop/_action_loop_utils.py | 8 ++-- .../_build_action_loop_callbacks.py | 3 +- .../src/vizro/actions/_actions_utils.py | 42 ++++++++--------- .../_callback_mapping_utils.py | 22 ++++----- .../_get_action_callback_mapping.py | 8 ++-- .../src/vizro/actions/_filter_action.py | 8 ++-- .../src/vizro/actions/_on_page_load_action.py | 4 +- .../src/vizro/actions/_parameter_action.py | 6 +-- .../src/vizro/actions/export_data_action.py | 6 +-- .../actions/filter_interaction_action.py | 4 +- vizro-core/src/vizro/figures/__init__.py | 1 - vizro-core/src/vizro/figures/_kpi_cards.py | 8 ---- .../vizro/integrations/kedro/_data_manager.py | 6 +-- .../src/vizro/managers/_data_manager.py | 4 +- .../src/vizro/managers/_model_manager.py | 17 +++---- vizro-core/src/vizro/models/__init__.py | 4 +- .../src/vizro/models/_action/_action.py | 20 ++++----- .../vizro/models/_action/_actions_chain.py | 6 +-- vizro-core/src/vizro/models/_base.py | 30 ++++++------- .../src/vizro/models/_components/_form.py | 6 +-- .../src/vizro/models/_components/ag_grid.py | 8 ++-- .../src/vizro/models/_components/button.py | 6 +-- .../src/vizro/models/_components/container.py | 6 +-- .../vizro/models/_components/form/__init__.py | 1 - .../vizro/models/_components/form/_alert.py | 6 +-- .../models/_components/form/_text_area.py | 6 +-- .../models/_components/form/_user_input.py | 6 +-- .../models/_components/form/checklist.py | 6 +-- .../models/_components/form/date_picker.py | 10 ++--- .../vizro/models/_components/form/dropdown.py | 8 ++-- .../models/_components/form/radio_items.py | 6 +-- .../models/_components/form/range_slider.py | 14 +++--- .../vizro/models/_components/form/slider.py | 10 ++--- .../src/vizro/models/_components/graph.py | 8 ++-- .../src/vizro/models/_components/table.py | 8 ++-- .../src/vizro/models/_components/tabs.py | 6 +-- .../src/vizro/models/_controls/filter.py | 14 +++--- .../src/vizro/models/_controls/parameter.py | 6 +-- vizro-core/src/vizro/models/_dashboard.py | 10 ++--- vizro-core/src/vizro/models/_layout.py | 18 ++++---- .../src/vizro/models/_navigation/accordion.py | 8 ++-- .../src/vizro/models/_navigation/nav_bar.py | 10 ++--- .../src/vizro/models/_navigation/nav_link.py | 2 +- vizro-core/src/vizro/models/_page.py | 15 ++++--- vizro-core/src/vizro/models/types.py | 16 ++++--- vizro-core/src/vizro/tables/__init__.py | 1 - vizro-core/src/vizro/tables/_utils.py | 5 ++- vizro-core/tests/tests_utils/demo_asserts.py | 4 +- vizro-core/tests/unit/test_vizro.py | 4 +- .../tests/unit/vizro/models/test_base.py | 44 +++++++++--------- 108 files changed, 500 insertions(+), 459 deletions(-) create mode 100644 vizro-ai/changelog.d/20241016_133757_antony.milne_bump_python_py39.md delete mode 100644 vizro-ai/snyk/requirements.txt create mode 100644 vizro-core/changelog.d/20241016_133749_antony.milne_bump_python_py39.md delete mode 100644 vizro-core/snyk/requirements.txt diff --git a/.github/workflows/checks-vizro-ai.yml b/.github/workflows/checks-vizro-ai.yml index ef8553789..33421feed 100644 --- a/.github/workflows/checks-vizro-ai.yml +++ b/.github/workflows/checks-vizro-ai.yml @@ -18,7 +18,7 @@ on: env: PYTHONUNBUFFERED: 1 FORCE_COLOR: 1 - PYTHON_VERSION: "3.11" + PYTHON_VERSION: "3.12" jobs: checks-vizro-ai: diff --git a/.github/workflows/checks-vizro-core.yml b/.github/workflows/checks-vizro-core.yml index e667bba74..334dc05f2 100644 --- a/.github/workflows/checks-vizro-core.yml +++ b/.github/workflows/checks-vizro-core.yml @@ -18,7 +18,7 @@ on: env: PYTHONUNBUFFERED: 1 FORCE_COLOR: 1 - PYTHON_VERSION: "3.11" + PYTHON_VERSION: "3.12" jobs: checks-vizro-core: @@ -42,7 +42,7 @@ jobs: run: hatch run pip tree - name: Check schema is up to date - run: hatch run schema --check + run: hatch run schema-check - name: Find changed files to see if changelog fragment needed id: changed-files diff --git a/.github/workflows/checks-workflows.yml b/.github/workflows/checks-workflows.yml index 9b034dba4..b5561fb3d 100644 --- a/.github/workflows/checks-workflows.yml +++ b/.github/workflows/checks-workflows.yml @@ -10,7 +10,7 @@ on: env: PYTHONUNBUFFERED: 1 FORCE_COLOR: 1 - PYTHON_VERSION: "3.11" + PYTHON_VERSION: "3.12" jobs: checks-workflows: diff --git a/.github/workflows/lint-vizro-all.yml b/.github/workflows/lint-vizro-all.yml index 84d26caaf..2c286c5b5 100644 --- a/.github/workflows/lint-vizro-all.yml +++ b/.github/workflows/lint-vizro-all.yml @@ -14,7 +14,7 @@ on: env: PYTHONUNBUFFERED: 1 FORCE_COLOR: 1 - PYTHON_VERSION: "3.11" + PYTHON_VERSION: "3.12" jobs: lint-vizro-all: diff --git a/.github/workflows/release-if-needed.yml b/.github/workflows/release-if-needed.yml index 405fd0a04..811001991 100644 --- a/.github/workflows/release-if-needed.yml +++ b/.github/workflows/release-if-needed.yml @@ -6,7 +6,7 @@ on: - main env: - PYTHON_VERSION: "3.11" + PYTHON_VERSION: "3.12" jobs: check-version: diff --git a/.github/workflows/secret-scan.yml b/.github/workflows/secret-scan.yml index 2ea01143f..c3f9bc1b8 100644 --- a/.github/workflows/secret-scan.yml +++ b/.github/workflows/secret-scan.yml @@ -8,7 +8,7 @@ on: - cron: "0 4 * * *" # run once a day at 4 AM UTC env: - PYTHON_VERSION: "3.11" + PYTHON_VERSION: "3.12" jobs: secret-scan: diff --git a/.github/workflows/test-integration-vizro-ai.yml b/.github/workflows/test-integration-vizro-ai.yml index 253cba3b3..1c7924eae 100644 --- a/.github/workflows/test-integration-vizro-ai.yml +++ b/.github/workflows/test-integration-vizro-ai.yml @@ -35,9 +35,10 @@ jobs: hatch-env: all.py3.11 - python-version: "3.12" hatch-env: all.py3.12 - - python-version: "3.11" + - python-version: "3.9" hatch-env: lower-bounds label: lower bounds + steps: - uses: actions/checkout@v4 @@ -60,7 +61,7 @@ jobs: hatch-env: all.py3.11 - python-version: "3.12" hatch-env: all.py3.12 - - python-version: "3.11" + - python-version: "3.9" hatch-env: lower-bounds label: lower bounds diff --git a/.github/workflows/test-integration-vizro-core.yml b/.github/workflows/test-integration-vizro-core.yml index e98a528d5..b4403d073 100644 --- a/.github/workflows/test-integration-vizro-core.yml +++ b/.github/workflows/test-integration-vizro-core.yml @@ -24,8 +24,6 @@ jobs: fail-fast: false matrix: include: - - python-version: "3.8" - hatch-env: all.py3.8 - python-version: "3.9" hatch-env: all.py3.9 - python-version: "3.10" @@ -34,7 +32,9 @@ jobs: hatch-env: all.py3.11 - python-version: "3.12" hatch-env: all.py3.12 - - python-version: "3.11" + - python-version: "3.13" + hatch-env: all.py3.13 + - python-version: "3.9" hatch-env: lower-bounds label: lower bounds diff --git a/.github/workflows/test-unit-vizro-ai.yml b/.github/workflows/test-unit-vizro-ai.yml index 0949b7215..d6e0d0be3 100644 --- a/.github/workflows/test-unit-vizro-ai.yml +++ b/.github/workflows/test-unit-vizro-ai.yml @@ -32,7 +32,7 @@ jobs: hatch-env: all.py3.11 - python-version: "3.12" hatch-env: all.py3.12 - - python-version: "3.11" + - python-version: "3.9" hatch-env: lower-bounds label: lower bounds diff --git a/.github/workflows/test-unit-vizro-core.yml b/.github/workflows/test-unit-vizro-core.yml index 1fa9d9621..b0a0ac92f 100644 --- a/.github/workflows/test-unit-vizro-core.yml +++ b/.github/workflows/test-unit-vizro-core.yml @@ -24,8 +24,6 @@ jobs: fail-fast: false matrix: include: - - python-version: "3.8" - hatch-env: all.py3.8 - python-version: "3.9" hatch-env: all.py3.9 - python-version: "3.10" @@ -34,7 +32,9 @@ jobs: hatch-env: all.py3.11 - python-version: "3.12" hatch-env: all.py3.12 - - python-version: "3.11" + - python-version: "3.13" + hatch-env: all.py3.13 + - python-version: "3.9" hatch-env: lower-bounds label: lower bounds diff --git a/.vale/styles/Microsoft/ignore.txt b/.vale/styles/Microsoft/ignore.txt index b526d97fc..b8e14f952 100644 --- a/.vale/styles/Microsoft/ignore.txt +++ b/.vale/styles/Microsoft/ignore.txt @@ -100,3 +100,4 @@ codespace codespaces uv jsDeliver +dash_table diff --git a/README.md b/README.md index 1bad6adb7..be083bde8 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@
-[![Python version](https://img.shields.io/badge/python-3.8%20%7C%203.9%20%7C%203.10%20%7C%203.11%20%7C%203.12-blue.svg)](https://pypi.org/project/vizro/) +[![Python version](https://img.shields.io/badge/python-3.9%20%7C%203.10%20%7C%203.11%20%7C%203.12%20%7C%203.13-blue.svg)](https://pypi.org/project/vizro/) [![PyPI version](https://badge.fury.io/py/vizro.svg)](https://badge.fury.io/py/vizro) [![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](https://github.com/mckinsey/vizro/blob/main/LICENSE.md) [![Documentation](https://readthedocs.org/projects/vizro/badge/?version=stable)](https://vizro.readthedocs.io/) diff --git a/pyproject.toml b/pyproject.toml index b80411c26..2a1469171 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -56,18 +56,23 @@ ignore = [ "D104", # undocumented-public-package "D401", # first-line should be in imperative mood # D407 needs to be ignored as it otherwise messes up the formatting in our API docs - "D407" # missing dashed underline after section + "D407", # missing dashed underline after section + "PD901" # allow using the generic variable name `df` for DataFrames ] select = [ - "E", # pycodestyle errors - "W", # pycodestyle warnings - "F", # pyflakes - "I", # isort - "D", # pydocstyle - "T201", # print - "C4", # flake8-comprehensions + "E", # pycodestyle errors for style conventions of PEP 8 + "W", # pycodestyle warnings for style conventions of PEP 8 + "F", # pyflakes for Python errors + "I", # isort for sorting imports + "D", # pydocstyle for docstrings + "T201", # flake8-print for detecting print statement + "C4", # flake8-comprehensions for better list/set/dict comprehensions "RUF", # Ruff-specific rules - "PL" # pylint + "PL", # pylint + "PD", # pandas-vet for linting pandas code + "UP", # pyupgrade for upgrading syntax to new Python versions + "PERF", # perflint for performance anti-patterns + "FURB" # refurb for reburbishing and modernizing ] [tool.ruff.lint.per-file-ignores] @@ -82,3 +87,9 @@ convention = "google" [tool.ruff.lint.pylint] max-args = 6 + +[tool.ruff.lint.pyupgrade] +# Don't do PEP 604 rewrites (e.g. Union[str, int] -> str | int), even in files that import +# `from __future__ import annotations`. This is needed since pydantic relies on the runtime behavior in Python 3.9. +# When we drop Python 3.9 we can remove this setting. +keep-runtime-typing = true diff --git a/tools/extract_release_notes.py b/tools/extract_release_notes.py index 3f2fed6cd..f1ba3f7a8 100644 --- a/tools/extract_release_notes.py +++ b/tools/extract_release_notes.py @@ -1,6 +1,7 @@ """Extracts latest release notes from CHANGELOG.md and saves to file.""" import sys +from pathlib import Path from werkzeug.utils import secure_filename @@ -8,7 +9,7 @@ def _extract_section(filename, heading): - with open(filename, "r") as file: + with open(filename) as file: lines = file.readlines() start_line, end_line = None, None @@ -42,5 +43,4 @@ def _extract_section(filename, heading): if not section: raise ValueError(f"Section not found under the {HEADING} heading") - with open("release_body.txt", "w") as text_file: - text_file.write(section) + Path("release_body.txt").write_text(section) diff --git a/vizro-ai/.readthedocs.yaml b/vizro-ai/.readthedocs.yaml index c46b7b2c0..2b50b4361 100644 --- a/vizro-ai/.readthedocs.yaml +++ b/vizro-ai/.readthedocs.yaml @@ -8,7 +8,7 @@ version: 2 build: os: ubuntu-22.04 tools: - python: "3.11" + python: "3.12" commands: - pip install hatch - cd vizro-ai/ && hatch run docs:pip tree diff --git a/vizro-ai/changelog.d/20241016_133757_antony.milne_bump_python_py39.md b/vizro-ai/changelog.d/20241016_133757_antony.milne_bump_python_py39.md new file mode 100644 index 000000000..98cf412db --- /dev/null +++ b/vizro-ai/changelog.d/20241016_133757_antony.milne_bump_python_py39.md @@ -0,0 +1,43 @@ + + + + + + + + + diff --git a/vizro-ai/examples/chart_by_vizro_ai.ipynb b/vizro-ai/examples/chart_by_vizro_ai.ipynb index d8991cfc3..eb6fb67e8 100644 --- a/vizro-ai/examples/chart_by_vizro_ai.ipynb +++ b/vizro-ai/examples/chart_by_vizro_ai.ipynb @@ -278,7 +278,7 @@ " df = gapminder()\n", "else:\n", " for fn in uploaded.keys():\n", - " print('User uploaded file \"{name}\"'.format(name=fn))\n", + " print(f'User uploaded file \"{fn}\"')\n", "\n", " df = pd.read_csv(fn)\n", "print(f\"Dataframe used for plotting: \\n{df.head()}\")" diff --git a/vizro-ai/examples/dashboard_by_vizro_ai.ipynb b/vizro-ai/examples/dashboard_by_vizro_ai.ipynb index 1348f711b..8f93a5a16 100644 --- a/vizro-ai/examples/dashboard_by_vizro_ai.ipynb +++ b/vizro-ai/examples/dashboard_by_vizro_ai.ipynb @@ -274,7 +274,7 @@ " dfs.append(df)\n", "else:\n", " for fn in uploaded.keys():\n", - " print('User uploaded file \"{name}\"'.format(name=fn))\n", + " print(f'User uploaded file \"{fn}\"')\n", "\n", " df_uploaded = pd.read_csv(fn)\n", " dfs.append(df_uploaded)" diff --git a/vizro-ai/examples/dashboard_ui/components.py b/vizro-ai/examples/dashboard_ui/components.py index b34a6a25e..dbfb90be1 100644 --- a/vizro-ai/examples/dashboard_ui/components.py +++ b/vizro-ai/examples/dashboard_ui/components.py @@ -1,6 +1,6 @@ """Contains custom components used within a dashboard.""" -from typing import List, Literal +from typing import Literal import black import dash_bootstrap_components as dbc @@ -21,12 +21,12 @@ class UserPromptTextArea(vm.VizroBaseModel): type (Literal["user_input"]): Defaults to `"user_text_area"`. title (str): Title to be displayed. Defaults to `""`. placeholder (str): Default text to display in input field. Defaults to `""`. - actions (Optional[List[Action]]): Defaults to `[]`. + actions (Optional[list[Action]]): Defaults to `[]`. """ type: Literal["user_text_area"] = "user_text_area" - actions: List[Action] = [] # noqa: RUF012 + actions: list[Action] = [] # noqa: RUF012 _set_actions = _action_validator_factory("value") @@ -50,12 +50,12 @@ class UserUpload(vm.VizroBaseModel): Args: type (Literal["upload"]): Defaults to `"upload"`. title (str): Title to be displayed. - actions (List[Action]): See [`Action`][vizro.models.Action]. Defaults to `[]`. + actions (list[Action]): See [`Action`][vizro.models.Action]. Defaults to `[]`. """ type: Literal["upload"] = "upload" - actions: List[Action] = [] # noqa: RUF012 + actions: list[Action] = [] # noqa: RUF012 # 'contents' property is input to custom action callback _input_property: str = PrivateAttr("contents") @@ -153,7 +153,7 @@ class OffCanvas(vm.VizroBaseModel): """OffCanvas component for settings.""" type: Literal["offcanvas"] = "offcanvas" - options: List[str] + options: list[str] value: str def build(self): diff --git a/vizro-ai/hatch.toml b/vizro-ai/hatch.toml index 30aadf73d..9e317a7da 100644 --- a/vizro-ai/hatch.toml +++ b/vizro-ai/hatch.toml @@ -30,7 +30,6 @@ dependencies = [ "pre-commit" ] installer = "uv" -python = "3.11" [envs.default.env-vars] VIZRO_AI_LOG_LEVEL = "DEBUG" @@ -79,7 +78,8 @@ pip = "'{env:HATCH_UV}' pip {args}" serve = "mkdocs serve --open" [envs.lower-bounds] -extra-dependencies = ["pydantic==1.10.13"] +extra-dependencies = ["pydantic==1.10.16"] +python = "3.9" [version] path = "src/vizro_ai/__init__.py" diff --git a/vizro-ai/pyproject.toml b/vizro-ai/pyproject.toml index 26dfc09de..015e302aa 100644 --- a/vizro-ai/pyproject.toml +++ b/vizro-ai/pyproject.toml @@ -64,7 +64,9 @@ filterwarnings = [ "ignore:(?s).*Pyarrow will become a required dependency of pandas:DeprecationWarning", # TODO update all LLMChain class and remove this warning # Ignore LLMchian deprecation warning: - "ignore:.*The class `LLMChain` was deprecated in LangChain 0.1.17" + "ignore:.*The class `LLMChain` was deprecated in LangChain 0.1.17", + # Ignore warning for Pydantic v1 API and Python 3.13: + "ignore:Failing to pass a value to the 'type_params' parameter of 'typing.ForwardRef._evaluate' is deprecated:DeprecationWarning" ] [tool.ruff] diff --git a/vizro-ai/snyk/requirements.txt b/vizro-ai/snyk/requirements.txt deleted file mode 100644 index 236647793..000000000 --- a/vizro-ai/snyk/requirements.txt +++ /dev/null @@ -1,11 +0,0 @@ -pandas -tabulate -openai>=1.0.0 -langchain>=0.1.0, <0.3.0 -langchain-openai -langgraph>=0.1.2 -python-dotenv>=1.0.0 -vizro>=0.1.20 -ipython>=8.10.0 -aiohttp>=3.9.2 -langchain-core>=0.1.31 diff --git a/vizro-ai/src/vizro_ai/_llm_models.py b/vizro-ai/src/vizro_ai/_llm_models.py index 74ba126db..fd05e4ddb 100644 --- a/vizro-ai/src/vizro_ai/_llm_models.py +++ b/vizro-ai/src/vizro_ai/_llm_models.py @@ -1,5 +1,5 @@ from contextlib import suppress -from typing import Dict, Optional, Union +from typing import Optional, Union from langchain_core.language_models.chat_models import BaseChatModel from langchain_openai import ChatOpenAI @@ -31,7 +31,7 @@ "Mistral": ["mistral-large-latest", "open-mistral-nemo", "codestral-latest"], } -DEFAULT_WRAPPER_MAP: Dict[str, BaseChatModel] = { +DEFAULT_WRAPPER_MAP: dict[str, BaseChatModel] = { "OpenAI": ChatOpenAI, "Anthropic": ChatAnthropic, "Mistral": ChatMistralAI, diff --git a/vizro-ai/src/vizro_ai/_vizro_ai.py b/vizro-ai/src/vizro_ai/_vizro_ai.py index 65e528bdf..73769672a 100644 --- a/vizro-ai/src/vizro_ai/_vizro_ai.py +++ b/vizro-ai/src/vizro_ai/_vizro_ai.py @@ -1,6 +1,6 @@ import logging from functools import wraps -from typing import List, Optional, Union +from typing import Optional, Union import pandas as pd import plotly.graph_objects as go @@ -98,7 +98,7 @@ def plot( def dashboard( self, - dfs: List[pd.DataFrame], + dfs: list[pd.DataFrame], user_input: str, return_elements: bool = False, ) -> Union[DashboardOutputs, vm.Dashboard]: diff --git a/vizro-ai/src/vizro_ai/dashboard/_graph/dashboard_creation.py b/vizro-ai/src/vizro_ai/dashboard/_graph/dashboard_creation.py index 691c87a54..79b061334 100644 --- a/vizro-ai/src/vizro_ai/dashboard/_graph/dashboard_creation.py +++ b/vizro-ai/src/vizro_ai/dashboard/_graph/dashboard_creation.py @@ -2,7 +2,7 @@ import logging import operator -from typing import Annotated, Dict, List, Optional +from typing import Annotated, Optional import pandas as pd import vizro.models as vm @@ -28,7 +28,7 @@ logger = logging.getLogger(__name__) -Messages = List[BaseMessage] +Messages = list[BaseMessage] """List of messages.""" @@ -46,14 +46,14 @@ class GraphState(BaseModel): """ - messages: List[BaseMessage] - dfs: List[pd.DataFrame] + messages: list[BaseMessage] + dfs: list[pd.DataFrame] all_df_metadata: AllDfMetadata dashboard_plan: Optional[DashboardPlan] = None - pages: Annotated[List, operator.add] + pages: Annotated[list, operator.add] dashboard: Optional[vm.Dashboard] = None - custom_charts_code: Annotated[List, operator.add] - custom_charts_imports: Annotated[List, operator.add] + custom_charts_code: Annotated[list, operator.add] + custom_charts_imports: Annotated[list, operator.add] class Config: """Pydantic configuration.""" @@ -61,7 +61,7 @@ class Config: arbitrary_types_allowed = True -def _store_df_info(state: GraphState, config: RunnableConfig) -> Dict[str, AllDfMetadata]: +def _store_df_info(state: GraphState, config: RunnableConfig) -> dict[str, AllDfMetadata]: """Store information about the dataframes.""" dfs = state.dfs all_df_metadata = state.all_df_metadata @@ -84,11 +84,11 @@ def _store_df_info(state: GraphState, config: RunnableConfig) -> Dict[str, AllDf ).dataset except DebugFailure as e: logger.warning(f"Failed in name generation {e}") - df_name = f"df_{len(current_df_names)+1}" + df_name = f"df_{len(current_df_names) + 1}" # fallback to a less descriptive but unique name if llm fails if df_name in current_df_names: - df_name = f"df_{len(current_df_names)+1}" + df_name = f"df_{len(current_df_names) + 1}" current_df_names.append(df_name) @@ -99,7 +99,7 @@ def _store_df_info(state: GraphState, config: RunnableConfig) -> Dict[str, AllDf return {"all_df_metadata": all_df_metadata} -def _dashboard_plan(state: GraphState, config: RunnableConfig) -> Dict[str, DashboardPlan]: +def _dashboard_plan(state: GraphState, config: RunnableConfig) -> dict[str, DashboardPlan]: """Generate a dashboard plan.""" node_desc = "Generate dashboard plan" pbar = tqdm(total=2, desc=node_desc) @@ -148,7 +148,7 @@ class BuildPageState(BaseModel): page_plan: Optional[PagePlan] = None -def _build_page(state: BuildPageState, config: RunnableConfig) -> Dict[str, List[vm.Page]]: +def _build_page(state: BuildPageState, config: RunnableConfig) -> dict[str, list[vm.Page]]: """Build a page.""" all_df_metadata = state["all_df_metadata"] page_plan = state["page_plan"] @@ -160,7 +160,7 @@ def _build_page(state: BuildPageState, config: RunnableConfig) -> Dict[str, List return {"pages": [page], "custom_charts_imports": [custom_chart_imports], "custom_charts_code": [custom_chart_code]} -def _continue_to_pages(state: GraphState) -> List[Send]: +def _continue_to_pages(state: GraphState) -> list[Send]: """Map-reduce logic to build pages in parallel.""" all_df_metadata = state.all_df_metadata return [ @@ -169,7 +169,7 @@ def _continue_to_pages(state: GraphState) -> List[Send]: ] -def _build_dashboard(state: GraphState) -> Dict[str, vm.Dashboard]: +def _build_dashboard(state: GraphState) -> dict[str, vm.Dashboard]: """Build a dashboard.""" dashboard_plan = state.dashboard_plan pages = state.pages diff --git a/vizro-ai/src/vizro_ai/dashboard/_response_models/controls.py b/vizro-ai/src/vizro_ai/dashboard/_response_models/controls.py index 13b0f695c..b32f0d8e5 100644 --- a/vizro-ai/src/vizro_ai/dashboard/_response_models/controls.py +++ b/vizro-ai/src/vizro_ai/dashboard/_response_models/controls.py @@ -1,7 +1,7 @@ """Controls plan model.""" import logging -from typing import List, Optional +from typing import Optional import pandas as pd import vizro.models as vm @@ -60,7 +60,7 @@ def validate_date_picker_column(cls, values): return create_model( "FilterProxy", targets=( - List[str], + list[str], Field( ..., description=f""" diff --git a/vizro-ai/src/vizro_ai/dashboard/_response_models/dashboard.py b/vizro-ai/src/vizro_ai/dashboard/_response_models/dashboard.py index a96550b61..64a305f33 100644 --- a/vizro-ai/src/vizro_ai/dashboard/_response_models/dashboard.py +++ b/vizro-ai/src/vizro_ai/dashboard/_response_models/dashboard.py @@ -1,7 +1,6 @@ """Dashboard plan model.""" import logging -from typing import List try: from pydantic.v1 import BaseModel, Field @@ -22,4 +21,4 @@ class DashboardPlan(BaseModel): make a short and concise title from the content of the pages. """, ) - pages: List[PagePlan] + pages: list[PagePlan] diff --git a/vizro-ai/src/vizro_ai/dashboard/_response_models/df_info.py b/vizro-ai/src/vizro_ai/dashboard/_response_models/df_info.py index 0ea59395b..1dd203564 100644 --- a/vizro-ai/src/vizro_ai/dashboard/_response_models/df_info.py +++ b/vizro-ai/src/vizro_ai/dashboard/_response_models/df_info.py @@ -1,7 +1,5 @@ """Data Summary Node.""" -from typing import Dict, List, Tuple - import pandas as pd try: @@ -26,14 +24,14 @@ class DfInfo(BaseModel): dataset: str = Field(pattern=r"^[a-z]+(_[a-z]+)?$", description="Small snake case name of the dataset.") -def _get_df_info(df: pd.DataFrame) -> Tuple[Dict[str, str], pd.DataFrame]: +def _get_df_info(df: pd.DataFrame) -> tuple[dict[str, str], pd.DataFrame]: """Get the dataframe schema and sample.""" formatted_pairs = dict(df.dtypes.astype(str)) df_sample = df.sample(5, replace=True, random_state=19) return formatted_pairs, df_sample -def _create_df_info_content(df_schema: Dict[str, str], df_sample: pd.DataFrame, current_df_names: List[str]) -> dict: +def _create_df_info_content(df_schema: dict[str, str], df_sample: pd.DataFrame, current_df_names: list[str]) -> dict: """Create the message content for the dataframe summarization.""" return DF_SUMMARY_PROMPT.format(df_sample=df_sample, df_schema=df_schema, current_df_names=current_df_names) diff --git a/vizro-ai/src/vizro_ai/dashboard/_response_models/layout.py b/vizro-ai/src/vizro_ai/dashboard/_response_models/layout.py index 7ecd33d42..fb008fa6c 100644 --- a/vizro-ai/src/vizro_ai/dashboard/_response_models/layout.py +++ b/vizro-ai/src/vizro_ai/dashboard/_response_models/layout.py @@ -1,7 +1,7 @@ """Layout plan model.""" import logging -from typing import List, Optional +from typing import Optional import vizro.models as vm @@ -13,7 +13,7 @@ logger = logging.getLogger(__name__) -def _convert_to_grid(layout_grid_template_areas: List[str], component_ids: List[str]) -> List[List[int]]: +def _convert_to_grid(layout_grid_template_areas: list[str], component_ids: list[str]) -> list[list[int]]: component_map = {component: index for index, component in enumerate(component_ids)} grid = [] @@ -42,7 +42,7 @@ def _convert_to_grid(layout_grid_template_areas: List[str], component_ids: List[ class LayoutPlan(BaseModel): """Layout plan model, which only applies to Vizro Components(Graph, AgGrid, Card).""" - layout_grid_template_areas: List[str] = Field( + layout_grid_template_areas: list[str] = Field( [], description=""" Generate grid template areas for the layout adhering to the grid-template-areas CSS property syntax. @@ -56,7 +56,7 @@ class LayoutPlan(BaseModel): """, ) - def create(self, component_ids: List[str]) -> Optional[vm.Layout]: + def create(self, component_ids: list[str]) -> Optional[vm.Layout]: """Create the layout.""" if not self.layout_grid_template_areas: return None diff --git a/vizro-ai/src/vizro_ai/dashboard/_response_models/page.py b/vizro-ai/src/vizro_ai/dashboard/_response_models/page.py index 6557c36f4..7606c39c1 100644 --- a/vizro-ai/src/vizro_ai/dashboard/_response_models/page.py +++ b/vizro-ai/src/vizro_ai/dashboard/_response_models/page.py @@ -3,7 +3,7 @@ import logging import re from collections import Counter -from typing import List, Optional, Tuple, Union +from typing import Optional, Union try: from pydantic.v1 import BaseModel, Field, PrivateAttr, ValidationError, root_validator, validator @@ -30,12 +30,12 @@ class PagePlan(BaseModel): make a concise and descriptive title from the components. """, ) - components_plan: List[ComponentPlan] = Field( + components_plan: list[ComponentPlan] = Field( ..., description="List of components. Must contain at least one component." ) - controls_plan: List[ControlPlan] = Field([], description="Controls of the page.") + controls_plan: list[ControlPlan] = Field([], description="Controls of the page.") layout_plan: LayoutPlan = Field(None, description="Layout of components on the page.") - unsupported_specs: List[str] = Field( + unsupported_specs: list[str] = Field( [], description=""" List of unsupported specs. If there are any unsupported specs, @@ -43,8 +43,8 @@ class PagePlan(BaseModel): """, ) - _components: List[Union[vm.Card, vm.AgGrid, vm.Figure]] = PrivateAttr() - _controls: List[vm.Filter] = PrivateAttr() + _components: list[Union[vm.Card, vm.AgGrid, vm.Figure]] = PrivateAttr() + _controls: list[vm.Filter] = PrivateAttr() _layout: vm.Layout = PrivateAttr() _components_code: dict = PrivateAttr() _components_imports: dict = PrivateAttr() @@ -170,7 +170,7 @@ def _build_controls(self, model, all_df_metadata): return controls - def create(self, model, all_df_metadata) -> Tuple[Union[vm.Page, None], Optional[str], Optional[str]]: + def create(self, model, all_df_metadata) -> tuple[Union[vm.Page, None], Optional[str], Optional[str]]: """Create the page.""" page_desc = f"Building page: {self.title}" logger.info(page_desc) diff --git a/vizro-ai/src/vizro_ai/dashboard/utils.py b/vizro-ai/src/vizro_ai/dashboard/utils.py index 62f0d12c5..22437406e 100644 --- a/vizro-ai/src/vizro_ai/dashboard/utils.py +++ b/vizro-ai/src/vizro_ai/dashboard/utils.py @@ -1,7 +1,7 @@ """Helper Functions For Vizro AI dashboard.""" from dataclasses import dataclass, field -from typing import Any, Dict, List, Optional, Set, Tuple, Union +from typing import Any, Optional, Union import pandas as pd import tqdm.std as tsd @@ -12,7 +12,7 @@ class DfMetadata: """Dataclass containing metadata content for a dataframe.""" - df_schema: Dict[str, str] + df_schema: dict[str, str] df: pd.DataFrame df_sample: pd.DataFrame @@ -21,9 +21,9 @@ class DfMetadata: class AllDfMetadata: """Dataclass containing metadata for all dataframes.""" - all_df_metadata: Dict[str, DfMetadata] = field(default_factory=dict) + all_df_metadata: dict[str, DfMetadata] = field(default_factory=dict) - def get_schemas_and_samples(self) -> Dict[str, Dict[str, str]]: + def get_schemas_and_samples(self) -> dict[str, dict[str, str]]: """Retrieve only the df_schema and df_sample for all datasets.""" return { name: {"df_schema": metadata.df_schema, "df_sample": metadata.df_sample} @@ -37,7 +37,7 @@ def get_df(self, name: str) -> pd.DataFrame: except KeyError: raise KeyError("Dataframe not found in metadata. Please ensure that the correct dataframe is provided.") - def get_df_schema(self, name: str) -> Dict[str, str]: + def get_df_schema(self, name: str) -> dict[str, str]: """Retrieve the schema of the dataframe by name.""" return self.all_df_metadata[name].df_schema @@ -74,8 +74,8 @@ def _register_data(all_df_metadata: AllDfMetadata) -> vm.Dashboard: def _extract_overall_imports_and_code( - custom_charts_code: List[List[Dict[str, str]]], custom_charts_imports: List[List[Dict[str, str]]] -) -> Tuple[Set[str], Set[str]]: + custom_charts_code: list[list[dict[str, str]]], custom_charts_imports: list[list[dict[str, str]]] +) -> tuple[set[str], set[str]]: """Extract custom functions and imports from the custom charts code. Args: diff --git a/vizro-ai/src/vizro_ai/plot/_response_models.py b/vizro-ai/src/vizro_ai/plot/_response_models.py index 4503f9940..8808cb0db 100644 --- a/vizro-ai/src/vizro_ai/plot/_response_models.py +++ b/vizro-ai/src/vizro_ai/plot/_response_models.py @@ -5,7 +5,7 @@ except ImportError: # pragma: no cov from pydantic import BaseModel, Field, PrivateAttr, create_model, validator import logging -from typing import List, Optional, Union +from typing import Optional, Union import autoflake import black @@ -57,7 +57,7 @@ class ChartPlan(BaseModel): Describes the chart type that best reflects the user request. """, ) - imports: List[str] = Field( + imports: list[str] = Field( ..., description=""" List of import statements required to render the chart defined by the `chart_code` field. @@ -85,7 +85,7 @@ class ChartPlan(BaseModel): Explanation of the code steps used for `chart_code` field.""", ) - _additional_vizro_imports: List[str] = PrivateAttr(ADDITIONAL_IMPORTS) + _additional_vizro_imports: list[str] = PrivateAttr(ADDITIONAL_IMPORTS) @validator("chart_code") def _check_chart_code(cls, v): diff --git a/vizro-ai/src/vizro_ai/utils/helper.py b/vizro-ai/src/vizro_ai/utils/helper.py index 9a574945e..74061ca9a 100644 --- a/vizro-ai/src/vizro_ai/utils/helper.py +++ b/vizro-ai/src/vizro_ai/utils/helper.py @@ -1,11 +1,9 @@ """Helper Functions For Vizro AI.""" -from typing import Tuple - import pandas as pd -def _get_df_info(df: pd.DataFrame, n_sample: int = 5) -> Tuple[str, str]: +def _get_df_info(df: pd.DataFrame, n_sample: int = 5) -> tuple[str, str]: """Get the dataframe schema and head info as string.""" formatted_pairs = [f"{col_name}: {dtype}" for col_name, dtype in df.dtypes.items()] schema_string = "\n".join(formatted_pairs) diff --git a/vizro-ai/tests/integration/test_example.py b/vizro-ai/tests/integration/test_example.py index 2e9dd756c..e18bfa4fc 100644 --- a/vizro-ai/tests/integration/test_example.py +++ b/vizro-ai/tests/integration/test_example.py @@ -1,5 +1,3 @@ -from typing import List - import vizro.plotly.express as px from hamcrest import any_of, assert_that, contains_string, is_not, matches_regexp @@ -12,7 +10,7 @@ POSSIBLE_CHART = ["px.bar", "go.Bar"] -def create_axis_conditions(axis: str, values: List[str]) -> List: +def create_axis_conditions(axis: str, values: list[str]) -> list: return [ matches_regexp(f".*{pattern}.*") for value in values diff --git a/vizro-ai/tests/unit/vizro-ai/dashboard/_response_models/conftest.py b/vizro-ai/tests/unit/vizro-ai/dashboard/_response_models/conftest.py index 82a557dff..28fd80c8d 100644 --- a/vizro-ai/tests/unit/vizro-ai/dashboard/_response_models/conftest.py +++ b/vizro-ai/tests/unit/vizro-ai/dashboard/_response_models/conftest.py @@ -1,4 +1,4 @@ -from typing import Any, List +from typing import Any import pandas as pd import pytest @@ -13,7 +13,7 @@ class MockStructuredOutputLLM(FakeListLLM): - def bind_tools(self, tools: List[Any]): + def bind_tools(self, tools: list[Any]): return super().bind(tools=tools) def with_structured_output(self, schema): diff --git a/vizro-ai/tests/unit/vizro-ai/dashboard/conftest.py b/vizro-ai/tests/unit/vizro-ai/dashboard/conftest.py index d370c1830..33059ae1b 100644 --- a/vizro-ai/tests/unit/vizro-ai/dashboard/conftest.py +++ b/vizro-ai/tests/unit/vizro-ai/dashboard/conftest.py @@ -1,4 +1,4 @@ -from typing import Any, List +from typing import Any import pytest import vizro.models as vm @@ -8,7 +8,7 @@ class MockStructuredOutputLLM(FakeListLLM): - def bind_tools(self, tools: List[Any]): + def bind_tools(self, tools: list[Any]): return super().bind(tools=tools) def with_structured_output(self, schema): diff --git a/vizro-core/.readthedocs.yaml b/vizro-core/.readthedocs.yaml index 2b5ae9a62..e5d53f95c 100644 --- a/vizro-core/.readthedocs.yaml +++ b/vizro-core/.readthedocs.yaml @@ -8,7 +8,7 @@ version: 2 build: os: ubuntu-22.04 tools: - python: "3.11" + python: "3.12" commands: - pip install hatch - cd vizro-core/ && hatch run docs:pip tree diff --git a/vizro-core/README.md b/vizro-core/README.md index 4b7c327e1..3a0cb5bc6 100644 --- a/vizro-core/README.md +++ b/vizro-core/README.md @@ -11,7 +11,7 @@
-[![Python version](https://img.shields.io/badge/python-3.8%20%7C%203.9%20%7C%203.10%20%7C%203.11%20%7C%203.12-blue.svg)](https://pypi.org/project/vizro/) +[![Python version](https://img.shields.io/badge/python-3.9%20%7C%203.10%20%7C%203.11%20%7C%203.12%20%7C%203.13-blue.svg)](https://pypi.org/project/vizro/) [![PyPI version](https://badge.fury.io/py/vizro.svg)](https://badge.fury.io/py/vizro) [![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](https://github.com/mckinsey/vizro/blob/main/LICENSE.md) [![Documentation](https://readthedocs.org/projects/vizro/badge/?version=stable)](https://vizro.readthedocs.io/) diff --git a/vizro-core/changelog.d/20241016_133749_antony.milne_bump_python_py39.md b/vizro-core/changelog.d/20241016_133749_antony.milne_bump_python_py39.md new file mode 100644 index 000000000..e4615ba40 --- /dev/null +++ b/vizro-core/changelog.d/20241016_133749_antony.milne_bump_python_py39.md @@ -0,0 +1,45 @@ + + + + +### Removed + +- Drop support for Python 3.8. ([#813](https://github.com/mckinsey/vizro/pull/813)) + +### Added + +- Add support for Python 3.13. ([#813](https://github.com/mckinsey/vizro/pull/813)) + + + + + diff --git a/vizro-core/docs/pages/user-guides/actions.md b/vizro-core/docs/pages/user-guides/actions.md index 99e14cc05..3c811eb48 100644 --- a/vizro-core/docs/pages/user-guides/actions.md +++ b/vizro-core/docs/pages/user-guides/actions.md @@ -315,7 +315,7 @@ Refer to our [user guide on custom actions](custom-actions.md) for more informat ## Chain actions -The `actions` parameter for the different screen components accepts a `List` of [`Action`][vizro.models.Action] models. +The `actions` parameter for the different screen components accepts a `list` of [`Action`][vizro.models.Action] models. This means that it's possible to chain together a list of actions that are executed by triggering only one component. The order of action execution is guaranteed, and the next action in the list will start executing only when the previous one is completed. diff --git a/vizro-core/docs/pages/user-guides/custom-components.md b/vizro-core/docs/pages/user-guides/custom-components.md index aa6465d52..bd73a5d72 100644 --- a/vizro-core/docs/pages/user-guides/custom-components.md +++ b/vizro-core/docs/pages/user-guides/custom-components.md @@ -308,7 +308,7 @@ Add the custom action `open_offcanvas` as a `function` argument inside the [`Act === "app.py" ```{.python pycafe-link} - from typing import List, Literal + from typing import Literal import dash_bootstrap_components as dbc import vizro.models as vm @@ -390,9 +390,9 @@ Add the custom action `open_offcanvas` as a `function` argument inside the [`Act As mentioned above, custom components can trigger action. To enable the custom component to trigger the action, we need to add some extra code: -1. **Add the `actions` argument to your custom component**. The type of the `actions` argument is `List[Action]`. +1. **Add the `actions` argument to your custom component**. The type of the `actions` argument is `list[Action]`. ```py - actions: List[Action] = [] + actions: list[Action] = [] ``` 2. **Set the action through `_set_actions`**. In doing so, any change in the `"active_index"` property of the custom component triggers the action. ```py @@ -404,7 +404,7 @@ As mentioned above, custom components can trigger action. To enable the custom c === "app.py" ```py - from typing import List, Literal + from typing import Literal import dash_bootstrap_components as dbc import vizro.models as vm @@ -424,8 +424,8 @@ As mentioned above, custom components can trigger action. To enable the custom c # 1. Create new custom component class Carousel(vm.VizroBaseModel): type: Literal["carousel"] = "carousel" - items: List - actions: List[Action] = [] + items: list + actions: list[Action] = [] # Here we set the action so a change in the active_index property of the custom component triggers the action _set_actions = _action_validator_factory("active_index") diff --git a/vizro-core/docs/pages/user-guides/custom-tables.md b/vizro-core/docs/pages/user-guides/custom-tables.md index 5e500e01c..8fa5f5252 100644 --- a/vizro-core/docs/pages/user-guides/custom-tables.md +++ b/vizro-core/docs/pages/user-guides/custom-tables.md @@ -22,8 +22,6 @@ The following examples show a possible version of a custom table. In this case t ??? example "Custom Dash DataTable" === "app.py" ```{.python pycafe-link} - from typing import List - from dash import dash_table import vizro.models as vm @@ -35,7 +33,7 @@ The following examples show a possible version of a custom table. In this case t @capture("table") - def my_custom_table(chosen_columns: List[str], data_frame=None): + def my_custom_table(chosen_columns: list[str], data_frame=None): """Custom table.""" columns = [{"name": i, "id": i} for i in chosen_columns] defaults = { @@ -84,8 +82,6 @@ The following examples show a possible version of a custom table. In this case t ??? example "Custom Dash AgGrid" === "app.py" ```{.python pycafe-link} - from typing import List - import vizro.models as vm import vizro.plotly.express as px from dash_ag_grid import AgGrid @@ -96,7 +92,7 @@ The following examples show a possible version of a custom table. In this case t @capture("ag_grid") - def my_custom_aggrid(chosen_columns: List[str], data_frame=None): + def my_custom_aggrid(chosen_columns: list[str], data_frame=None): """Custom ag_grid.""" defaults = { "className": "ag-theme-quartz-dark ag-theme-vizro", diff --git a/vizro-core/docs/pages/user-guides/install.md b/vizro-core/docs/pages/user-guides/install.md index 3909b337c..bbc09abda 100644 --- a/vizro-core/docs/pages/user-guides/install.md +++ b/vizro-core/docs/pages/user-guides/install.md @@ -8,7 +8,7 @@ We recommend that you create a virtual environment for each Vizro project you wo ## Prerequisites to working locally -* **Python**: Vizro supports macOS, Linux, and Windows. It works with Python 3.8 and later. +* **Python**: Vizro supports macOS, Linux, and Windows. It works with Python 3.9 and later. * **Virtual environment**: You specify the version of Python to use with Vizro when you set up the virtual environment. See the following references to learn more about [Python virtual environments](https://realpython.com/python-virtual-environments-a-primer/), [Conda virtual environments](https://docs.conda.io/projects/conda/en/latest/user-guide/getting-started.html#starting-conda) or [watch an explainer video about them](https://youtu.be/YKfAwIItO7M). ### How to create a virtual environment for your Vizro project diff --git a/vizro-core/docs/pages/user-guides/layouts.md b/vizro-core/docs/pages/user-guides/layouts.md index fb9b18698..8361560db 100644 --- a/vizro-core/docs/pages/user-guides/layouts.md +++ b/vizro-core/docs/pages/user-guides/layouts.md @@ -54,7 +54,7 @@ grid = [[0, 1], [0, 2]] ``` -- The `grid` must be provided as `List[List[int]]` (for example, `grid = [[0, 1], [0, 2]]`). +- The `grid` must be provided as `list[list[int]]` (for example, `grid = [[0, 1], [0, 2]]`). - The integers in the `grid` must be consecutive integers starting with 0 (for example, `0`, `1`, `2`). - The integers correspond to the index of the chart/component inside the list of `components` provided to [`Page`][vizro.models.Page]. - The number of integers in the `grid` needs to match the number of chart/components provided. diff --git a/vizro-core/examples/dev/app.py b/vizro-core/examples/dev/app.py index 8f4862707..aa56f9ff1 100644 --- a/vizro-core/examples/dev/app.py +++ b/vizro-core/examples/dev/app.py @@ -1,7 +1,7 @@ """Example app to show all features of Vizro.""" from time import sleep -from typing import List, Literal, Optional +from typing import Literal, Optional import dash_bootstrap_components as dbc import pandas as pd @@ -601,7 +601,7 @@ def waterfall(data_frame, measure, x, y, text, title=None): # CUSTOM TABLE ------------------------------------------------------------------ @capture("table") -def my_custom_table(data_frame=None, chosen_columns: Optional[List[str]] = None): +def my_custom_table(data_frame=None, chosen_columns: Optional[list[str]] = None): """Custom table with added logic to filter on chosen columns.""" columns = [{"name": i, "id": i} for i in chosen_columns] defaults = { diff --git a/vizro-core/examples/dev/jupyter_version/app.ipynb b/vizro-core/examples/dev/jupyter_version/app.ipynb index cd2e2699c..a1bd24223 100644 --- a/vizro-core/examples/dev/jupyter_version/app.ipynb +++ b/vizro-core/examples/dev/jupyter_version/app.ipynb @@ -7,7 +7,7 @@ "outputs": [], "source": [ "from time import sleep\n", - "from typing import List, Literal, Optional\n", + "from typing import Literal, Optional\n", "\n", "import dash_bootstrap_components as dbc\n", "import pandas as pd\n", @@ -620,7 +620,7 @@ "\n", "# CUSTOM TABLE ------------------------------------------------------------------\n", "@capture(\"table\")\n", - "def my_custom_table(data_frame=None, chosen_columns: Optional[List[str]] = None):\n", + "def my_custom_table(data_frame=None, chosen_columns: Optional[list[str]] = None):\n", " \"\"\"Custom table with added logic to filter on chosen columns.\"\"\"\n", " columns = [{\"name\": i, \"id\": i} for i in chosen_columns]\n", " defaults = {\n", diff --git a/vizro-core/examples/visual-vocabulary/app.py b/vizro-core/examples/visual-vocabulary/app.py index 4835da8fe..c465de0ed 100644 --- a/vizro-core/examples/visual-vocabulary/app.py +++ b/vizro-core/examples/visual-vocabulary/app.py @@ -1,6 +1,6 @@ """App configuration for dashboard.""" -from typing import List, Union +from typing import Union import vizro.models as vm from chart_groups import ALL_CHART_GROUP, CHART_GROUPS, ChartGroup, IncompletePage @@ -60,7 +60,7 @@ def make_homepage_container(chart_group: ChartGroup) -> vm.Container: ) -def _remove_duplicates(pages: List[Union[vm.Page, IncompletePage]]) -> List[Union[vm.Page, IncompletePage]]: +def _remove_duplicates(pages: list[Union[vm.Page, IncompletePage]]) -> list[Union[vm.Page, IncompletePage]]: # Deduplicate pages that have the same title. Using reversed means that the page that is kept is the first one # in the dashboard. This will be the one that the card on the homepage links to. return list({page.title: page for page in reversed(pages)}.values()) diff --git a/vizro-core/examples/visual-vocabulary/chart_groups.py b/vizro-core/examples/visual-vocabulary/chart_groups.py index 2e6f4f228..0acc2dab2 100644 --- a/vizro-core/examples/visual-vocabulary/chart_groups.py +++ b/vizro-core/examples/visual-vocabulary/chart_groups.py @@ -2,7 +2,6 @@ import itertools from dataclasses import dataclass -from typing import List import pages.correlation import pages.deviation @@ -36,8 +35,8 @@ class ChartGroup: """Represents a group of charts like "Deviation".""" name: str - pages: List[vm.Page] - incomplete_pages: List[IncompletePage] + pages: list[vm.Page] + incomplete_pages: list[IncompletePage] intro_text: str icon: str = "" # ALL_CHART_GROUP is the only one that doesn't require an icon. diff --git a/vizro-core/examples/visual-vocabulary/custom_charts.py b/vizro-core/examples/visual-vocabulary/custom_charts.py index 82b021eac..9ed5e78db 100644 --- a/vizro-core/examples/visual-vocabulary/custom_charts.py +++ b/vizro-core/examples/visual-vocabulary/custom_charts.py @@ -1,7 +1,5 @@ """Contains custom charts used inside the dashboard.""" -from typing import List - import pandas as pd import vizro.plotly.express as px from plotly import graph_objects as go @@ -51,7 +49,7 @@ def butterfly(data_frame: pd.DataFrame, x1: str, x2: str, y: str) -> go.Figure: @capture("graph") -def sankey(data_frame: pd.DataFrame, source: str, target: str, value: str, labels: List[str]) -> go.Figure: +def sankey(data_frame: pd.DataFrame, source: str, target: str, value: str, labels: list[str]) -> go.Figure: """Creates a custom sankey chart using Plotly's `go.Sankey`. A Sankey chart is a type of flow diagram where the width of the arrows is proportional to the flow rate. @@ -62,7 +60,7 @@ def sankey(data_frame: pd.DataFrame, source: str, target: str, value: str, label source (str): The name of the column in the data frame for the source nodes. target (str): The name of the column in the data frame for the target nodes. value (str): The name of the column in the data frame for the values representing the flow between nodes. - labels (List[str]): A list of labels for the nodes. + labels (list[str]): A list of labels for the nodes. Returns: go.Figure: A Plotly Figure object representing the Sankey chart. @@ -145,7 +143,7 @@ def categorical_column(data_frame: pd.DataFrame, x: str, y: str): @capture("graph") -def waterfall(data_frame: pd.DataFrame, x: str, y: str, measure: List[str]) -> go.Figure: +def waterfall(data_frame: pd.DataFrame, x: str, y: str, measure: list[str]) -> go.Figure: """Creates a waterfall chart using Plotly's `go.Waterfall`. A Waterfall chart visually breaks down the cumulative effect of sequential positive and negative values, @@ -155,7 +153,7 @@ def waterfall(data_frame: pd.DataFrame, x: str, y: str, measure: List[str]) -> g data_frame (pd.DataFrame): The data source for the chart. x (str): Column name in `data_frame` for x-axis values. y (str): Column name in `data_frame` for y-axis values. - measure (List[str]): List specifying the type of each bar, can be "relative", "total", or "absolute". + measure (list[str]): List specifying the type of each bar, can be "relative", "total", or "absolute". Returns: go.Figure: A Plotly Figure object representing the Waterfall chart. diff --git a/vizro-core/examples/visual-vocabulary/pages/examples/sankey.py b/vizro-core/examples/visual-vocabulary/pages/examples/sankey.py index 21789018a..c96c927e5 100644 --- a/vizro-core/examples/visual-vocabulary/pages/examples/sankey.py +++ b/vizro-core/examples/visual-vocabulary/pages/examples/sankey.py @@ -1,5 +1,3 @@ -from typing import List - import pandas as pd import plotly.graph_objects as go import vizro.models as vm @@ -21,7 +19,7 @@ def sankey( source: str, target: str, value: str, - labels: List[str], + labels: list[str], ): fig = go.Figure( data=[ diff --git a/vizro-core/examples/visual-vocabulary/pages/examples/waterfall.py b/vizro-core/examples/visual-vocabulary/pages/examples/waterfall.py index 00d925f0b..e5d4c029e 100644 --- a/vizro-core/examples/visual-vocabulary/pages/examples/waterfall.py +++ b/vizro-core/examples/visual-vocabulary/pages/examples/waterfall.py @@ -1,5 +1,3 @@ -from typing import List - import pandas as pd import plotly.graph_objects as go import vizro.models as vm @@ -20,7 +18,7 @@ def waterfall( data_frame: pd.DataFrame, x: str, y: str, - measure: List[str], + measure: list[str], ): fig = go.Figure( go.Waterfall( diff --git a/vizro-core/hatch.toml b/vizro-core/hatch.toml index dc80a9e9e..3e64f4fe9 100644 --- a/vizro-core/hatch.toml +++ b/vizro-core/hatch.toml @@ -1,21 +1,15 @@ [envs.all] [[envs.all.matrix]] -python = ["3.8", "3.9", "3.10", "3.11", "3.12"] +python = ["3.9", "3.10", "3.11", "3.12", "3.13"] [envs.all.overrides] -# Kedro is currently not compatible with Python 3.12 and returns exceptions when trying to run the unit tests on -# Python 3.12. These exceptions turned out to be difficult to ignore: https://github.com/mckinsey/vizro/pull/216 +# Kedro is currently not compatible with Python 3.13 and returns exceptions when trying to run the unit tests on +# Python 3.13. These exceptions turned out to be difficult to ignore: https://github.com/mckinsey/vizro/pull/216 matrix.python.features = [ - {value = "kedro", if = ["3.8", "3.9", "3.10", "3.11"]} + {value = "kedro", if = ["3.9", "3.10", "3.11", "3.12"]} ] -[envs."all.py3.11".scripts] -# Ideally schema would work best as a Python script with the Python version pinned, but in Hatch it's not possible to -# specify the current vizro as a dependency in a Python script (this is possible with uv project management). Instead -# you'd need to add the path of vizro *and all its dependencies* in the file's add `sys.path`, which is not nice. -schema = ["python schemas/generate.py {args}", '- SKIP=gitleaks pre-commit run --files="schemas/$(hatch version).json" > /dev/null'] - [envs.changelog] dependencies = ["scriv"] detached = true @@ -53,10 +47,9 @@ prep-release = [ 'echo "Now raise a PR to merge into main with title: [Release] Release of vizro $(hatch version)"' ] pypath = "python -c 'import sys; print(sys.executable)'" -# Ideally just doing hatch run schema would be fine, but the schema slightly depends on Python version (Python 3.8 vs. -# Python 3.11 give different results), even for the same pydantic version. So we point to a script that runs -# specifically on Python 3.11. -schema = "hatch run all.py3.11:schema {args}" +# Only run pre-commit hooks when schema is generated, not when it's checked. This keeps the check fast in CI. +schema = ["python schemas/generate.py", 'SKIP=gitleaks pre-commit run --files="schemas/$(hatch version).json" > /dev/null'] +schema-check = ["python schemas/generate.py --check"] secrets = "pre-commit run gitleaks --all-files" # Note `hatch run test` currently fails due to interference between integration tests and unit tests. Ideally we would # fix this, but we don't actually use `hatch run test` anywhere right now. @@ -114,10 +107,12 @@ VIZRO_LOG_LEVEL = "DEBUG" [envs.lower-bounds] extra-dependencies = [ - "pydantic==1.10.13", + "pydantic==1.10.16", "dash==2.17.1", "plotly==5.12.0" ] +features = ["kedro"] +python = "3.9" [publish.index] disable = true diff --git a/vizro-core/pyproject.toml b/vizro-core/pyproject.toml index 325990971..aa511adc6 100644 --- a/vizro-core/pyproject.toml +++ b/vizro-core/pyproject.toml @@ -8,11 +8,11 @@ authors = [ ] classifiers = [ "Programming Language :: Python", - "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", - "Programming Language :: Python :: 3.12" + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13" ] dependencies = [ "dash>=2.17.1", # 2.17.1 needed for no_output fix in clientside_callback @@ -20,7 +20,7 @@ dependencies = [ "dash-ag-grid>=31.0.0", "pandas", "plotly>=5.12.0", - "pydantic>=1.10.13", # must be synced with pre-commit mypy hook manually + "pydantic>=1.10.16", # must be synced with pre-commit mypy hook manually "dash_mantine_components<0.13.0", # 0.13.0 is not compatible with 0.12, "flask_caching>=2", "wrapt>=1", @@ -32,7 +32,7 @@ dynamic = ["version"] license-files = {paths = ["LICENSE.txt"]} name = "vizro" readme = "README.md" -requires-python = ">=3.8" +requires-python = ">=3.9" [project.optional-dependencies] kedro = [ @@ -76,10 +76,10 @@ filterwarnings = [ "ignore:(?s).*Pyarrow will become a required dependency of pandas:DeprecationWarning", # Ignore until plotly fixes so the warning is no longer raised: "ignore:When grouping with a length-1 list-like, you will need to pass a length-1 tuple to get_group:FutureWarning", - # Ignore warning when providing a custom format string to the KPI cards: - "ignore:Custom format string detected.", - # Ignore warning when using the fig.layout.title inside examples - "ignore:Using the `title` argument in your Plotly chart function may cause misalignment:UserWarning" + # Ignore warning when using the fig.layout.title inside examples: + "ignore:Using the `title` argument in your Plotly chart function may cause misalignment:UserWarning", + # Ignore warning for Pydantic v1 API and Python 3.13: + "ignore:Failing to pass a value to the 'type_params' parameter of 'typing.ForwardRef._evaluate' is deprecated:DeprecationWarning" ] norecursedirs = ["tests/tests_utils", "tests/js"] pythonpath = ["tests/tests_utils"] diff --git a/vizro-core/schemas/0.1.26.dev0.json b/vizro-core/schemas/0.1.26.dev0.json index 10d95ab73..d5002ea1f 100644 --- a/vizro-core/schemas/0.1.26.dev0.json +++ b/vizro-core/schemas/0.1.26.dev0.json @@ -1,6 +1,6 @@ { "title": "Dashboard", - "description": "Vizro Dashboard to be used within [`Vizro`][vizro._vizro.Vizro.build].\n\nArgs:\n pages (List[Page]): See [`Page`][vizro.models.Page].\n theme (Literal[\"vizro_dark\", \"vizro_light\"]): Layout theme to be applied across dashboard.\n Defaults to `vizro_dark`.\n navigation (Navigation): See [`Navigation`][vizro.models.Navigation]. Defaults to `None`.\n title (str): Dashboard title to appear on every page on top left-side. Defaults to `\"\"`.", + "description": "Vizro Dashboard to be used within [`Vizro`][vizro._vizro.Vizro.build].\n\nArgs:\n pages (list[Page]): See [`Page`][vizro.models.Page].\n theme (Literal[\"vizro_dark\", \"vizro_light\"]): Layout theme to be applied across dashboard.\n Defaults to `vizro_dark`.\n navigation (Navigation): See [`Navigation`][vizro.models.Navigation]. Defaults to `None`.\n title (str): Dashboard title to appear on every page on top left-side. Defaults to `\"\"`.", "type": "object", "properties": { "id": { @@ -38,7 +38,7 @@ "definitions": { "Action": { "title": "Action", - "description": "Action to be inserted into `actions` of relevant component.\n\nArgs:\n function (CapturedCallable): Action function. See [`vizro.actions`][vizro.actions].\n inputs (List[str]): Inputs in the form `.` passed to the action function.\n Defaults to `[]`.\n outputs (List[str]): Outputs in the form `.` changed by the action function.\n Defaults to `[]`.", + "description": "Action to be inserted into `actions` of relevant component.\n\nArgs:\n function (CapturedCallable): Action function. See [`vizro.actions`][vizro.actions].\n inputs (list[str]): Inputs in the form `.` passed to the action function.\n Defaults to `[]`.\n outputs (list[str]): Outputs in the form `.` changed by the action function.\n Defaults to `[]`.", "type": "object", "properties": { "id": { @@ -74,7 +74,7 @@ }, "AgGrid": { "title": "AgGrid", - "description": "Wrapper for `dash-ag-grid.AgGrid` to visualize grids in dashboard.\n\nArgs:\n type (Literal[\"ag_grid\"]): Defaults to `\"ag_grid\"`.\n figure (CapturedCallable): Function that returns a Dash AgGrid. See [`vizro.tables`][vizro.tables].\n title (str): Title of the `AgGrid`. Defaults to `\"\"`.\n header (str): Markdown text positioned below the `AgGrid.title`. Follows the CommonMark specification.\n Ideal for adding supplementary information such as subtitles, descriptions, or additional context.\n Defaults to `\"\"`.\n footer (str): Markdown text positioned below the `AgGrid`. Follows the CommonMark specification.\n Ideal for providing further details such as sources, disclaimers, or additional notes. Defaults to `\"\"`.\n actions (List[Action]): See [`Action`][vizro.models.Action]. Defaults to `[]`.", + "description": "Wrapper for `dash-ag-grid.AgGrid` to visualize grids in dashboard.\n\nArgs:\n type (Literal[\"ag_grid\"]): Defaults to `\"ag_grid\"`.\n figure (CapturedCallable): Function that returns a Dash AgGrid. See [`vizro.tables`][vizro.tables].\n title (str): Title of the `AgGrid`. Defaults to `\"\"`.\n header (str): Markdown text positioned below the `AgGrid.title`. Follows the CommonMark specification.\n Ideal for adding supplementary information such as subtitles, descriptions, or additional context.\n Defaults to `\"\"`.\n footer (str): Markdown text positioned below the `AgGrid`. Follows the CommonMark specification.\n Ideal for providing further details such as sources, disclaimers, or additional notes. Defaults to `\"\"`.\n actions (list[Action]): See [`Action`][vizro.models.Action]. Defaults to `[]`.", "type": "object", "properties": { "id": { @@ -120,7 +120,7 @@ }, "Button": { "title": "Button", - "description": "Component provided to `Page` to trigger any defined `action` in `Page`.\n\nArgs:\n type (Literal[\"button\"]): Defaults to `\"button\"`.\n text (str): Text to be displayed on button. Defaults to `\"Click me!\"`.\n actions (List[Action]): See [`Action`][vizro.models.Action]. Defaults to `[]`.", + "description": "Component provided to `Page` to trigger any defined `action` in `Page`.\n\nArgs:\n type (Literal[\"button\"]): Defaults to `\"button\"`.\n text (str): Text to be displayed on button. Defaults to `\"Click me!\"`.\n actions (list[Action]): See [`Action`][vizro.models.Action]. Defaults to `[]`.", "type": "object", "properties": { "id": { @@ -206,7 +206,7 @@ }, "Graph": { "title": "Graph", - "description": "Wrapper for `dcc.Graph` to visualize charts in dashboard.\n\nArgs:\n type (Literal[\"graph\"]): Defaults to `\"graph\"`.\n figure (CapturedCallable): Function that returns a graph.\n See `CapturedCallable`][vizro.models.types.CapturedCallable].\n title (str): Title of the `Graph`. Defaults to `\"\"`.\n header (str): Markdown text positioned below the `Graph.title`. Follows the CommonMark specification.\n Ideal for adding supplementary information such as subtitles, descriptions, or additional context.\n Defaults to `\"\"`.\n footer (str): Markdown text positioned below the `Graph`. Follows the CommonMark specification.\n Ideal for providing further details such as sources, disclaimers, or additional notes. Defaults to `\"\"`.\n actions (List[Action]): See [`Action`][vizro.models.Action]. Defaults to `[]`.", + "description": "Wrapper for `dcc.Graph` to visualize charts in dashboard.\n\nArgs:\n type (Literal[\"graph\"]): Defaults to `\"graph\"`.\n figure (CapturedCallable): Function that returns a graph.\n See `CapturedCallable`][vizro.models.types.CapturedCallable].\n title (str): Title of the `Graph`. Defaults to `\"\"`.\n header (str): Markdown text positioned below the `Graph.title`. Follows the CommonMark specification.\n Ideal for adding supplementary information such as subtitles, descriptions, or additional context.\n Defaults to `\"\"`.\n footer (str): Markdown text positioned below the `Graph`. Follows the CommonMark specification.\n Ideal for providing further details such as sources, disclaimers, or additional notes. Defaults to `\"\"`.\n actions (list[Action]): See [`Action`][vizro.models.Action]. Defaults to `[]`.", "type": "object", "properties": { "id": { @@ -252,7 +252,7 @@ }, "Table": { "title": "Table", - "description": "Wrapper for `dash_table.DataTable` to visualize tables in dashboard.\n\nArgs:\n type (Literal[\"table\"]): Defaults to `\"table\"`.\n figure (CapturedCallable): Function that returns a Dash DataTable. See [`vizro.tables`][vizro.tables].\n title (str): Title of the `Table`. Defaults to `\"\"`.\n header (str): Markdown text positioned below the `Table.title`. Follows the CommonMark specification.\n Ideal for adding supplementary information such as subtitles, descriptions, or additional context.\n Defaults to `\"\"`.\n footer (str): Markdown text positioned below the `Table`. Follows the CommonMark specification.\n Ideal for providing further details such as sources, disclaimers, or additional notes. Defaults to `\"\"`.\n actions (List[Action]): See [`Action`][vizro.models.Action]. Defaults to `[]`.", + "description": "Wrapper for `dash_table.DataTable` to visualize tables in dashboard.\n\nArgs:\n type (Literal[\"table\"]): Defaults to `\"table\"`.\n figure (CapturedCallable): Function that returns a Dash DataTable. See [`vizro.tables`][vizro.tables].\n title (str): Title of the `Table`. Defaults to `\"\"`.\n header (str): Markdown text positioned below the `Table.title`. Follows the CommonMark specification.\n Ideal for adding supplementary information such as subtitles, descriptions, or additional context.\n Defaults to `\"\"`.\n footer (str): Markdown text positioned below the `Table`. Follows the CommonMark specification.\n Ideal for providing further details such as sources, disclaimers, or additional notes. Defaults to `\"\"`.\n actions (list[Action]): See [`Action`][vizro.models.Action]. Defaults to `[]`.", "type": "object", "properties": { "id": { @@ -298,7 +298,7 @@ }, "Tabs": { "title": "Tabs", - "description": "Tabs to group together a set of containers on a page.\n\nArgs:\n type (Literal[\"tabs\"]): Defaults to `\"tabs\"`.\n tabs (List[Container]): See [`Container`][vizro.models.Container].", + "description": "Tabs to group together a set of containers on a page.\n\nArgs:\n type (Literal[\"tabs\"]): Defaults to `\"tabs\"`.\n tabs (list[Container]): See [`Container`][vizro.models.Container].", "type": "object", "properties": { "id": { @@ -326,7 +326,7 @@ }, "Layout": { "title": "Layout", - "description": "Grid specification to place chart/components on the [`Page`][vizro.models.Page].\n\nArgs:\n grid (List[List[int]]): Grid specification to arrange components on screen.\n row_gap (str): Gap between rows in px. Defaults to `\"12px\"`.\n col_gap (str): Gap between columns in px. Defaults to `\"12px\"`.\n row_min_height (str): Minimum row height in px. Defaults to `\"0px\"`.\n col_min_width (str): Minimum column width in px. Defaults to `\"0px\"`.", + "description": "Grid specification to place chart/components on the [`Page`][vizro.models.Page].\n\nArgs:\n grid (list[list[int]]): Grid specification to arrange components on screen.\n row_gap (str): Gap between rows in px. Defaults to `\"12px\"`.\n col_gap (str): Gap between columns in px. Defaults to `\"12px\"`.\n row_min_height (str): Minimum row height in px. Defaults to `\"0px\"`.\n col_min_width (str): Minimum column width in px. Defaults to `\"0px\"`.", "type": "object", "properties": { "id": { @@ -380,7 +380,7 @@ }, "Container": { "title": "Container", - "description": "Container to group together a set of components on a page.\n\nArgs:\n type (Literal[\"container\"]): Defaults to `\"container\"`.\n components (List[ComponentType]): See [ComponentType][vizro.models.types.ComponentType]. At least one component\n has to be provided.\n title (str): Title to be displayed.\n layout (Layout): Layout to place components in. Defaults to `None`.", + "description": "Container to group together a set of components on a page.\n\nArgs:\n type (Literal[\"container\"]): Defaults to `\"container\"`.\n components (list[ComponentType]): See [ComponentType][vizro.models.types.ComponentType]. At least one component\n has to be provided.\n title (str): Title to be displayed.\n layout (Layout): Layout to place components in. Defaults to `None`.", "type": "object", "properties": { "id": { @@ -484,7 +484,7 @@ }, "Checklist": { "title": "Checklist", - "description": "Categorical multi-option selector `Checklist`.\n\nCan be provided to [`Filter`][vizro.models.Filter] or\n[`Parameter`][vizro.models.Parameter]. Based on the underlying\n[`dcc.Checklist`](https://dash.plotly.com/dash-core-components/checklist).\n\nArgs:\n type (Literal[\"checklist\"]): Defaults to `\"checklist\"`.\n options (OptionsType): See [`OptionsType`][vizro.models.types.OptionsType]. Defaults to `[]`.\n value (Optional[MultiValueType]): See [`MultiValueType`][vizro.models.types.MultiValueType]. Defaults to `None`.\n title (str): Title to be displayed. Defaults to `\"\"`.\n actions (List[Action]): See [`Action`][vizro.models.Action]. Defaults to `[]`.", + "description": "Categorical multi-option selector `Checklist`.\n\nCan be provided to [`Filter`][vizro.models.Filter] or\n[`Parameter`][vizro.models.Parameter]. Based on the underlying\n[`dcc.Checklist`](https://dash.plotly.com/dash-core-components/checklist).\n\nArgs:\n type (Literal[\"checklist\"]): Defaults to `\"checklist\"`.\n options (OptionsType): See [`OptionsType`][vizro.models.types.OptionsType]. Defaults to `[]`.\n value (Optional[MultiValueType]): See [`MultiValueType`][vizro.models.types.MultiValueType]. Defaults to `None`.\n title (str): Title to be displayed. Defaults to `\"\"`.\n actions (list[Action]): See [`Action`][vizro.models.Action]. Defaults to `[]`.", "type": "object", "properties": { "id": { @@ -585,7 +585,7 @@ }, "DatePicker": { "title": "DatePicker", - "description": "Temporal single/range option selector `DatePicker`.\n\nCan be provided to [`Filter`][vizro.models.Filter] or [`Parameter`][vizro.models.Parameter].\nBased on the underlying [`dmc.DatePicker`](https://www.dash-mantine-components.com/components/datepicker) or\n[`dmc.DateRangePicker`](https://www.dash-mantine-components.com/components/datepicker#daterangepicker).\n\nArgs:\n type (Literal[\"date_picker\"]): Defaults to `\"date_picker\"`.\n min (Optional[date]): Start date for date picker. Defaults to `None`.\n max (Optional[date]): End date for date picker. Defaults to `None`.\n value (Union[List[date], date]): Default date/dates for date picker. Defaults to `None`.\n title (str): Title to be displayed. Defaults to `\"\"`.\n range (bool): Boolean flag for displaying range picker. Default to `True`.\n actions (List[Action]): See [`Action`][vizro.models.Action]. Defaults to `[]`.", + "description": "Temporal single/range option selector `DatePicker`.\n\nCan be provided to [`Filter`][vizro.models.Filter] or [`Parameter`][vizro.models.Parameter].\nBased on the underlying [`dmc.DatePicker`](https://www.dash-mantine-components.com/components/datepicker) or\n[`dmc.DateRangePicker`](https://www.dash-mantine-components.com/components/datepicker#daterangepicker).\n\nArgs:\n type (Literal[\"date_picker\"]): Defaults to `\"date_picker\"`.\n min (Optional[date]): Start date for date picker. Defaults to `None`.\n max (Optional[date]): End date for date picker. Defaults to `None`.\n value (Union[list[date], date]): Default date/dates for date picker. Defaults to `None`.\n title (str): Title to be displayed. Defaults to `\"\"`.\n range (bool): Boolean flag for displaying range picker. Default to `True`.\n actions (list[Action]): See [`Action`][vizro.models.Action]. Defaults to `[]`.", "type": "object", "properties": { "id": { @@ -654,7 +654,7 @@ }, "Dropdown": { "title": "Dropdown", - "description": "Categorical single/multi-option selector `Dropdown`.\n\nCan be provided to [`Filter`][vizro.models.Filter] or\n[`Parameter`][vizro.models.Parameter]. Based on the underlying\n[`dcc.Dropdown`](https://dash.plotly.com/dash-core-components/dropdown).\n\nArgs:\n type (Literal[\"dropdown\"]): Defaults to `\"dropdown\"`.\n options (OptionsType): See [`OptionsType`][vizro.models.types.OptionsType]. Defaults to `[]`.\n value (Optional[Union[SingleValueType, MultiValueType]]): See\n [`SingleValueType`][vizro.models.types.SingleValueType] and\n [`MultiValueType`][vizro.models.types.MultiValueType]. Defaults to `None`.\n multi (bool): Whether to allow selection of multiple values. Defaults to `True`.\n title (str): Title to be displayed. Defaults to `\"\"`.\n actions (List[Action]): See [`Action`][vizro.models.Action]. Defaults to `[]`.", + "description": "Categorical single/multi-option selector `Dropdown`.\n\nCan be provided to [`Filter`][vizro.models.Filter] or\n[`Parameter`][vizro.models.Parameter]. Based on the underlying\n[`dcc.Dropdown`](https://dash.plotly.com/dash-core-components/dropdown).\n\nArgs:\n type (Literal[\"dropdown\"]): Defaults to `\"dropdown\"`.\n options (OptionsType): See [`OptionsType`][vizro.models.types.OptionsType]. Defaults to `[]`.\n value (Optional[Union[SingleValueType, MultiValueType]]): See\n [`SingleValueType`][vizro.models.types.SingleValueType] and\n [`MultiValueType`][vizro.models.types.MultiValueType]. Defaults to `None`.\n multi (bool): Whether to allow selection of multiple values. Defaults to `True`.\n title (str): Title to be displayed. Defaults to `\"\"`.\n actions (list[Action]): See [`Action`][vizro.models.Action]. Defaults to `[]`.", "type": "object", "properties": { "id": { @@ -774,7 +774,7 @@ }, "RadioItems": { "title": "RadioItems", - "description": "Categorical single-option selector `RadioItems`.\n\nCan be provided to [`Filter`][vizro.models.Filter] or\n[`Parameter`][vizro.models.Parameter]. Based on the underlying\n[`dcc.RadioItems`](https://dash.plotly.com/dash-core-components/radioitems).\n\nArgs:\n type (Literal[\"radio_items\"]): Defaults to `\"radio_items\"`.\n options (OptionsType): See [`OptionsType`][vizro.models.types.OptionsType]. Defaults to `[]`.\n value (Optional[SingleValueType]): See [`SingleValueType`][vizro.models.types.SingleValueType].\n Defaults to `None`.\n title (str): Title to be displayed. Defaults to `\"\"`.\n actions (List[Action]): See [`Action`][vizro.models.Action]. Defaults to `[]`.", + "description": "Categorical single-option selector `RadioItems`.\n\nCan be provided to [`Filter`][vizro.models.Filter] or\n[`Parameter`][vizro.models.Parameter]. Based on the underlying\n[`dcc.RadioItems`](https://dash.plotly.com/dash-core-components/radioitems).\n\nArgs:\n type (Literal[\"radio_items\"]): Defaults to `\"radio_items\"`.\n options (OptionsType): See [`OptionsType`][vizro.models.types.OptionsType]. Defaults to `[]`.\n value (Optional[SingleValueType]): See [`SingleValueType`][vizro.models.types.SingleValueType].\n Defaults to `None`.\n title (str): Title to be displayed. Defaults to `\"\"`.\n actions (list[Action]): See [`Action`][vizro.models.Action]. Defaults to `[]`.", "type": "object", "properties": { "id": { @@ -863,7 +863,7 @@ }, "RangeSlider": { "title": "RangeSlider", - "description": "Numeric multi-option selector `RangeSlider`.\n\nCan be provided to [`Filter`][vizro.models.Filter] or\n[`Parameter`][vizro.models.Parameter]. Based on the underlying\n[`dcc.RangeSlider`](https://dash.plotly.com/dash-core-components/rangeslider).\n\nArgs:\n type (Literal[\"range_slider\"]): Defaults to `\"range_slider\"`.\n min (Optional[float]): Start value for slider. Defaults to `None`.\n max (Optional[float]): End value for slider. Defaults to `None`.\n step (Optional[float]): Step-size for marks on slider. Defaults to `None`.\n marks (Optional[Dict[int, Union[str, dict]]]): Marks to be displayed on slider. Defaults to `{}`.\n value (Optional[List[float]]): Default start and end value for slider. Must be 2 items. Defaults to `None`.\n title (str): Title to be displayed. Defaults to `\"\"`.\n actions (List[Action]): See [`Action`][vizro.models.Action]. Defaults to `[]`.", + "description": "Numeric multi-option selector `RangeSlider`.\n\nCan be provided to [`Filter`][vizro.models.Filter] or\n[`Parameter`][vizro.models.Parameter]. Based on the underlying\n[`dcc.RangeSlider`](https://dash.plotly.com/dash-core-components/rangeslider).\n\nArgs:\n type (Literal[\"range_slider\"]): Defaults to `\"range_slider\"`.\n min (Optional[float]): Start value for slider. Defaults to `None`.\n max (Optional[float]): End value for slider. Defaults to `None`.\n step (Optional[float]): Step-size for marks on slider. Defaults to `None`.\n marks (Optional[dict[int, Union[str, dict]]]): Marks to be displayed on slider. Defaults to `{}`.\n value (Optional[list[float]]): Default start and end value for slider. Must be 2 items. Defaults to `None`.\n title (str): Title to be displayed. Defaults to `\"\"`.\n actions (list[Action]): See [`Action`][vizro.models.Action]. Defaults to `[]`.", "type": "object", "properties": { "id": { @@ -931,7 +931,7 @@ }, "Slider": { "title": "Slider", - "description": "Numeric single-option selector `Slider`.\n\nCan be provided to [`Filter`][vizro.models.Filter] or\n[`Parameter`][vizro.models.Parameter]. Based on the underlying\n[`dcc.Slider`](https://dash.plotly.com/dash-core-components/slider).\n\nArgs:\n type (Literal[\"range_slider\"]): Defaults to `\"range_slider\"`.\n min (Optional[float]): Start value for slider. Defaults to `None`.\n max (Optional[float]): End value for slider. Defaults to `None`.\n step (Optional[float]): Step-size for marks on slider. Defaults to `None`.\n marks (Optional[Dict[int, Union[str, dict]]]): Marks to be displayed on slider. Defaults to `{}`.\n value (Optional[float]): Default value for slider. Defaults to `None`.\n title (str): Title to be displayed. Defaults to `\"\"`.\n actions (List[Action]): See [`Action`][vizro.models.Action]. Defaults to `[]`.", + "description": "Numeric single-option selector `Slider`.\n\nCan be provided to [`Filter`][vizro.models.Filter] or\n[`Parameter`][vizro.models.Parameter]. Based on the underlying\n[`dcc.Slider`](https://dash.plotly.com/dash-core-components/slider).\n\nArgs:\n type (Literal[\"range_slider\"]): Defaults to `\"range_slider\"`.\n min (Optional[float]): Start value for slider. Defaults to `None`.\n max (Optional[float]): End value for slider. Defaults to `None`.\n step (Optional[float]): Step-size for marks on slider. Defaults to `None`.\n marks (Optional[dict[int, Union[str, dict]]]): Marks to be displayed on slider. Defaults to `{}`.\n value (Optional[float]): Default value for slider. Defaults to `None`.\n title (str): Title to be displayed. Defaults to `\"\"`.\n actions (list[Action]): See [`Action`][vizro.models.Action]. Defaults to `[]`.", "type": "object", "properties": { "id": { @@ -994,7 +994,7 @@ }, "Filter": { "title": "Filter", - "description": "Filter the data supplied to `targets` on the [`Page`][vizro.models.Page].\n\nExamples:\n >>> print(repr(Filter(column=\"species\")))\n\nArgs:\n type (Literal[\"filter\"]): Defaults to `\"filter\"`.\n column (str): Column of `DataFrame` to filter.\n targets (List[ModelID]): Target component to be affected by filter. If none are given then target all components\n on the page that use `column`.\n selector (SelectorType): See [SelectorType][vizro.models.types.SelectorType]. Defaults to `None`.", + "description": "Filter the data supplied to `targets` on the [`Page`][vizro.models.Page].\n\nExamples:\n >>> print(repr(Filter(column=\"species\")))\n\nArgs:\n type (Literal[\"filter\"]): Defaults to `\"filter\"`.\n column (str): Column of `DataFrame` to filter.\n targets (list[ModelID]): Target component to be affected by filter. If none are given then target all components\n on the page that use `column`.\n selector (SelectorType): See [SelectorType][vizro.models.types.SelectorType]. Defaults to `None`.", "type": "object", "properties": { "id": { @@ -1064,7 +1064,7 @@ }, "Parameter": { "title": "Parameter", - "description": "Alter the arguments supplied to any `targets` on the [`Page`][vizro.models.Page].\n\nExamples:\n >>> Parameter(targets=[\"scatter.x\"], selector=Slider(min=0, max=1, default=0.8, title=\"Bubble opacity\"))\n\nArgs:\n type (Literal[\"parameter\"]): Defaults to `\"parameter\"`.\n targets (List[str]): Targets in the form of `.`.\n selector (SelectorType): See [SelectorType][vizro.models.types.SelectorType]. Converts selector value\n `\"NONE\"` into `None` to allow optional parameters.", + "description": "Alter the arguments supplied to any `targets` on the [`Page`][vizro.models.Page].\n\nExamples:\n >>> Parameter(targets=[\"scatter.x\"], selector=Slider(min=0, max=1, default=0.8, title=\"Bubble opacity\"))\n\nArgs:\n type (Literal[\"parameter\"]): Defaults to `\"parameter\"`.\n targets (list[str]): Targets in the form of `.`.\n selector (SelectorType): See [SelectorType][vizro.models.types.SelectorType]. Converts selector value\n `\"NONE\"` into `None` to allow optional parameters.", "type": "object", "properties": { "id": { @@ -1167,7 +1167,7 @@ }, "Page": { "title": "Page", - "description": "A page in [`Dashboard`][vizro.models.Dashboard] with its own URL path and place in the `Navigation`.\n\nArgs:\n components (List[ComponentType]): See [ComponentType][vizro.models.types.ComponentType]. At least one component\n has to be provided.\n title (str): Title to be displayed.\n description (str): Description for meta tags.\n layout (Layout): Layout to place components in. Defaults to `None`.\n controls (List[ControlType]): See [ControlType][vizro.models.types.ControlType]. Defaults to `[]`.\n path (str): Path to navigate to page. Defaults to `\"\"`.", + "description": "A page in [`Dashboard`][vizro.models.Dashboard] with its own URL path and place in the `Navigation`.\n\nArgs:\n components (list[ComponentType]): See [ComponentType][vizro.models.types.ComponentType]. At least one component\n has to be provided.\n title (str): Title to be displayed.\n description (str): Description for meta tags.\n layout (Layout): Layout to place components in. Defaults to `None`.\n controls (list[ControlType]): See [ControlType][vizro.models.types.ControlType]. Defaults to `[]`.\n path (str): Path to navigate to page. Defaults to `\"\"`.", "type": "object", "properties": { "id": { @@ -1277,7 +1277,7 @@ }, "Accordion": { "title": "Accordion", - "description": "Accordion to be used as nav_selector in [`Navigation`][vizro.models.Navigation].\n\nArgs:\n type (Literal[\"accordion\"]): Defaults to `\"accordion\"`.\n pages (Dict[str, List[str]]): Mapping from name of a pages group to a list of page IDs. Defaults to `{}`.", + "description": "Accordion to be used as nav_selector in [`Navigation`][vizro.models.Navigation].\n\nArgs:\n type (Literal[\"accordion\"]): Defaults to `\"accordion\"`.\n pages (dict[str, list[str]]): Mapping from name of a pages group to a list of page IDs. Defaults to `{}`.", "type": "object", "properties": { "id": { @@ -1356,7 +1356,7 @@ }, "NavBar": { "title": "NavBar", - "description": "Navigation bar to be used as a nav_selector for `Navigation`.\n\nArgs:\n type (Literal[\"nav_bar\"]): Defaults to `\"nav_bar\"`.\n pages (Dict[str, List[str]]): Mapping from name of a pages group to a list of page IDs. Defaults to `{}`.\n items (List[NavLink]): See [`NavLink`][vizro.models.NavLink]. Defaults to `[]`.", + "description": "Navigation bar to be used as a nav_selector for `Navigation`.\n\nArgs:\n type (Literal[\"nav_bar\"]): Defaults to `\"nav_bar\"`.\n pages (dict[str, list[str]]): Mapping from name of a pages group to a list of page IDs. Defaults to `{}`.\n items (list[NavLink]): See [`NavLink`][vizro.models.NavLink]. Defaults to `[]`.", "type": "object", "properties": { "id": { diff --git a/vizro-core/snyk/requirements.txt b/vizro-core/snyk/requirements.txt deleted file mode 100644 index c8d336618..000000000 --- a/vizro-core/snyk/requirements.txt +++ /dev/null @@ -1,17 +0,0 @@ -dash>=2.17.1 -dash_bootstrap_components -dash-ag-grid>=31.0.0 -pandas -pydantic>=1.10.13 -dash_mantine_components<0.13.0 -flask_caching>=2 -wrapt>=1 -numpy>=1.22.2 -setuptools>=65.5.1 -werkzeug>=3.0.1 -ruff -kedro>=0.17.3 -kedro-datasets -wheel>=0.38.0 -ipython>=8.10.0 -tornado>=6.3.2 diff --git a/vizro-core/src/vizro/_vizro.py b/vizro-core/src/vizro/_vizro.py index d2dc07bc6..3350cf182 100644 --- a/vizro-core/src/vizro/_vizro.py +++ b/vizro-core/src/vizro/_vizro.py @@ -2,9 +2,10 @@ import logging import warnings +from collections.abc import Iterable from contextlib import suppress from pathlib import Path -from typing import TYPE_CHECKING, Iterable, TypedDict +from typing import TYPE_CHECKING, TypedDict import dash import plotly.io as pio diff --git a/vizro-core/src/vizro/actions/__init__.py b/vizro-core/src/vizro/actions/__init__.py index 39224154f..6ea11830d 100644 --- a/vizro-core/src/vizro/actions/__init__.py +++ b/vizro-core/src/vizro/actions/__init__.py @@ -4,5 +4,4 @@ from vizro.actions.export_data_action import export_data from vizro.actions.filter_interaction_action import filter_interaction -# Please keep alphabetically ordered __all__ = ["export_data", "filter_interaction"] diff --git a/vizro-core/src/vizro/actions/_action_loop/_action_loop.py b/vizro-core/src/vizro/actions/_action_loop/_action_loop.py index 88e2f92a6..d9caac0ff 100644 --- a/vizro-core/src/vizro/actions/_action_loop/_action_loop.py +++ b/vizro-core/src/vizro/actions/_action_loop/_action_loop.py @@ -23,7 +23,7 @@ def _build_action_loop(): """Builds callbacks for the action loop and returns required components for the action loop mechanism to work. Returns: - List of required components for the action loop e.g. List[dcc.Store, html.Div]. + List of required components for the action loop e.g. list[dcc.Store, html.Div]. """ _build_action_loop_callbacks() @@ -34,7 +34,7 @@ def _build_actions_models(): """Builds a callback for each `Action` model and returns required components for these callbacks. Returns: - List of required components for each `Action` in the `Dashboard` e.g. List[dcc.Download] + List of required components for each `Action` in the `Dashboard` e.g. list[dcc.Download] """ actions = _get_actions_on_registered_pages() diff --git a/vizro-core/src/vizro/actions/_action_loop/_action_loop_utils.py b/vizro-core/src/vizro/actions/_action_loop/_action_loop_utils.py index 3617e62e4..d640f24bb 100644 --- a/vizro-core/src/vizro/actions/_action_loop/_action_loop_utils.py +++ b/vizro-core/src/vizro/actions/_action_loop/_action_loop_utils.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import TYPE_CHECKING, List +from typing import TYPE_CHECKING import dash @@ -14,9 +14,9 @@ from vizro.models._action._actions_chain import ActionsChain -def _get_actions_chains_on_all_pages() -> List[ActionsChain]: +def _get_actions_chains_on_all_pages() -> list[ActionsChain]: """Gets list of ActionsChain models for registered pages.""" - actions_chains: List[ActionsChain] = [] + actions_chains: list[ActionsChain] = [] # TODO: once dash.page_registry matches up with model_manager, change this to use purely model_manager. # Making the change now leads to problems since there can be Action models defined that aren't used in the # dashboard. @@ -30,6 +30,6 @@ def _get_actions_chains_on_all_pages() -> List[ActionsChain]: return actions_chains -def _get_actions_on_registered_pages() -> List[Action]: +def _get_actions_on_registered_pages() -> list[Action]: """Gets list of Action models for registered pages.""" return [action for action_chain in _get_actions_chains_on_all_pages() for action in action_chain.actions] diff --git a/vizro-core/src/vizro/actions/_action_loop/_build_action_loop_callbacks.py b/vizro-core/src/vizro/actions/_action_loop/_build_action_loop_callbacks.py index 64c128d80..bc76a146d 100644 --- a/vizro-core/src/vizro/actions/_action_loop/_build_action_loop_callbacks.py +++ b/vizro-core/src/vizro/actions/_action_loop/_build_action_loop_callbacks.py @@ -1,7 +1,6 @@ """Contains utilities to create required dash callbacks for the action loop.""" import logging -from typing import List from dash import ClientsideFunction, Input, Output, State, clientside_callback @@ -23,7 +22,7 @@ def _build_action_loop_callbacks() -> None: if not actions_chains: return - gateway_inputs: List[Input] = [] + gateway_inputs: list[Input] = [] for actions_chain in actions_chains: # Recalculating the trigger component id to use the underlying callable object as a trigger component if needed. actions_chain_trigger_component_id = actions_chain.trigger.component_id diff --git a/vizro-core/src/vizro/actions/_actions_utils.py b/vizro-core/src/vizro/actions/_actions_utils.py index e7a532f99..a4d6a78c0 100644 --- a/vizro-core/src/vizro/actions/_actions_utils.py +++ b/vizro-core/src/vizro/actions/_actions_utils.py @@ -4,7 +4,7 @@ from collections import defaultdict from copy import deepcopy -from typing import TYPE_CHECKING, Any, Dict, List, Literal, Optional, TypedDict, Union +from typing import TYPE_CHECKING, Any, Literal, Optional, TypedDict, Union import pandas as pd @@ -16,7 +16,7 @@ if TYPE_CHECKING: from vizro.models import Action, VizroBaseModel -ValidatedNoneValueType = Union[SingleValueType, MultiValueType, None, List[None]] +ValidatedNoneValueType = Union[SingleValueType, MultiValueType, None, list[None]] class CallbackTriggerDict(TypedDict): @@ -39,7 +39,7 @@ class CallbackTriggerDict(TypedDict): # Utility functions for helper functions used in pre-defined actions ---- -def _get_component_actions(component) -> List[Action]: +def _get_component_actions(component) -> list[Action]: return ( [action for actions_chain in component.actions for action in actions_chain.actions] if hasattr(component, "actions") @@ -47,7 +47,7 @@ def _get_component_actions(component) -> List[Action]: ) -def _apply_filters(data_frame: pd.DataFrame, ctds_filters: List[CallbackTriggerDict], target: str) -> pd.DataFrame: +def _apply_filters(data_frame: pd.DataFrame, ctds_filters: list[CallbackTriggerDict], target: str) -> pd.DataFrame: for ctd in ctds_filters: selector_value = ctd["value"] selector_value = selector_value if isinstance(selector_value, list) else [selector_value] @@ -84,7 +84,7 @@ def _get_parent_vizro_model(_underlying_callable_object_id: str) -> VizroBaseMod def _apply_filter_interaction( - data_frame: pd.DataFrame, ctds_filter_interaction: List[Dict[str, CallbackTriggerDict]], target: str + data_frame: pd.DataFrame, ctds_filter_interaction: list[dict[str, CallbackTriggerDict]], target: str ) -> pd.DataFrame: for ctd_filter_interaction in ctds_filter_interaction: triggered_model = model_manager[ctd_filter_interaction["modelID"]["id"]] @@ -105,7 +105,7 @@ def _validate_selector_value_none(value: Union[SingleValueType, MultiValueType]) return value -def _create_target_arg_mapping(dot_separated_strings: List[str]) -> Dict[str, List[str]]: +def _create_target_arg_mapping(dot_separated_strings: list[str]) -> dict[str, list[str]]: results = defaultdict(list) for string in dot_separated_strings: if "." not in string: @@ -116,8 +116,8 @@ def _create_target_arg_mapping(dot_separated_strings: List[str]) -> Dict[str, Li def _update_nested_graph_properties( - graph_config: Dict[str, Any], dot_separated_string: str, value: Any -) -> Dict[str, Any]: + graph_config: dict[str, Any], dot_separated_string: str, value: Any +) -> dict[str, Any]: keys = dot_separated_string.split(".") current_property = graph_config @@ -128,7 +128,7 @@ def _update_nested_graph_properties( return graph_config -def _get_parametrized_config(target: ModelID, ctd_parameters: List[CallbackTriggerDict]) -> Dict[str, Any]: +def _get_parametrized_config(target: ModelID, ctd_parameters: list[CallbackTriggerDict]) -> dict[str, Any]: # TODO - avoid calling _captured_callable. Once we have done this we can remove _arguments from # CapturedCallable entirely. config = deepcopy(model_manager[target].figure._arguments) @@ -144,8 +144,8 @@ def _get_parametrized_config(target: ModelID, ctd_parameters: List[CallbackTrigg if hasattr(selector_value, "__iter__") and ALL_OPTION in selector_value: # type: ignore[operator] selector: SelectorType = model_manager[ctd["id"]] - # Even if options are provided as List[Dict], the Dash component only returns a List of values. - # So we need to ensure that we always return a List only as well to provide consistent types. + # Even if options are provided as list[dict], the Dash component only returns a list of values. + # So we need to ensure that we always return a list only as well to provide consistent types. if all(isinstance(option, dict) for option in selector.options): selector_value = [option["value"] for option in selector.options] else: @@ -173,10 +173,10 @@ def _get_parametrized_config(target: ModelID, ctd_parameters: List[CallbackTrigg # Helper functions used in pre-defined actions ---- def _get_targets_data_and_config( - ctds_filter: List[CallbackTriggerDict], - ctds_filter_interaction: List[Dict[str, CallbackTriggerDict]], - ctds_parameters: List[CallbackTriggerDict], - targets: List[ModelID], + ctds_filter: list[CallbackTriggerDict], + ctds_filter_interaction: list[dict[str, CallbackTriggerDict]], + ctds_parameters: list[CallbackTriggerDict], + targets: list[ModelID], ): all_filtered_data = {} all_parameterized_config = {} @@ -203,11 +203,11 @@ def _get_targets_data_and_config( def _get_modified_page_figures( - ctds_filter: List[CallbackTriggerDict], - ctds_filter_interaction: List[Dict[str, CallbackTriggerDict]], - ctds_parameters: List[CallbackTriggerDict], - targets: Optional[List[ModelID]] = None, -) -> Dict[str, Any]: + ctds_filter: list[CallbackTriggerDict], + ctds_filter_interaction: list[dict[str, CallbackTriggerDict]], + ctds_parameters: list[CallbackTriggerDict], + targets: Optional[list[ModelID]] = None, +) -> dict[str, Any]: targets = targets or [] filtered_data, parameterized_config = _get_targets_data_and_config( @@ -217,7 +217,7 @@ def _get_modified_page_figures( targets=targets, ) - outputs: Dict[str, Any] = {} + outputs: dict[str, Any] = {} for target in targets: outputs[target] = model_manager[target](data_frame=filtered_data[target], **parameterized_config[target]) diff --git a/vizro-core/src/vizro/actions/_callback_mapping/_callback_mapping_utils.py b/vizro-core/src/vizro/actions/_callback_mapping/_callback_mapping_utils.py index 214f04589..4bf82991c 100644 --- a/vizro-core/src/vizro/actions/_callback_mapping/_callback_mapping_utils.py +++ b/vizro-core/src/vizro/actions/_callback_mapping/_callback_mapping_utils.py @@ -1,6 +1,6 @@ """Contains utilities to create the action_callback_mapping.""" -from typing import Any, Callable, Dict, List, Union +from typing import Any, Callable, Union from dash import Output, State, dcc @@ -16,8 +16,8 @@ # Potentially this could be a way to reconcile predefined with custom actions, # and make that predefined actions see and add into account custom actions. def _get_matching_actions_by_function( - page_id: ModelID, action_function: Callable[[Any], Dict[str, Any]] -) -> List[Action]: + page_id: ModelID, action_function: Callable[[Any], dict[str, Any]] +) -> list[Action]: """Gets list of `Actions` on triggered `Page` that match the provided `action_function`.""" return [ action @@ -28,7 +28,7 @@ def _get_matching_actions_by_function( # CALLBACK STATES -------------- -def _get_inputs_of_controls(page: Page, control_type: ControlType) -> List[State]: +def _get_inputs_of_controls(page: Page, control_type: ControlType) -> list[State]: """Gets list of `States` for selected `control_type` of triggered `Page`.""" return [ State(component_id=control.selector.id, component_property=control.selector._input_property) @@ -38,8 +38,8 @@ def _get_inputs_of_controls(page: Page, control_type: ControlType) -> List[State def _get_inputs_of_figure_interactions( - page: Page, action_function: Callable[[Any], Dict[str, Any]] -) -> List[Dict[str, State]]: + page: Page, action_function: Callable[[Any], dict[str, Any]] +) -> list[dict[str, State]]: """Gets list of `States` for selected chart interaction `action_function` of triggered `Page`.""" figure_interactions_on_page = _get_matching_actions_by_function( page_id=ModelID(str(page.id)), action_function=action_function @@ -60,14 +60,14 @@ def _get_inputs_of_figure_interactions( # TODO: Refactor this and util functions once we implement "_get_input_property" method in VizroBaseModel models -def _get_action_callback_inputs(action_id: ModelID) -> Dict[str, List[Union[State, Dict[str, State]]]]: +def _get_action_callback_inputs(action_id: ModelID) -> dict[str, list[Union[State, dict[str, State]]]]: """Creates mapping of pre-defined action names and a list of `States`.""" page: Page = model_manager[model_manager._get_model_page_id(model_id=action_id)] action_input_mapping = { "filters": _get_inputs_of_controls(page=page, control_type=Filter), "parameters": _get_inputs_of_controls(page=page, control_type=Parameter), - # TODO: Probably need to adjust other inputs to follow the same structure List[Dict[str, State]] + # TODO: Probably need to adjust other inputs to follow the same structure list[dict[str, State]] "filter_interaction": _get_inputs_of_figure_interactions( page=page, action_function=filter_interaction.__wrapped__ ), @@ -76,7 +76,7 @@ def _get_action_callback_inputs(action_id: ModelID) -> Dict[str, List[Union[Stat # CALLBACK OUTPUTS -------------- -def _get_action_callback_outputs(action_id: ModelID) -> Dict[str, Output]: +def _get_action_callback_outputs(action_id: ModelID) -> dict[str, Output]: """Creates mapping of target names and their `Output`.""" action_function = model_manager[action_id].function._function @@ -103,7 +103,7 @@ def _get_action_callback_outputs(action_id: ModelID) -> Dict[str, Output]: } -def _get_export_data_callback_outputs(action_id: ModelID) -> Dict[str, Output]: +def _get_export_data_callback_outputs(action_id: ModelID) -> dict[str, Output]: """Gets mapping of relevant output target name and `Outputs` for `export_data` action.""" action = model_manager[action_id] @@ -127,7 +127,7 @@ def _get_export_data_callback_outputs(action_id: ModelID) -> Dict[str, Output]: # CALLBACK COMPONENTS -------------- -def _get_export_data_callback_components(action_id: ModelID) -> List[dcc.Download]: +def _get_export_data_callback_components(action_id: ModelID) -> list[dcc.Download]: """Creates dcc.Downloads for target components of the `export_data` action.""" action = model_manager[action_id] diff --git a/vizro-core/src/vizro/actions/_callback_mapping/_get_action_callback_mapping.py b/vizro-core/src/vizro/actions/_callback_mapping/_get_action_callback_mapping.py index a147ec35d..10841e18b 100644 --- a/vizro-core/src/vizro/actions/_callback_mapping/_get_action_callback_mapping.py +++ b/vizro-core/src/vizro/actions/_callback_mapping/_get_action_callback_mapping.py @@ -1,6 +1,6 @@ """Creates action_callback_mapping to map callback arguments to action functions.""" -from typing import Any, Dict, List, Union +from typing import Any, Union from dash import dcc from dash.dependencies import DashDependency @@ -21,11 +21,11 @@ def _get_action_callback_mapping( action_id: ModelID, argument: str -) -> Union[List[dcc.Download], Dict[str, DashDependency]]: +) -> Union[list[dcc.Download], dict[str, DashDependency]]: """Creates mapping of action name and required callback input/output.""" action_function = model_manager[action_id].function._function - action_callback_mapping: Dict[str, Any] = { + action_callback_mapping: dict[str, Any] = { export_data.__wrapped__: { "inputs": _get_action_callback_inputs, "components": _get_export_data_callback_components, @@ -49,5 +49,5 @@ def _get_action_callback_mapping( }, } action_call = action_callback_mapping.get(action_function, {}).get(argument) - default_value: Union[List[dcc.Download], Dict[str, DashDependency]] = [] if argument == "components" else {} + default_value: Union[list[dcc.Download], dict[str, DashDependency]] = [] if argument == "components" else {} return default_value if not action_call else action_call(action_id=action_id) diff --git a/vizro-core/src/vizro/actions/_filter_action.py b/vizro-core/src/vizro/actions/_filter_action.py index 93c36870d..409428e01 100644 --- a/vizro-core/src/vizro/actions/_filter_action.py +++ b/vizro-core/src/vizro/actions/_filter_action.py @@ -1,6 +1,6 @@ """Pre-defined action function "_filter" to be reused in `action` parameter of VizroBaseModels.""" -from typing import Any, Callable, Dict, List +from typing import Any, Callable import pandas as pd from dash import ctx @@ -13,10 +13,10 @@ @capture("action") def _filter( filter_column: str, - targets: List[ModelID], + targets: list[ModelID], filter_function: Callable[[pd.Series, Any], pd.Series], - **inputs: Dict[str, Any], -) -> Dict[str, Any]: + **inputs: dict[str, Any], +) -> dict[str, Any]: """Filters targeted charts/components on page by interaction with `Filter` control. Args: diff --git a/vizro-core/src/vizro/actions/_on_page_load_action.py b/vizro-core/src/vizro/actions/_on_page_load_action.py index 151fa77c0..5b2d97cdb 100644 --- a/vizro-core/src/vizro/actions/_on_page_load_action.py +++ b/vizro-core/src/vizro/actions/_on_page_load_action.py @@ -1,6 +1,6 @@ """Pre-defined action function "_on_page_load" to be reused in `action` parameter of VizroBaseModels.""" -from typing import Any, Dict, List +from typing import Any from dash import ctx @@ -10,7 +10,7 @@ @capture("action") -def _on_page_load(targets: List[ModelID], **inputs: Dict[str, Any]) -> Dict[str, Any]: +def _on_page_load(targets: list[ModelID], **inputs: dict[str, Any]) -> dict[str, Any]: """Applies controls to charts on page once the page is opened (or refreshed). Args: diff --git a/vizro-core/src/vizro/actions/_parameter_action.py b/vizro-core/src/vizro/actions/_parameter_action.py index e996dec91..e96b136fb 100644 --- a/vizro-core/src/vizro/actions/_parameter_action.py +++ b/vizro-core/src/vizro/actions/_parameter_action.py @@ -1,6 +1,6 @@ """Pre-defined action function "_parameter" to be reused in `action` parameter of VizroBaseModels.""" -from typing import Any, Dict, List +from typing import Any from dash import ctx @@ -10,7 +10,7 @@ @capture("action") -def _parameter(targets: List[str], **inputs: Dict[str, Any]) -> Dict[str, Any]: +def _parameter(targets: list[str], **inputs: dict[str, Any]) -> dict[str, Any]: """Modifies parameters of targeted charts/components on page. Args: @@ -22,7 +22,7 @@ def _parameter(targets: List[str], **inputs: Dict[str, Any]) -> Dict[str, Any]: Dict mapping target component ids to modified charts/components e.g. {'my_scatter': Figure({})} """ - target_ids: List[ModelID] = [target.split(".")[0] for target in targets] # type: ignore[misc] + target_ids: list[ModelID] = [target.split(".")[0] for target in targets] # type: ignore[misc] return _get_modified_page_figures( targets=target_ids, diff --git a/vizro-core/src/vizro/actions/export_data_action.py b/vizro-core/src/vizro/actions/export_data_action.py index 5bd6b6ef1..fb87f419e 100644 --- a/vizro-core/src/vizro/actions/export_data_action.py +++ b/vizro-core/src/vizro/actions/export_data_action.py @@ -1,6 +1,6 @@ """Pre-defined action function "export_data" to be reused in `action` parameter of VizroBaseModels.""" -from typing import Any, Dict, List, Optional +from typing import Any, Optional from dash import ctx, dcc from typing_extensions import Literal @@ -13,8 +13,8 @@ @capture("action") def export_data( - targets: Optional[List[ModelID]] = None, file_format: Literal["csv", "xlsx"] = "csv", **inputs: Dict[str, Any] -) -> Dict[str, Any]: + targets: Optional[list[ModelID]] = None, file_format: Literal["csv", "xlsx"] = "csv", **inputs: dict[str, Any] +) -> dict[str, Any]: """Exports visible data of target charts/components on page after being triggered. Args: diff --git a/vizro-core/src/vizro/actions/filter_interaction_action.py b/vizro-core/src/vizro/actions/filter_interaction_action.py index a78b30aeb..1f40f3171 100644 --- a/vizro-core/src/vizro/actions/filter_interaction_action.py +++ b/vizro-core/src/vizro/actions/filter_interaction_action.py @@ -1,6 +1,6 @@ """Pre-defined action function "filter_interaction" to be reused in `action` parameter of VizroBaseModels.""" -from typing import Any, Dict, List, Optional +from typing import Any, Optional from dash import ctx @@ -10,7 +10,7 @@ @capture("action") -def filter_interaction(targets: Optional[List[ModelID]] = None, **inputs: Dict[str, Any]) -> Dict[str, Any]: +def filter_interaction(targets: Optional[list[ModelID]] = None, **inputs: dict[str, Any]) -> dict[str, Any]: """Filters targeted charts/components on page by clicking on data points or table cells of the source chart. To set up filtering on specific columns of the target graph(s), include these columns in the 'custom_data' diff --git a/vizro-core/src/vizro/figures/__init__.py b/vizro-core/src/vizro/figures/__init__.py index 89406f312..17fba6c55 100644 --- a/vizro-core/src/vizro/figures/__init__.py +++ b/vizro-core/src/vizro/figures/__init__.py @@ -1,4 +1,3 @@ from vizro.figures._kpi_cards import kpi_card, kpi_card_reference -# Please keep alphabetically ordered __all__ = ["kpi_card", "kpi_card_reference"] diff --git a/vizro-core/src/vizro/figures/_kpi_cards.py b/vizro-core/src/vizro/figures/_kpi_cards.py index f71702a30..a635369f6 100644 --- a/vizro-core/src/vizro/figures/_kpi_cards.py +++ b/vizro-core/src/vizro/figures/_kpi_cards.py @@ -49,10 +49,6 @@ def kpi_card( icon: Name of the icon from the [Google Material Icon Library](https://fonts.google.com/icons) to be displayed on the left side of the KPI title. If not provided, no icon is displayed. - Raises: - UserWarning: If `value_format` is provided, a warning is raised to make aware that only trusted user - input should be provided. - Returns: A Dash Bootstrap Components card (`dbc.Card`) containing the formatted KPI value. @@ -123,10 +119,6 @@ def kpi_card_reference( # noqa: PLR0913 icon: Name of the icon from the [Google Material Icon Library](https://fonts.google.com/icons) to be displayed on the left side of the KPI title. If not provided, no icon is displayed. - Raises: - UserWarning: If `value_format` or `reference_format` is provided, a warning is raised to make aware - that only trusted user input should be provided. - Returns: A Dash Bootstrap Components card (`dbc.Card`) containing the formatted KPI value and reference. diff --git a/vizro-core/src/vizro/integrations/kedro/_data_manager.py b/vizro-core/src/vizro/integrations/kedro/_data_manager.py index aec2b8f18..28c565a6c 100644 --- a/vizro-core/src/vizro/integrations/kedro/_data_manager.py +++ b/vizro-core/src/vizro/integrations/kedro/_data_manager.py @@ -1,5 +1,5 @@ from pathlib import Path -from typing import Any, Dict, Optional, Union +from typing import Any, Optional, Union from kedro.framework.session import KedroSession from kedro.framework.startup import bootstrap_project @@ -9,7 +9,7 @@ def catalog_from_project( - project_path: Union[str, Path], env: Optional[str] = None, extra_params: Optional[Dict[str, Any]] = None + project_path: Union[str, Path], env: Optional[str] = None, extra_params: Optional[dict[str, Any]] = None ) -> DataCatalog: bootstrap_project(project_path) with KedroSession.create( @@ -18,7 +18,7 @@ def catalog_from_project( return session.load_context().catalog -def datasets_from_catalog(catalog: DataCatalog) -> Dict[str, pd_DataFrameCallable]: +def datasets_from_catalog(catalog: DataCatalog) -> dict[str, pd_DataFrameCallable]: datasets = {} for name in catalog.list(): dataset = catalog._get_dataset(name, suggest=False) diff --git a/vizro-core/src/vizro/managers/_data_manager.py b/vizro-core/src/vizro/managers/_data_manager.py index 66e0346cb..44e7972db 100644 --- a/vizro-core/src/vizro/managers/_data_manager.py +++ b/vizro-core/src/vizro/managers/_data_manager.py @@ -7,7 +7,7 @@ import os import warnings from functools import partial -from typing import Callable, Dict, Optional, Union +from typing import Callable, Optional, Union import pandas as pd import wrapt @@ -138,7 +138,7 @@ class DataManager: """ def __init__(self): - self.__data: Dict[DataSourceName, Union[_DynamicData, _StaticData]] = {} + self.__data: dict[DataSourceName, Union[_DynamicData, _StaticData]] = {} self._frozen_state = False self.cache = Cache(config={"CACHE_TYPE": "NullCache"}) # In future, possibly we will accept just a config dict. Would need to work out whether to handle merging with diff --git a/vizro-core/src/vizro/managers/_model_manager.py b/vizro-core/src/vizro/managers/_model_manager.py index 22dced235..14081681a 100644 --- a/vizro-core/src/vizro/managers/_model_manager.py +++ b/vizro-core/src/vizro/managers/_model_manager.py @@ -4,7 +4,8 @@ import random import uuid -from typing import TYPE_CHECKING, Dict, Generator, List, NewType, Optional, Tuple, Type, TypeVar, cast +from collections.abc import Generator +from typing import TYPE_CHECKING, NewType, Optional, TypeVar, cast from vizro.managers._managers_utils import _state_modifier @@ -26,7 +27,7 @@ class DuplicateIDError(ValueError): class ModelManager: def __init__(self): - self.__models: Dict[ModelID, VizroBaseModel] = {} + self.__models: dict[ModelID, VizroBaseModel] = {} self._frozen_state = False # TODO: Consider storing "page_id" or "parent_model_id" and make searching helper methods easier? @@ -52,15 +53,15 @@ def __iter__(self) -> Generator[ModelID, None, None]: yield from self.__models # TODO: Consider adding an option to iterate only through specific page - "in_page_with_id=None" - def _items_with_type(self, model_type: Type[Model]) -> Generator[Tuple[ModelID, Model], None, None]: + def _items_with_type(self, model_type: type[Model]) -> Generator[tuple[ModelID, Model], None, None]: """Iterates through all models of type `model_type` (including subclasses).""" for model_id in self: if isinstance(self[model_id], model_type): yield model_id, cast(Model, self[model_id]) # TODO: Consider returning with yield - # TODO: Make collection of model ids (throughout this file) to be Set[ModelID]. - def _get_model_children(self, model_id: ModelID, all_model_ids: Optional[List[ModelID]] = None) -> List[ModelID]: + # TODO: Make collection of model ids (throughout this file) to be set[ModelID]. + def _get_model_children(self, model_id: ModelID, all_model_ids: Optional[list[ModelID]] = None) -> list[ModelID]: if all_model_ids is None: all_model_ids = [] @@ -85,7 +86,7 @@ def _get_model_page_id(self, model_id: ModelID) -> ModelID: # type: ignore[retu for actions_chain in self._get_page_actions_chains(page_id=page_id): page_model_ids.append(actions_chain.id) for action in actions_chain.actions: - page_model_ids.append(action.id) + page_model_ids.append(action.id) # noqa: PERF401 for control in page.controls: page_model_ids.append(control.id) @@ -98,7 +99,7 @@ def _get_model_page_id(self, model_id: ModelID) -> ModelID: # type: ignore[retu return cast(ModelID, page.id) # TODO: Increase the genericity of this method - def _get_page_actions_chains(self, page_id: ModelID) -> List[ActionsChain]: + def _get_page_actions_chains(self, page_id: ModelID) -> list[ActionsChain]: """Gets all ActionsChains present on the page.""" page = self[page_id] page_actions_chains = [] @@ -125,7 +126,7 @@ def _get_action_trigger(self, action_id: ModelID) -> VizroBaseModel: # type: ig if action_id in [action.id for action in actions_chain.actions]: return self[ModelID(str(actions_chain.trigger.component_id))] - def _get_page_model_ids_with_figure(self, page_id: ModelID) -> List[ModelID]: + def _get_page_model_ids_with_figure(self, page_id: ModelID) -> list[ModelID]: """Gets ids of all components from the page that have a 'figure' registered.""" return [ model_id diff --git a/vizro-core/src/vizro/models/__init__.py b/vizro-core/src/vizro/models/__init__.py index d8216d482..c19ff4515 100644 --- a/vizro-core/src/vizro/models/__init__.py +++ b/vizro-core/src/vizro/models/__init__.py @@ -34,15 +34,15 @@ Dashboard.update_forward_refs(Page=Page, Navigation=Navigation) NavBar.update_forward_refs(NavLink=NavLink) NavLink.update_forward_refs(Accordion=Accordion) -# Please keep alphabetically ordered + __all__ = [ "Accordion", "Action", "AgGrid", "Button", "Card", - "Container", "Checklist", + "Container", "Dashboard", "DatePicker", "Dropdown", diff --git a/vizro-core/src/vizro/models/_action/_action.py b/vizro-core/src/vizro/models/_action/_action.py index c2fee2a58..9aac00ca1 100644 --- a/vizro-core/src/vizro/models/_action/_action.py +++ b/vizro-core/src/vizro/models/_action/_action.py @@ -2,7 +2,7 @@ import logging from collections.abc import Collection, Mapping from pprint import pformat -from typing import Any, Dict, List, Union +from typing import Any, Union from dash import Input, Output, State, callback, html @@ -24,20 +24,20 @@ class Action(VizroBaseModel): Args: function (CapturedCallable): Action function. See [`vizro.actions`][vizro.actions]. - inputs (List[str]): Inputs in the form `.` passed to the action function. + inputs (list[str]): Inputs in the form `.` passed to the action function. Defaults to `[]`. - outputs (List[str]): Outputs in the form `.` changed by the action function. + outputs (list[str]): Outputs in the form `.` changed by the action function. Defaults to `[]`. """ function: CapturedCallable = Field(..., import_path="vizro.actions", mode="action", description="Action function.") - inputs: List[str] = Field( + inputs: list[str] = Field( [], description="Inputs in the form `.` passed to the action function.", regex="^[^.]+[.][^.]+$", ) - outputs: List[str] = Field( + outputs: list[str] = Field( [], description="Outputs in the form `.` changed by the action function.", regex="^[^.]+[.][^.]+$", @@ -75,13 +75,13 @@ def _get_callback_mapping(self): """ from vizro.actions._callback_mapping._get_action_callback_mapping import _get_action_callback_mapping - callback_inputs: Union[List[State], Dict[str, State]] + callback_inputs: Union[list[State], dict[str, State]] if self.inputs: callback_inputs = [State(*input.split(".")) for input in self.inputs] else: callback_inputs = _get_action_callback_mapping(action_id=ModelID(str(self.id)), argument="inputs") - callback_outputs: Union[List[Output], Dict[str, Output]] + callback_outputs: Union[list[Output], dict[str, Output]] if self.outputs: callback_outputs = [Output(*output.split("."), allow_duplicate=True) for output in self.outputs] @@ -99,8 +99,8 @@ def _get_callback_mapping(self): def _action_callback_function( self, - inputs: Union[Dict[str, Any], List[Any]], - outputs: Union[Dict[str, Output], List[Output], Output, None], + inputs: Union[dict[str, Any], list[Any]], + outputs: Union[dict[str, Output], list[Output], Output, None], ) -> Any: logger.debug("===== Running action with id %s, function %s =====", self.id, self.function._function.__name__) if logger.isEnabledFor(logging.DEBUG): @@ -178,7 +178,7 @@ def build(self) -> html.Div: logger.debug("Callback outputs:\n%s", pformat(callback_outputs.get("external"), width=200)) @callback(output=callback_outputs, inputs=callback_inputs, prevent_initial_call=True) - def callback_wrapper(external: Union[List[Any], Dict[str, Any]], internal: Dict[str, Any]) -> Dict[str, Any]: + def callback_wrapper(external: Union[list[Any], dict[str, Any]], internal: dict[str, Any]) -> dict[str, Any]: return_value = self._action_callback_function(inputs=external, outputs=callback_outputs.get("external")) if "external" in callback_outputs: return {"internal": {"action_finished": None}, "external": return_value} diff --git a/vizro-core/src/vizro/models/_action/_actions_chain.py b/vizro-core/src/vizro/models/_action/_actions_chain.py index 2d710cbfb..31049929c 100644 --- a/vizro-core/src/vizro/models/_action/_actions_chain.py +++ b/vizro-core/src/vizro/models/_action/_actions_chain.py @@ -1,5 +1,5 @@ from functools import partial -from typing import Any, Dict, List, NamedTuple +from typing import Any, NamedTuple try: from pydantic.v1 import validator @@ -16,11 +16,11 @@ class Trigger(NamedTuple): class ActionsChain(VizroBaseModel): trigger: Trigger - actions: List[Action] = [] + actions: list[Action] = [] # Validators for reuse in other models to convert to ActionsChain -def _set_actions(actions: List[Action], values: Dict[str, Any], trigger_property: str) -> List[ActionsChain]: +def _set_actions(actions: list[Action], values: dict[str, Any], trigger_property: str) -> list[ActionsChain]: return [ ActionsChain( trigger=Trigger(component_id=values["id"], component_property=trigger_property), diff --git a/vizro-core/src/vizro/models/_base.py b/vizro-core/src/vizro/models/_base.py index e07d61ab9..40b00deb6 100644 --- a/vizro-core/src/vizro/models/_base.py +++ b/vizro-core/src/vizro/models/_base.py @@ -1,5 +1,6 @@ +from collections.abc import Mapping from contextlib import contextmanager -from typing import Any, List, Mapping, Optional, Set, Type, Union +from typing import Annotated, Any, Optional, Union try: from pydantic.v1 import BaseModel, Field, validator @@ -17,7 +18,6 @@ import autoflake import black -from typing_extensions import Annotated from vizro.managers import model_manager from vizro.models._models_utils import REPLACEMENT_STRINGS, _log_call @@ -104,7 +104,7 @@ def _dict_to_python(object: Any) -> str: fields = ", ".join(f"'{field_name}': {_dict_to_python(value)}" for field_name, value in object.items()) return "{" + fields + "}" elif isinstance(object, list): - # Need to do this manually to avoid extra quotation marks that arise when doing repr(List). + # Need to do this manually to avoid extra quotation marks that arise when doing repr(list). code_string = ", ".join(_dict_to_python(item) for item in object) return f"[{code_string}]" elif isinstance(object, CapturedCallable): @@ -117,7 +117,7 @@ def _dict_to_python(object: Any) -> str: # are created. An alternative approach to iterating through the model_manager is to recurse through the object as # is done in the _dict_to_python function. # Note also that these functions find also unintended model_manager additions, a known but accepted limitation. -def _extract_captured_callable_source() -> Set[str]: +def _extract_captured_callable_source() -> set[str]: from vizro.models.types import CapturedCallable captured_callable_sources = set() @@ -140,7 +140,7 @@ def _extract_captured_callable_source() -> Set[str]: return captured_callable_sources -def _extract_captured_callable_data_info() -> Set[str]: +def _extract_captured_callable_data_info() -> set[str]: from vizro.models.types import CapturedCallable return { @@ -180,7 +180,7 @@ def __init__(self, **data: Any): model_manager[self.id] = self @classmethod - def add_type(cls, field_name: str, new_type: Type[Any]): + def add_type(cls, field_name: str, new_type: type[Any]): """Adds a new type to an existing field based on a discriminated union. Args: @@ -209,8 +209,8 @@ def _is_discriminated_union(field): # Field itself is a non-optional discriminated union, e.g. selector: SelectorType or Optional[SelectorType]. new_annotation = _add_to_discriminated_union(field.outer_type_) elif sub_field is not None and _is_discriminated_union(sub_field): - # Field is a list of discriminated union e.g. components: List[ComponentType]. - new_annotation = List[_add_to_discriminated_union(sub_field.outer_type_)] # type: ignore[misc] + # Field is a list of discriminated union e.g. components: list[ComponentType]. + new_annotation = list[_add_to_discriminated_union(sub_field.outer_type_)] # type: ignore[misc] else: raise ValueError( f"Field '{field_name}' must be a discriminated union or list of discriminated union type. " @@ -258,11 +258,11 @@ def dict(self, **kwargs): # exists in pydantic v2). # Root validators with pre=True are always included, even when exclude_default=True, and so this is needed # to potentially exclude fields set this way, like Page.id. - def __vizro_exclude_fields__(self) -> Optional[Union[Set[str], Mapping[str, Any]]]: + def __vizro_exclude_fields__(self) -> Optional[Union[set[str], Mapping[str, Any]]]: return None def _to_python( - self, extra_imports: Optional[Set[str]] = None, extra_callable_defs: Optional[Set[str]] = None + self, extra_imports: Optional[set[str]] = None, extra_callable_defs: Optional[set[str]] = None ) -> str: """Converts a Vizro model to the Python code that would create it. @@ -286,8 +286,8 @@ def _to_python( >>> print( ... card._to_python( - ... extra_imports={"from typing import List"}, - ... extra_callable_defs={"def test(foo:List[str]): return foo"}, + ... extra_imports={"from typing import Optional"}, + ... extra_callable_defs={"def test(foo: Optional[str]): return foo"}, ... ) ... ) @@ -296,9 +296,7 @@ def _to_python( extra_imports_concat = "\n".join(extra_imports) if extra_imports else None # CapturedCallable definitions - NOTE that order is not guaranteed - callable_defs_set = _extract_captured_callable_source() | ( - extra_callable_defs if extra_callable_defs else set() - ) + callable_defs_set = _extract_captured_callable_source() | (extra_callable_defs or set()) callable_defs_concat = "\n".join(callable_defs_set) if callable_defs_set else None # Data Manager @@ -318,7 +316,7 @@ def _to_python( data_settings_template = DATA_TEMPLATE.format(data_setting=data_defs_concat) if data_defs_concat else "" unformatted_code = TO_PYTHON_TEMPLATE.format( code=model_code, - extra_imports=extra_imports_concat if extra_imports_concat else "", + extra_imports=extra_imports_concat or "", callable_defs_template=callable_defs_template, data_settings_template=data_settings_template, ) diff --git a/vizro-core/src/vizro/models/_components/_form.py b/vizro-core/src/vizro/models/_components/_form.py index 20daf5f51..3cbcd0918 100644 --- a/vizro-core/src/vizro/models/_components/_form.py +++ b/vizro-core/src/vizro/models/_components/_form.py @@ -1,6 +1,6 @@ from __future__ import annotations -from typing import TYPE_CHECKING, List, Literal +from typing import TYPE_CHECKING, Literal from dash import html @@ -24,13 +24,13 @@ class Form(VizroBaseModel): Args: type (Literal["form"]): Defaults to `"form"`. - components (List[FormComponentType]): List of components used in the form. + components (list[FormComponentType]): List of components used in the form. layout (Layout): Defaults to `None`. """ type: Literal["form"] = "form" - components: List[_FormComponentType] + components: list[_FormComponentType] layout: Layout = None # type: ignore[assignment] # Re-used validators diff --git a/vizro-core/src/vizro/models/_components/ag_grid.py b/vizro-core/src/vizro/models/_components/ag_grid.py index 47000358c..25c8aef18 100644 --- a/vizro-core/src/vizro/models/_components/ag_grid.py +++ b/vizro-core/src/vizro/models/_components/ag_grid.py @@ -1,5 +1,5 @@ import logging -from typing import Dict, List, Literal +from typing import Literal import pandas as pd from dash import State, dcc, html @@ -33,7 +33,7 @@ class AgGrid(VizroBaseModel): Defaults to `""`. footer (str): Markdown text positioned below the `AgGrid`. Follows the CommonMark specification. Ideal for providing further details such as sources, disclaimers, or additional notes. Defaults to `""`. - actions (List[Action]): See [`Action`][vizro.models.Action]. Defaults to `[]`. + actions (list[Action]): See [`Action`][vizro.models.Action]. Defaults to `[]`. """ @@ -52,7 +52,7 @@ class AgGrid(VizroBaseModel): description="Markdown text positioned below the `AgGrid`. Follows the CommonMark specification. Ideal for " "providing further details such as sources, disclaimers, or additional notes.", ) - actions: List[Action] = [] + actions: list[Action] = [] _input_component_id: str = PrivateAttr() @@ -91,7 +91,7 @@ def _filter_interaction_input(self): } def _filter_interaction( - self, data_frame: pd.DataFrame, target: str, ctd_filter_interaction: Dict[str, CallbackTriggerDict] + self, data_frame: pd.DataFrame, target: str, ctd_filter_interaction: dict[str, CallbackTriggerDict] ) -> pd.DataFrame: """Function to be carried out for pre-defined `filter_interaction`.""" # data_frame is the DF of the target, ie the data to be filtered, hence we cannot get the DF from this model diff --git a/vizro-core/src/vizro/models/_components/button.py b/vizro-core/src/vizro/models/_components/button.py index 1e6f47da8..500c8800b 100644 --- a/vizro-core/src/vizro/models/_components/button.py +++ b/vizro-core/src/vizro/models/_components/button.py @@ -1,4 +1,4 @@ -from typing import List, Literal +from typing import Literal import dash_bootstrap_components as dbc @@ -18,13 +18,13 @@ class Button(VizroBaseModel): Args: type (Literal["button"]): Defaults to `"button"`. text (str): Text to be displayed on button. Defaults to `"Click me!"`. - actions (List[Action]): See [`Action`][vizro.models.Action]. Defaults to `[]`. + actions (list[Action]): See [`Action`][vizro.models.Action]. Defaults to `[]`. """ type: Literal["button"] = "button" text: str = Field("Click me!", description="Text to be displayed on button.") - actions: List[Action] = [] + actions: list[Action] = [] # Re-used validators _set_actions = _action_validator_factory("n_clicks") diff --git a/vizro-core/src/vizro/models/_components/container.py b/vizro-core/src/vizro/models/_components/container.py index 0aac10c09..6b56b5769 100644 --- a/vizro-core/src/vizro/models/_components/container.py +++ b/vizro-core/src/vizro/models/_components/container.py @@ -1,6 +1,6 @@ from __future__ import annotations -from typing import TYPE_CHECKING, List, Literal +from typing import TYPE_CHECKING, Literal from dash import html @@ -23,7 +23,7 @@ class Container(VizroBaseModel): Args: type (Literal["container"]): Defaults to `"container"`. - components (List[ComponentType]): See [ComponentType][vizro.models.types.ComponentType]. At least one component + components (list[ComponentType]): See [ComponentType][vizro.models.types.ComponentType]. At least one component has to be provided. title (str): Title to be displayed. layout (Layout): Layout to place components in. Defaults to `None`. @@ -31,7 +31,7 @@ class Container(VizroBaseModel): """ type: Literal["container"] = "container" - components: List[ComponentType] + components: list[ComponentType] title: str = Field(..., description="Title to be displayed.") layout: Layout = None # type: ignore[assignment] diff --git a/vizro-core/src/vizro/models/_components/form/__init__.py b/vizro-core/src/vizro/models/_components/form/__init__.py index 6d3e5b10b..8bbba6ce5 100644 --- a/vizro-core/src/vizro/models/_components/form/__init__.py +++ b/vizro-core/src/vizro/models/_components/form/__init__.py @@ -6,5 +6,4 @@ from vizro.models._components.form.range_slider import RangeSlider from vizro.models._components.form.slider import Slider -# Please keep alphabetically ordered __all__ = ["Button", "Checklist", "DatePicker", "Dropdown", "RadioItems", "RangeSlider", "Slider"] diff --git a/vizro-core/src/vizro/models/_components/form/_alert.py b/vizro-core/src/vizro/models/_components/form/_alert.py index 28e1f6b7e..9cc2cfaee 100644 --- a/vizro-core/src/vizro/models/_components/form/_alert.py +++ b/vizro-core/src/vizro/models/_components/form/_alert.py @@ -1,4 +1,4 @@ -from typing import List, Literal, Optional +from typing import Literal, Optional import dash_bootstrap_components as dbc from dash import html @@ -20,7 +20,7 @@ class Alert(VizroBaseModel): text (str): Text to be displayed in the alert. is_open (bool): Flag indicating whether alert should be open by default. Defaults to `True`. duration (Optional[int]): Duration in milliseconds for the alert to appear. Defaults to `None`. - actions (List[Action]): See [`Action`][vizro.models.Action]. Defaults to `[]`. + actions (list[Action]): See [`Action`][vizro.models.Action]. Defaults to `[]`. """ @@ -28,7 +28,7 @@ class Alert(VizroBaseModel): text: str = Field(..., description="Text to be displayed in the alert.") is_open: bool = Field(True, description="Flag indicating whether alert should be open by default.") duration: Optional[int] = Field(None, description="Duration in milliseconds for the alert to appear.", ge=0) - actions: List[Action] = [] + actions: list[Action] = [] @_log_call def build(self): diff --git a/vizro-core/src/vizro/models/_components/form/_text_area.py b/vizro-core/src/vizro/models/_components/form/_text_area.py index a359baa40..5ac25fdb7 100644 --- a/vizro-core/src/vizro/models/_components/form/_text_area.py +++ b/vizro-core/src/vizro/models/_components/form/_text_area.py @@ -1,4 +1,4 @@ -from typing import List, Literal +from typing import Literal import dash_bootstrap_components as dbc from dash import html @@ -22,7 +22,7 @@ class TextArea(VizroBaseModel): type (Literal["text_area"]): Defaults to `"text_area"`. title (str): Title to be displayed. Defaults to `""`. placeholder (str): Default text to display in input field. Defaults to `""`. - actions (Optional[List[Action]]): Defaults to `[]`. + actions (Optional[list[Action]]): Defaults to `[]`. """ @@ -30,7 +30,7 @@ class TextArea(VizroBaseModel): # TODO: before making public consider naming this field (or giving an alias) label instead of title title: str = Field("", description="Title to be displayed") placeholder: str = Field("", description="Default text to display in input field") - actions: List[Action] = [] + actions: list[Action] = [] # Re-used validators # TODO: Before making public, consider how actions should be triggered and what the default property should be diff --git a/vizro-core/src/vizro/models/_components/form/_user_input.py b/vizro-core/src/vizro/models/_components/form/_user_input.py index a784bb2cd..bb98a14bb 100644 --- a/vizro-core/src/vizro/models/_components/form/_user_input.py +++ b/vizro-core/src/vizro/models/_components/form/_user_input.py @@ -1,4 +1,4 @@ -from typing import List, Literal +from typing import Literal import dash_bootstrap_components as dbc from dash import html @@ -22,7 +22,7 @@ class UserInput(VizroBaseModel): type (Literal["user_input"]): Defaults to `"user_input"`. title (str): Title to be displayed. Defaults to `""`. placeholder (str): Default text to display in input field. Defaults to `""`. - actions (Optional[List[Action]]): Defaults to `[]`. + actions (Optional[list[Action]]): Defaults to `[]`. """ @@ -30,7 +30,7 @@ class UserInput(VizroBaseModel): # TODO: before making public consider naming this field (or giving an alias) label instead of title title: str = Field("", description="Title to be displayed") placeholder: str = Field("", description="Default text to display in input field") - actions: List[Action] = [] + actions: list[Action] = [] # Re-used validators # TODO: Before making public, consider how actions should be triggered and what the default property should be diff --git a/vizro-core/src/vizro/models/_components/form/checklist.py b/vizro-core/src/vizro/models/_components/form/checklist.py index 3279f940d..68cb26ad1 100644 --- a/vizro-core/src/vizro/models/_components/form/checklist.py +++ b/vizro-core/src/vizro/models/_components/form/checklist.py @@ -1,4 +1,4 @@ -from typing import List, Literal, Optional +from typing import Literal, Optional from dash import html @@ -28,7 +28,7 @@ class Checklist(VizroBaseModel): options (OptionsType): See [`OptionsType`][vizro.models.types.OptionsType]. Defaults to `[]`. value (Optional[MultiValueType]): See [`MultiValueType`][vizro.models.types.MultiValueType]. Defaults to `None`. title (str): Title to be displayed. Defaults to `""`. - actions (List[Action]): See [`Action`][vizro.models.Action]. Defaults to `[]`. + actions (list[Action]): See [`Action`][vizro.models.Action]. Defaults to `[]`. """ @@ -36,7 +36,7 @@ class Checklist(VizroBaseModel): options: OptionsType = [] value: Optional[MultiValueType] = None title: str = Field("", description="Title to be displayed") - actions: List[Action] = [] + actions: list[Action] = [] # Component properties for actions and interactions _input_property: str = PrivateAttr("value") diff --git a/vizro-core/src/vizro/models/_components/form/date_picker.py b/vizro-core/src/vizro/models/_components/form/date_picker.py index 9fe3b9473..b3dc416fd 100644 --- a/vizro-core/src/vizro/models/_components/form/date_picker.py +++ b/vizro-core/src/vizro/models/_components/form/date_picker.py @@ -1,4 +1,4 @@ -from typing import List, Literal, Optional, Union +from typing import Literal, Optional, Union import dash_mantine_components as dmc from dash import ClientsideFunction, Input, Output, State, clientside_callback, dcc, html @@ -30,20 +30,20 @@ class DatePicker(VizroBaseModel): type (Literal["date_picker"]): Defaults to `"date_picker"`. min (Optional[date]): Start date for date picker. Defaults to `None`. max (Optional[date]): End date for date picker. Defaults to `None`. - value (Union[List[date], date]): Default date/dates for date picker. Defaults to `None`. + value (Union[list[date], date]): Default date/dates for date picker. Defaults to `None`. title (str): Title to be displayed. Defaults to `""`. range (bool): Boolean flag for displaying range picker. Default to `True`. - actions (List[Action]): See [`Action`][vizro.models.Action]. Defaults to `[]`. + actions (list[Action]): See [`Action`][vizro.models.Action]. Defaults to `[]`. """ type: Literal["date_picker"] = "date_picker" min: Optional[date] = Field(None, description="Start date for date picker.") max: Optional[date] = Field(None, description="End date for date picker.") - value: Optional[Union[List[date], date]] = Field(None, description="Default date for date picker") + value: Optional[Union[list[date], date]] = Field(None, description="Default date for date picker") title: str = Field("", description="Title to be displayed.") range: bool = Field(True, description="Boolean flag for displaying range picker.") - actions: List[Action] = [] + actions: list[Action] = [] _input_property: str = PrivateAttr("value") _set_actions = _action_validator_factory("value") diff --git a/vizro-core/src/vizro/models/_components/form/dropdown.py b/vizro-core/src/vizro/models/_components/form/dropdown.py index 60d7981f6..d0fa24444 100755 --- a/vizro-core/src/vizro/models/_components/form/dropdown.py +++ b/vizro-core/src/vizro/models/_components/form/dropdown.py @@ -1,6 +1,6 @@ import math from datetime import date -from typing import List, Literal, Optional, Union +from typing import Literal, Optional, Union from dash import dcc, html @@ -18,7 +18,7 @@ from vizro.models.types import MultiValueType, OptionsType, SingleValueType -def _get_list_of_labels(full_options: OptionsType) -> Union[List[StrictBool], List[float], List[str], List[date]]: +def _get_list_of_labels(full_options: OptionsType) -> Union[list[StrictBool], list[float], list[str], list[date]]: """Returns a list of labels from the selector options provided.""" if all(isinstance(option, dict) for option in full_options): return [option["label"] for option in full_options] # type: ignore[index] @@ -54,7 +54,7 @@ class Dropdown(VizroBaseModel): [`MultiValueType`][vizro.models.types.MultiValueType]. Defaults to `None`. multi (bool): Whether to allow selection of multiple values. Defaults to `True`. title (str): Title to be displayed. Defaults to `""`. - actions (List[Action]): See [`Action`][vizro.models.Action]. Defaults to `[]`. + actions (list[Action]): See [`Action`][vizro.models.Action]. Defaults to `[]`. """ @@ -63,7 +63,7 @@ class Dropdown(VizroBaseModel): value: Optional[Union[SingleValueType, MultiValueType]] = None multi: bool = Field(True, description="Whether to allow selection of multiple values") title: str = Field("", description="Title to be displayed") - actions: List[Action] = [] + actions: list[Action] = [] # Component properties for actions and interactions _input_property: str = PrivateAttr("value") diff --git a/vizro-core/src/vizro/models/_components/form/radio_items.py b/vizro-core/src/vizro/models/_components/form/radio_items.py index e91d53f51..dfa282126 100644 --- a/vizro-core/src/vizro/models/_components/form/radio_items.py +++ b/vizro-core/src/vizro/models/_components/form/radio_items.py @@ -1,4 +1,4 @@ -from typing import List, Literal, Optional +from typing import Literal, Optional from dash import html @@ -29,7 +29,7 @@ class RadioItems(VizroBaseModel): value (Optional[SingleValueType]): See [`SingleValueType`][vizro.models.types.SingleValueType]. Defaults to `None`. title (str): Title to be displayed. Defaults to `""`. - actions (List[Action]): See [`Action`][vizro.models.Action]. Defaults to `[]`. + actions (list[Action]): See [`Action`][vizro.models.Action]. Defaults to `[]`. """ @@ -37,7 +37,7 @@ class RadioItems(VizroBaseModel): options: OptionsType = [] value: Optional[SingleValueType] = None title: str = Field("", description="Title to be displayed") - actions: List[Action] = [] + actions: list[Action] = [] # Component properties for actions and interactions _input_property: str = PrivateAttr("value") diff --git a/vizro-core/src/vizro/models/_components/form/range_slider.py b/vizro-core/src/vizro/models/_components/form/range_slider.py index ee48b31c0..16f0cb8c9 100644 --- a/vizro-core/src/vizro/models/_components/form/range_slider.py +++ b/vizro-core/src/vizro/models/_components/form/range_slider.py @@ -1,4 +1,4 @@ -from typing import Dict, List, Literal, Optional +from typing import Literal, Optional from dash import ClientsideFunction, Input, Output, State, clientside_callback, dcc, html @@ -32,10 +32,10 @@ class RangeSlider(VizroBaseModel): min (Optional[float]): Start value for slider. Defaults to `None`. max (Optional[float]): End value for slider. Defaults to `None`. step (Optional[float]): Step-size for marks on slider. Defaults to `None`. - marks (Optional[Dict[int, Union[str, dict]]]): Marks to be displayed on slider. Defaults to `{}`. - value (Optional[List[float]]): Default start and end value for slider. Must be 2 items. Defaults to `None`. + marks (Optional[dict[int, Union[str, dict]]]): Marks to be displayed on slider. Defaults to `{}`. + value (Optional[list[float]]): Default start and end value for slider. Must be 2 items. Defaults to `None`. title (str): Title to be displayed. Defaults to `""`. - actions (List[Action]): See [`Action`][vizro.models.Action]. Defaults to `[]`. + actions (list[Action]): See [`Action`][vizro.models.Action]. Defaults to `[]`. """ @@ -43,12 +43,12 @@ class RangeSlider(VizroBaseModel): min: Optional[float] = Field(None, description="Start value for slider.") max: Optional[float] = Field(None, description="End value for slider.") step: Optional[float] = Field(None, description="Step-size for marks on slider.") - marks: Optional[Dict[float, str]] = Field({}, description="Marks to be displayed on slider.") - value: Optional[List[float]] = Field( + marks: Optional[dict[float, str]] = Field({}, description="Marks to be displayed on slider.") + value: Optional[list[float]] = Field( None, description="Default start and end value for slider", min_items=2, max_items=2 ) title: str = Field("", description="Title to be displayed.") - actions: List[Action] = [] + actions: list[Action] = [] # Component properties for actions and interactions _input_property: str = PrivateAttr("value") diff --git a/vizro-core/src/vizro/models/_components/form/slider.py b/vizro-core/src/vizro/models/_components/form/slider.py index 937904f29..65b37fe9a 100644 --- a/vizro-core/src/vizro/models/_components/form/slider.py +++ b/vizro-core/src/vizro/models/_components/form/slider.py @@ -1,4 +1,4 @@ -from typing import Dict, List, Literal, Optional +from typing import Literal, Optional from dash import ClientsideFunction, Input, Output, State, clientside_callback, dcc, html @@ -32,10 +32,10 @@ class Slider(VizroBaseModel): min (Optional[float]): Start value for slider. Defaults to `None`. max (Optional[float]): End value for slider. Defaults to `None`. step (Optional[float]): Step-size for marks on slider. Defaults to `None`. - marks (Optional[Dict[int, Union[str, dict]]]): Marks to be displayed on slider. Defaults to `{}`. + marks (Optional[dict[int, Union[str, dict]]]): Marks to be displayed on slider. Defaults to `{}`. value (Optional[float]): Default value for slider. Defaults to `None`. title (str): Title to be displayed. Defaults to `""`. - actions (List[Action]): See [`Action`][vizro.models.Action]. Defaults to `[]`. + actions (list[Action]): See [`Action`][vizro.models.Action]. Defaults to `[]`. """ @@ -43,10 +43,10 @@ class Slider(VizroBaseModel): min: Optional[float] = Field(None, description="Start value for slider.") max: Optional[float] = Field(None, description="End value for slider.") step: Optional[float] = Field(None, description="Step-size for marks on slider.") - marks: Optional[Dict[float, str]] = Field({}, description="Marks to be displayed on slider.") + marks: Optional[dict[float, str]] = Field({}, description="Marks to be displayed on slider.") value: Optional[float] = Field(None, description="Default value for slider.") title: str = Field("", description="Title to be displayed.") - actions: List[Action] = [] + actions: list[Action] = [] # Component properties for actions and interactions _input_property: str = PrivateAttr("value") diff --git a/vizro-core/src/vizro/models/_components/graph.py b/vizro-core/src/vizro/models/_components/graph.py index e07ba678f..1250a2992 100644 --- a/vizro-core/src/vizro/models/_components/graph.py +++ b/vizro-core/src/vizro/models/_components/graph.py @@ -1,7 +1,7 @@ import logging import warnings from contextlib import suppress -from typing import Dict, List, Literal +from typing import Literal from dash import ClientsideFunction, Input, Output, State, clientside_callback, dcc, html, set_props from dash.exceptions import MissingCallbackContextException @@ -39,7 +39,7 @@ class Graph(VizroBaseModel): Defaults to `""`. footer (str): Markdown text positioned below the `Graph`. Follows the CommonMark specification. Ideal for providing further details such as sources, disclaimers, or additional notes. Defaults to `""`. - actions (List[Action]): See [`Action`][vizro.models.Action]. Defaults to `[]`. + actions (list[Action]): See [`Action`][vizro.models.Action]. Defaults to `[]`. """ @@ -58,7 +58,7 @@ class Graph(VizroBaseModel): description="Markdown text positioned below the `Graph`. Follows the CommonMark specification. Ideal for " "providing further details such as sources, disclaimers, or additional notes.", ) - actions: List[Action] = [] + actions: list[Action] = [] # Component properties for actions and interactions _output_component_property: str = PrivateAttr("figure") @@ -106,7 +106,7 @@ def _filter_interaction_input(self): } def _filter_interaction( - self, data_frame: pd.DataFrame, target: str, ctd_filter_interaction: Dict[str, CallbackTriggerDict] + self, data_frame: pd.DataFrame, target: str, ctd_filter_interaction: dict[str, CallbackTriggerDict] ) -> pd.DataFrame: """Function to be carried out for pre-defined `filter_interaction`.""" # data_frame is the DF of the target, ie the data to be filtered, hence we cannot get the DF from this model diff --git a/vizro-core/src/vizro/models/_components/table.py b/vizro-core/src/vizro/models/_components/table.py index ffaf5b51c..8ffb4ea8d 100644 --- a/vizro-core/src/vizro/models/_components/table.py +++ b/vizro-core/src/vizro/models/_components/table.py @@ -1,5 +1,5 @@ import logging -from typing import Dict, List, Literal +from typing import Literal import pandas as pd from dash import State, dcc, html @@ -32,7 +32,7 @@ class Table(VizroBaseModel): Defaults to `""`. footer (str): Markdown text positioned below the `Table`. Follows the CommonMark specification. Ideal for providing further details such as sources, disclaimers, or additional notes. Defaults to `""`. - actions (List[Action]): See [`Action`][vizro.models.Action]. Defaults to `[]`. + actions (list[Action]): See [`Action`][vizro.models.Action]. Defaults to `[]`. """ @@ -51,7 +51,7 @@ class Table(VizroBaseModel): description="Markdown text positioned below the `Table`. Follows the CommonMark specification. Ideal for " "providing further details such as sources, disclaimers, or additional notes.", ) - actions: List[Action] = [] + actions: list[Action] = [] _input_component_id: str = PrivateAttr() @@ -94,7 +94,7 @@ def _filter_interaction_input(self): } def _filter_interaction( - self, data_frame: pd.DataFrame, target: str, ctd_filter_interaction: Dict[str, CallbackTriggerDict] + self, data_frame: pd.DataFrame, target: str, ctd_filter_interaction: dict[str, CallbackTriggerDict] ) -> pd.DataFrame: """Function to be carried out for pre-defined `filter_interaction`.""" # data_frame is the DF of the target, ie the data to be filtered, hence we cannot get the DF from this model diff --git a/vizro-core/src/vizro/models/_components/tabs.py b/vizro-core/src/vizro/models/_components/tabs.py index d11de0357..bd19f40cf 100644 --- a/vizro-core/src/vizro/models/_components/tabs.py +++ b/vizro-core/src/vizro/models/_components/tabs.py @@ -1,6 +1,6 @@ from __future__ import annotations -from typing import TYPE_CHECKING, List, Literal +from typing import TYPE_CHECKING, Literal import dash_mantine_components as dmc from dash import html @@ -22,12 +22,12 @@ class Tabs(VizroBaseModel): Args: type (Literal["tabs"]): Defaults to `"tabs"`. - tabs (List[Container]): See [`Container`][vizro.models.Container]. + tabs (list[Container]): See [`Container`][vizro.models.Container]. """ type: Literal["tabs"] = "tabs" - tabs: List[Container] + tabs: list[Container] _validate_tabs = validator("tabs", allow_reuse=True, always=True)(validate_min_length) diff --git a/vizro-core/src/vizro/models/_controls/filter.py b/vizro-core/src/vizro/models/_controls/filter.py index 5ae2e0f13..a66e8d62d 100644 --- a/vizro-core/src/vizro/models/_controls/filter.py +++ b/vizro-core/src/vizro/models/_controls/filter.py @@ -1,6 +1,6 @@ from __future__ import annotations -from typing import List, Literal, Union +from typing import Literal, Union import pandas as pd from pandas.api.types import is_datetime64_any_dtype, is_numeric_dtype @@ -44,7 +44,7 @@ } -def _filter_between(series: pd.Series, value: Union[List[float], List[str]]) -> pd.Series: +def _filter_between(series: pd.Series, value: Union[list[float], list[str]]) -> pd.Series: if is_datetime64_any_dtype(series): # Each value will always have time 00:00:00. In order for the filter to include all times during # the end date value[1] we need to remove the time part of every value in series so that it's 00:00:00. @@ -71,7 +71,7 @@ class Filter(VizroBaseModel): Args: type (Literal["filter"]): Defaults to `"filter"`. column (str): Column of `DataFrame` to filter. - targets (List[ModelID]): Target component to be affected by filter. If none are given then target all components + targets (list[ModelID]): Target component to be affected by filter. If none are given then target all components on the page that use `column`. selector (SelectorType): See [SelectorType][vizro.models.types.SelectorType]. Defaults to `None`. @@ -79,7 +79,7 @@ class Filter(VizroBaseModel): type: Literal["filter"] = "filter" column: str = Field(..., description="Column of DataFrame to filter.") - targets: List[ModelID] = Field( + targets: list[ModelID] = Field( [], description="Target component to be affected by filter. " "If none are given then target all components on the page that use `column`.", @@ -158,10 +158,8 @@ def _set_numerical_and_temporal_selectors_values(self): max_values.append(data_frame[self.column].max()) if not ( - is_numeric_dtype(pd.Series(min_values)) - and is_numeric_dtype(pd.Series(max_values)) - or is_datetime64_any_dtype(pd.Series(min_values)) - and is_datetime64_any_dtype(pd.Series(max_values)) + (is_numeric_dtype(pd.Series(min_values)) and is_numeric_dtype(pd.Series(max_values))) + or (is_datetime64_any_dtype(pd.Series(min_values)) and is_datetime64_any_dtype(pd.Series(max_values))) ): raise ValueError( f"Inconsistent types detected in the shared data column '{self.column}' for targeted charts " diff --git a/vizro-core/src/vizro/models/_controls/parameter.py b/vizro-core/src/vizro/models/_controls/parameter.py index 748a669b0..e7d6d537c 100644 --- a/vizro-core/src/vizro/models/_controls/parameter.py +++ b/vizro-core/src/vizro/models/_controls/parameter.py @@ -1,4 +1,4 @@ -from typing import List, Literal +from typing import Literal try: from pydantic.v1 import Field, validator @@ -22,14 +22,14 @@ class Parameter(VizroBaseModel): Args: type (Literal["parameter"]): Defaults to `"parameter"`. - targets (List[str]): Targets in the form of `.`. + targets (list[str]): Targets in the form of `.`. selector (SelectorType): See [SelectorType][vizro.models.types.SelectorType]. Converts selector value `"NONE"` into `None` to allow optional parameters. """ type: Literal["parameter"] = "parameter" - targets: List[str] = Field(..., description="Targets in the form of `.`.") + targets: list[str] = Field(..., description="Targets in the form of `.`.") selector: SelectorType @validator("targets", each_item=True) diff --git a/vizro-core/src/vizro/models/_dashboard.py b/vizro-core/src/vizro/models/_dashboard.py index afecd226a..477dfca3d 100644 --- a/vizro-core/src/vizro/models/_dashboard.py +++ b/vizro-core/src/vizro/models/_dashboard.py @@ -4,7 +4,7 @@ import logging from functools import partial from pathlib import Path -from typing import TYPE_CHECKING, List, Literal, TypedDict +from typing import TYPE_CHECKING, Literal, TypedDict import dash import dash_bootstrap_components as dbc @@ -45,7 +45,7 @@ logger = logging.getLogger(__name__) -def _all_hidden(components: List[Component]): +def _all_hidden(components: list[Component]): """Returns True if all `components` are either None and/or have hidden=True and/or className contains `d-none`.""" return all( component is None @@ -80,7 +80,7 @@ class Dashboard(VizroBaseModel): """Vizro Dashboard to be used within [`Vizro`][vizro._vizro.Vizro.build]. Args: - pages (List[Page]): See [`Page`][vizro.models.Page]. + pages (list[Page]): See [`Page`][vizro.models.Page]. theme (Literal["vizro_dark", "vizro_light"]): Layout theme to be applied across dashboard. Defaults to `vizro_dark`. navigation (Navigation): See [`Navigation`][vizro.models.Navigation]. Defaults to `None`. @@ -88,7 +88,7 @@ class Dashboard(VizroBaseModel): """ - pages: List[Page] + pages: list[Page] theme: Literal["vizro_dark", "vizro_light"] = Field( "vizro_dark", description="Layout theme to be applied across dashboard. Defaults to `vizro_dark`" ) @@ -114,7 +114,7 @@ def set_navigation_pages(cls, navigation, values): def pre_build(self): self._validate_logos() - # Setting order here ensures that the pages in dash.page_registry preserves the order of the List[Page]. + # Setting order here ensures that the pages in dash.page_registry preserves the order of the list[Page]. # For now the homepage (path /) corresponds to self.pages[0]. # Note redirect_from=["/"] doesn't work and so the / route must be defined separately. self.pages[0].path = "/" diff --git a/vizro-core/src/vizro/models/_layout.py b/vizro-core/src/vizro/models/_layout.py index 938a9daf7..201f7f9c2 100644 --- a/vizro-core/src/vizro/models/_layout.py +++ b/vizro-core/src/vizro/models/_layout.py @@ -1,4 +1,4 @@ -from typing import List, NamedTuple, Optional, Tuple +from typing import NamedTuple, Optional import numpy as np from dash import html @@ -26,7 +26,7 @@ class ColRowGridLines(NamedTuple): row_end: int -def _get_unique_grid_component_ids(grid: List[List[int]]): +def _get_unique_grid_component_ids(grid: list[list[int]]): unique_grid_idx = np.unique(grid) unique_grid_comp_idx = unique_grid_idx[unique_grid_idx != EMPTY_SPACE_CONST] return unique_grid_comp_idx @@ -73,7 +73,7 @@ def _convert_to_combined_grid_coord(matrix: ma.MaskedArray) -> ColRowGridLines: ) -def _convert_to_single_grid_coord(matrix: ma.MaskedArray) -> List[ColRowGridLines]: +def _convert_to_single_grid_coord(matrix: ma.MaskedArray) -> list[ColRowGridLines]: """Converts `matrix` coordinates from user `grid` to list of grid areas spanned by each placement of component i. Required for validation of grid areas spanned by spaces, where the combined area does not need to be rectangular. @@ -122,7 +122,7 @@ def _do_rectangles_overlap(r1: ColRowGridLines, r2: ColRowGridLines) -> bool: return x1 < x2 and y1 < y2 -def _validate_grid_areas(grid_areas: List[ColRowGridLines]) -> None: +def _validate_grid_areas(grid_areas: list[ColRowGridLines]) -> None: """Validates `grid_areas` spanned by screen components in `Layout`.""" for i, r1 in enumerate(grid_areas): for r2 in grid_areas[i + 1 :]: @@ -130,7 +130,7 @@ def _validate_grid_areas(grid_areas: List[ColRowGridLines]) -> None: raise ValueError("Grid areas must be rectangular and not overlap!") -def _get_grid_lines(grid: List[List[int]]) -> Tuple[List[ColRowGridLines], List[ColRowGridLines]]: +def _get_grid_lines(grid: list[list[int]]) -> tuple[list[ColRowGridLines], list[ColRowGridLines]]: """Gets list of ColRowGridLines for components and spaces on screen for validation and placement.""" component_grid_lines = [] unique_grid_idx = _get_unique_grid_component_ids(grid) @@ -148,7 +148,7 @@ class Layout(VizroBaseModel): """Grid specification to place chart/components on the [`Page`][vizro.models.Page]. Args: - grid (List[List[int]]): Grid specification to arrange components on screen. + grid (list[list[int]]): Grid specification to arrange components on screen. row_gap (str): Gap between rows in px. Defaults to `"12px"`. col_gap (str): Gap between columns in px. Defaults to `"12px"`. row_min_height (str): Minimum row height in px. Defaults to `"0px"`. @@ -156,14 +156,14 @@ class Layout(VizroBaseModel): """ - grid: List[List[int]] = Field(..., description="Grid specification to arrange components on screen.") + grid: list[list[int]] = Field(..., description="Grid specification to arrange components on screen.") row_gap: str = Field(GAP_DEFAULT, description="Gap between rows in px. Defaults to 12px.", regex="[0-9]+px") col_gap: str = Field(GAP_DEFAULT, description="Gap between columns in px. Defaults to 12px.", regex="[0-9]+px") row_min_height: str = Field(MIN_DEFAULT, description="Minimum row height in px. Defaults to 0px.", regex="[0-9]+px") col_min_width: str = Field( MIN_DEFAULT, description="Minimum column width in px. Defaults to 0px.", regex="[0-9]+px" ) - _component_grid_lines: Optional[List[ColRowGridLines]] = PrivateAttr() + _component_grid_lines: Optional[list[ColRowGridLines]] = PrivateAttr() @validator("grid") def validate_grid(cls, grid): @@ -172,7 +172,7 @@ def validate_grid(cls, grid): # Validate grid type and values unique_grid_idx = _get_unique_grid_component_ids(grid) - if 0 not in unique_grid_idx or not np.array_equal(unique_grid_idx, np.arange((unique_grid_idx.max() + 1))): + if 0 not in unique_grid_idx or not np.array_equal(unique_grid_idx, np.arange(unique_grid_idx.max() + 1)): raise ValueError("Grid must contain consecutive integers starting from 0.") # Validates grid areas spanned by components and spaces diff --git a/vizro-core/src/vizro/models/_navigation/accordion.py b/vizro-core/src/vizro/models/_navigation/accordion.py index 563a44b78..e8f27c1ff 100644 --- a/vizro-core/src/vizro/models/_navigation/accordion.py +++ b/vizro-core/src/vizro/models/_navigation/accordion.py @@ -1,6 +1,6 @@ import itertools from collections.abc import Mapping -from typing import Dict, List, Literal +from typing import Literal import dash_bootstrap_components as dbc from dash import get_relative_path @@ -22,12 +22,12 @@ class Accordion(VizroBaseModel): Args: type (Literal["accordion"]): Defaults to `"accordion"`. - pages (Dict[str, List[str]]): Mapping from name of a pages group to a list of page IDs. Defaults to `{}`. + pages (dict[str, list[str]]): Mapping from name of a pages group to a list of page IDs. Defaults to `{}`. """ type: Literal["accordion"] = "accordion" - pages: Dict[str, List[str]] = Field({}, description="Mapping from name of a pages group to a list of page IDs.") + pages: dict[str, list[str]] = Field({}, description="Mapping from name of a pages group to a list of page IDs.") _validate_pages = validator("pages", allow_reuse=True)(_validate_pages) @@ -77,7 +77,7 @@ def build(self, *, active_page_id=None): id="nav-panel", ) - def _create_nav_links(self, pages: List[str]): + def _create_nav_links(self, pages: list[str]): """Creates a `NavLink` for each provided page.""" nav_links = [] diff --git a/vizro-core/src/vizro/models/_navigation/nav_bar.py b/vizro-core/src/vizro/models/_navigation/nav_bar.py index 4802b306e..325573542 100644 --- a/vizro-core/src/vizro/models/_navigation/nav_bar.py +++ b/vizro-core/src/vizro/models/_navigation/nav_bar.py @@ -1,7 +1,7 @@ from __future__ import annotations from collections.abc import Mapping -from typing import Dict, List, Literal +from typing import Literal import dash_bootstrap_components as dbc from dash import html @@ -23,14 +23,14 @@ class NavBar(VizroBaseModel): Args: type (Literal["nav_bar"]): Defaults to `"nav_bar"`. - pages (Dict[str, List[str]]): Mapping from name of a pages group to a list of page IDs. Defaults to `{}`. - items (List[NavLink]): See [`NavLink`][vizro.models.NavLink]. Defaults to `[]`. + pages (dict[str, list[str]]): Mapping from name of a pages group to a list of page IDs. Defaults to `{}`. + items (list[NavLink]): See [`NavLink`][vizro.models.NavLink]. Defaults to `[]`. """ type: Literal["nav_bar"] = "nav_bar" - pages: Dict[str, List[str]] = Field({}, description="Mapping from name of a pages group to a list of page IDs.") - items: List[NavLink] = [] + pages: dict[str, list[str]] = Field({}, description="Mapping from name of a pages group to a list of page IDs.") + items: list[NavLink] = [] # validators _validate_pages = validator("pages", allow_reuse=True)(_validate_pages) diff --git a/vizro-core/src/vizro/models/_navigation/nav_link.py b/vizro-core/src/vizro/models/_navigation/nav_link.py index 2177bd078..a288181ac 100644 --- a/vizro-core/src/vizro/models/_navigation/nav_link.py +++ b/vizro-core/src/vizro/models/_navigation/nav_link.py @@ -49,7 +49,7 @@ def pre_build(self): @_log_call def build(self, *, active_page_id=None): - # _nav_selector is an Accordion, so _nav_selector._pages is guaranteed to be Dict[str, List[str]]. + # _nav_selector is an Accordion, so _nav_selector._pages is guaranteed to be dict[str, list[str]]. # `active_page_id` is still required here for the automatic opening of the Accordion when navigating # from homepage to a page within the Accordion and there are several Accordions within the page. all_page_ids = list(itertools.chain(*self._nav_selector.pages.values())) diff --git a/vizro-core/src/vizro/models/_page.py b/vizro-core/src/vizro/models/_page.py index 4ed119823..6b45a409c 100644 --- a/vizro-core/src/vizro/models/_page.py +++ b/vizro-core/src/vizro/models/_page.py @@ -1,6 +1,7 @@ from __future__ import annotations -from typing import Any, List, Mapping, Optional, Set, TypedDict, Union +from collections.abc import Mapping +from typing import Any, Optional, TypedDict, Union from dash import dcc, html @@ -31,25 +32,25 @@ class Page(VizroBaseModel): """A page in [`Dashboard`][vizro.models.Dashboard] with its own URL path and place in the `Navigation`. Args: - components (List[ComponentType]): See [ComponentType][vizro.models.types.ComponentType]. At least one component + components (list[ComponentType]): See [ComponentType][vizro.models.types.ComponentType]. At least one component has to be provided. title (str): Title to be displayed. description (str): Description for meta tags. layout (Layout): Layout to place components in. Defaults to `None`. - controls (List[ControlType]): See [ControlType][vizro.models.types.ControlType]. Defaults to `[]`. + controls (list[ControlType]): See [ControlType][vizro.models.types.ControlType]. Defaults to `[]`. path (str): Path to navigate to page. Defaults to `""`. """ - components: List[ComponentType] + components: list[ComponentType] title: str = Field(..., description="Title to be displayed.") description: str = Field("", description="Description for meta tags.") layout: Layout = None # type: ignore[assignment] - controls: List[ControlType] = [] + controls: list[ControlType] = [] path: str = Field("", description="Path to navigate to page.") # TODO: Remove default on page load action if possible - actions: List[ActionsChain] = [] + actions: list[ActionsChain] = [] # Re-used validators _check_captured_callable = validator("components", allow_reuse=True, each_item=True, pre=True)( @@ -90,7 +91,7 @@ def __init__(self, **data): f"as the page title. If you have multiple pages with the same title then you must assign a unique id." ) from exc - def __vizro_exclude_fields__(self) -> Optional[Union[Set[str], Mapping[str, Any]]]: + def __vizro_exclude_fields__(self) -> Optional[Union[set[str], Mapping[str, Any]]]: return {"id"} if self.id == self.title else None @_log_call diff --git a/vizro-core/src/vizro/models/types.py b/vizro-core/src/vizro/models/types.py index 9cc629d8a..4f28bc92a 100644 --- a/vizro-core/src/vizro/models/types.py +++ b/vizro-core/src/vizro/models/types.py @@ -8,7 +8,7 @@ import inspect from contextlib import contextmanager from datetime import date -from typing import Any, Dict, List, Literal, Protocol, Union, runtime_checkable +from typing import Any, Literal, Protocol, Union, runtime_checkable import plotly.io as pio @@ -22,7 +22,9 @@ from pydantic.schema import SkipField -from typing_extensions import Annotated, TypedDict +from typing import Annotated + +from typing_extensions import TypedDict from vizro.charts._charts_utils import _DashboardReadyFigure @@ -170,7 +172,7 @@ def _function(self): return self.__function @classmethod - def __modify_schema__(cls, field_schema: Dict[str, Any], field: ModelField): + def __modify_schema__(cls, field_schema: dict[str, Any], field: ModelField): """Generates schema for field of this type.""" raise SkipField(f"{cls.__name__} {field.name} is excluded from the schema.") @@ -191,7 +193,7 @@ def __get_validators__(cls): @classmethod def _parse_json( cls, - captured_callable_config: Union[_SupportsCapturedCallable, CapturedCallable, Dict[str, Any]], + captured_callable_config: Union[_SupportsCapturedCallable, CapturedCallable, dict[str, Any]], field: ModelField, ) -> Union[CapturedCallable, _SupportsCapturedCallable]: """Parses captured_callable_config specification from JSON/YAML. @@ -452,7 +454,7 @@ def wrapped(*args, **kwargs): # Types used for selector values and options. Note the docstrings here are rendered on the API reference. SingleValueType = Union[StrictBool, float, str, date] """Permissible value types for single-value selectors. Values are displayed as default.""" -MultiValueType = Union[List[StrictBool], List[float], List[str], List[date]] +MultiValueType = Union[list[StrictBool], list[float], list[str], list[date]] """Permissible value types for multi-value selectors. Values are displayed as default.""" @@ -463,7 +465,7 @@ class OptionsDictType(TypedDict): value: SingleValueType -OptionsType = Union[List[StrictBool], List[float], List[str], List[date], List[OptionsDictType]] +OptionsType = Union[list[StrictBool], list[float], list[str], list[date], list[OptionsDictType]] """Permissible options types for selectors. Options are available choices for user to select from.""" # All the below types rely on models and so must use ForwardRef (i.e. "Checklist" rather than actual Checklist class). @@ -498,7 +500,7 @@ class OptionsDictType(TypedDict): [`Button`][vizro.models.Button], [`Card`][vizro.models.Card], [`Table`][vizro.models.Table], [`Graph`][vizro.models.Graph] or [`AgGrid`][vizro.models.AgGrid].""" -NavPagesType = Union[List[str], Dict[str, List[str]]] +NavPagesType = Union[list[str], dict[str, list[str]]] "List of page IDs or a mapping from name of a group to a list of page IDs (for hierarchical sub-navigation)." NavSelectorType = Annotated[ diff --git a/vizro-core/src/vizro/tables/__init__.py b/vizro-core/src/vizro/tables/__init__.py index 3ec9ce4d2..e437f2d89 100644 --- a/vizro-core/src/vizro/tables/__init__.py +++ b/vizro-core/src/vizro/tables/__init__.py @@ -1,5 +1,4 @@ from vizro.tables._dash_ag_grid import dash_ag_grid from vizro.tables._dash_table import dash_data_table -# Please keep alphabetically ordered __all__ = ["dash_ag_grid", "dash_data_table"] diff --git a/vizro-core/src/vizro/tables/_utils.py b/vizro-core/src/vizro/tables/_utils.py index 63fe98c68..c8eaefb13 100644 --- a/vizro-core/src/vizro/tables/_utils.py +++ b/vizro-core/src/vizro/tables/_utils.py @@ -1,10 +1,11 @@ """Contains utilities for the implementation of table callables.""" from collections import defaultdict -from typing import Any, Dict, Mapping +from collections.abc import Mapping +from typing import Any -def _set_defaults_nested(supplied: Mapping[str, Any], defaults: Mapping[str, Any]) -> Dict[str, Any]: +def _set_defaults_nested(supplied: Mapping[str, Any], defaults: Mapping[str, Any]) -> dict[str, Any]: supplied = defaultdict(dict, supplied) for default_key, default_value in defaults.items(): if isinstance(default_value, Mapping): diff --git a/vizro-core/tests/tests_utils/demo_asserts.py b/vizro-core/tests/tests_utils/demo_asserts.py index 3f9dcacc2..1a7dd22d7 100644 --- a/vizro-core/tests/tests_utils/demo_asserts.py +++ b/vizro-core/tests/tests_utils/demo_asserts.py @@ -1,7 +1,5 @@ """Demo to show how to use asserts. These are not real tests that are run as part of testing, just a teaching aid.""" -from typing import List - from asserts import STRIP_ALL, assert_component_equal from dash import html @@ -20,7 +18,7 @@ def build(self): class Y(VizroBaseModel): # Higher-level container model. - children: List[X] + children: list[X] def build(self): return html.Div([child.build() for child in self.children], id=self.id, className="container") diff --git a/vizro-core/tests/unit/test_vizro.py b/vizro-core/tests/unit/test_vizro.py index aca2a4eb8..6b7459653 100644 --- a/vizro-core/tests/unit/test_vizro.py +++ b/vizro-core/tests/unit/test_vizro.py @@ -1,3 +1,5 @@ +import operator + import dash import pytest @@ -33,7 +35,7 @@ def test_css(self, serve_locally, resource_key, resource_value): # Check vizro-bootstrap comes first and looks right assert framework_css[0] == {"namespace": "vizro", resource_key: resource_value} # Check rest is in alphabetical order - assert framework_css[1:] == sorted(framework_css[1:], key=lambda resource: resource[resource_key]) + assert framework_css[1:] == sorted(framework_css[1:], key=operator.itemgetter(resource_key)) # Only external_url or relative_package_path will exist in the resource specification depending on # whether serve_locally=True (the Dash and Vizro default) or False. diff --git a/vizro-core/tests/unit/vizro/models/test_base.py b/vizro-core/tests/unit/vizro/models/test_base.py index 3534019c0..763bfe5e6 100644 --- a/vizro-core/tests/unit/vizro/models/test_base.py +++ b/vizro-core/tests/unit/vizro/models/test_base.py @@ -1,4 +1,4 @@ -from typing import List, Literal, Optional, Union +from typing import Literal, Optional, Union import pytest @@ -8,8 +8,7 @@ from pydantic import Field, ValidationError, root_validator, validator import logging import textwrap - -from typing_extensions import Annotated +from typing import Annotated import vizro.models as vm import vizro.plotly.express as px @@ -61,9 +60,9 @@ class _ParentWithOptional(vm.VizroBaseModel): @pytest.fixture() def ParentWithList(): - # e.g. Page.controls: List[ControlType] and Page.components: List[ComponentType] + # e.g. Page.controls: list[ControlType] and Page.components: list[ComponentType] class _ParentWithList(vm.VizroBaseModel): - child: List[ChildType] + child: list[ChildType] return _ParentWithList @@ -282,11 +281,11 @@ def page_pre_defined_actions(): @pytest.fixture def page_two_captured_callables(): @capture("graph") - def chart(data_frame, hover_data: Optional[List[str]] = None): + def chart(data_frame, hover_data: Optional[list[str]] = None): return px.bar(data_frame, x="sepal_width", y="sepal_length", hover_data=hover_data) @capture("graph") - def chart2(data_frame, hover_data: Optional[List[str]] = None): + def chart2(data_frame, hover_data: Optional[list[str]] = None): return px.bar(data_frame, x="sepal_width", y="sepal_length", hover_data=hover_data) return vm.Page( @@ -303,19 +302,20 @@ def chart_dynamic(): function_string = textwrap.dedent( """ @capture("graph") - def chart_dynamic(data_frame, hover_data: Optional[List[str]] = None): + def chart_dynamic(data_frame, hover_data: Optional[list[str]] = None): return px.bar(data_frame, x="sepal_width", y="sepal_length", hover_data=hover_data) """ ) - exec(function_string) - return locals()["chart_dynamic"] + result = {} + exec(function_string, globals(), result) + return result["chart_dynamic"] @pytest.fixture def complete_dashboard(): @capture("graph") - def chart(data_frame, hover_data: Optional[List[str]] = None): + def chart(data_frame, hover_data: Optional[list[str]] = None): return px.bar(data_frame, x="sepal_width", y="sepal_length", hover_data=hover_data) page = vm.Page( @@ -378,12 +378,12 @@ def chart(data_frame, hover_data: Optional[List[str]] = None): import vizro.plotly.express as px import vizro.models as vm from vizro.models.types import capture -from typing import Optional, List +from typing import Optional ####### Function definitions ###### @capture("graph") -def chart(data_frame, hover_data: Optional[List[str]] = None): +def chart(data_frame, hover_data: Optional[list[str]] = None): return px.bar(data_frame, x="sepal_width", y="sepal_length", hover_data=hover_data) @@ -443,7 +443,7 @@ def chart(data_frame, hover_data: Optional[List[str]] = None): extra_callable = """@capture("graph") -def extra(data_frame, hover_data: Optional[List[str]] = None): +def extra(data_frame, hover_data: Optional[list[str]] = None): return px.bar(data_frame, x="sepal_width", y="sepal_length", hover_data=hover_data) """ @@ -456,7 +456,7 @@ def extra(data_frame, hover_data: Optional[List[str]] = None): ####### Function definitions ###### @capture("graph") -def extra(data_frame, hover_data: Optional[List[str]] = None): +def extra(data_frame, hover_data: Optional[list[str]] = None): return px.bar(data_frame, x="sepal_width", y="sepal_length", hover_data=hover_data) @@ -470,12 +470,12 @@ def extra(data_frame, hover_data: Optional[List[str]] = None): import vizro.models as vm import vizro.actions as va from vizro.models.types import capture -from typing import Optional, List +from typing import Optional ####### Function definitions ###### @capture("graph") -def chart(data_frame, hover_data: Optional[List[str]] = None): +def chart(data_frame, hover_data: Optional[list[str]] = None): return px.bar(data_frame, x="sepal_width", y="sepal_length", hover_data=hover_data) @@ -540,18 +540,18 @@ def test_to_python_captured_callable_chart_plus_extra_imports(self): # Test if captured callable is included correctly in output # Test if extra imports are included correctly in output (typing yes, pandas no) @capture("graph") - def chart(data_frame, hover_data: Optional[List[str]] = None): + def chart(data_frame, hover_data: Optional[list[str]] = None): return px.bar(data_frame, x="sepal_width", y="sepal_length", hover_data=hover_data) graph = vm.Graph(figure=chart(data_frame="iris")) - result = graph._to_python(extra_imports={"from typing import Optional, List", "import pandas as pd"}) + result = graph._to_python(extra_imports={"from typing import Optional", "import pandas as pd"}) assert result == expected_graph_with_callable def test_to_python_two_captured_callable_charts(self, page_two_captured_callables): # Test if two captured callables are included. Note that the order in which they are included is not guaranteed. result = page_two_captured_callables._to_python() - assert "def chart(data_frame, hover_data: Optional[List[str]] = None):" in result - assert "def chart2(data_frame, hover_data: Optional[List[str]] = None):" in result + assert "def chart(data_frame, hover_data: Optional[list[str]] = None):" in result + assert "def chart2(data_frame, hover_data: Optional[list[str]] = None):" in result def test_to_python_pre_defined_actions(self, page_pre_defined_actions): # Test if pre-defined actions are included correctly in output, ie no ActionsChain model @@ -575,5 +575,5 @@ def test_to_python_with_extra_callable(self): def test_to_python_complete_dashboard(self, complete_dashboard): # Test more complete and nested model - result = complete_dashboard._to_python(extra_imports={"from typing import Optional,List"}) + result = complete_dashboard._to_python(extra_imports={"from typing import Optional"}) assert result == expected_complete_dashboard