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\")"