diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 7f7d383c7..833d85d87 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -112,7 +112,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: [3.8, "3.9"] + python-version: ["3.9", "3.12"] # 3.9 is the lowest version pre-commit supports env: LOCK_FILE_LOCATION: .ci-package-locks/code-quality/python${{ matrix.python-version }}.txt diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index fa12d7b6b..bfcb0c7aa 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -3,9 +3,15 @@ repos: rev: v4.5.0 hooks: - id: check-yaml + - id: check-toml - id: end-of-file-fixer - id: trailing-whitespace exclude: .bumpversion.cfg + - repo: https://github.com/asottile/pyupgrade + rev: v3.17.0 + hooks: + - id: pyupgrade + args: [--py36-plus] - repo: https://github.com/codespell-project/codespell rev: v2.2.6 hooks: @@ -14,18 +20,18 @@ repos: args: ["--skip=**/solara_portal/**"] additional_dependencies: - tomli - - repo: https://github.com/charliermarsh/ruff-pre-commit - rev: "v0.3.4" + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.6.1 hooks: - id: ruff stages: [commit] - id: ruff-format stages: [commit] - repo: https://github.com/pre-commit/mirrors-mypy - rev: "v1.9.0" # Use the sha / tag you want to point at + rev: v1.9.0 hooks: - id: mypy pass_filenames: false args: [--explicit-package-bases, .] additional_dependencies: [types-requests, types-markdown, types-PyYAML, types-filelock, types-cachetools, types-redis, types-python-dateutil, types-pycurl, reacton, types-six, types-decorator, ipython, ipykernel] - exclude: tests/unit/solara_test_apps/multipage/04-a_directory/*|nogit + exclude: tests/unit/solara_test_apps/multipage/04-a_directory/.*|nogit diff --git a/solara/components/cross_filter.py b/solara/components/cross_filter.py index 1304ec7f4..f4c2775f0 100644 --- a/solara/components/cross_filter.py +++ b/solara/components/cross_filter.py @@ -275,14 +275,14 @@ def update_filter(): with solara.HBox(align_items="center"): label = f"Select {column} {mode} " if not invert else f"Drop {column} {mode} " - if py_types[column] == int: + if py_types[column] is int: if isinstance(filter_value, int): solara.SliderInt(label=label, value=filter_value, min=vmin, max=vmax, on_value=set_filter_value, disabled=not enable, thumb_label=False) else: solara.Error(f"Filter value is not an integer type, but {type(filter_value)} (value = {filter_value})") if filter_value is not None: solara.Text(f"{filter_value:,}") - elif py_types[column] == float: + elif py_types[column] is float: if isinstance(filter_value, float): solara.SliderFloat(label=label, value=filter_value, min=vmin, max=vmax, on_value=set_filter_value, disabled=not enable, thumb_label=False) else: diff --git a/solara/minisettings.py b/solara/minisettings.py index b6ea1fa2b..a08dda34e 100644 --- a/solara/minisettings.py +++ b/solara/minisettings.py @@ -14,7 +14,7 @@ def _get_type(annotation): if annotation == Optional[check_type]: return check_type if hasattr(annotation, "__origin__"): - if annotation.__origin__ == dict: + if annotation.__origin__ is dict: return dict return annotation @@ -72,13 +72,13 @@ def convert(annotation, value: str) -> Any: annotation = sub_type values = value.split(",") return [convert(sub_type, k) for k in values] - if annotation == str: + if annotation is str: return value - elif annotation == int: + elif annotation is int: return int(value) - elif annotation == float: + elif annotation is float: return float(value) - elif annotation == bool: + elif annotation is bool: if value in ("True", "true", "1"): return True elif value in ("False", "false", "0"): diff --git a/solara/toestand.py b/solara/toestand.py index a448b19ab..51aae1639 100644 --- a/solara/toestand.py +++ b/solara/toestand.py @@ -144,7 +144,6 @@ def fire(self, new: T, old: T): for listener2, scope in self.listeners2[scope_id].copy(): if scope is not None: scopes.add(scope) - stack = contextlib.ExitStack() with contextlib.ExitStack() as stack: for scope in scopes: stack.enter_context(scope) diff --git a/solara/website/pages/doc_use_download.py b/solara/website/pages/doc_use_download.py index 8b7b6e01c..f9557b9a4 100644 --- a/solara/website/pages/doc_use_download.py +++ b/solara/website/pages/doc_use_download.py @@ -20,7 +20,7 @@ def DownloadFile(file_path=file_path, url=url, expected_size=expected_size, on_d status = "Done 🎉" else: MEGABYTES = 2.0**20.0 - status = "Downloading {}... ({:6.2f}/{:6.2f} MB)".format(file_path, downloaded_size / MEGABYTES, expected_size / MEGABYTES) + status = f"Downloading {file_path}... ({downloaded_size / MEGABYTES:6.2f}/{expected_size / MEGABYTES:6.2f} MB)" # status = "hi" # return MarkdownIt(f'{status}') assert download.progress is not None diff --git a/solara/website/pages/documentation/getting_started/content/04-tutorials/_data_science.ipynb b/solara/website/pages/documentation/getting_started/content/04-tutorials/_data_science.ipynb index 659f518aa..a4dd057cc 100644 --- a/solara/website/pages/documentation/getting_started/content/04-tutorials/_data_science.ipynb +++ b/solara/website/pages/documentation/getting_started/content/04-tutorials/_data_science.ipynb @@ -69,7 +69,7 @@ "\n", "\n", "df = px.data.iris()\n", - "df\n" + "df" ] }, { @@ -163,6 +163,7 @@ "columns = list(df.columns)\n", "x_axis = solara.reactive(\"sepal_length\")\n", "\n", + "\n", "@solara.component\n", "def Page():\n", " # Create a scatter plot by passing \"x_axis.value\" to px.scatter\n", @@ -170,10 +171,10 @@ " # and re-execute this function when x_axis value changes\n", " fig = px.scatter(df, x_axis.value, \"sepal_width\")\n", " solara.FigurePlotly(fig)\n", - " \n", + "\n", " # Pass x_axis to Select component\n", " # The select will control the x_axis reactive variable\n", - " solara.Select(label=\"X-axis\", value=x_axis, values=columns)\n" + " solara.Select(label=\"X-axis\", value=x_axis, values=columns)" ] }, { @@ -219,12 +220,13 @@ "source": [ "y_axis = solara.reactive(\"sepal_width\")\n", "\n", + "\n", "@solara.component\n", "def Page():\n", " fig = px.scatter(df, x_axis.value, y_axis.value)\n", " solara.FigurePlotly(fig)\n", " solara.Select(label=\"X-axis\", value=x_axis, values=columns)\n", - " solara.Select(label=\"Y-axis\", value=y_axis, values=columns) " + " solara.Select(label=\"Y-axis\", value=y_axis, values=columns)" ] }, { @@ -267,8 +269,7 @@ " solara.Select(label=\"X-axis\", value=x_axis, values=columns)\n", " solara.Select(label=\"Y-axis\", value=y_axis, values=columns)\n", " # display it pre-formatted using the backticks `` using Markdown\n", - " solara.Markdown(f\"`{click_data}`\")\n", - " " + " solara.Markdown(f\"`{click_data}`\")" ] }, { @@ -319,7 +320,7 @@ " row_index = click_data.value[\"points\"][\"point_indexes\"][0]\n", " x = click_data.value[\"points\"][\"xs\"][0]\n", " y = click_data.value[\"points\"][\"ys\"][0]\n", - " solara.Markdown(f\"`Click on index={row_index} x={x} y={y}`\")\n" + " solara.Markdown(f\"`Click on index={row_index} x={x} y={y}`\")" ] }, { @@ -373,8 +374,8 @@ "\n", "def find_nearest_neighbours(df, xcol, ycol, x, y, n=10):\n", " df = df.copy()\n", - " df[\"distance\"] = ((df[xcol] - x)**2 + (df[ycol] - y)**2)**0.5\n", - " return df.sort_values('distance')[1:n+1]\n", + " df[\"distance\"] = ((df[xcol] - x) ** 2 + (df[ycol] - y) ** 2) ** 0.5\n", + " return df.sort_values(\"distance\")[1 : n + 1]\n", "\n", "\n", "@solara.component\n", @@ -385,13 +386,12 @@ " x = click_data.value[\"points\"][\"xs\"][0]\n", " y = click_data.value[\"points\"][\"ys\"][0]\n", "\n", - " # add an indicator \n", + " # add an indicator\n", " fig.add_trace(px.scatter(x=[x], y=[y], text=[\"⭐️\"]).data[0])\n", " df_nearest = find_nearest_neighbours(df, x_axis.value, y_axis.value, x, y, n=3)\n", " else:\n", " df_nearest = None\n", "\n", - "\n", " solara.FigurePlotly(fig, on_click=click_data.set)\n", " solara.Select(label=\"X-axis\", value=x_axis, values=columns)\n", " solara.Select(label=\"Y-axis\", value=y_axis, values=columns)\n", diff --git a/solara/website/pages/documentation/getting_started/content/04-tutorials/_jupyter_dashboard_1.ipynb b/solara/website/pages/documentation/getting_started/content/04-tutorials/_jupyter_dashboard_1.ipynb index 8483ab6bd..46c0fb955 100644 --- a/solara/website/pages/documentation/getting_started/content/04-tutorials/_jupyter_dashboard_1.ipynb +++ b/solara/website/pages/documentation/getting_started/content/04-tutorials/_jupyter_dashboard_1.ipynb @@ -348,8 +348,8 @@ "from pathlib import Path\n", "import solara\n", "\n", - "ROOT = Path(solara.__file__).parent / 'website' / 'pages' / 'docs' / 'content' / '04-tutorial'\n", - "path = ROOT / Path('SF_crime_sample.csv.gz')\n", + "ROOT = Path(solara.__file__).parent / \"website\" / \"pages\" / \"docs\" / \"content\" / \"04-tutorial\"\n", + "path = ROOT / Path(\"SF_crime_sample.csv.gz\")\n", "url = \"https://raw.githubusercontent.com/widgetti/solara/master/solara/website/pages/docs/content/04-tutorial/SF_crime_sample.csv\"\n", "\n", "if path.exists():\n", @@ -357,7 +357,7 @@ "else:\n", " df_crime = pd.read_csv(url)\n", "\n", - "df_crime\n" + "df_crime" ] }, { @@ -666,9 +666,9 @@ } ], "source": [ - "df_crime['Category'] = df_crime['Category'].str.title()\n", - "df_crime['PdDistrict'] = df_crime['PdDistrict'].str.title()\n", - "df_crime\n" + "df_crime[\"Category\"] = df_crime[\"Category\"].str.title()\n", + "df_crime[\"PdDistrict\"] = df_crime[\"PdDistrict\"].str.title()\n", + "df_crime" ] }, { @@ -687,12 +687,12 @@ "outputs": [], "source": [ "def crime_filter(df, district_values, category_values):\n", - " df_dist = df.loc[df['PdDistrict'].isin(district_values)]\n", - " df_category = df_dist.loc[df_dist['Category'].isin(category_values)]\n", + " df_dist = df.loc[df[\"PdDistrict\"].isin(district_values)]\n", + " df_category = df_dist.loc[df_dist[\"Category\"].isin(category_values)]\n", " return df_category\n", "\n", "\n", - "dff_crime = crime_filter(df_crime, ['Bayview', 'Northern'], ['Vandalism', 'Assault', 'Robbery'])\n" + "dff_crime = crime_filter(df_crime, [\"Bayview\", \"Northern\"], [\"Vandalism\", \"Assault\", \"Robbery\"])" ] }, { @@ -723,24 +723,26 @@ "source": [ "import matplotlib.pyplot as plt\n", "\n", + "\n", "def crime_charts(df):\n", - " cat_unique = df['Category'].value_counts()\n", + " cat_unique = df[\"Category\"].value_counts()\n", " cat_unique = cat_unique.reset_index()\n", - " \n", - " dist_unique = df['PdDistrict'].value_counts()\n", + "\n", + " dist_unique = df[\"PdDistrict\"].value_counts()\n", " dist_unique = dist_unique.reset_index()\n", - " \n", - " fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(20,10))\n", "\n", - " ax1.bar(cat_unique['Category'], cat_unique['count'])\n", - " ax1.set_title('Amount of Criminal Case Based on Category')\n", - " ax2.bar(dist_unique['PdDistrict'], dist_unique['count'])\n", - " ax2.set_title('Amount of Criminal Case in Selected District')\n", + " fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(20, 10))\n", + "\n", + " ax1.bar(cat_unique[\"Category\"], cat_unique[\"count\"])\n", + " ax1.set_title(\"Amount of Criminal Case Based on Category\")\n", + " ax2.bar(dist_unique[\"PdDistrict\"], dist_unique[\"count\"])\n", + " ax2.set_title(\"Amount of Criminal Case in Selected District\")\n", "\n", " display(fig)\n", " plt.close(fig)\n", "\n", - "crime_charts(dff_crime)\n" + "\n", + "crime_charts(dff_crime)" ] }, { @@ -767,22 +769,28 @@ "def crime_map(df):\n", " latitude = 37.77\n", " longitude = -122.42\n", - " \n", + "\n", " sanfran_map = folium.Map(location=[latitude, longitude], zoom_start=12)\n", "\n", " incidents = folium.plugins.MarkerCluster().add_to(sanfran_map)\n", "\n", " # loop through the dataframe and add each data point to the mark cluster\n", - " for lat, lng, label, in zip(df.Y, df.X, df.Category):\n", + " for (\n", + " lat,\n", + " lng,\n", + " label,\n", + " ) in zip(df.Y, df.X, df.Category):\n", " folium.Marker(\n", - " location=[lat, lng],\n", - " icon=None,\n", - " popup=label,\n", + " location=[lat, lng],\n", + " icon=None,\n", + " popup=label,\n", " ).add_to(incidents)\n", - " \n", + "\n", " # show map\n", " display(sanfran_map)\n", - "crime_map(dff_crime.iloc[0:50, :])\n" + "\n", + "\n", + "crime_map(dff_crime.iloc[0:50, :])" ] }, { @@ -805,9 +813,12 @@ "outputs": [], "source": [ "import solara\n", - "districts = solara.reactive(['Bayview', 'Northern'],)\n", - "categories = solara.reactive(['Vandalism', 'Assault', 'Robbery'])\n", - "limit = solara.reactive(100)\n" + "\n", + "districts = solara.reactive(\n", + " [\"Bayview\", \"Northern\"],\n", + ")\n", + "categories = solara.reactive([\"Vandalism\", \"Assault\", \"Robbery\"])\n", + "limit = solara.reactive(100)" ] }, { @@ -833,12 +844,14 @@ " row_count = len(dff)\n", " if row_count > limit.value:\n", " solara.Warning(f\"Only showing the first {limit.value} of {row_count:,} crimes on map\")\n", - " crime_map(dff.iloc[:limit.value])\n", + " crime_map(dff.iloc[: limit.value])\n", " if row_count > 0:\n", " crime_charts(dff)\n", " else:\n", " solara.Warning(\"You filtered out all the data, no charts shown\")\n", - "View()\n" + "\n", + "\n", + "View()" ] }, { @@ -857,7 +870,7 @@ "outputs": [], "source": [ "limit.value = 70\n", - "districts.value = ['Soutern', 'Northern']\n" + "districts.value = [\"Soutern\", \"Northern\"]" ] }, { @@ -885,7 +898,7 @@ "metadata": {}, "outputs": [], "source": [ - "solara.SelectMultiple('District', all_values=[str(k) for k in df_crime['PdDistrict'].unique().tolist()], values=districts)\n" + "solara.SelectMultiple(\"District\", all_values=[str(k) for k in df_crime[\"PdDistrict\"].unique().tolist()], values=districts)" ] }, { @@ -907,11 +920,13 @@ "source": [ "@solara.component\n", "def Controls():\n", - " solara.SelectMultiple('District', all_values=[str(k) for k in df_crime['PdDistrict'].unique().tolist()], values=districts)\n", - " solara.SelectMultiple('Category', all_values=[str(k) for k in df_crime['Category'].unique().tolist()], values=categories)\n", + " solara.SelectMultiple(\"District\", all_values=[str(k) for k in df_crime[\"PdDistrict\"].unique().tolist()], values=districts)\n", + " solara.SelectMultiple(\"Category\", all_values=[str(k) for k in df_crime[\"Category\"].unique().tolist()], values=categories)\n", " solara.Text(\"Maximum number of rows to show on map\")\n", - " solara.SliderInt('', value=limit, min=1, max=1000)\n", - "Controls()\n" + " solara.SliderInt(\"\", value=limit, min=1, max=1000)\n", + "\n", + "\n", + "Controls()" ] }, { @@ -930,7 +945,7 @@ "outputs": [], "source": [ "# Note that we can read AND write reactive variables\n", - "categories.value = [*categories.value, 'Warrants']\n" + "categories.value = [*categories.value, \"Warrants\"]" ] }, { @@ -957,7 +972,9 @@ " with solara.Sidebar():\n", " Controls()\n", " View()\n", - "Page()\n" + "\n", + "\n", + "Page()" ] }, { diff --git a/tests/unit/solara_test_apps/multipage-widgets/04-color.ipynb b/tests/unit/solara_test_apps/multipage-widgets/04-color.ipynb index 4cca57a88..d94e4b4fd 100644 --- a/tests/unit/solara_test_apps/multipage-widgets/04-color.ipynb +++ b/tests/unit/solara_test_apps/multipage-widgets/04-color.ipynb @@ -10,8 +10,12 @@ "\n", "color = widgets.ColorPicker(value=\"red\", description=\"Pick a color\")\n", "info = widgets.HTML(value=\"Pick a color \")\n", + "\n", + "\n", "def on_color_change(change):\n", - " info.value = f\" You picked {change.new}\"\n", + " info.value = f' You picked {change.new}'\n", + "\n", + "\n", "color.observe(on_color_change, names=\"value\")\n", "page = widgets.VBox([color, info])\n", "page" diff --git a/tests/unit/solara_test_apps/multipage/05-and-notebooks.ipynb b/tests/unit/solara_test_apps/multipage/05-and-notebooks.ipynb index 3a955c2c8..5596e4425 100644 --- a/tests/unit/solara_test_apps/multipage/05-and-notebooks.ipynb +++ b/tests/unit/solara_test_apps/multipage/05-and-notebooks.ipynb @@ -9,6 +9,7 @@ "import reacton.ipyvuetify as v\n", "import solara\n", "\n", + "\n", "@solara.component\n", "def Page():\n", " return v.Slider(label=\"Language\")" diff --git a/tests/unit/solara_test_apps/notebookapp_component.ipynb b/tests/unit/solara_test_apps/notebookapp_component.ipynb index e0acf8bb0..eb2f97e5d 100644 --- a/tests/unit/solara_test_apps/notebookapp_component.ipynb +++ b/tests/unit/solara_test_apps/notebookapp_component.ipynb @@ -8,6 +8,7 @@ "source": [ "import solara\n", "\n", + "\n", "@solara.component\n", "def Page():\n", " return solara.Button(\"Click me\")"