scilens 0.3.8__py3-none-any.whl → 0.3.10__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,3 +1,4 @@
1
+ _A=None
1
2
  import logging,os,shutil,stat,subprocess,platform,tempfile,zipfile
2
3
  from scilens.config.models import ExecuteConfig
3
4
  from scilens.utils.file import dir_remove,dir_create
@@ -27,30 +28,36 @@ def find_command(command_path,working_dirs,guess_os_extension=False):
27
28
  B=os.path.join(E,F)
28
29
  if os.path.exists(B):return B
29
30
  class Executor:
30
- def __init__(A,absolute_working_dir,config,alternative_working_dir=None):
31
- D=alternative_working_dir;C=absolute_working_dir;B=config;A.config=B;A.working_dir=C;A.dirs=[C]+([D]if D else[]);A.command_path=None;A.temp_dir=None
31
+ def __init__(A,absolute_working_dir,config,config_file_path=_A,alternative_working_dir=_A):
32
+ D=alternative_working_dir;C=absolute_working_dir;B=config;A.config=B;A.config_file_path=config_file_path;A.working_dir=C;A.dirs=[C]+([D]if D else[]);A.command_path=_A;A.temp_dir=_A
32
33
  if not bool(B.exe_url)+bool(B.exe_url)!=1:raise Exception('exe_url and exe_path are mutually exclusive.')
33
34
  if not os.path.exists(A.working_dir):logging.info(f"Creating working directory {A.working_dir}");dir_create(A.working_dir)
34
35
  def __enter__(A):return A
35
36
  def __exit__(A,exc_type,exc_value,traceback):A._cleanup()
36
37
  def _cleanup(A):0
37
38
  def _pre_operations(A):
38
- logging.info(f"Execute - Pre Operations");logging.info(f"Folders deletion")
39
- for dir in A.config.pre_folder_delete or[]:dir_remove(os.path.join(A.working_dir,dir))
39
+ D=A.working_dir;logging.info(f"Execute - Pre Operations")
40
+ if A.config.pre_files_delete:
41
+ logging.info(f"Files deletion")
42
+ for F in os.listdir(D):
43
+ E=os.path.join(D,F)
44
+ if not F.startswith('.')and not os.path.isdir(E)and E!=A.config_file_path:logging.debug(f"Delete file {E}");os.remove(E)
45
+ logging.info(f"Folders deletion")
46
+ for dir in A.config.pre_folder_delete or[]:dir_remove(os.path.join(D,dir))
40
47
  logging.info(f"Folders creation")
41
- for dir in A.config.pre_folder_creation or[]:dir_create(os.path.join(A.working_dir,dir))
48
+ for dir in A.config.pre_folder_creation or[]:dir_create(os.path.join(D,dir))
42
49
  if A.config.exe_url or A.config.exe_path:
43
50
  logging.info(f"Executable file preparation")
44
51
  if A.config.exe_url:
45
- logging.info(f"Download executable {A.config.exe_url}");A.temp_dir=tempfile.mkdtemp();E='executable';B=os.path.join(A.temp_dir,E)
52
+ logging.info(f"Download executable {A.config.exe_url}");A.temp_dir=tempfile.mkdtemp();H='executable';B=os.path.join(A.temp_dir,H)
46
53
  try:Web().download_progress(A.config.exe_url,B,headers=A.config.exe_url_headers,callback100=lambda percentage:logging.info(f"Downloaded {percentage}%"))
47
- except Exception as F:raise ValueError(f"Error downloading executable: {F}")
54
+ except Exception as I:raise ValueError(f"Error downloading executable: {I}")
48
55
  logging.info(f"Download completed")
49
56
  elif A.config.exe_path:B=A.config.exe_path
50
- if A.config.exe_unzip_and_use:logging.info(f"Unzip archive");D=os.path.dirname(B);unzip_file(B,D);B=os.path.join(D,A.config.exe_unzip_and_use);logging.info(f"Unzip completed")
57
+ if A.config.exe_unzip_and_use:logging.info(f"Unzip archive");G=os.path.dirname(B);unzip_file(B,G);B=os.path.join(G,A.config.exe_unzip_and_use);logging.info(f"Unzip completed")
51
58
  C=find_command(B,A.dirs,guess_os_extension=A.config.exe_guess_os_extension)
52
59
  if not C:raise FileNotFoundError(f"Command not found: {B}")
53
- logging.info(f"Command path resolved: {C}");logging.info(f"Add executable permissions");G=os.stat(C).st_mode;os.chmod(C,G|stat.S_IXUSR|stat.S_IXGRP|stat.S_IXOTH)
60
+ logging.info(f"Command path resolved: {C}");logging.info(f"Add executable permissions");J=os.stat(C).st_mode;os.chmod(C,J|stat.S_IXUSR|stat.S_IXGRP|stat.S_IXOTH)
54
61
  elif A.config.exe_command:logging.info(f"Command path: {A.config.exe_command}");C=A.config.exe_command
55
62
  A.command_path=C
56
63
  def _post_operations(A):logging.info(f"Execute - Post Operations")
scilens/config/load.py CHANGED
@@ -2,7 +2,7 @@ import logging,os,json,yaml
2
2
  from pydantic import BaseModel
3
3
  from scilens.config.models import AppConfig
4
4
  from scilens.config.env_var import get_vars
5
- from scilens.utils.dict import dict_path_set,dict_path_get
5
+ from scilens.utils.dict import dict_path_set,dict_path_get,dict_update_rec
6
6
  PATH_ENV_VARS_VALUES={}
7
7
  def env_vars_load():
8
8
  B=get_vars()
@@ -25,7 +25,7 @@ def config_load(config,options_path_value=None,config_override=None):
25
25
  try:I=yaml.safe_load(G)
26
26
  except yaml.YAMLError as D:raise Exception(f"Error in configuration file {B}: {D}")
27
27
  elif isinstance(A,dict):I=B
28
- C.update(I)
28
+ dict_update_rec(C,I)
29
29
  for(E,H)in PATH_ENV_VARS_VALUES.items():
30
30
  if not dict_path_get(C,E):dict_path_set(C,E,H)
31
31
  if F:
@@ -0,0 +1,11 @@
1
+ import types,pydantic
2
+ class StrOrPath(str):
3
+ @classmethod
4
+ def __get_pydantic_core_schema__(A,source_type,handler):return handler(str)
5
+ def __repr__(A):return f"{A.__class__.__name__}({super().__repr__()})"
6
+ def is_StrOrPath_and_path(value,field_info):
7
+ D=False;B=field_info;A=value;C='file://'
8
+ if not isinstance(A,str):return D,''
9
+ if B.annotation==StrOrPath or isinstance(B.annotation,types.UnionType)and StrOrPath in B.annotation.__args__:
10
+ if A.startswith(C):return True,A[len(C):]
11
+ return D,''
@@ -1,3 +1,3 @@
1
1
  _A=None
2
2
  from pydantic import BaseModel,Field
3
- class ExecuteConfig(BaseModel):pre_folder_delete:list[str]|_A=Field(default=_A,description='Liste de répertoire à supprimer avant l\'éxecution. Ex: `["DEBUG", "LOG", "OUT"]`');pre_folder_creation:list[str]|_A=Field(default=_A,description='Liste de répertoire à créeravant l\'éxecution. Ex : `["INI", "DAT"]`');exe_path:str|_A=Field(default=_A,description="Chemin de l'exécutable. Ex : `/absolute/path/executable` or `relative/path/executable`. Dans le cas, d'un chemin relatif, il testera le `working directory` et le `origin working directory` (exclusif avec `exe_url` et `exe_command`).");exe_url:str|_A=Field(default=_A,description="Url de l'exécutable à télécharger avant de l'exécuter. Ex : `https://github.com/org/app/releases/download/v3.31.5/app-2.12.2-linux-x86-64` (exclusif avec `exe_path` et `exe_command`).");exe_command:str|_A=Field(default=_A,description='Commande à exécuter sans résolution de chemin. Ex : `./app-2.12.2-linux-x86-64` ou `python3 app.py` (exclusif avec `exe_path` et `exe_url`).');exe_url_headers:dict[str,str]|_A=Field(default=_A,description='Si `exe_url` les en-têtes à ajouter à la requête de téléchargement de l\'exécutable. Ex : `{"Authorization": "Bearer token"}`');exe_unzip_and_use:str|_A=Field(default=_A,description="Si l'exécutable (`exe_path` ou `exe_url`) est zippé, alors décompresse et utilise le fichier spécifié. Ex : `app-2.12.2-linux-x86-64`");exe_guess_os_extension:bool=Field(default=False,description="Si l'exécutable (`exe_path` ou `exe_url`) n'est pas trouvée, cherche avec des extensions en fonction de l'OS. Ex : `.exe`, `.bat` pour windows");command_suffix:str|_A=Field(default=_A,description='Suffixe à ajouter à la commande. Typiquemnt des secrets. Ex : ` --token DGDFGDFGDH`');working_dir:str|_A=Field(default=_A,description="Chemin relatif du répertoire de travail pour l'éxecution de la commande. Dans le contexte processeur `ExecuteAndCompare` si non défini, récupère respectivement la valeur de `compare.sources.test_folder_relative_path` ou `compare.sources.reference_folder_relative_path`")
3
+ class ExecuteConfig(BaseModel):pre_files_delete:bool=Field(default=False,description="Si `true`, supprime les fichiers avant l'éxecution. (le fichier de configuration et les fichiers . ne seront pas supprimés)");pre_folder_delete:list[str]|_A=Field(default=_A,description='Liste de répertoire à supprimer avant l\'éxecution. Ex: `["DEBUG", "LOG", "OUT"]`');pre_folder_creation:list[str]|_A=Field(default=_A,description='Liste de répertoire à créeravant l\'éxecution. Ex : `["INI", "DAT"]`');exe_path:str|_A=Field(default=_A,description="Chemin de l'exécutable. Ex : `/absolute/path/executable` or `relative/path/executable`. Dans le cas, d'un chemin relatif, il testera le `working directory` et le `origin working directory` (exclusif avec `exe_url` et `exe_command`).");exe_url:str|_A=Field(default=_A,description="Url de l'exécutable à télécharger avant de l'exécuter. Ex : `https://github.com/org/app/releases/download/v3.31.5/app-2.12.2-linux-x86-64` (exclusif avec `exe_path` et `exe_command`).");exe_command:str|_A=Field(default=_A,description='Commande à exécuter sans résolution de chemin. Ex : `./app-2.12.2-linux-x86-64` ou `python3 app.py` (exclusif avec `exe_path` et `exe_url`).');exe_url_headers:dict[str,str]|_A=Field(default=_A,description='Si `exe_url` les en-têtes à ajouter à la requête de téléchargement de l\'exécutable. Ex : `{"Authorization": "Bearer token"}`');exe_unzip_and_use:str|_A=Field(default=_A,description="Si l'exécutable (`exe_path` ou `exe_url`) est zippé, alors décompresse et utilise le fichier spécifié. Ex : `app-2.12.2-linux-x86-64`");exe_guess_os_extension:bool=Field(default=False,description="Si l'exécutable (`exe_path` ou `exe_url`) n'est pas trouvée, cherche avec des extensions en fonction de l'OS. Ex : `.exe`, `.bat` pour windows");command_suffix:str|_A=Field(default=_A,description='Suffixe à ajouter à la commande. Typiquemnt des secrets. Ex : ` --token DGDFGDFGDH`');working_dir:str|_A=Field(default=_A,description="Chemin relatif du répertoire de travail pour l'éxecution de la commande. Dans le contexte processeur `ExecuteAndCompare` si non défini, récupère respectivement la valeur de `compare.sources.test_folder_relative_path` ou `compare.sources.reference_folder_relative_path`")
@@ -2,5 +2,5 @@ _B=False
2
2
  _A=None
3
3
  from pydantic import BaseModel,Field
4
4
  from scilens.config.models.reader_format_cols_curve import ReaderColsCurveParserConfig
5
- class ReaderCsvMatrixConfig(BaseModel):x_value_line:int|_A=Field(default=_A,description="Indique la ligne des valeurs x si applicable. Peut être la ligne d'en-tête (=1).");has_y:bool=Field(default=_B,description='Indique si la première colonne est la colonne des valeurs y.');display_spectrogram:bool=Field(default=_B,description='Indique si la matrice doit être affichée en mode spectrogramme.');display_frameseries:bool=Field(default=_B,description='Indique si la matrice doit être affichée en mode frameseries.')
6
- class ReaderCsvConfig(BaseModel):delimiter:str|_A=Field(default=',',description='Délimiteur de colonnes.');quotechar:str|_A=Field(default='"',description='Délimiteur de texte.');has_header:bool|_A=Field(default=_A,description="Indique si la 1ère ligne est une ligne d'en-tête. Si non spécifié, il y aura une détection automatique.");is_matrix:bool=Field(default=_B,description='Indique si le fichier est une matrice.');ignore_columns:list[str]|_A=Field(default=_A,description='Liste des noms des colonnes à ignorer. (Valide seulement si la première ligne est une ligne en-têtes et non matrice)');curve_parser:ReaderColsCurveParserConfig|_A=Field(default=_A,description='Parseur de courbe à utiliser.');matrix:ReaderCsvMatrixConfig|_A=Field(default=_A,description='Configuration de la matrice. (Valide seulement si `is_matrix` est vrai)')
5
+ class ReaderCsvMatrixConfig(BaseModel):x_value_line:int|_A=Field(default=_A,description="Indique la ligne des valeurs x si applicable. Peut être la ligne d'en-tête (=1).");has_y:bool=Field(default=_B,description='Indique si la première colonne est la colonne des valeurs y.');x_name:str=Field(default='X',description='Nom de la colonne des valeurs x.');y_name:str=Field(default='Y',description='Nom de la colonne des valeurs y.');export_report:bool=Field(default=_B,description='Indique si les matrices doivent être exportées dans les rapports.')
6
+ class ReaderCsvConfig(BaseModel):delimiter:str|_A=Field(default=',',description='Délimiteur de colonnes.');quotechar:str|_A=Field(default='"',description='Délimiteur de texte.');has_header:bool|_A=Field(default=_A,description="Indique si la 1ère ligne est une ligne d'en-tête. Si non spécifié, il y aura une détection automatique.");is_matrix:bool=Field(default=_B,description='Indique si le fichier est une matrice.');ignore_columns:list[str]|_A=Field(default=_A,description='Liste des noms des colonnes à ignorer. (Valide seulement si la première ligne est une ligne en-têtes et non matrice)');curve_parser:ReaderColsCurveParserConfig|_A=Field(default=_A,description='Parseur de courbe à utiliser.');ignore_lines_patterns:list[str]|_A=Field(default=_A,description='Liste des patterns de lignes à ignorer. Ex: ["^#", "^//"]. Non applicable si `is_matrix` est vrai.');matrix:ReaderCsvMatrixConfig|_A=Field(default=_A,description='Configuration de la matrice. (Valide seulement si `is_matrix` est vrai)')
@@ -1,4 +1,4 @@
1
1
  _A=None
2
2
  from pydantic import BaseModel,Field
3
3
  from scilens.config.models.reader_format_cols_curve import ReaderColsCurveParserConfig
4
- class ReaderTxtFixedColsConfig(BaseModel):ignore_lines_patterns:list[str]|_A=Field(default=_A,description='Liste des patterns de lignes à ignorer. Ex: ["^#", "^//"].');has_header:bool=Field(default=False,description="Indique si le dataset contient une ligne d'entête.");has_header_repetition:bool=Field(default=False,description="Indique si l'entête est répétée (pagination).");has_header_ignore:list[str]|_A=Field(default=_A,description="Chaînes de caractères à ignorer dans la ligne d'entête. eex: ['##', '|'].");column_widths:list[int]|_A=Field(default=_A,description='Liste des largeurs de colonnes. Ex: [9, 13, 12]. Exclusif avec `column_indexes`.');column_indexes:list[list[int]]|_A=Field(default=_A,description='Liste des index de début et fin de colonnes. Ex: [[0, 8], [9, 12], [13, 28]]. Exclusif avec `column_widths`.');curve_parser:ReaderColsCurveParserConfig|_A=Field(default=_A,description='Parseur de courbe à utiliser.')
4
+ class ReaderTxtFixedColsConfig(BaseModel):ignore_lines_patterns:list[str]|_A=Field(default=_A,description='Liste des patterns de lignes à ignorer. Ex: ["^#", "^//"].');has_header:bool=Field(default=False,description="Indique si le dataset contient une ligne d'entête.");has_header_line:int|_A=Field(default=_A,description="Numéro de la ligne d'entête. Si None, la première ligne non ignorée est considérée comme l'entête.");has_header_ignore:list[str]|_A=Field(default=_A,description="Chaînes de caractères à ignorer dans la ligne d'entête. eex: ['##', '|'].");column_widths:list[int]|_A=Field(default=_A,description='Liste des largeurs de colonnes. Ex: [9, 13, 12]. Exclusif avec `column_indexes`.');column_indexes:list[tuple[int,int]]|_A=Field(default=_A,description='Liste des index de début et fin de colonnes. Ex: [[0, 8], [9, 12], [13, 28]]. Exclusif avec `column_widths`.');curve_parser:ReaderColsCurveParserConfig|_A=Field(default=_A,description='Parseur de courbe à utiliser.')
@@ -1,17 +1,13 @@
1
- _B='netcdf'
2
- _A='txt_fixed_cols'
3
1
  from typing import Literal
4
- from pydantic import BaseModel,Field,model_validator
2
+ from pydantic import BaseModel,Field
5
3
  from scilens.config.models.reader_format_txt import ReaderTxtConfig
6
4
  from scilens.config.models.reader_format_csv import ReaderCsvConfig
7
5
  from scilens.config.models.reader_format_txt_fixed_cols import ReaderTxtFixedColsConfig
8
6
  from scilens.config.models.reader_format_netcdf import ReaderNetcdfConfig
9
- TYPE_PARAMETERS_CLASS={'txt':ReaderTxtConfig,'csv':ReaderCsvConfig,_A:ReaderTxtFixedColsConfig,_B:ReaderNetcdfConfig}
10
- class ReaderConfig(BaseModel):
11
- type:Literal['txt','csv',_A,_B]=Field(description='Type du reader. Les paramètres `parameters` dépendent de ce type.');parameters:ReaderTxtConfig|ReaderCsvConfig|ReaderTxtFixedColsConfig|ReaderNetcdfConfig=Field(description='Paramètres du reader')
12
- @model_validator(mode='after')
13
- def validate_model(cls,model):
14
- A=model
15
- if not isinstance(A.parameters,TYPE_PARAMETERS_CLASS[A.type]):raise ValueError(f"Reader Type {A.type} Parameters are not correct")
16
- return A
17
- class ReadersConfig(BaseModel):txt:ReaderTxtConfig=Field(default=ReaderTxtConfig(),description='Configuration des readers txt.');csv:ReaderCsvConfig=Field(default=ReaderCsvConfig(),description='Configuration des readers csv.');txt_fixed_cols:ReaderTxtFixedColsConfig=Field(default=ReaderTxtFixedColsConfig(),description='Configuration des readers txt avec colonnes fixes.');netcdf:ReaderNetcdfConfig=Field(default=ReaderNetcdfConfig(),description='Configuration des readers NetCDF.');catalog:dict[str,ReaderConfig]|None=Field(default=None,description="Catalogue de configuration de readers par clé. Ex: `{'csv_comma': {'type': 'csv', 'parameters': {'delimiter': ','}}, 'csv_semicolon': {'type': 'csv', 'parameters': {'delimiter': ';'}}}`")
7
+ class BaseCatalogItem(BaseModel):type:str
8
+ class ReaderTxtConfigItem(BaseCatalogItem):type:Literal['txt'];parameters:ReaderTxtConfig
9
+ class ReaderCsvConfigItem(BaseCatalogItem):type:Literal['csv'];parameters:ReaderCsvConfig
10
+ class ReaderTxtFixedColsConfigItem(BaseCatalogItem):type:Literal['txt_fixed_cols'];parameters:ReaderTxtFixedColsConfig
11
+ class ReaderNetcdfConfigItem(BaseCatalogItem):type:Literal['netcdf'];parameters:ReaderNetcdfConfig
12
+ CATALOG_ITEM_TYPE=ReaderTxtConfigItem|ReaderCsvConfigItem|ReaderTxtFixedColsConfigItem|ReaderNetcdfConfigItem
13
+ class ReadersConfig(BaseModel):txt:ReaderTxtConfig=Field(default=ReaderTxtConfig(),description='Configuration des readers txt.');csv:ReaderCsvConfig=Field(default=ReaderCsvConfig(),description='Configuration des readers csv.');txt_fixed_cols:ReaderTxtFixedColsConfig=Field(default=ReaderTxtFixedColsConfig(),description='Configuration des readers txt avec colonnes fixes.');netcdf:ReaderNetcdfConfig=Field(default=ReaderNetcdfConfig(),description='Configuration des readers NetCDF.');catalog:dict[str,CATALOG_ITEM_TYPE]|None=Field(default=None,description="Catalogue de configuration de readers par clé. Ex: `{'csv_comma': {'type': 'csv', 'parameters': {'delimiter': ','}}, 'csv_semicolon': {'type': 'csv', 'parameters': {'delimiter': ';'}}}`")
@@ -2,7 +2,11 @@ _C="Paramètre modifiable par l'utilisateur"
2
2
  _B=True
3
3
  _A=None
4
4
  from pydantic import BaseModel,Field
5
+ from scilens.config.models.base import StrOrPath
5
6
  class ReportParameterPageModeConfig(BaseModel):is_user_preference:bool=Field(default=_B,description=_C);default_value:str=Field(default='onepage',description='`tabs` ou `onepage`')
6
7
  class ReportParameterOpenFileInConfig(BaseModel):is_user_preference:bool=Field(default=_B,description=_C);default_value:str=Field(default='browser',description='`browser` ou `vscode`')
7
- class ReportHtmlCurvesConfig(BaseModel):display_on_load:bool=Field(default=False,description="Si `true`, affiche tous les graphiques courbes à l'ouverture du rapport.");init_width:int=Field(default=600,description='Largeur initiale des graphiques courbes.');init_height:int=Field(default=400,description='Hauteur initiale des graphiques courbes.');compare_vs_values:bool=Field(default=_B,description='Dans le chart de comparaison, affiche les valeurs de référence et de test.');compare_vs_difference:bool=Field(default=_B,description='Dans le chart de comparaison, affiche la différence entre les valeurs de référence et de test.')
8
- class ReportHtmlConfig(BaseModel):custom_style:str|_A=Field(default=_A,description='CSS personnalisé.');custom_script_head:str|_A=Field(default=_A,description='Script personnalisé dans le `<head>`.');custom_script_body:str|_A=Field(default=_A,description='Script personnalisé en fin de `<body>`.');extra_html_start:str|_A=Field(default=_A,description='HTML personnalisé en début de rapport.');extra_html_summary:str|_A=Field(default=_A,description='HTML personnalisé dans la section `Summary`.');extra_html_end:str|_A=Field(default=_A,description='HTML personnalisé en fin de rapport.');logo_height:int=Field(default=40,description='Hauteur du logo dans le titre.');compare_color_test:str=Field(default='1982c4',description='Couleur pour les données de test.');compare_color_reference:str=Field(default='6a4c93',description='Couleur pour les données de référence.');collapse_if_successful:bool=Field(default=_B,description="N'affiche par défaut les sections de comparaison sans erreur.");parameter_page_mode:ReportParameterPageModeConfig=ReportParameterPageModeConfig();parameter_open_file_in:ReportParameterOpenFileInConfig=ReportParameterOpenFileInConfig();curves:ReportHtmlCurvesConfig=ReportHtmlCurvesConfig()
8
+ class ReportHtmlCurvesConfig(BaseModel):display_on_load:bool=Field(default=False,description="Si `true`, affiche tous les graphiques courbes à l'ouverture du rapport.");init_width:int=Field(default=600,description='Largeur initiale des graphiques courbes.');init_height:int=Field(default=400,description='Hauteur initiale des graphiques courbes.');compare_vs_values:bool=Field(default=_B,description='Dans le chart de comparaison, affiche les valeurs de référence et de test.');compare_vs_difference:bool=Field(default=False,description='Dans le chart de comparaison, affiche la différence entre les valeurs de référence et de test.')
9
+ class ReportHtmlSpectrogramsConfig(BaseModel):test_ref:bool=Field(default=_B,description='Indique si les spectrogrammes de test doivent être affichés.');differences:bool=Field(default=_B,description='Indique si les spectrogrammes de différence doivent être affichés.');init_width:int=Field(default=300,description='Largeur initiale des spectrogrammes.');init_height:int=Field(default=300,description='Hauteur initiale des spectrogrammes.')
10
+ class ReportHtmlFrameseriesConfig(BaseModel):width:int=Field(default=300,description='Largeur initiale des graphiques frameseries.');height:int=Field(default=300,description='Hauteur initiale des graphiques frameseries.')
11
+ class ReportHtmlMatrixConfig(BaseModel):spectrograms:ReportHtmlSpectrogramsConfig|_A=_A;frameseries:ReportHtmlFrameseriesConfig|_A=_A
12
+ class ReportHtmlConfig(BaseModel):custom_style:StrOrPath|_A=Field(default=_A,description='CSS personnalisé.');custom_script_head:StrOrPath|_A=Field(default=_A,description="Script personnalisé dans le `<head>`. Chaine de caractères ou chemin d'un fichier sous la forme `file://`.");custom_script_body:StrOrPath|_A=Field(default=_A,description="Script personnalisé en fin de `<body>`. Chaine de caractères ou chemin d'un fichier sous la forme `file://`.");extra_html_start:StrOrPath|_A=Field(default=_A,description="HTML personnalisé en début de rapport. Chaine de caractères ou chemin d'un fichier sous la forme `file://`.");extra_html_summary:StrOrPath|_A=Field(default=_A,description="HTML personnalisé dans la section `Summary`. Chaine de caractères ou chemin d'un fichier sous la forme `file://`.");extra_html_end:StrOrPath|_A=Field(default=_A,description="HTML personnalisé en fin de rapport. Chaine de caractères ou chemin d'un fichier sous la forme `file://`.");logo_height:int=Field(default=40,description='Hauteur du logo dans le titre.');compare_color_test:str=Field(default='1982c4',description='Couleur pour les données de test.');compare_color_reference:str=Field(default='6a4c93',description='Couleur pour les données de référence.');collapse_if_successful:bool=Field(default=_B,description="N'affiche par défaut les sections de comparaison sans erreur.");parameter_page_mode:ReportParameterPageModeConfig=ReportParameterPageModeConfig();parameter_open_file_in:ReportParameterOpenFileInConfig=ReportParameterOpenFileInConfig();curves:ReportHtmlCurvesConfig=ReportHtmlCurvesConfig();matrix:ReportHtmlMatrixConfig=ReportHtmlMatrixConfig()
@@ -11,7 +11,7 @@ class ExecuteAndCompare:
11
11
  if not F.test_only:G.append({I:'reference',J:N,B:F.reference})
12
12
  for A in G:
13
13
  if not A[B]:C=D
14
- else:C=ExecuteConfig();C.pre_folder_delete=A[B].pre_folder_delete or D.pre_folder_delete;C.pre_folder_creation=A[B].pre_folder_creation or D.pre_folder_creation;C.exe_path=A[B].exe_path or D.exe_path;C.exe_url=A[B].exe_url or D.exe_url;C.exe_command=A[B].exe_command or D.exe_command;C.exe_url_headers=A[B].exe_url_headers or D.exe_url_headers;C.exe_unzip_and_use=A[B].exe_unzip_and_use or D.exe_unzip_and_use;C.exe_guess_os_extension=A[B].exe_guess_os_extension or D.exe_guess_os_extension;C.command_suffix=A[B].command_suffix or D.command_suffix
14
+ else:C=ExecuteConfig();C.pre_files_delete=A[B].pre_files_delete or D.pre_files_delete;C.pre_folder_delete=A[B].pre_folder_delete or D.pre_folder_delete;C.pre_folder_creation=A[B].pre_folder_creation or D.pre_folder_creation;C.exe_path=A[B].exe_path or D.exe_path;C.exe_url=A[B].exe_url or D.exe_url;C.exe_command=A[B].exe_command or D.exe_command;C.exe_url_headers=A[B].exe_url_headers or D.exe_url_headers;C.exe_unzip_and_use=A[B].exe_unzip_and_use or D.exe_unzip_and_use;C.exe_guess_os_extension=A[B].exe_guess_os_extension or D.exe_guess_os_extension;C.command_suffix=A[B].command_suffix or D.command_suffix
15
15
  logging.info(f"Execute {A[I]} Command")
16
- with Executor(A[J],C,alternative_working_dir=E.context.origin_working_dir)as O:O.process()
16
+ with Executor(A[J],C,E.context.config_file,alternative_working_dir=E.context.origin_working_dir)as O:O.process()
17
17
  G=E.compare_folders.compute_list_filenames();logging.info(f"Number files to compare: {len(G)}");K=E.compare_folders.compute_comparison(G);H.warnings=[A[L]for A in K if A.get(L)];H.data=K;return H
@@ -1,4 +1,3 @@
1
- _B=False
2
1
  _A=None
3
2
  import csv
4
3
  from collections.abc import Iterator
@@ -6,8 +5,8 @@ from dataclasses import dataclass,field,asdict
6
5
  from scilens.components.compare_models import CompareGroup
7
6
  from scilens.components.compare_floats import CompareFloats
8
7
  @dataclass
9
- class MatDataset:nb_lines:int=0;nb_columns:int=0;data:list[list[float]]=field(default_factory=lambda:[]);x_values:list[float]|_A=_A;y_values:list[float]|_A=_A
10
- def from_reader(reader,x_value_line=_A,has_header=_B,has_y=_B):
8
+ class MatDataset:x_name:str;y_name:str;nb_lines:int=0;nb_columns:int=0;data:list[list[float]]=field(default_factory=lambda:[]);x_values:list[float]|_A=_A;y_values:list[float]|_A=_A
9
+ def from_iterator(x_name,y_name,reader,x_value_line=_A,has_header=False,has_y=False):
11
10
  E=has_y;D=x_value_line;B=reader;H=_A;I=[]if E else _A;A=[];F=0
12
11
  if D:
13
12
  J=1 if E else 0
@@ -19,14 +18,9 @@ def from_reader(reader,x_value_line=_A,has_header=_B,has_y=_B):
19
18
  for C in B:L=float(C[0]);G=[float(A)for A in C[1:]];I.append(L);A.append(G)
20
19
  else:
21
20
  for C in B:G=[float(A)for A in C];A.append(G)
22
- return MatDataset(nb_lines=len(A),nb_columns=len(A[0])if len(A)>0 else 0,data=A,x_values=H,y_values=I)
21
+ return MatDataset(x_name=x_name,y_name=y_name,nb_lines=len(A),nb_columns=len(A[0])if len(A)>0 else 0,data=A,x_values=H,y_values=I)
23
22
  def compare(parent_group,compare_floats,test,ref,group_name=''):B=parent_group;A=test;D,C,E=compare_floats.add_group_and_compare_matrices(group_name,B,group_data=_A,test_mat=A.data,ref_mat=ref.data,x_vector=A.x_values,y_vector=A.y_values);B.error='Errors limit reached'if C else _A
24
- def get_data(datasets,names,display_spectrograms=_B,display_frameseries=_B,frameseries_steps_data=_A,frameseries_steps_name=_A):
25
- F='frameseries';E='display';D=frameseries_steps_data;C=names;B=datasets
26
- if len(B)!=len(C):raise ValueError('Datasets and names must have the same length')
27
- A={'datasets':[asdict(A)for A in B],'names':C}
28
- if display_spectrograms:A['spectrograms']={E:1}
29
- if display_frameseries:
30
- A[F]={E:1}
31
- if D:A[F]['steps']={'name':frameseries_steps_name,'data':D}
32
- return A
23
+ def get_data(datasets,names,frameseries_steps_data=_A,frameseries_steps_name=_A):
24
+ B=names;A=datasets
25
+ if len(A)!=len(B):raise ValueError('Datasets and names must have the same length')
26
+ C={'datasets':[asdict(A)for A in A],'names':B};return C
@@ -1,8 +1,8 @@
1
1
  _A=None
2
- import logging,csv
2
+ import logging,csv,re
3
3
  from scilens.readers.reader_interface import ReaderInterface
4
4
  from scilens.readers.cols_dataset import ColsDataset,ColsCurves,cols_dataset_get_curves_col_x,compare as cols_compare
5
- from scilens.readers.mat_dataset import MatDataset,from_reader as mat_from_reader,compare as mat_compare,get_data
5
+ from scilens.readers.mat_dataset import MatDataset,from_iterator as mat_from_iterator,compare as mat_compare,get_data
6
6
  from scilens.config.models.reader_format_csv import ReaderCsvConfig,ReaderCsvMatrixConfig
7
7
  from scilens.config.models.reader_format_cols_curve import ReaderCurveParserNameConfig
8
8
  from scilens.components.compare_models import CompareGroup
@@ -20,31 +20,37 @@ def csv_detect(path,delimiter,quotechar,encoding):
20
20
  class ReaderCsv(ReaderInterface):
21
21
  configuration_type_code='csv';category='datalines';extensions=['CSV']
22
22
  def read(A,reader_options):
23
- B=reader_options;A.reader_options=B;A.raw_lines_number=_A;A.curves=_A;A.report_matrices=_A;D,F,N=csv_detect(A.origin.path,A.reader_options.delimiter,A.reader_options.quotechar,encoding=A.encoding);A.has_header=D;A.cols=F;A.numeric_col_indexes=N;J=open(A.origin.path,'r',encoding=A.encoding);K=csv.reader(J,delimiter=A.reader_options.delimiter,quotechar=A.reader_options.quotechar)
24
- if B.is_matrix:
25
- E=B.matrix or ReaderCsvMatrixConfig();G=mat_from_reader(K,has_header=D,x_value_line=E.x_value_line,has_y=E.has_y)
26
- if E.display_spectrogram or E.display_frameseries:A.report_matrices=get_data([G],['csv'],E.display_spectrogram,E.display_frameseries)
27
- A.mat_dataset=G;A.raw_lines_number=G.nb_lines+(1 if D else 0)
28
- else:
29
- if B.ignore_columns:
30
- if not D:raise Exception('Ignore columns is not supported without header.')
31
- A.numeric_col_indexes=[C for C in A.numeric_col_indexes if A.cols[C]not in B.ignore_columns]
32
- L=len(F);C=ColsDataset(cols_count=L,names=F,numeric_col_indexes=A.numeric_col_indexes,data=[[]for A in range(L)]);H=0
33
- for O in K:
34
- H+=1
35
- if D and H==1:continue
36
- for(M,I)in enumerate(O):
37
- if M in C.numeric_col_indexes:I=float(I)
38
- C.data[M].append(I)
39
- C.origin_line_nb.append(H)
40
- C.rows_count=len(C.origin_line_nb);A.cols_dataset=C;A.raw_lines_number=C.rows_count+(1 if D else 0)
41
- if B.curve_parser:
42
- if B.curve_parser.name==ReaderCurveParserNameConfig.COL_X:
43
- A.curves,P=cols_dataset_get_curves_col_x(C,B.curve_parser.parameters.x)
44
- if A.curves:A.cols_curve=ColsCurves(type=ReaderCurveParserNameConfig.COL_X,info=P,curves=A.curves)
45
- elif B.curve_parser.name==ReaderCurveParserNameConfig.COLS_COUPLE:raise NotImplementedError('cols_couple not implemented')
46
- else:raise Exception('Curve parser not supported.')
47
- J.close()
23
+ B=reader_options;A.reader_options=B;J=B.ignore_lines_patterns;A.raw_lines_number=_A;A.curves=_A;A.report_matrices=_A;D,F,P=csv_detect(A.origin.path,A.reader_options.delimiter,A.reader_options.quotechar,encoding=A.encoding);A.has_header=D;A.cols=F;A.numeric_col_indexes=P
24
+ with open(A.origin.path,'r',encoding=A.encoding)as Q:
25
+ K=Q.readlines();L=csv.reader(K,delimiter=A.reader_options.delimiter,quotechar=A.reader_options.quotechar)
26
+ if B.is_matrix:
27
+ E=B.matrix or ReaderCsvMatrixConfig();G=mat_from_iterator(x_name=E.x_name,y_name=E.y_name,reader=L,has_header=D,x_value_line=E.x_value_line,has_y=E.has_y)
28
+ if E.export_report:A.report_matrices=get_data([G],['csv'])
29
+ A.mat_dataset=G;A.raw_lines_number=G.nb_lines+(1 if D else 0)
30
+ else:
31
+ if B.ignore_columns:
32
+ if not D:raise Exception('Ignore columns is not supported without header.')
33
+ A.numeric_col_indexes=[C for C in A.numeric_col_indexes if A.cols[C]not in B.ignore_columns]
34
+ M=len(F);C=ColsDataset(cols_count=M,names=F,numeric_col_indexes=A.numeric_col_indexes,data=[[]for A in range(M)]);H=0
35
+ for(R,S)in zip(K,L):
36
+ H+=1
37
+ if D and H==1:continue
38
+ if J:
39
+ N=False
40
+ for T in J:
41
+ if bool(re.match(T,R)):N=True;break
42
+ if N:continue
43
+ for(O,I)in enumerate(S):
44
+ if O in C.numeric_col_indexes:I=float(I)
45
+ C.data[O].append(I)
46
+ C.origin_line_nb.append(H)
47
+ C.rows_count=len(C.origin_line_nb);A.cols_dataset=C;A.raw_lines_number=C.rows_count+(1 if D else 0)
48
+ if B.curve_parser:
49
+ if B.curve_parser.name==ReaderCurveParserNameConfig.COL_X:
50
+ A.curves,U=cols_dataset_get_curves_col_x(C,B.curve_parser.parameters.x)
51
+ if A.curves:A.cols_curve=ColsCurves(type=ReaderCurveParserNameConfig.COL_X,info=U,curves=A.curves)
52
+ elif B.curve_parser.name==ReaderCurveParserNameConfig.COLS_COUPLE:raise NotImplementedError('cols_couple not implemented')
53
+ else:raise Exception('Curve parser not supported.')
48
54
  def compare(A,compare_floats,param_reader,param_is_ref=True):
49
55
  H='node';D=param_is_ref;C=param_reader;B=compare_floats;I=A.reader_options
50
56
  if I.is_matrix:E=A.mat_dataset if D else C.mat_dataset;F=A.mat_dataset if not D else C.mat_dataset;J,G=B.compare_errors.add_group(H,'csv matrix');mat_compare(G,B,E,F)
@@ -1,38 +1,81 @@
1
+ _A=None
1
2
  import logging,re
3
+ from dataclasses import dataclass
2
4
  from scilens.readers.transform import string_2_float
3
5
  from scilens.readers.reader_interface import ReaderInterface
4
6
  from scilens.readers.cols_dataset import ColsDataset,ColsCurves,cols_dataset_get_curves_col_x,compare
5
7
  from scilens.config.models import ReaderTxtFixedColsConfig
6
8
  from scilens.config.models.reader_format_cols_curve import ReaderCurveParserNameConfig
7
9
  from scilens.components.compare_floats import CompareFloats
10
+ @dataclass
11
+ class ParsedHeaders:raw:str;cleaned:str;data:list[str];ori_line_idx:int|_A=_A
8
12
  class ReaderTxtFixedCols(ReaderInterface):
9
13
  configuration_type_code='txt_fixed_cols';category='datalines';extensions=[]
10
- def read(B,reader_options):
11
- A=reader_options;B.reader_options=A;J=open(B.origin.path,'r',encoding=B.encoding);K=A.column_widths;L=A.ignore_lines_patterns;E=len(K);C=ColsDataset(cols_count=E,names=[f"Column {A+1}"for A in range(E)],numeric_col_indexes=[A for A in range(E)],data=[[]for A in range(E)]);F=None;G=0
12
- for D in J:
14
+ def _ignore_line(A,line):
15
+ if not line.strip():return True
16
+ if A.reader_options.ignore_lines_patterns:
17
+ for B in A.reader_options.ignore_lines_patterns:
18
+ if bool(re.match(B,line)):return True
19
+ return False
20
+ def _get_parsed_headers(A,path):
21
+ B=A.reader_options;C=_A
22
+ with open(A.origin.path,'r',encoding=A.encoding)as G:
23
+ D=-1
24
+ if B.has_header_line is not _A:
25
+ for E in G:
26
+ D+=1
27
+ if D+1==B.has_header_line:C=E;break
28
+ else:
29
+ for E in G:
30
+ D+=1
31
+ if not A._ignore_line(E):C=E;break
32
+ if C:
33
+ H=C.strip();F=H
34
+ if B.has_header_ignore:
35
+ for I in B.has_header_ignore:F=F.replace(I,'')
36
+ return ParsedHeaders(raw=H,cleaned=F,data=F.split(),ori_line_idx=D)
37
+ def _get_first_data_line(A,path):
38
+ D=A.reader_options;B=D.has_header
39
+ with open(A.origin.path,'r',encoding=A.encoding)as E:
40
+ for C in E:
41
+ if not A._ignore_line(C):
42
+ if B:B=False;continue
43
+ else:return C
44
+ def _discover_col_idx_ralgin_spaces(G,line):
45
+ A=line;A=A.rstrip();C=[];D=_A;B=0
46
+ for(E,F)in enumerate(A):
47
+ if D is not _A and D!=' 'and F==' ':C.append((B,E));B=E
48
+ D=F
49
+ if B<len(A):C.append((B,len(A)))
50
+ return C
51
+ def _derive_col_indexes(A,header_row=_A):0
52
+ def read(A,reader_options):
53
+ B=reader_options;A.reader_options=B;E=A._get_parsed_headers(A.origin.path)if B.has_header else _A;I=open(A.origin.path,'r',encoding=A.encoding);C=[]
54
+ if B.column_indexes or B.column_widths:
55
+ if B.column_indexes and B.column_widths:raise Exception('column_indexes and column_widths are exclusive.')
56
+ if B.column_widths:
57
+ logging.debug(f"Using column widths: {B.column_widths}");H=0
58
+ for J in B.column_widths:C+=[(H,H+J)];H+=J
59
+ else:logging.debug(f"Using column indexes: {B.column_indexes}");C=B.column_indexes
60
+ else:logging.debug(f"Using auto derived column indexes.");M=A._get_first_data_line(A.origin.path);C=A._discover_col_idx_ralgin_spaces(M)
61
+ logging.debug(f"Column indexes: {C}")
62
+ if not C:raise Exception('No column indexes or widths provided, and no headers found to derive column indexes.')
63
+ F=len(C);D=ColsDataset(cols_count=F,names=[f"Column {A+1}"for A in range(F)],numeric_col_indexes=[A for A in range(F)],data=[[]for A in range(F)])
64
+ if E:D.names=E.data
65
+ G=0
66
+ for K in I:
13
67
  G+=1
14
- if L:
15
- M=False
16
- for P in L:
17
- if bool(re.match(P,D)):M=True;break
18
- if M:continue
19
- if A.has_header:
20
- if not F:
21
- F=D.strip();H=F
22
- if A.has_header_ignore:
23
- for Q in A.has_header_ignore:H=H.replace(Q,'')
24
- C.names=H.split();continue
25
- elif A.has_header_repetition and F==D.strip():continue
26
- if not D.strip():continue
27
- I=0;N=0
28
- for O in K:R=D[I:I+O].strip();S=string_2_float(R);C.data[N].append(S);I+=O;N+=1
29
- C.origin_line_nb.append(G)
30
- C.rows_count=len(C.origin_line_nb);J.close();B.cols_dataset=C;B.raw_lines_number=G;B.curves=None
31
- if A.curve_parser:
32
- if A.curve_parser.name==ReaderCurveParserNameConfig.COL_X:
33
- B.curves,T=cols_dataset_get_curves_col_x(C,A.curve_parser.parameters.x)
34
- if B.curves:B.cols_curve=ColsCurves(type=ReaderCurveParserNameConfig.COL_X,info=T,curves=B.curves)
35
- elif A.curve_parser.name==ReaderCurveParserNameConfig.COLS_COUPLE:raise NotImplementedError('cols_couple not implemented')
68
+ if A._ignore_line(K):continue
69
+ if E:
70
+ if E.ori_line_idx==G-1:continue
71
+ for(N,L)in enumerate(C):O=K[L[0]:L[1]].strip();P=string_2_float(O);D.data[N].append(P)
72
+ D.origin_line_nb.append(G)
73
+ D.rows_count=len(D.origin_line_nb);I.close();A.cols_dataset=D;A.raw_lines_number=G;A.curves=_A;A.cols_curve=_A
74
+ if B.curve_parser:
75
+ if B.curve_parser.name==ReaderCurveParserNameConfig.COL_X:
76
+ A.curves,Q=cols_dataset_get_curves_col_x(D,B.curve_parser.parameters.x)
77
+ if A.curves:A.cols_curve=ColsCurves(type=ReaderCurveParserNameConfig.COL_X,info=Q,curves=A.curves)
78
+ elif B.curve_parser.name==ReaderCurveParserNameConfig.COLS_COUPLE:raise NotImplementedError('cols_couple not implemented')
36
79
  else:raise Exception('Curve parser not supported.')
37
80
  def compare(A,compare_floats,param_reader,param_is_ref=True):D=param_is_ref;C=param_reader;B=compare_floats;E=A.cols_dataset if D else C.cols_dataset;F=A.cols_dataset if not D else C.cols_dataset;G=A.cols_curve;I,H=B.compare_errors.add_group('node','txt cols');return compare(H,B,E,F,G)
38
81
  def class_info(A):return{'cols':A.cols_dataset.names,'raw_lines_number':A.raw_lines_number,'curves':A.curves}
@@ -137,7 +137,7 @@
137
137
  <!-- MATRICES -->
138
138
  {% if file.test.matrices %}
139
139
  {% for item in [{"id": "spectrograms", "label": "Spectrograms"}, {"id": "frameseries", "label": "Frameseries"}] %}
140
- {% if file.test.matrices[item.id] %}
140
+ {% if meta.config.matrix[item.id] %}
141
141
  <h3>{{ item.label }} <action data-command="toogle" data-args="{{ item.id }}_{{ file_index|string }}"></action></h3>
142
142
  <div id="{{ item.id }}_{{ file_index }}" ></div>
143
143
  {% endif %}
@@ -13,8 +13,8 @@
13
13
  {% set ns.statuses = ns.statuses + ['SKIPPED' if file.skipped else ('ERROR' if file.error else ('WARNING' if file.comparison_errors and file.comparison_errors.error_nb > 0 else 'SUCCESS'))] %}
14
14
  {% if file.test.matrices %}
15
15
  {% set ns.has_matrices = true %}
16
- {% if file.test.matrices.spectrograms %}{% set ns.has_spectrograms = true %}{% endif %}
17
- {% if file.test.matrices.frameseries %}{% set ns.has_frameseries = true %}{% endif %}
16
+ {% if meta.config.matrix.spectrograms %}{% set ns.has_spectrograms = true %}{% endif %}
17
+ {% if meta.config.matrix.frameseries %}{% set ns.has_frameseries = true %}{% endif %}
18
18
  {% endif %}
19
19
  {% endfor %}
20
20
  <html>
@@ -27,7 +27,7 @@
27
27
 
28
28
  <script>
29
29
 
30
- ((w_1, undef) => { w_1.None = undef; })(window); // for Python None = undef when templating
30
+ ((w_1, undef) => { w_1.None = undef; w_1.True = true; ; w_1.False = false; })(window); // for Python None = undef when templating
31
31
  {% include 'js_dom.js' %}
32
32
  {% include 'js_palette.js' %}
33
33
 
@@ -38,7 +38,18 @@
38
38
  {% include 'utils_compare_report_anim.js' %}
39
39
  {% include 'utils_compare_report_framesseries.js' %}
40
40
 
41
- {% if ns.has_spectrograms %}{% include 'uti_spectrograms.js' %}{% endif %}
41
+ {% if meta.config.matrix.spectrograms %}
42
+ {% include 'uti_spectrograms.js' %}
43
+ Spectrograms.config({
44
+ "DISPLAY_TESTREF": {{ meta.config.matrix.spectrograms.test_ref }},
45
+ "DISPLAY_DIFF": {{ meta.config.matrix.spectrograms.differences }},
46
+ "WIDTH": {{ meta.config.matrix.spectrograms.init_width }},
47
+ "HEIGHT": {{ meta.config.matrix.spectrograms.init_height }},
48
+ });
49
+ {% endif %}
50
+ {% if meta.config.matrix.frameseries %}
51
+ {% include 'uti_frameseries.js' %}
52
+ {% endif %}
42
53
  {% if ns.has_matrices %}{% include 'uti_matrix.js' %}{% endif %}
43
54
 
44
55
  </script>
@@ -127,7 +138,7 @@ function load_file_section(global_var, section_prefix, cls) {
127
138
  test : [ {% for file in data.files %} {{ file.test.matrices or 'null' }} , {% endfor %} ],
128
139
  reference : [ {% for file in data.files %} {{ file.ref.matrices or 'null' }} , {% endfor %} ],
129
140
  };
130
- MatrixMgmt.loadGlobal();
141
+ MatrixMgmt.loadGlobal({{ns.has_spectrograms}}, {{ns.has_frameseries}});
131
142
  </script>
132
143
  {% endif %}
133
144
  {% if meta.config.custom_script_body %}<script>{{ meta.config.custom_script_body }}</script>{% endif %}
@@ -21,7 +21,7 @@
21
21
  if (item.special) {
22
22
  switch (item.special) {
23
23
  case 'diff':
24
- yaxis2 = {title: 'Difference',overlaying: 'y',side: 'right'}
24
+ yaxis2 = {title: 'Difference',overlaying: 'y',side: 'right', color: 'rgba(255, 0, 0, 1)'}
25
25
  serie.line.color = 'rgba(255, 0, 0, 0.5)';
26
26
  serie.yaxis = 'y2';
27
27
  serie.fill = 'tozeroy';
@@ -190,7 +190,7 @@
190
190
  }
191
191
  },
192
192
  init_page: function() {
193
- console.log(parameters)
193
+ //console.log(parameters)
194
194
  build_parameters();
195
195
  action.init();
196
196
  this.render_page();
@@ -346,7 +346,6 @@ w_1.curvemgr = {
346
346
  }
347
347
  },
348
348
  init(config) {
349
- console.log(config)
350
349
  for (const k in CONFIG) {
351
350
  if (config[k] != undef) {CONFIG[k] = config[k];}
352
351
  }
@@ -0,0 +1,61 @@
1
+ ((w_1, undef) => {
2
+
3
+ //
4
+ //
5
+ //
6
+ const PREFIX = "frameseries_"; // section prefix
7
+ const CFG = {
8
+ "WIDTH": 300, // default width
9
+ "HEIGHT": 300, // default height
10
+ }
11
+
12
+ //
13
+ class Frameseries {
14
+ constructor(index, arr_mat, frames_vector) {
15
+ // DEBUG
16
+ // console.log("index", index);
17
+ // console.log("arr_mat", arr_mat);
18
+ // console.log("frames_vector", frames_vector);
19
+ // data
20
+ this.size = [CFG.WIDTH, CFG.HEIGHT]; // default size
21
+ this.arr_mat = arr_mat;
22
+ this.elt = dom.get(PREFIX+(1+index));
23
+ // frames
24
+ if (frames_vector) {
25
+ this.frame_len = frames_vector.length;
26
+ this.frame_min = frames_vector[0];
27
+ this.frame_max = frames_vector[this.frame_len-1];
28
+ } else {
29
+ this.frame_len = arr_mat[0].data.length;
30
+ this.frame_min = 0;
31
+ this.frame_max = this.frame_len-1;
32
+ }
33
+ // init
34
+ this.init();
35
+ }
36
+ init() {
37
+ // resize
38
+ const that = this;
39
+ //
40
+ // const tmpls = []
41
+ // this.arr_mat.forEach((mat, i) => { tmpls.push({tag:"button", html: mat.name, click: function() { that.var_toogle(i); } }) });
42
+ const tmpls = data.arr_mat.map((x,i) => { return {out:"variable_"+i, tag:"div", style:"width:"+this.size+"px;height:"+this.size+"px;"} ; } );
43
+
44
+
45
+ }
46
+ var_get_id(idx) {
47
+ return PREFIX+"block_"+idx;
48
+ }
49
+ var_toogle(idx) {
50
+ if (dom.get(this.var_get_id(idx))) { this.var_rmv(idx); }
51
+ else { this.var_add(idx); }
52
+ }
53
+ var_add(idx) {
54
+ }
55
+ var_rmv(idx) {
56
+ dom.get(this.var_get_id(idx)).remove();
57
+ }
58
+ }
59
+ Frameseries.config = function(cfg) {for (k in cfg) {CFG[k] = cfg[k];}};
60
+ w_1.Frameseries = Frameseries;
61
+ })(window);
@@ -21,13 +21,18 @@ function subtractMatrices(A, B) {
21
21
  row.map((v, j) => v - B[i][j])
22
22
  );
23
23
  }
24
+ function absolueMatrice(A) {
25
+ return A.map(row => row.map(v => Math.abs(v)));
26
+ }
24
27
  //
25
28
  class Matrix {
26
- constructor(data, x, y, name, ref) {
29
+ constructor(data, x, y, name, x_name, y_name, ref) {
27
30
  this.data = data; // Matrix data array[array[float]]
28
31
  this.x = x; // X-axis values array[float]
29
32
  this.y = y; // Y-axis values array[float]
30
33
  this.name = name; // string
34
+ this.x_name = x_name; // X-axis Name
35
+ this.y_name = y_name; // Y-axis Name
31
36
  this.ref = ref; // Reference matrix data (optional) array[array[float]]
32
37
  // // Check if the matrix is valid (rectangular)
33
38
  // const rowLength = data[0].length;
@@ -45,43 +50,48 @@ class Matrix {
45
50
  // ) { throw new Error("Matrices must have the same dimensions."); }
46
51
  return new Matrix(subtractMatrices(this.data, other.data), this.x, this.y, name);
47
52
  }
48
- ref_diff_data() {
49
- return subtractMatrices(this.data, this.ref);
53
+ ref_diff_abs_data() {
54
+ return absolueMatrice(subtractMatrices(this.data, this.ref));
50
55
  }
56
+ absolueMatrice
51
57
  }
52
58
  class MatrixGroup {
53
59
  constructor(arr, is_spectro, is_frameseries, has_ref) {
54
60
  this.arr = arr; // array of Matrix objects
55
- this.is_spectro = is_spectro;
56
- this.is_frameseries = is_frameseries;
57
61
  this.has_ref = has_ref;
58
62
  }
59
63
  }
60
64
  const MatrixMgmt = {
61
65
  groups: [],
62
- loadGlobal: function() {
66
+ loadGlobal: function(has_spectrograms, has_frameseries) {
63
67
  // load loop GLOBAL_VARS groups
64
68
  const g = GLOBAL_VARS.matrices;
65
69
  g.test.forEach((data, i) => {
66
70
  const group_data = [];
67
71
  const ref = g.reference[i];
68
72
  data.datasets.forEach((dataset, j) => {
69
- const mat = new Matrix(dataset.data, dataset.x_values, dataset.y_values, data.names[j], ref.datasets[j].data);
73
+ // console.log(dataset);
74
+ const mat = new Matrix(
75
+ dataset.data,
76
+ dataset.x_values,
77
+ dataset.y_values,
78
+ data.names[j],
79
+ dataset.x_name,
80
+ dataset.y_name,
81
+ ref.datasets[j].data,
82
+ );
70
83
  group_data.push(mat);
71
84
  });
72
- const group = new MatrixGroup(group_data, Boolean(data.spectrograms), Boolean(data.frameseries), true);
85
+ const group = new MatrixGroup(group_data, true);
73
86
  this.groups.push(group);
74
87
  });
75
88
  // IMPORTANT
76
89
  // Release Global
77
90
  delete GLOBAL_VARS.matrices;
78
- // Init
91
+ // Init Frameseries / Spectrograms
79
92
  this.groups.forEach((group, i) => {
80
- // Init Spectrograms
81
- if (group.is_spectro) {
82
- const spec = new Spectrograms(i, group.arr);
83
- }
84
- // Init Frameseries
93
+ if (has_spectrograms) { new Spectrograms(i, group.arr); }
94
+ if (has_frameseries) { new Frameseries(i, group.arr); }
85
95
  }
86
96
  );
87
97
  },
@@ -4,14 +4,15 @@
4
4
  //
5
5
  function resize22(obj, parent, dir) { // ASSUMPTIONS : obj.size int, "js-plotly-plot"
6
6
  // size
7
- const size = obj.size + (dir * obj.size * 0.1); // new size
8
- obj.size = obj.size + (dir * obj.size * 0.1); // save
7
+ const w = obj.size[0] + (dir * obj.size[0] * 0.1);
8
+ const h = obj.size[0] + (dir * obj.size[0] * 0.1);
9
+ obj.size = [w, h];
9
10
  // update widgets
10
- const update = { width: size, height: size };
11
+ const update = { width: w, height: h };
11
12
  const nodes = dom.q(parent, ".js-plotly-plot");
12
13
  nodes.forEach((node) => {
13
- node.style.width = size + "px";
14
- node.style.height = size + "px";
14
+ node.style.width = w + "px";
15
+ node.style.height = h + "px";
15
16
  Plotly.relayout(node, update); // update plotly
16
17
  });
17
18
  }
@@ -19,15 +20,21 @@ function resize22(obj, parent, dir) { // ASSUMPTIONS : obj.size int, "js-plotly-
19
20
  //
20
21
  //
21
22
  const PREFIX = "spectrograms_"; // section prefix
22
- const DEFAULT_SIZE = 300;
23
23
  const COLORSCALE = "Viridis"; // plotly
24
24
  const COLORSCALE_DIFF = "RdBu"; // plotly
25
+ const CFG = {
26
+ "DISPLAY_TESTREF": true, // display test reference
27
+ "DISPLAY_DIFF": true, // display diff
28
+ "WIDTH": 300, // default width
29
+ "HEIGHT": 300, // default height
30
+ }
31
+
25
32
  //
26
33
  class Spectrograms {
27
34
  constructor(index, arr_mat) {
28
- console.log("index data", index);
35
+ //console.log("index data", index);
29
36
  // data
30
- this.size = DEFAULT_SIZE;
37
+ this.size = [CFG.WIDTH, CFG.HEIGHT]; // default size
31
38
  this.arr_mat = arr_mat;
32
39
  this.elt = dom.get(PREFIX+(1+index));
33
40
  // init
@@ -64,13 +71,14 @@ class Spectrograms {
64
71
  var_add(idx) {
65
72
  const mat = this.arr_mat[idx];
66
73
  //
67
- const style = "width:"+this.size+"px;height:"+this.size+"px;";
74
+ const style = "width:"+this.size[0]+"px;height:"+this.size[1]+"px;";
68
75
  const attrs = { class: "m-1 shadow-lg" };
69
76
  //
70
- const templs = [{out:"var", tag:"div", attrs: attrs, style:style} ];
77
+ const templs = [];
78
+ if (CFG.DISPLAY_TESTREF) templs.push({out:"var", tag:"div", attrs: attrs, style:style});
71
79
  if (mat.ref) {
72
- templs.push({out:"ref", tag:"div", attrs: attrs, style:style});
73
- templs.push({out:"dif", tag:"div", attrs: attrs, style:style});
80
+ if (CFG.DISPLAY_TESTREF) templs.push({out:"ref", tag:"div", attrs: attrs, style:style});
81
+ if (CFG.DISPLAY_DIFF) templs.push({out:"dif", tag:"div", attrs: attrs, style:style});
74
82
  }
75
83
  const e = {};
76
84
  dom.tree(
@@ -81,30 +89,31 @@ class Spectrograms {
81
89
  e
82
90
  );
83
91
 
84
- this.add_widget(e["var"], mat.data);
92
+ if (CFG.DISPLAY_TESTREF) this.add_widget(e["var"], mat, mat.data);
85
93
  if (mat.ref) {
86
- this.add_widget(e["ref"], mat.ref);
87
- this.add_widget(e["dif"], mat.ref_diff_data(), COLORSCALE_DIFF);
94
+ if (CFG.DISPLAY_TESTREF) this.add_widget(e["ref"], mat, mat.ref, " - Ref.");
95
+ if (CFG.DISPLAY_DIFF) this.add_widget(e["dif"], mat, mat.ref_diff_abs_data(), " - Diff.", COLORSCALE_DIFF);
88
96
  }
89
97
  }
90
98
  var_rmv(idx) {
91
99
  dom.get(this.var_get_id(idx)).remove();
92
100
  }
93
- add_widget(elt, mat, colorscale=COLORSCALE) {
101
+ add_widget(elt, mat, matdata, suffix="", colorscale=COLORSCALE) {
94
102
  const data = [{
95
- z: mat,
103
+ z: matdata,
96
104
  type: 'heatmap',
97
105
  colorscale: colorscale,
98
106
  }];
99
107
 
100
108
  const layout = {
101
- // title: mat.name,
102
- xaxis: { title: 'X' },
103
- yaxis: { title: 'Y' }
109
+ title: mat.name + suffix,
110
+ xaxis: { title: mat.x_name || 'X' },
111
+ yaxis: { title: mat.y_name || 'Y' },
104
112
  };
105
113
 
106
114
  Plotly.newPlot(elt, data, layout);
107
115
  }
108
116
  }
117
+ Spectrograms.config = function(cfg) {for (k in cfg) {CFG[k] = cfg[k];}};
109
118
  w_1.Spectrograms = Spectrograms;
110
119
  })(window);
@@ -1,3 +1,4 @@
1
+ ((w_1, undef) => {
1
2
  const Anim = function (elt, options, options_2) {
2
3
  const that = this;
3
4
  // options
@@ -70,4 +71,6 @@ update: function () {
70
71
  };
71
72
  Anim.create = function(parent, options, options_2) {
72
73
  new Anim(parent, options, options_2)
73
- }
74
+ }
75
+ w_1.Anim = Anim;
76
+ })(window);
@@ -1,3 +1,4 @@
1
+ ((w_1, undef) => {
1
2
  const Framesseries = function (elt, data, data_ref) {
2
3
  const that = this;
3
4
  // data
@@ -21,7 +22,7 @@ const Framesseries = function (elt, data, data_ref) {
21
22
  // steps
22
23
  const steps = []
23
24
  data.frames_steps_variable.data.forEach((e,i) => {
24
- console.log(e)
25
+ // console.log(e)
25
26
  steps.push({
26
27
  start: e,
27
28
  color: palette.get(i),
@@ -131,7 +132,7 @@ Framesseries.prototype = {
131
132
  labels.push({label: "Step", val: step, max: steps.length, color: color, val2: val2})
132
133
  }
133
134
  // labels
134
- console.log(labels)
135
+ // console.log(labels)
135
136
  this.lab.innerHTML = labels.map(x => '<span style="padding:3px 5px;background-color:'+x.color+';"><b> ' + x.label + "</b> " + x.val + "/" + x.max + ( x.val2 ? " (" + x.val2 + ")" : "") +"</span>").join(" - ");
136
137
 
137
138
 
@@ -140,3 +141,5 @@ Framesseries.prototype = {
140
141
  Framesseries.create = function(parent, options, options_2) {
141
142
  new Framesseries(parent, options, options_2)
142
143
  }
144
+ w_1.Framesseries = Framesseries;
145
+ })(window);
scilens/run/run_task.py CHANGED
@@ -11,24 +11,31 @@ from scilens.report.report import Report
11
11
  from scilens.utils.system import info as system_info
12
12
  from scilens.utils.time_tracker import TimeTracker
13
13
  from scilens.utils.template import template_render_string
14
+ from scilens.config.models.base import is_StrOrPath_and_path
14
15
  def var_render(value,runtime):return template_render_string(value,runtime.model_dump())
15
16
  def runtime_process_vars(config):
16
17
  A=TaskRuntime(sys=system_info(),env=os.environ.copy(),vars={})
17
18
  for(B,C)in config.variables.items():A.vars[B]=var_render(C,A)
18
19
  return A
19
- def runtime_apply_to_config(runtime,config_model):
20
- C=runtime;B=config_model
21
- for(D,J)in B.__class__.__pydantic_fields__.items():
22
- A=getattr(B,D);E=issubclass(A.__class__,BaseModel);F=isinstance(A.__class__,type)and issubclass(A.__class__,Enum);G=isinstance(A,str);H=isinstance(A,list)and all(isinstance(A,str)for A in A);I=isinstance(A,dict)and all(isinstance(A,str)and isinstance(B,str)for(A,B)in A.items())
23
- if E:runtime_apply_to_config(C,A)
24
- elif G and not F:setattr(B,D,var_render(A,C))
25
- elif H:setattr(B,D,[var_render(A,C)for A in A])
26
- elif I:setattr(B,D,{A:var_render(B,C)for(A,B)in A.items()})
20
+ def runtime_apply_to_config(runtime,config_model,working_dir):
21
+ G=working_dir;D=runtime;B=config_model
22
+ for(C,H)in B.__class__.__pydantic_fields__.items():
23
+ A=getattr(B,C);I,E=is_StrOrPath_and_path(A,H)
24
+ if I:
25
+ F=os.path.join(G,E)if not os.path.isabs(E)else E
26
+ if not os.path.exists(F):raise Exception(f"Config {C}: {A} Path '{F}' does not exist.")
27
+ else:
28
+ with open(F,'r')as J:A=J.read();setattr(B,C,A)
29
+ K=issubclass(A.__class__,BaseModel);L=isinstance(A.__class__,type)and issubclass(A.__class__,Enum);M=isinstance(A,str);N=isinstance(A,list)and all(isinstance(A,str)for A in A);O=isinstance(A,dict)and all(isinstance(A,str)and isinstance(B,str)for(A,B)in A.items())
30
+ if K:runtime_apply_to_config(D,A,G)
31
+ elif M and not L:setattr(B,C,var_render(A,D))
32
+ elif N:setattr(B,C,[var_render(A,D)for A in A])
33
+ elif O:setattr(B,C,{A:var_render(B,D)for(A,B)in A.items()})
27
34
  class RunTask:
28
35
  def __init__(A,context):A.context=context
29
36
  def _get_processors(A):return{A.__name__:A for A in[Analyse,Compare,ExecuteAndCompare]}
30
37
  def process(A):
31
- logging.info(f"Running task");logging.info(f"Prepare runtime variables");H=runtime_process_vars(A.context.config);logging.info(f"Apply runtime variables to config");runtime_apply_to_config(H,A.context.config);logging.debug(f"on working_dir '{A.context.working_dir}'");logging.debug(f"with origin_working_dir '{A.context.origin_working_dir}'");logging.debug(f"with config {A.context.config.model_dump_json(indent=4)}");C=A.context.config.processor
38
+ logging.info(f"Running task");logging.info(f"Prepare runtime variables");H=runtime_process_vars(A.context.config);logging.info(f"Apply runtime variables to config");runtime_apply_to_config(H,A.context.config,A.context.working_dir);logging.debug(f"on working_dir '{A.context.working_dir}'");logging.debug(f"with origin_working_dir '{A.context.origin_working_dir}'");logging.debug(f"with config {A.context.config.model_dump_json(indent=4)}");C=A.context.config.processor
32
39
  if not C:raise Exception('Processor not defined in config.')
33
40
  D=A._get_processors().get(C)
34
41
  if not D:raise Exception('Processor not found.')
@@ -5,5 +5,5 @@ from scilens.run.run_task import RunTask
5
5
  from scilens.config.models import AppConfig
6
6
  class StandaloneTaskRunner:
7
7
  config:AppConfig;config_path=None
8
- def __init__(A,config):A.config=config_load(config)
8
+ def __init__(A,config,config_override=None):A.config=config_load(config,config_override=config_override)
9
9
  def process(A,working_dir,origin_working_dir=None):B=TaskContext(config=A.config,config_file=A.config_path,working_dir=working_dir,origin_working_dir=origin_working_dir);C=RunTask(B);D=C.process();return D
scilens/utils/dict.py CHANGED
@@ -3,4 +3,9 @@ def dict_path_set(obj,path,value):
3
3
  A=obj;B=path.split('.')
4
4
  for C in B[:-1]:A=A.setdefault(C,{})
5
5
  A[B[-1]]=value
6
- def dict_path_get(obj,path):return reduce(dict.get,path.split('.'),obj)
6
+ def dict_path_get(obj,path):return reduce(dict.get,path.split('.'),obj)
7
+ def dict_update_rec(base,updates):
8
+ A=base
9
+ for(B,C)in updates.items():
10
+ if B in A and isinstance(A[B],dict)and isinstance(C,dict):dict_update_rec(A[B],C)
11
+ else:A[B]=C
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: scilens
3
- Version: 0.3.8
3
+ Version: 0.3.10
4
4
  Summary: A CesGensLaB framework for data collecting and deep analysis
5
5
  Home-page: https://scilens.dev
6
6
  License: Proprietary
@@ -13,27 +13,28 @@ scilens/components/compare_errors.py,sha256=vGb4DWP89HMIeBm0dZU2nt-ksppAs_37xtCH
13
13
  scilens/components/compare_floats.py,sha256=yYJZ_QpAZUhP1uwNtGshXQLIzKtki9ifCN3hd9AFj2U,5916
14
14
  scilens/components/compare_folders.py,sha256=LZ1AuYxLVHMNbtXWXQrdms4vZgOQthvDy-8NFD_EFjc,2617
15
15
  scilens/components/compare_models.py,sha256=SCPd747h_nd4ewZsqLB6CFr27v6q99NELJb-gpkdj0o,918
16
- scilens/components/executor.py,sha256=j5xejkCaaPyl3V38Q4HxxXcAx4Tnj8CILAjSJ1G7OIE,3417
16
+ scilens/components/executor.py,sha256=PLeKolzPd4wPX8e6DdfOb0uHGky3DxTcKN9QtB6oe3Q,3712
17
17
  scilens/components/file_reader.py,sha256=7SbKCqb4Co_pqAKX3wweYhqAcVkU7BDlT903sLd76Kc,1407
18
18
  scilens/config/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
19
19
  scilens/config/cli_run_options.py,sha256=Ls7yK5QDUPFbk73nbjGuPvuRbBRYw4Miag5ISpu3prg,281
20
20
  scilens/config/env_var.py,sha256=NqNBoIfngJEXaGEm7jGqre5pmkJ9eUjiWzbDrTVfi2c,292
21
- scilens/config/load.py,sha256=4U51o4cJfqhSuRIHKUDIsDQA0C4wv6SzTkVmInGDJdI,1647
21
+ scilens/config/load.py,sha256=ltcv90GlsMJR2FE2ZL_jDscL7k5aGoHoMatWw61lrTw,1672
22
22
  scilens/config/models/__init__.py,sha256=eLCW1OLVINewGFy5GXSrOk8Rab_QsgKAuoErBjphHRs,673
23
23
  scilens/config/models/app.py,sha256=JltWRjjqXYkH6rg3OHYhMfkBqHFhZEZdthqES3LxvzY,1453
24
+ scilens/config/models/base.py,sha256=k92CR8TA5L8dZJtg28c8albk16AK9-3umdosA7aYsxw,499
24
25
  scilens/config/models/compare.py,sha256=esRqW3PNVOqkA_mt4_qbS7dVCLulUrZTBUhANQOHoqE,1847
25
26
  scilens/config/models/compare_float_thresholds.py,sha256=mHu48-70i3o_qUw6x-1A7XeRwFUNAO6WP6qNPGwAew0,2097
26
- scilens/config/models/execute.py,sha256=8issd_hg49SdVkDq2TLDB1vBJY4M1t279XERNUd3VVs,2142
27
+ scilens/config/models/execute.py,sha256=Hx3DoDJ0fq7bZruqwtPtSKL6PVOF_LpsaDCLrn5klLk,2325
27
28
  scilens/config/models/execute_and_compare.py,sha256=TWL6yXGvQSaaV6nhHqWLvtr3v396APIoDNt0U1TbMro,582
28
29
  scilens/config/models/file_reader.py,sha256=c18vKhVcBX4ufpbnCBJyVyAsQtlxpwx0lGVuf1i8EGA,1176
29
30
  scilens/config/models/reader_format_cols_curve.py,sha256=eKLvifq1xuN8sPds9ijfru3vgMZ3Odv5tGfeiK4Sfk4,1860
30
- scilens/config/models/reader_format_csv.py,sha256=si422pyd3kwxXWb4u_L-0dsBxTouHDu2AWdh2a5OfD4,1512
31
+ scilens/config/models/reader_format_csv.py,sha256=EQ1nCYsv6Cf4rtK3AUW5LbJakRcutdaNSl4UN634evs,1708
31
32
  scilens/config/models/reader_format_netcdf.py,sha256=k-AMdm239T6I42R8jzyRlPKKJ8zkRrN8XS8yU6ZkFu0,1256
32
33
  scilens/config/models/reader_format_txt.py,sha256=eHg90gwEI_VpqwqEjMRhwlS8dHcl5G4ow-37HjQq_zY,1168
33
- scilens/config/models/reader_format_txt_fixed_cols.py,sha256=xHD1_JOoRZow8lSNaDSYFeNckojctkT4C61mbBcjeKg,1079
34
- scilens/config/models/readers.py,sha256=Pq5kOGW3b6g1x5cp_BbwUF7LUB_P3m9bHDYLSTVXNBY,1769
34
+ scilens/config/models/reader_format_txt_fixed_cols.py,sha256=SQ84OW9BLc5mr_TC6gQuYzzHJvrU-sVz223WOtAQMc0,1133
35
+ scilens/config/models/readers.py,sha256=oWdE4AkckvwN6boln55orq3hUeAt6S9IdQAZkGROR6E,1657
35
36
  scilens/config/models/report.py,sha256=6mzqZMJnS_z5Rs01ISo8L8HRcWvmiQrK0dYqu8a58vM,993
36
- scilens/config/models/report_html.py,sha256=W4ATubdtxnW-vSOPXBZ6PNKMPcexpB9jeFi7c6b5VOc,2327
37
+ scilens/config/models/report_html.py,sha256=3epqs-tyjicueMqh3b52JP0HURG0reLwYfkXt5VUWA8,3621
37
38
  scilens/config/models/report_output.py,sha256=XoqUe-t-y8GRbUR3_bDwwaWf6hif-rZ-5pKDGdCMugw,875
38
39
  scilens/helpers/assets.py,sha256=XphDA3-yE1PPKw4XFZhDrlLQjMZfGMlpOBXa8uy_xX0,1552
39
40
  scilens/helpers/search_and_index.py,sha256=kXZ7124ra_SGAdKUZ7msy55UOWQ9dCSuPuNoU-NdUyM,1522
@@ -42,19 +43,19 @@ scilens/helpers/templates/style.css,sha256=2_IndKW2qtGhuoU9T3Sru4NkHR5CXTTs5_nc9
42
43
  scilens/processors/__init__.py,sha256=x6bmqQVCcdJ7R2oG-_xTVtvl9qRleliEZlZR-Hq9Yc0,105
43
44
  scilens/processors/analyse.py,sha256=hG2jALUqtoEwTPiLxDGV9Nbv6TU_SrfzwV_-1RkuiKw,828
44
45
  scilens/processors/compare.py,sha256=wCdtDC8nJUeG9dolu2B6rTg4-jW0MYllPbvXFBX64nU,529
45
- scilens/processors/execute_and_compare.py,sha256=KX0bVSLzsc2VvxivTksGoLg8612WRjPkFAMWqB0hfYg,1784
46
+ scilens/processors/execute_and_compare.py,sha256=-JXnZewkza29L3TAsvaAuHTHRNG8biaKMFwpwdeCCbQ,1869
46
47
  scilens/processors/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
47
48
  scilens/processors/models/results.py,sha256=KoWxh13Zgi7PuPql8hkf4VjCis42ZxAuzIgJxBWVaX8,119
48
49
  scilens/processors/processor_interface.py,sha256=jzMp1529JXnMGTJijVy6b_1zmARAMNv70f2lgys7vn4,452
49
50
  scilens/readers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
50
51
  scilens/readers/cols_dataset.py,sha256=C4N030_Iqq5KZVpQ0NVjAw4DctALuz_YBb6f6yi35Jk,2452
51
52
  scilens/readers/exceptions.py,sha256=JzmxcjnR5sH-IOWVeCC5A1bSwxv-jCAtIJvDjzx1CTI,32
52
- scilens/readers/mat_dataset.py,sha256=6hmXIdGCfQrd4Y2_v-p65VmrO4I2J8ZddGBy-AgYLX0,1683
53
- scilens/readers/reader_csv.py,sha256=LFjbTv2CLungV8UwXzob5o_9G2c4cLEUCMoRXAyErKQ,3739
53
+ scilens/readers/mat_dataset.py,sha256=Z9TYDWaH2aqdniLNDjlpR6VVNHMSARjh52clhdMyOn4,1496
54
+ scilens/readers/reader_csv.py,sha256=MXjGdNHm1i9phhYLeMuNFjCvxuIeZH_KNs6ni3a4nS8,3893
54
55
  scilens/readers/reader_interface.py,sha256=nnttHL7wt4MOXpi-SBkk8DYxVWscOPG8JFl_z12mIAo,922
55
56
  scilens/readers/reader_manager.py,sha256=DFinxIk3IIIcB6JxybGcv-mXt3jhXgCwUtzR0TqhB2Q,2684
56
57
  scilens/readers/reader_txt.py,sha256=WPsFunEA_idzAKkD3UJQbLnaOzG2U03P3gY4gphuIw0,3868
57
- scilens/readers/reader_txt_fixed_cols.py,sha256=vIA6e38_3nkFeCT835eSyCufCXQNGav8Iy7VgHlT_EE,2314
58
+ scilens/readers/reader_txt_fixed_cols.py,sha256=B7toE3G9KGcgD_p15jzGHOLGIKZ7KMmEQoTt6-4UtHo,4064
58
59
  scilens/readers/transform.py,sha256=kppfgPkXymF0qtquFivuosLVfF66L9bE-wGx-3bMHv8,307
59
60
  scilens/report/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
60
61
  scilens/report/assets/logo.svg,sha256=W-1OVqcvdBjf-1AHHcV6WciIUqBoVFUh52Tc3o_jqtA,4519
@@ -67,32 +68,33 @@ scilens/report/templates/body_01_title.html,sha256=LJOWO6ImNPW9cg3tCDlgdllVTwnFG
67
68
  scilens/report/templates/body_02_tabs.html,sha256=oOFslWcfNsWpCX12GECZDzdR5uAHE54HPP6IYUf7y0U,412
68
69
  scilens/report/templates/body_99_footer.html,sha256=8cWebeWfZwZ-9bYAMZkZj8rbCWq3BLIMjKQThWQxoQM,362
69
70
  scilens/report/templates/compare_11_summary.html,sha256=qVvFydtAvAYyVOOTqjTN3LUj5Lh_Cl680EYL5SCZkd4,4086
70
- scilens/report/templates/compare_12_sections.html,sha256=8hCQRvdD_xhv8PGqT3WcfKxakWdCfGUFbv9HPBrNCro,6431
71
+ scilens/report/templates/compare_12_sections.html,sha256=EYYMqF2HeRXnWRke2vn9O2JCm8oKbx-r1NL7FJvYFDg,6431
71
72
  scilens/report/templates/compare_13_section_numbers copy.html,sha256=0PWK_I2kNX3LjPLkkY4eSYIeB7YFkA28nk-PPLDhnaY,1753
72
73
  scilens/report/templates/compare_13_section_numbers.html,sha256=9etEMSqwrDyJIn_nMbKEVaDgnFL_hBxSjPR-hU2wgDI,851
73
74
  scilens/report/templates/compare_13_section_numbers_table.html,sha256=sJy6ZYtjl80vM1b3oqZSXawZWp7KNIwLI_wCnvBwYPE,3270
74
- scilens/report/templates/index.html,sha256=NwIjcv_h_xu2tY7y2DNZup5UwohmSuejz2AF1EmgPxI,5370
75
+ scilens/report/templates/index.html,sha256=9XHzIJ6MPYq059oL1yoz01zv2LTVRcaTHmdspd3dS-c,5844
75
76
  scilens/report/templates/js_chartlibs_echarts.js,sha256=6YicVhTNIBmmBpV31XCVN5oBeiD0t29JIosJZRUv01M,907
76
- scilens/report/templates/js_chartlibs_plotly.js,sha256=mDf4O1pHqK69IqwGe6Irw8xLV-cnL7WZZ5ZEfUI2DZ4,2082
77
- scilens/report/templates/js_com_page.js,sha256=ZxYHR-KGQRH726rPOXrEgyzBKM9NtGH3_APvcawKxQw,6862
78
- scilens/report/templates/js_curvemgr.js,sha256=9t5ZDogVJTiI0oullrZ2IT7_qXG73CH_m2gNUpuY4oY,12199
77
+ scilens/report/templates/js_chartlibs_plotly.js,sha256=3uiQfbd95NMN-3N2NX3c4CC7zFb0JRtH-ZzezDVGeO8,2111
78
+ scilens/report/templates/js_com_page.js,sha256=Q-_Smn77IYIAdlrS1zJtsVIYBOL1t-J1AYYJKji4eL0,6864
79
+ scilens/report/templates/js_curvemgr.js,sha256=gnRLO6HbZOMLIBQKjVhV2PciqXtuNKxpGx4boijV2Qc,12175
79
80
  scilens/report/templates/js_dom.js,sha256=XnxgdB0x-Xtt0eQFrwjcFO1cb_KPsTImpJBB6m_y8FI,1229
80
81
  scilens/report/templates/js_palette.js,sha256=HeewAmkR67QiqXSanJS3cCgp6IPKomlULUTKt55F6es,218
81
82
  scilens/report/templates/style.css,sha256=SOKxdCqoj0yBt2zt3g1RkYx4ZV0_9PhGtO-TDWjmSHE,4217
82
- scilens/report/templates/uti_matrix.js,sha256=L2NqR9fu1075JGStWy6yS7EX4pHGAcBrhfR_cAL4VYw,2675
83
- scilens/report/templates/uti_spectrograms.js,sha256=EoZtBUYbup0KOvmcZRpnUGNrIZVbveqQK0aoIqkq94E,3066
84
- scilens/report/templates/utils_compare_report_anim.js,sha256=a7FHRco17BmgOAHb9kiDsFcSoxbmTGqjBbXBprf3hnU,2923
85
- scilens/report/templates/utils_compare_report_framesseries.js,sha256=su4zy29yZMqBlL213B1oLFpzBrmwta5jlc96fN_pphc,5697
83
+ scilens/report/templates/uti_frameseries.js,sha256=bYWmGByfWVHPfh-_3O7u10fhYd8SjWorXz4XzPpbp0A,1600
84
+ scilens/report/templates/uti_matrix.js,sha256=7QSslQ6RsHJGLuf4gnxpWYL8QVTcsjiV3ruGXo67PaM,2949
85
+ scilens/report/templates/uti_spectrograms.js,sha256=WYnNt5d8aGIeUCXy8q3MWRtpJzr4htMiH-mlxXpBeug,3586
86
+ scilens/report/templates/utils_compare_report_anim.js,sha256=6Yg1nQDrmAQSJzHtsmA0CO2Ng1ddiLIhrbKXSZAB-Ms,2971
87
+ scilens/report/templates/utils_compare_report_framesseries.js,sha256=kg5NDVJYL0dF2cwdunD4WpnckvfGOsxXuO1ttmEV8hw,5766
86
88
  scilens/report/vendors/tailwindcss_3_4_15.js,sha256=niHw6Rf0uS2pE5_8h-E18NI24o1urZL5Ac31_n9htKE,407279
87
89
  scilens/report/vendors/tailwindcss_min_4.0.0-beta.4.js,sha256=fy2LOvMX7m4b1V9WdtWC0dCPNIYhE2cLkFiD3JNcYhI,177617
88
90
  scilens/run/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
89
91
  scilens/run/models/task_results.py,sha256=hdr_QEwMnjdfdawpfuBRMGqCHWQvsF61G39CVEMXKl8,284
90
92
  scilens/run/models/task_runtime.py,sha256=VNbMPS1ocl6WUDG5ipUxp3RSAST2OZ5DqGcfJWFEed8,114
91
- scilens/run/run_task.py,sha256=suCnACK2RmcwGdmOUAxnb0UD3LC_VT8RH9S525rsr14,2828
92
- scilens/run/standalone_task_runner.py,sha256=D3SUgVzoYtFvfDRacX286gXswuyN4z37et_qxfly4Rs,515
93
+ scilens/run/run_task.py,sha256=EDi9Lk69DC5ik9ArWF47hZ5j9Z_TTAES7liTXzuUZEg,3183
94
+ scilens/run/standalone_task_runner.py,sha256=QYUZ22YPV8hlUFANRcfxy_RXAmwKSfb7glPqPdcgdMA,568
93
95
  scilens/run/task_context.py,sha256=NnujvpwnxY-YEzivYPYWaX-YChcZlEXt9y0_DXLqZkk,659
94
96
  scilens/run/tasks_collector.py,sha256=m_FQaJdQRi4fCLW17ryJxU0TvGNJN54JTw2Mg6XPojY,3174
95
- scilens/utils/dict.py,sha256=1MVQc8vZCs8_gQJMBkBSXO828wMe2eIWFiraLVmcjqk,214
97
+ scilens/utils/dict.py,sha256=ORdZ_521Em4YjV5S8EqzESi9eM2Dh5CR4JpLbd8JASk,384
96
98
  scilens/utils/file.py,sha256=ljtTHCvT7vfDSbHA-5aKDl9885SVce3TBXWRIA-aRx0,1664
97
99
  scilens/utils/load_model_from_file.py,sha256=k5I-B6s5nVZu90MgzKSM0_IRj9oNL-4oJJRTwEvOyw8,619
98
100
  scilens/utils/php.py,sha256=VBJxpzwwRPNcr3379f6ViwhpTzjGc4BKlSXHv4lnor8,444
@@ -101,7 +103,7 @@ scilens/utils/template.py,sha256=9dlXX3nmfzDRUwzPJOkoxk15UXivZ2SW-McdCwokFa4,443
101
103
  scilens/utils/time_tracker.py,sha256=DdVBoMpVLXrX0qZZXyLm4g38EwDVLlRcBqcpNex1mYY,545
102
104
  scilens/utils/vectors.py,sha256=4N2BZSC5n3HgZqPujDGF5NdjVmSL1rOHb_qw4OoABQY,103
103
105
  scilens/utils/web.py,sha256=MAFWpIFOKz7QhqDoFh-Qwstvc76KpcxstSgHFT8FOL4,901
104
- scilens-0.3.8.dist-info/METADATA,sha256=RTctyV618MmgiLWuaf1NfysYdqN1CC6SZKpCEFTpTzY,1367
105
- scilens-0.3.8.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
106
- scilens-0.3.8.dist-info/entry_points.txt,sha256=DaKGgxUEUv34GJAoXtta6ecL37ercejep9sCSSRQK2s,48
107
- scilens-0.3.8.dist-info/RECORD,,
106
+ scilens-0.3.10.dist-info/METADATA,sha256=aPB0OOpdRzsrIsxsGSYKGtJOVQ0lk_0-Zfgi8G3x0mc,1368
107
+ scilens-0.3.10.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
108
+ scilens-0.3.10.dist-info/entry_points.txt,sha256=DaKGgxUEUv34GJAoXtta6ecL37ercejep9sCSSRQK2s,48
109
+ scilens-0.3.10.dist-info/RECORD,,