Fix type on dashboard source
Some checks failed
/ test (push) Failing after 27s

This commit is contained in:
phil 2024-12-15 18:29:37 +01:00
parent 9af30d582f
commit a94d27db0c

View file

@ -4,6 +4,7 @@ from pathlib import Path
from datetime import datetime from datetime import datetime
import logging import logging
from typing import Any from typing import Any
# from typing import Any # from typing import Any
from matplotlib.figure import Figure from matplotlib.figure import Figure
@ -22,9 +23,8 @@ import matplotlib.pyplot as plt
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
class DashboardPageSource(Model, table=True): class DashboardPageSource(Model, table=True):
__tablename__ = 'dashboard_page_source' # type: ignore __tablename__ = "dashboard_page_source" # type: ignore
__table_args__ = gisaf.table_args __table_args__ = gisaf.table_args
id: str = Field(primary_key=True) id: str = Field(primary_key=True)
@ -36,10 +36,11 @@ class DashboardPageCommon(Model):
Base class for DashboardPage and DashboardPageSection, where some methods Base class for DashboardPage and DashboardPageSection, where some methods
are common, eg. attachments are common, eg. attachments
""" """
name: str name: str
df: bytes | None = None df: bytes | None = None
plot: bytes | None = None plot: bytes | None = None
#plot: dict[str, Any] | None = Field(sa_type=JSON(none_as_null=True)) # type: ignore # plot: dict[str, Any] | None = Field(sa_type=JSON(none_as_null=True)) # type: ignore
attachment: str | None = None attachment: str | None = None
html: str | None = None html: str | None = None
@ -55,7 +56,7 @@ class DashboardPageCommon(Model):
def get_plot_file_name(self): def get_plot_file_name(self):
raise NotImplementedError() raise NotImplementedError()
def save_plot(self, plot: plt.Axes | plt.Figure): # type: ignore def save_plot(self, plot: plt.Axes | plt.Figure): # type: ignore
""" """
Render the matplotlib plot (or figure) and save it in the filesystem Render the matplotlib plot (or figure) and save it in the filesystem
:param plot: matplotlib plot or figure... :param plot: matplotlib plot or figure...
@ -65,20 +66,20 @@ class DashboardPageCommon(Model):
## Different types of figures supported ## Different types of figures supported
fig: Figure | None = None fig: Figure | None = None
if isinstance(plot, plt.Axes): # type: ignore if isinstance(plot, plt.Axes): # type: ignore
fig = plot.figure # type: ignore fig = plot.figure # type: ignore
elif isinstance(plot, plt.Figure): # type: ignore elif isinstance(plot, plt.Figure): # type: ignore
fig = plot fig = plot
if fig: if fig:
fig.savefig(self.get_plot_file_path(), bbox_inches='tight') fig.savefig(self.get_plot_file_path(), bbox_inches="tight")
plt.close(fig) plt.close(fig)
if plot and not fig: if plot and not fig:
logger.warning('Cannot save dashboard attachment (unknown attachment type)') logger.warning("Cannot save dashboard attachment (unknown attachment type)")
return return
#logger.info(f'Saved attachment of dashboard page {self.group}/{self.name} ' # logger.info(f'Saved attachment of dashboard page {self.group}/{self.name} '
#f'in {self.get_attachment_file_name()}') # f'in {self.get_attachment_file_name()}')
return self.get_plot_file_name() return self.get_plot_file_name()
def save_attachment(self, attached, name=None) -> str | None: def save_attachment(self, attached, name=None) -> str | None:
@ -89,27 +90,27 @@ class DashboardPageCommon(Model):
""" """
if not self.attachment: if not self.attachment:
## Not set yet (creation) ## Not set yet (creation)
self.attachment = f'{self.name}.png' self.attachment = f"{self.name}.png"
self.ensure_dir_exists() self.ensure_dir_exists()
## Different types of figures supported ## Different types of figures supported
fig: Figure | None = None fig: Figure | None = None
if plt: if plt:
if isinstance(attached, plt.Axes): # type: ignore if isinstance(attached, plt.Axes): # type: ignore
fig = attached.figure # type: ignore fig = attached.figure # type: ignore
elif isinstance(attached, plt.Figure): # type: ignore elif isinstance(attached, plt.Figure): # type: ignore
fig = attached fig = attached
if fig: if fig:
fig.savefig(self.get_attachment_file_name(), bbox_inches='tight') fig.savefig(self.get_attachment_file_name(), bbox_inches="tight")
plt.close(fig) plt.close(fig)
if attached and not fig: if attached and not fig:
logger.warning('Cannot save dashboard attachment (unknown attachment type)') logger.warning("Cannot save dashboard attachment (unknown attachment type)")
return None return None
#logger.info(f'Saved attachment of dashboard page {self.group}/{self.name} ' # logger.info(f'Saved attachment of dashboard page {self.group}/{self.name} '
#f'in {self.get_attachment_file_name()}') # f'in {self.get_attachment_file_name()}')
return self.attachment return self.attachment
def get_page_df(self) -> pd.DataFrame | None: def get_page_df(self) -> pd.DataFrame | None:
@ -140,25 +141,25 @@ class DashboardPageMetaData(BaseModel):
class DashboardPage(DashboardPageCommon, DashboardPageMetaData, table=True): class DashboardPage(DashboardPageCommon, DashboardPageMetaData, table=True):
__tablename__ = 'dashboard_page' # type: ignore __tablename__ = "dashboard_page" # type: ignore
__table_args__ = gisaf.table_args __table_args__ = gisaf.table_args
class Admin: class Admin:
menu = 'Dashboard' menu = "Dashboard"
id: int = Field(primary_key=True) id: int = Field(primary_key=True)
time: datetime | None = Field(default_factory=datetime.now) time: datetime | None = Field(default_factory=datetime.now)
notebook: str | None = None notebook: str | None = None
source_id: int | None = Field(foreign_key=gisaf.table('dashboard_page_source.id')) source_id: str | None = Field(foreign_key=gisaf.table("dashboard_page_source.id"))
expanded_panes: str | None expanded_panes: str | None
source: DashboardPageSource = Relationship() source: DashboardPageSource = Relationship()
sections: list['DashboardPageSection'] = Relationship() sections: list["DashboardPageSection"] = Relationship()
def __str__(self): def __str__(self):
return f'{self.group:s}/{self.name:s}' return f"{self.group:s}/{self.name:s}"
def __repr__(self): def __repr__(self):
return f'<models.DashboardPage {self.group:s}/{self.name:s}>' return f"<models.DashboardPage {self.group:s}/{self.name:s}>"
@classmethod @classmethod
def selectinload(cls): def selectinload(cls):
@ -180,9 +181,11 @@ class DashboardPage(DashboardPageCommon, DashboardPageMetaData, table=True):
if self.attachment: if self.attachment:
base_dir = Path(conf.dashboard.base_storage_dir) base_dir = Path(conf.dashboard.base_storage_dir)
if base_dir: if base_dir:
return base_dir/self.group/self.attachment return base_dir / self.group / self.attachment
else: else:
raise UserWarning('Cannot save attachment: no notebook/base_storage_dir in gisaf config') raise UserWarning(
"Cannot save attachment: no notebook/base_storage_dir in gisaf config"
)
def get_attachment_url(self): def get_attachment_url(self):
## Serve through web front-end (nginx static file) ## Serve through web front-end (nginx static file)
@ -190,37 +193,37 @@ class DashboardPage(DashboardPageCommon, DashboardPageMetaData, table=True):
return return
base_storage_url = conf.dashboard.base_storage_url base_storage_url = conf.dashboard.base_storage_url
if not base_storage_url: if not base_storage_url:
base_storage_url = '/dashboard-attachment/' base_storage_url = "/dashboard-attachment/"
return f'{base_storage_url}{self.group}/{self.attachment}' return f"{base_storage_url}{self.group}/{self.attachment}"
def get_notebook_url(self): def get_notebook_url(self):
if self.notebook: if self.notebook:
base_url = conf.dashboard.base_source_url base_url = conf.dashboard.base_source_url
if base_url: if base_url:
return f'{base_url}{self.notebook}' return f"{base_url}{self.notebook}"
else: else:
logger.debug('Notebook: no base_url in gisaf config') logger.debug("Notebook: no base_url in gisaf config")
class DashboardPageSection(DashboardPageCommon, table=True): class DashboardPageSection(DashboardPageCommon, table=True):
__tablename__ = 'dashboard_page_section' # type: ignore __tablename__ = "dashboard_page_section" # type: ignore
__table_args__ = gisaf.table_args __table_args__ = gisaf.table_args
class Admin: class Admin:
menu = 'Dashboard' menu = "Dashboard"
id: str = Field(primary_key=True) id: str = Field(primary_key=True)
name: str name: str
dashboard_page_id: int = Field(foreign_key=gisaf.table('dashboard_page.id')) dashboard_page_id: int = Field(foreign_key=gisaf.table("dashboard_page.id"))
dashboard_page: DashboardPage = Relationship(back_populates='sections') dashboard_page: DashboardPage = Relationship(back_populates="sections")
description: str description: str
def __str__(self): def __str__(self):
return f'{self.name} for dashboard page #{self.dashboard_page_id}' return f"{self.name} for dashboard page #{self.dashboard_page_id}"
def __repr__(self): def __repr__(self):
return f'<models.DashboardPageSection #{self.id}>' return f"<models.DashboardPageSection #{self.id}>"
@classmethod @classmethod
def selectinload(cls): def selectinload(cls):
@ -230,16 +233,23 @@ class DashboardPageSection(DashboardPageCommon, table=True):
## Serve through web front-end (nginx static file) ## Serve through web front-end (nginx static file)
if not self.plot: if not self.plot:
return return
return conf.dashboard.base_storage_url \ return (
+ self.dashboard_page.group + '/' \ conf.dashboard.base_storage_url
+ self.dashboard_page.name + '/' \ + self.dashboard_page.group
+ self.name + '.png' + "/"
+ self.dashboard_page.name
+ "/"
+ self.name
+ ".png"
)
def ensure_dir_exists(self): def ensure_dir_exists(self):
""" """
Make sure the directory exists, before saving the file Make sure the directory exists, before saving the file
""" """
dir_name = Path(conf.dashboard.base_storage_dir) / self.page.group / self.page.name dir_name = (
Path(conf.dashboard.base_storage_dir) / self.page.group / self.page.name
)
dir_name.mkdir(exist_ok=True) dir_name.mkdir(exist_ok=True)
return dir_name return dir_name
@ -252,11 +262,13 @@ class DashboardPageSection(DashboardPageCommon, table=True):
return return
base_dir = Path(conf.dashboard.base_storage_dir) base_dir = Path(conf.dashboard.base_storage_dir)
if not base_dir: if not base_dir:
raise UserWarning('Cannot save attachment: no notebook/base_storage_dir in gisaf config') raise UserWarning(
return base_dir/self.page.group/self.page.name/self.attachment "Cannot save attachment: no notebook/base_storage_dir in gisaf config"
)
return base_dir / self.page.group / self.page.name / self.attachment
def get_plot_file_name(self): def get_plot_file_name(self):
return f'{self.name}.png' return f"{self.name}.png"
def get_plot_file_path(self): def get_plot_file_path(self):
""" """
@ -267,15 +279,17 @@ class DashboardPageSection(DashboardPageCommon, table=True):
return return
base_dir = Path(conf.dashboard.base_storage_dir) base_dir = Path(conf.dashboard.base_storage_dir)
if not base_dir: if not base_dir:
raise UserWarning('Cannot save attachment: no notebook/base_storage_dir in gisaf config') raise UserWarning(
return base_dir/self.page.group/self.page.name/self.get_plot_file_name() "Cannot save attachment: no notebook/base_storage_dir in gisaf config"
)
return base_dir / self.page.group / self.page.name / self.get_plot_file_name()
class Widget(Model, table=True): class Widget(Model, table=True):
__tablename__ = 'widget' # type: ignore __tablename__ = "widget" # type: ignore
__table_args__ = gisaf.table_args __table_args__ = gisaf.table_args
## CREATE TABLE gisaf.widget (name char(50) not null PRIMARY KEY, title varchar, subtitle varchar, notebook varchar, content varchar, time timestamp); ## CREATE TABLE gisaf.widget (name char(50) not null PRIMARY KEY, title varchar, subtitle varchar, notebook varchar, content varchar, time timestamp);
name: str = Field(primary_key=True, sa_type=String(50)) # type: ignore name: str = Field(primary_key=True, sa_type=String(50)) # type: ignore
title: str title: str
subtitle: str subtitle: str
content: str content: str
@ -283,7 +297,7 @@ class Widget(Model, table=True):
notebook: str | None = None notebook: str | None = None
class Admin: class Admin:
menu = 'Dashboard' menu = "Dashboard"
class DashboardSection(BaseModel): class DashboardSection(BaseModel):
@ -314,4 +328,5 @@ class DashboardGroup(BaseModel):
class DashboardHome(BaseModel): class DashboardHome(BaseModel):
title: str title: str
content: str content: str
footer: str footer: str