Release v1.0.3

This commit is contained in:
Oleg Sheynin
2026-07-29 01:01:08 +00:00
parent a3e5acd765
commit 9d553dcf1a
5 changed files with 34 additions and 8 deletions
+7
View File
@@ -6,6 +6,13 @@ All notable changes to this project are documented in this file.
No unreleased changes yet. No unreleased changes yet.
## 2026-07-29 v1.0.3
- Removed invalid fixed sizing mode from Panel Tabulator grids to avoid Bokeh
layout warnings while preserving compact table layout.
- Changed the Panel Calculate action to refresh the result-file list before
loading data and removed the standalone Panel Refresh button.
## 2026-07-29 v1.0.2 ## 2026-07-29 v1.0.2
- Added a Panel application for single-day SPBT result analysis with result-file - Added a Panel application for single-day SPBT result analysis with result-file
+6 -5
View File
@@ -45,7 +45,6 @@ class SpbtDayPanelApp:
value=str(self.repo_root / "data"), value=str(self.repo_root / "data"),
) )
self.show_all_files = pn.widgets.Checkbox(label="Show all files", value=False) self.show_all_files = pn.widgets.Checkbox(label="Show all files", value=False)
self.refresh_button = pn.widgets.Button(label="Refresh")
self.file_select = pn.widgets.Select( self.file_select = pn.widgets.Select(
label="SQLite result file", label="SQLite result file",
options={}, options={},
@@ -85,7 +84,6 @@ class SpbtDayPanelApp:
sizing_mode="stretch_width", sizing_mode="stretch_width",
) )
self.refresh_button.on_click(self.refresh_files)
self.calculate_button.on_click(self.calculate) self.calculate_button.on_click(self.calculate)
self.directory_input.param.watch(self.refresh_files, "value") self.directory_input.param.watch(self.refresh_files, "value")
self.show_all_files.param.watch(self.refresh_files, "value") self.show_all_files.param.watch(self.refresh_files, "value")
@@ -111,7 +109,7 @@ class SpbtDayPanelApp:
raise ValueError(f"Selected database path is not a file: {db_path}") raise ValueError(f"Selected database path is not a file: {db_path}")
return db_path return db_path
def refresh_files(self, *_events: Any) -> None: def refresh_files(self, *_events: Any) -> bool:
"""Refresh selectable SQLite files from the configured directory.""" """Refresh selectable SQLite files from the configured directory."""
try: try:
directory = spbt_day.normalize_directory( directory = spbt_day.normalize_directory(
@@ -126,7 +124,7 @@ class SpbtDayPanelApp:
self.file_select.options = {} self.file_select.options = {}
self.file_select.value = None self.file_select.value = None
self.set_status(str(exc), error=True) self.set_status(str(exc), error=True)
return return False
options = {path.name: str(path) for path in candidates} options = {path.name: str(path) for path in candidates}
previous_value = self.file_select.value previous_value = self.file_select.value
@@ -142,11 +140,14 @@ class SpbtDayPanelApp:
self.set_status(f"Found {len(options):,} file(s) in {directory}.") self.set_status(f"Found {len(options):,} file(s) in {directory}.")
else: else:
self.set_status(f"No selectable files found in {directory}.") self.set_status(f"No selectable files found in {directory}.")
return True
def calculate(self, *_events: Any) -> None: def calculate(self, *_events: Any) -> None:
"""Load selected data and calculate all-pair TheoRet.""" """Load selected data and calculate all-pair TheoRet."""
self.calculate_button.loading = True self.calculate_button.loading = True
try: try:
if not self.refresh_files():
return
db_path = self.selected_database_path() db_path = self.selected_database_path()
self.min_pctg_change = float(self.min_pctg_change_input.value) self.min_pctg_change = float(self.min_pctg_change_input.value)
@@ -260,7 +261,7 @@ class SpbtDayPanelApp:
"""Return the app layout.""" """Return the app layout."""
controls = pn.Column( controls = pn.Column(
"## Inputs", "## Inputs",
pn.Row(self.directory_input, self.refresh_button), self.directory_input,
self.show_all_files, self.show_all_files,
self.file_select, self.file_select,
self.min_pctg_change_input, self.min_pctg_change_input,
-2
View File
@@ -1137,7 +1137,6 @@ def create_pair_theo_ret_analyze_grid(
pagination=None, pagination=None,
layout="fit_data_table", layout="fit_data_table",
height=height, height=height,
sizing_mode="fixed",
selectable=False, selectable=False,
) )
@@ -1161,7 +1160,6 @@ def create_selected_pair_executions_grid(
pagination=None, pagination=None,
layout="fit_data_table", layout="fit_data_table",
height=height, height=height,
sizing_mode="fixed",
selectable=False, selectable=False,
) )
+1 -1
View File
@@ -1023,7 +1023,7 @@ def test_create_panel_grids_use_analyze_button_and_hidden_pair_column():
assert pair_grid.disabled is False assert pair_grid.disabled is False
assert pair_grid.pagination is None assert pair_grid.pagination is None
assert pair_grid.layout == "fit_data_table" assert pair_grid.layout == "fit_data_table"
assert pair_grid.sizing_mode == "fixed" assert pair_grid.sizing_mode is None
assert executions_grid.value.columns.tolist() == [ assert executions_grid.value.columns.tolist() == [
"time", "time",
"asset", "asset",
+20
View File
@@ -166,6 +166,7 @@ def test_panel_app_uses_fast_list_template(tmp_path):
app = module.SpbtDayPanelApp(repo_root=tmp_path) app = module.SpbtDayPanelApp(repo_root=tmp_path)
view = app.view view = app.view
assert not hasattr(app, "refresh_button")
assert isinstance(view, module.pn.template.FastListTemplate) assert isinstance(view, module.pn.template.FastListTemplate)
assert view.title == module.APP_TITLE assert view.title == module.APP_TITLE
assert view.sidebar_width == 430 assert view.sidebar_width == 430
@@ -216,3 +217,22 @@ def test_panel_app_calculates_pairs_and_selected_pair_outputs(tmp_path):
"CLOSE", "CLOSE",
] ]
assert app.selected_pair_market_plot.object is not None assert app.selected_pair_market_plot.object is not None
def test_calculate_refreshes_file_list_before_loading(tmp_path):
module = load_panel_app_module()
data_dir = tmp_path / "data"
data_dir.mkdir()
app = module.SpbtDayPanelApp(repo_root=tmp_path)
app.directory_input.value = str(data_dir)
app.refresh_files()
assert app.file_select.value is None
db_path = data_dir / "20260617.spbt_results.db"
create_panel_fixture_db(db_path)
app.calculate()
assert app.file_select.value == str(db_path)
assert app.pair_theo_ret_table.value["pair_name"].tolist() == ["AAA-BBB"]