scilens 0.4.11__py3-none-any.whl → 0.5.0__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.
@@ -6,82 +6,80 @@ import logging
6
6
  from scilens.components.compare_models import SEVERITY_ERROR,SEVERITY_WARNING,CompareGroup,CompareFloatsErr,Compare2ValuesResults
7
7
  from scilens.components.compare_errors import CompareErrors
8
8
  from scilens.config.models import CompareFloatThresholdsConfig
9
- try:from scilens_compare import vectors as CheckVectors
10
- except ModuleNotFoundError:pass
11
- def vector_get_amplitude(vector):min_val=min(vector);max_val=max(vector);return{'min':min_val,'max':max_val,_D:abs(max_val-min_val)}
9
+ from scilens.components.num import vectors as CheckVectors
10
+ def vector_get_amplitude(vector):A=vector;B=min(A);C=max(A);return{'min':B,'max':C,_D:abs(C-B)}
12
11
  class CompareFloats:
13
- def __init__(self,compare_errors,config):self.compare_errors=compare_errors;self.thresholds=config
14
- def compare_2_values(self,test,reference):
15
- thr=self.thresholds;sign=-1 if test-reference<0 else 1
16
- if abs(test)>thr.relative_vs_absolute_min and reference!=0:
17
- err=abs(test-reference)/abs(reference);comp_err=CompareFloatsErr(is_relative=True,value=sign*err,test=test,reference=reference)
18
- if err<thr.relative_error_max:
19
- if err>thr.relative_error_min:return Compare2ValuesResults(SEVERITY_WARNING,f"Rel. err. > {thr.relative_error_min} and < {thr.relative_error_max}",comp_err)
20
- else:return Compare2ValuesResults(SEVERITY_ERROR,f"Rel. err. > {thr.relative_error_max}",comp_err)
12
+ def __init__(A,compare_errors,config):A.compare_errors=compare_errors;A.thresholds=config
13
+ def compare_2_values(G,test,reference):
14
+ D=test;B=reference;A=G.thresholds;F=-1 if D-B<0 else 1
15
+ if abs(D)>A.relative_vs_absolute_min and B!=0:
16
+ C=abs(D-B)/abs(B);E=CompareFloatsErr(is_relative=True,value=F*C,test=D,reference=B)
17
+ if C<A.relative_error_max:
18
+ if C>A.relative_error_min:return Compare2ValuesResults(SEVERITY_WARNING,f"Rel. err. > {A.relative_error_min} and < {A.relative_error_max}",E)
19
+ else:return Compare2ValuesResults(SEVERITY_ERROR,f"Rel. err. > {A.relative_error_max}",E)
21
20
  else:
22
- err=abs(test-reference);comp_err=CompareFloatsErr(is_relative=_B,value=sign*err,test=test,reference=reference)
23
- if err<thr.absolute_error_max:
24
- if err>thr.absolute_error_min:return Compare2ValuesResults(SEVERITY_WARNING,f"Abs. err. > {thr.absolute_error_min} and < {thr.absolute_error_max}",comp_err)
25
- else:return Compare2ValuesResults(SEVERITY_ERROR,f"Abs. err. > {thr.absolute_error_max}",comp_err)
26
- def compare_dicts(self,test_dict,reference_dict,group):
27
- diffs_count=0;err_limit_reached=_B
28
- if set(test_dict.keys())!=set(reference_dict.keys()):raise Exception('Dictionaries have different keys')
29
- for key in test_dict:
30
- test_value=test_dict[key];reference_value=reference_dict[key];res_compare=self.compare_2_values(test_value,reference_value)
31
- if res_compare:err_limit_reached=self.compare_errors.add(group,res_compare,info={'key':key});diffs_count+=1;group.incr(_C)
32
- if err_limit_reached:break
33
- return err_limit_reached,diffs_count
34
- def compare_vectors(self,test_vector,reference_vector,group,info_vector=_A):
35
- B='ignore';A='RIAE_trapezoid'
36
- if len(test_vector)!=len(reference_vector):raise Exception('Vectors have different lengths')
37
- diffs_count=0;err_limit_reached=_B;ponderation_method=self.thresholds.vectors.ponderation_method if self.thresholds.vectors else _A
38
- if ponderation_method=='RIAE':ponderation_method=A
39
- if ponderation_method:logging.debug(f"Using ponderation method: {ponderation_method} with reduction_method {self.thresholds.vectors.reduction_method}")
40
- amplitude_compare=_A
41
- if self.thresholds.vectors and ponderation_method=='amplitude_moderation':amplitude=vector_get_amplitude(test_vector)[_D];amplitude_compare=amplitude*self.thresholds.vectors.amplitude_moderation_multiplier;reduction_method=self.thresholds.vectors.reduction_method
42
- RIAE_force_severity=_A
43
- if self.thresholds.vectors and ponderation_method in[A,'RIAE_midpoint']:
44
- if'CheckVectors'not in globals():raise Exception('scilens_compare not found. Please install scilens-compare package with `pip install scilens-compare`.')
45
- riae_error=CheckVectors.relative_integral_absolute_error_trapezoid(reference_vector,test_vector,range(len(test_vector)))if ponderation_method==A else CheckVectors.relative_integral_absolute_error_midpoint(reference_vector,test_vector,range(len(test_vector)))
46
- if riae_error is _A:logging.warning('RIAE calculation returned None. This may indicate an issue with the vectors.')
21
+ C=abs(D-B);E=CompareFloatsErr(is_relative=_B,value=F*C,test=D,reference=B)
22
+ if C<A.absolute_error_max:
23
+ if C>A.absolute_error_min:return Compare2ValuesResults(SEVERITY_WARNING,f"Abs. err. > {A.absolute_error_min} and < {A.absolute_error_max}",E)
24
+ else:return Compare2ValuesResults(SEVERITY_ERROR,f"Abs. err. > {A.absolute_error_max}",E)
25
+ def compare_dicts(D,test_dict,reference_dict,group):
26
+ F=group;E=reference_dict;A=test_dict;G=0;B=_B
27
+ if set(A.keys())!=set(E.keys()):raise Exception('Dictionaries have different keys')
28
+ for C in A:
29
+ I=A[C];J=E[C];H=D.compare_2_values(I,J)
30
+ if H:B=D.compare_errors.add(F,H,info={'key':C});G+=1;F.incr(_C)
31
+ if B:break
32
+ return B,G
33
+ def compare_vectors(A,test_vector,reference_vector,group,info_vector=_A):
34
+ R='ignore';M=info_vector;L='RIAE_trapezoid';H=group;F=reference_vector;B=test_vector
35
+ if len(B)!=len(F):raise Exception('Vectors have different lengths')
36
+ N=0;G=_B;D=A.thresholds.vectors.ponderation_method if A.thresholds.vectors else _A
37
+ if D=='RIAE':D=L
38
+ if D:logging.debug(f"Using ponderation method: {D} with reduction_method {A.thresholds.vectors.reduction_method}")
39
+ I=_A
40
+ if A.thresholds.vectors and D=='amplitude_moderation':S=vector_get_amplitude(B)[_D];I=S*A.thresholds.vectors.amplitude_moderation_multiplier;O=A.thresholds.vectors.reduction_method
41
+ J=_A
42
+ if A.thresholds.vectors and D in[L,'RIAE_midpoint']:
43
+ K=CheckVectors.relative_integral_absolute_error_trapezoid(F,B,range(len(B)))if D==L else CheckVectors.relative_integral_absolute_error_midpoint(F,B,range(len(B)))
44
+ if K is _A:logging.warning('RIAE calculation returned None. This may indicate an issue with the vectors.')
47
45
  else:
48
- RIAE_force_severity=self.thresholds.vectors.reduction_method
49
- if riae_error>self.thresholds.vectors.riae_threshold:ee=CompareFloatsErr(is_relative=_B,value=riae_error);res_compare=Compare2ValuesResults(SEVERITY_ERROR,f"RIAE ({ponderation_method}) > {self.thresholds.vectors.riae_threshold}",ee);err_limit_reached=self.compare_errors.add(group,res_compare)
50
- nb=len(test_vector)
51
- for idx in range(nb):
52
- diff=test_vector[idx]-reference_vector[idx]
53
- if diff==0:continue
54
- else:diffs_count+=1;group.incr(_C)
55
- if err_limit_reached:continue
56
- if RIAE_force_severity==B:continue
57
- if amplitude_compare is not _A and abs(diff)<amplitude_compare:
58
- if reduction_method==B:continue
59
- elif reduction_method=='soften':
60
- res_compare=self.compare_2_values(test_vector[idx],reference_vector[idx])
61
- if res_compare:res_compare.severity=SEVERITY_WARNING
46
+ J=A.thresholds.vectors.reduction_method
47
+ if K>A.thresholds.vectors.riae_threshold:T=CompareFloatsErr(is_relative=_B,value=K);C=Compare2ValuesResults(SEVERITY_ERROR,f"RIAE ({D}) > {A.thresholds.vectors.riae_threshold}",T);G=A.compare_errors.add(H,C)
48
+ U=len(B)
49
+ for E in range(U):
50
+ P=B[E]-F[E]
51
+ if P==0:continue
52
+ else:N+=1;H.incr(_C)
53
+ if G:continue
54
+ if J==R:continue
55
+ if I is not _A and abs(P)<I:
56
+ if O==R:continue
57
+ elif O=='soften':
58
+ C=A.compare_2_values(B[E],F[E])
59
+ if C:C.severity=SEVERITY_WARNING
62
60
  else:
63
- res_compare=self.compare_2_values(test_vector[idx],reference_vector[idx])
64
- if res_compare and RIAE_force_severity:res_compare.severity=SEVERITY_WARNING
65
- if res_compare:
66
- info={'index':idx}
67
- if info_vector:info['info']=info_vector[idx]
68
- err_limit_reached=self.compare_errors.add(group,res_compare,info=info)
69
- return err_limit_reached,diffs_count
70
- def add_group_and_compare_vectors(self,group_name,parent_group,group_data,test_vector,reference_vector,info_vector=_A):_,group=self.compare_errors.add_group('vectors',group_name,parent=parent_group,data=group_data);return(group,)+self.compare_vectors(test_vector,reference_vector,group,info_vector=info_vector)
71
- def compare_matrices(self,test_mat,ref_mat,group,x_vector=_A,y_vector=_A):
72
- diffs_count=0;err_limit_reached=_B;test_nb_lines=len(test_mat);test_nb_columns=len(test_mat[0])if test_nb_lines>0 else 0;ref_nb_lines=len(ref_mat);ref_nb_columns=len(ref_mat[0])if ref_nb_lines>0 else 0
73
- if test_nb_lines!=ref_nb_lines or test_nb_columns!=ref_nb_columns:raise Exception('Matrices have different dimensions')
74
- for i in range(test_nb_lines):
75
- for j in range(test_nb_columns):
76
- diff=test_mat[i][j]-ref_mat[i][j]
77
- if diff==0:continue
78
- else:diffs_count+=1;group.incr(_C)
79
- if err_limit_reached:continue
80
- res_compare=self.compare_2_values(test_mat[i][j],ref_mat[i][j])
81
- if res_compare:
82
- info={'i':i+1,'j':j+1}
83
- if x_vector:info['x']=x_vector[j]
84
- if y_vector:info['y']=y_vector[i]
85
- err_limit_reached=self.compare_errors.add(group,res_compare,info=info)
86
- return err_limit_reached,diffs_count
87
- def add_group_and_compare_matrices(self,group_name,parent_group,group_data,test_mat,ref_mat,x_vector=_A,y_vector=_A):_,group=self.compare_errors.add_group('matrix',group_name,parent=parent_group,data=group_data);return(group,)+self.compare_matrices(test_mat,ref_mat,group,x_vector=x_vector,y_vector=y_vector)
61
+ C=A.compare_2_values(B[E],F[E])
62
+ if C and J:C.severity=SEVERITY_WARNING
63
+ if C:
64
+ Q={'index':E}
65
+ if M:Q['info']=M[E]
66
+ G=A.compare_errors.add(H,C,info=Q)
67
+ return G,N
68
+ def add_group_and_compare_vectors(A,group_name,parent_group,group_data,test_vector,reference_vector,info_vector=_A):C,B=A.compare_errors.add_group('vectors',group_name,parent=parent_group,data=group_data);return(B,)+A.compare_vectors(test_vector,reference_vector,B,info_vector=info_vector)
69
+ def compare_matrices(H,test_mat,ref_mat,group,x_vector=_A,y_vector=_A):
70
+ K=y_vector;J=x_vector;I=group;D=ref_mat;C=test_mat;L=0;E=_B;F=len(C);M=len(C[0])if F>0 else 0;N=len(D);P=len(D[0])if N>0 else 0
71
+ if F!=N or M!=P:raise Exception('Matrices have different dimensions')
72
+ for A in range(F):
73
+ for B in range(M):
74
+ Q=C[A][B]-D[A][B]
75
+ if Q==0:continue
76
+ else:L+=1;I.incr(_C)
77
+ if E:continue
78
+ O=H.compare_2_values(C[A][B],D[A][B])
79
+ if O:
80
+ G={'i':A+1,'j':B+1}
81
+ if J:G['x']=J[B]
82
+ if K:G['y']=K[A]
83
+ E=H.compare_errors.add(I,O,info=G)
84
+ return E,L
85
+ def add_group_and_compare_matrices(A,group_name,parent_group,group_data,test_mat,ref_mat,x_vector=_A,y_vector=_A):C,B=A.compare_errors.add_group('matrix',group_name,parent=parent_group,data=group_data);return(B,)+A.compare_matrices(test_mat,ref_mat,B,x_vector=x_vector,y_vector=y_vector)
@@ -8,7 +8,7 @@ SEVERITY_WARNING='warning'
8
8
  class CompareFloatsErr:is_relative:bool;value:float;test:float|_A=_A;reference:float|_A=_A
9
9
  @dataclass
10
10
  class Compare2ValuesResults:severity:str;message:str;comp_err:CompareFloatsErr|_A=_A
11
- class CompareErr(BaseModel):err:CompareFloatsErr|_A;msg:int;group:int|_A=_A;info:dict|_A=_A
11
+ class CompareErr(BaseModel):err:CompareFloatsErr|_A;msg:int;group:int|_A=_A;info:dict|str|_A=_A
12
12
  COMPARE_GROUP_TYPE=Literal['node','lines','vectors',' matrix','metrics','pixels']
13
13
  @dataclass
14
14
  class CompareGroup:
@@ -0,0 +1,3 @@
1
+ import numpy as np
2
+ def relative_integral_absolute_error_trapezoid(ref_array_like,test_array_like,x_array_like):C=x_array_like;B=test_array_like;A=ref_array_like;F=B if isinstance(B,np.ndarray)else np.array(B);G=A if isinstance(A,np.ndarray)else np.array(A);D=C if isinstance(C,np.ndarray)else np.array(C);H=np.abs(G-F);I=np.trapezoid(H,D);E=np.trapezoid(np.abs(A),D);return I/E if E!=0 else None
3
+ def relative_integral_absolute_error_midpoint(ref_array_like,test_array_like,x_array_like):C=x_array_like;B=test_array_like;A=ref_array_like;G=B if isinstance(B,np.ndarray)else np.array(B);D=A if isinstance(A,np.ndarray)else np.array(A);H=C if isinstance(C,np.ndarray)else np.array(C);I=np.abs(D-G);E=np.diff(H);J=np.sum(I[:-1]*E);F=np.sum(np.abs(D[:-1])*E);return J/F if F!=0 else None
@@ -6,6 +6,7 @@ from.execute import ExecuteConfig
6
6
  from.reader_format_txt import ReaderTxtIgnoreConfig,ReaderTxtConfig
7
7
  from.reader_format_csv import ReaderCsvConfig
8
8
  from.reader_format_txt_fixed_cols import ReaderTxtFixedColsConfig
9
+ from.reader_format_trees import ReaderJsonConfig,ReaderXmlConfig,ReaderYamlConfig
9
10
  from.readers import ReadersConfig
10
11
  from.file_reader import FileReaderConfig
11
12
  from.report_html import ReportHtmlConfig,ReportHtmlCurvesConfig,ReportParameterOpenFileInConfig,ReportParameterPageModeConfig
@@ -2,7 +2,7 @@ _B='forbid'
2
2
  _A=None
3
3
  from pydantic import BaseModel,Field,model_validator
4
4
  class CompareFloatVectorsConfig(BaseModel,extra=_B):
5
- reduction_method:str=Field(default='soften',description="Méthode de réduction de sévérité des erreurs. Peut être `soften` ou `ignore`. Si `soften`, réduit la sévérité de l'erreur. Si `ignore`, ne lève pas d'erreur.");ponderation_method:str=Field(description='Méthode de calcul de reduction de sévérité. Peut être`amplitude_moderation`, `RIAE`, `RIAE_trapezoid` ou `RIAE_midpoint`.');amplitude_moderation_multiplier:float|_A=Field(default=_A,description="Multipler utilisé dans l'amplitude pondérée `multiplier * |Max(Vector)-Min(Vector)|` qui sera comparée à l'erreur absolue `|Test-Reference|`.");riae_threshold:float|_A=Field(default=_A,description="Seuil de l'erreur relative intégrale absolue. Si l'erreur est supérieure à ce seuil, on appliquera la reduction_method globalement.")
5
+ reduction_method:str=Field(default='soften',description="Méthode de réduction de sévérité des erreurs. Peut être `soften` ou `ignore`. Si `soften`, réduit la sévérité de l'erreur. Si `ignore`, ne lève pas d'erreur.");ponderation_method:str=Field(description='Méthode de calcul de reduction de sévérité. Peut être`amplitude_moderation`, `RIAE`, `RIAE_trapezoid` ou `RIAE_midpoint` (`RIAE`=`RIAE_trapezoid`).');amplitude_moderation_multiplier:float|_A=Field(default=_A,description="Multipler utilisé dans l'amplitude pondérée `multiplier * |Max(Vector)-Min(Vector)|` qui sera comparée à l'erreur absolue `|Test-Reference|`.");riae_threshold:float|_A=Field(default=_A,description="Seuil de l'erreur relative intégrale absolue. Si l'erreur est supérieure à ce seuil, on appliquera la reduction_method globalement.")
6
6
  @model_validator(mode='after')
7
7
  def check_value_required(self):
8
8
  A=self
@@ -17,4 +17,4 @@ class ReaderColsCurveParserConfig(BaseModel,extra=_B):
17
17
  elif A.name==ReaderCurveParserNameConfig.COLS_COUPLE:A.parameters=ReaderCurveParserColsCoupleConfig(**A.parameters)
18
18
  return A
19
19
  class ReaderColsRowsConfig(BaseModel,extra=_B):ignore_patterns:list[str]|_A=Field(default=_A,description='Liste des patterns de lignes à ignorer. Ex: ["^#", "^//"]. Non applicable si `is_matrix` est vrai.');line_start:int|_A=Field(default=_A,description='Ligne de début pour lire le fichier (les en-têtes sont comptées comme une ligne). Si non défini, commence à la première ligne.');line_end:int|_A=Field(default=_A,description="Ligne de fin pour lire le fichier (les en-têtes sont comptées comme une ligne). Si non défini, lit jusqu'à la dernière ligne.");index_min_value:float|_A=Field(default=_A,description="Valeur minimale de l'index pour les lignes à lire (valeur incluses).");index_max_value:float|_A=Field(default=_A,description="Valeur maximale de l'index pour les lignes à lire (valeur incluses).")
20
- class ReaderColsConfig(BaseModel,extra=_B):ignore_columns:list[str]|list[int]|_A=Field(default=_A,description="Liste des colonnes à ignorer (nom de l'en tête ou numéro de colonne).");index_col:int|str|list[str]|_A=Field(default=_A,description='Colonne(s) à utiliser comme index (date/heure, itération, étape, ...) (Utilisé dans différentes règles). Numéro de colonne ou nom(s) de colonne. (Valide seulement si non matrice)');rows:ReaderColsRowsConfig|_A=Field(default=_A,description='Configuration des lignes à lire.');curve_parser:ReaderColsCurveParserConfig|_A=Field(default=_A,description='Parseur de courbe à utiliser.')
20
+ class ReaderColsConfig(BaseModel,extra=_B):ignore_columns:list[str]|list[int]|_A=Field(default=_A,description="Liste des colonnes à ignorer (nom de l'en tête ou numéro de colonne).");select_columns:list[str]|list[int]|_A=Field(default=_A,description="Liste des colonnes à sélectionner (nom de l'en tête ou numéro de colonne).");index_col:int|str|list[str]|_A=Field(default=_A,description='Colonne(s) à utiliser comme index (date/heure, itération, étape, ...) (Utilisé dans différentes règles). Numéro de colonne ou nom(s) de colonne. (Valide seulement si non matrice)');rows:ReaderColsRowsConfig|_A=Field(default=_A,description='Configuration des lignes à lire.');curve_parser:ReaderColsCurveParserConfig|_A=Field(default=_A,description='Parseur de courbe à utiliser.')
@@ -0,0 +1,7 @@
1
+ _B=None
2
+ _A='forbid'
3
+ from pydantic import BaseModel,Field
4
+ class ReaderTreeBaseConfig(BaseModel,extra=_A):path_exclude_patterns:list[str]|_B=Field(default=_B,description='Patterns (Unix shell-style wildcards) to exclude certain paths from processing.');path_include_patterns:list[str]|_B=Field(default=_B,description='Patterns (Unix shell-style wildcards) to include certain paths from processing.')
5
+ class ReaderJsonConfig(ReaderTreeBaseConfig,extra=_A):0
6
+ class ReaderXmlConfig(ReaderTreeBaseConfig,extra=_A):0
7
+ class ReaderYamlConfig(ReaderTreeBaseConfig,extra=_A):0
@@ -1,14 +1,19 @@
1
+ _B=None
1
2
  _A='forbid'
2
- from typing import Literal
3
+ from typing import Literal,Optional
3
4
  from pydantic import BaseModel,Field
4
5
  from scilens.config.models.reader_format_txt import ReaderTxtConfig
5
6
  from scilens.config.models.reader_format_csv import ReaderCsvConfig
6
7
  from scilens.config.models.reader_format_txt_fixed_cols import ReaderTxtFixedColsConfig
8
+ from scilens.config.models.reader_format_trees import ReaderJsonConfig,ReaderXmlConfig,ReaderYamlConfig
7
9
  from scilens.config.models.reader_format_netcdf import ReaderNetcdfConfig
8
10
  class BaseCatalogItem(BaseModel,extra=_A):type:str
9
11
  class ReaderTxtConfigItem(BaseCatalogItem,extra=_A):type:Literal['txt'];parameters:ReaderTxtConfig
10
12
  class ReaderCsvConfigItem(BaseCatalogItem,extra=_A):type:Literal['csv'];parameters:ReaderCsvConfig
11
13
  class ReaderTxtFixedColsConfigItem(BaseCatalogItem,extra=_A):type:Literal['txt_fixed_cols'];parameters:ReaderTxtFixedColsConfig
14
+ class ReaderJsonFixedColsConfigItem(BaseCatalogItem,extra=_A):type:Literal['json_fixed_cols'];parameters:ReaderTxtFixedColsConfig
15
+ class ReaderXmlFixedColsConfigItem(BaseCatalogItem,extra=_A):type:Literal['xml_fixed_cols'];parameters:ReaderTxtFixedColsConfig
16
+ class ReaderYamlFixedColsConfigItem(BaseCatalogItem,extra=_A):type:Literal['yaml_fixed_cols'];parameters:ReaderTxtFixedColsConfig
12
17
  class ReaderNetcdfConfigItem(BaseCatalogItem,extra=_A):type:Literal['netcdf'];parameters:ReaderNetcdfConfig
13
- CATALOG_ITEM_TYPE=ReaderTxtConfigItem|ReaderCsvConfigItem|ReaderTxtFixedColsConfigItem|ReaderNetcdfConfigItem
14
- class ReadersConfig(BaseModel,extra=_A):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': ';'}}}`")
18
+ CATALOG_ITEM_TYPE=ReaderTxtConfigItem|ReaderCsvConfigItem|ReaderTxtFixedColsConfigItem|ReaderJsonFixedColsConfigItem|ReaderXmlFixedColsConfigItem|ReaderYamlFixedColsConfigItem|ReaderNetcdfConfigItem
19
+ class ReadersConfig(BaseModel,extra=_A):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.');json:ReaderJsonConfig|_B=Field(default=_B,description='Configuration des readers json.');xml:ReaderXmlConfig|_B=Field(default=_B,description='Configuration des readers xml.');yaml:ReaderYamlConfig|_B=Field(default=_B,description='Configuration des readers yaml.');netcdf:ReaderNetcdfConfig=Field(default=ReaderNetcdfConfig(),description='Configuration des readers netcdf.');catalog:dict[str,CATALOG_ITEM_TYPE]|_B=Field(default=_B,description="Catalogue de configuration de readers par clé. Ex: `{'csv_comma': {'type': 'csv', 'parameters': {'delimiter': ','}}, 'csv_semicolon': {'type': 'csv', 'parameters': {'delimiter': ';'}}}`")
@@ -0,0 +1,11 @@
1
+ import logging
2
+ from scilens.readers.reader_interface import ReaderInterface
3
+ from scilens.config.models import ReaderJsonConfig
4
+ from scilens.components.compare_floats import CompareFloats
5
+ import json
6
+ from.tree import Tree
7
+ class ReaderJson(ReaderInterface):
8
+ configuration_type_code='json';category='datalines';extensions=['JSON']
9
+ def read(A,config):C=None;B=config;A.reader_options=B;D=open(A.origin.path,'r',encoding=A.encoding);E=json.load(D);D.close();A.floats_data=Tree.data_to_numeric_values(E,include_patterns=B.path_include_patterns if B else C,exclude_patterns=B.path_exclude_patterns if B else C);A.metrics=C
10
+ def compare(A,compare_floats,param_reader,param_is_ref=True):C=param_is_ref;B=param_reader;D=A if C else B;E=A if not C else B;Tree.compare(compare_floats,test_floats_data=D.floats_data,ref_floats_data=E.floats_data)
11
+ def class_info(A):return{'metrics':A.metrics}
@@ -12,7 +12,10 @@ def extension_format(extension):
12
12
  from scilens.readers.reader_txt import ReaderTxt
13
13
  from scilens.readers.reader_csv import ReaderCsv
14
14
  from scilens.readers.reader_txt_fixed_cols import ReaderTxtFixedCols
15
- BUILTIN_PLUGINS=[ReaderTxt,ReaderCsv,ReaderTxtFixedCols]
15
+ from scilens.readers.reader_json import ReaderJson
16
+ from scilens.readers.reader_yaml import ReaderYaml
17
+ from scilens.readers.reader_xml import ReaderXml
18
+ BUILTIN_PLUGINS=[ReaderTxt,ReaderCsv,ReaderTxtFixedCols,ReaderJson,ReaderYaml,ReaderXml]
16
19
  LIB_PLUGINS_ENTRY_POINT='scilens.reader_plugins'
17
20
  class ReaderManager:
18
21
  def __init__(A):
@@ -28,23 +31,26 @@ class ReaderManager:
28
31
  for A in B.plugins:
29
32
  if code==A.configuration_type_code:return A
30
33
  def get_reader_from_file(F,path,name='',config=_A,readers_config=_A,curve_parser=_A):
31
- I=curve_parser;G=path;C=readers_config;A=config;J=ReaderOrigin(type='file',path=G,short_name=os.path.basename(G));K=A.encoding if A else'utf-8';Q,D=os.path.splitext(G);D=extension_format(D)
32
- if A and A.extension_readers_catalog:
33
- for(M,L)in A.extension_readers_catalog.items():
34
- if extension_format(M)==D:
35
- if not C.catalog or L not in C.catalog.keys():raise NoReaderFound(f"Reader config not found for {D}")
36
- H=C.catalog[L];B=F._get_reader_from_configuration_type_code(H.type)
37
- if not B:raise Exception(f"Reader not found for contiguration type code {H.type}")
38
- N=H.parameters;return B(J,name=name,encoding=K,curve_parser=I),N
39
- if A and A.extension_mapping:
40
- for(O,P)in A.extension_mapping.items():
41
- if extension_format(O)==D:D=extension_format(P);break
42
- B=F._get_reader_from_extension(D)
43
- if not B and A and A.extension_fallback:B=F._get_reader_from_extension(A.extension_fallback)
44
- if not B:raise NoReaderFound(f"Reader cound not be derived")
45
- E=_A
46
- if B.__name__=='ReaderTxt':E=C.txt
47
- elif B.__name__=='ReaderCsv':E=C.csv
48
- elif B.__name__=='ReaderTxtFixedCols':E=C.txt_fixed_cols
49
- elif B.__name__=='ReaderNetcdf':E=C.netcdf
50
- return B(J,name=name,encoding=K,curve_parser=I),E
34
+ I=curve_parser;G=path;C=readers_config;B=config;J=ReaderOrigin(type='file',path=G,short_name=os.path.basename(G));K=B.encoding if B else'utf-8';Q,E=os.path.splitext(G);E=extension_format(E)
35
+ if B and B.extension_readers_catalog:
36
+ for(M,L)in B.extension_readers_catalog.items():
37
+ if extension_format(M)==E:
38
+ if not C.catalog or L not in C.catalog.keys():raise NoReaderFound(f"Reader config not found for {E}")
39
+ H=C.catalog[L];A=F._get_reader_from_configuration_type_code(H.type)
40
+ if not A:raise Exception(f"Reader not found for contiguration type code {H.type}")
41
+ N=H.parameters;return A(J,name=name,encoding=K,curve_parser=I),N
42
+ if B and B.extension_mapping:
43
+ for(O,P)in B.extension_mapping.items():
44
+ if extension_format(O)==E:E=extension_format(P);break
45
+ A=F._get_reader_from_extension(E)
46
+ if not A and B and B.extension_fallback:A=F._get_reader_from_extension(B.extension_fallback)
47
+ if not A:raise NoReaderFound(f"Reader cound not be derived")
48
+ D=_A
49
+ if A.__name__=='ReaderTxt':D=C.txt
50
+ elif A.__name__=='ReaderCsv':D=C.csv
51
+ elif A.__name__=='ReaderTxtFixedCols':D=C.txt_fixed_cols
52
+ elif A.__name__=='ReaderJson':D=C.json
53
+ elif A.__name__=='ReaderXml':D=C.xml
54
+ elif A.__name__=='ReaderYaml':D=C.yaml
55
+ elif A.__name__=='ReaderNetcdf':D=C.netcdf
56
+ return A(J,name=name,encoding=K,curve_parser=I),D
@@ -69,21 +69,24 @@ class ReaderTxtFixedCols(ReaderInterface):
69
69
  if D and D.ignore_columns:
70
70
  if isinstance(D.ignore_columns[0],str):C.numeric_col_indexes=[A for A in C.numeric_col_indexes if C.names[A]not in D.ignore_columns]
71
71
  if isinstance(D.ignore_columns[0],int):Q=[A-1 for A in D.ignore_columns];C.numeric_col_indexes=[A for A in C.numeric_col_indexes if A not in Q]
72
+ if D and D.select_columns:
73
+ if isinstance(D.select_columns[0],str):C.numeric_col_indexes=[A for A in C.numeric_col_indexes if C.names[A]in D.select_columns]
74
+ if isinstance(D.select_columns[0],int):R=[A-1 for A in D.select_columns];C.numeric_col_indexes=[A for A in C.numeric_col_indexes if A in R]
72
75
  H=I or 0
73
76
  for N in islice(L,I,K):
74
77
  H+=1
75
78
  if A._ignore_line(N):continue
76
79
  if F:
77
80
  if F.ori_line_idx==H-1:continue
78
- for(R,O)in enumerate(E):S=N[O[0]:O[1]].strip();T=string_2_float(S);C.data[R].append(T)
81
+ for(S,O)in enumerate(E):T=N[O[0]:O[1]].strip();U=string_2_float(T);C.data[S].append(U)
79
82
  C.origin_line_nb.append(H)
80
83
  C.rows_count=len(C.origin_line_nb);L.close();A.cols_dataset=C;A.raw_lines_number=H;A.metrics=_A
81
84
  if B.metrics:A.metrics=C.compute_metrics(B.metrics)
82
85
  A.curves=_A;A.cols_curve=_A
83
86
  if B.cols and B.cols.curve_parser:
84
87
  if B.cols.curve_parser.name==ReaderCurveParserNameConfig.COL_X:
85
- A.curves,U=C.get_curves_col_x(B.cols.curve_parser.parameters.x)
86
- if A.curves:A.cols_curve=ColsCurves(type=ReaderCurveParserNameConfig.COL_X,info=U,curves=A.curves)
88
+ A.curves,V=C.get_curves_col_x(B.cols.curve_parser.parameters.x)
89
+ if A.curves:A.cols_curve=ColsCurves(type=ReaderCurveParserNameConfig.COL_X,info=V,curves=A.curves)
87
90
  elif B.cols.curve_parser.name==ReaderCurveParserNameConfig.COLS_COUPLE:raise NotImplementedError('cols_couple not implemented')
88
91
  else:raise Exception('Curve parser not supported.')
89
92
  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)
@@ -0,0 +1,12 @@
1
+ import logging
2
+ from scilens.readers.reader_interface import ReaderInterface
3
+ from scilens.config.models import ReaderXmlConfig
4
+ from scilens.components.compare_floats import CompareFloats
5
+ from.tree import Tree
6
+ from scilens.utils.xml import etree_to_dict
7
+ import xml.etree.ElementTree as ET
8
+ class ReaderXml(ReaderInterface):
9
+ configuration_type_code='xml';category='datalines';extensions=['XML']
10
+ def read(A,config):C=None;B=config;A.reader_options=B;D=open(A.origin.path,'r',encoding=A.encoding);E=ET.parse(D);F=E.getroot();G=etree_to_dict(F);D.close();A.floats_data=Tree.data_to_numeric_values(G,include_patterns=B.path_include_patterns if B else C,exclude_patterns=B.path_exclude_patterns if B else C);A.metrics=C
11
+ def compare(A,compare_floats,param_reader,param_is_ref=True):C=param_is_ref;B=param_reader;D=A if C else B;E=A if not C else B;Tree.compare(compare_floats,test_floats_data=D.floats_data,ref_floats_data=E.floats_data)
12
+ def class_info(A):return{'metrics':A.metrics}
@@ -0,0 +1,11 @@
1
+ import logging
2
+ from scilens.readers.reader_interface import ReaderInterface
3
+ from scilens.config.models import ReaderYamlConfig
4
+ from scilens.components.compare_floats import CompareFloats
5
+ import yaml
6
+ from.tree import Tree
7
+ class ReaderYaml(ReaderInterface):
8
+ configuration_type_code='yaml';category='datalines';extensions=['YAML']
9
+ def read(A,config):C=None;B=config;A.reader_options=B;D=open(A.origin.path,'r',encoding=A.encoding);E=yaml.safe_load(D);D.close();A.floats_data=Tree.data_to_numeric_values(E,include_patterns=B.path_include_patterns if B else C,exclude_patterns=B.path_exclude_patterns if B else C);A.metrics=C
10
+ def compare(A,compare_floats,param_reader,param_is_ref=True):C=param_is_ref;B=param_reader;D=A if C else B;E=A if not C else B;Tree.compare(compare_floats,test_floats_data=D.floats_data,ref_floats_data=E.floats_data)
11
+ def class_info(A):return{'metrics':A.metrics}
@@ -0,0 +1,69 @@
1
+ _B=False
2
+ _A=None
3
+ import logging,fnmatch
4
+ from scilens.components.compare_floats import CompareFloats
5
+ from scilens.components.compare_models import SEVERITY_ERROR,Compare2ValuesResults
6
+ NumericPathValues=list[tuple[str,float]]
7
+ def find_numeric_values_and_keys(k,v):
8
+ A=[]
9
+ if isinstance(v,dict):
10
+ for(B,C)in v.items():A.extend(find_numeric_values_and_keys(f"{k}/{B}",C))
11
+ elif isinstance(v,list):
12
+ for(B,C)in enumerate(v):A.extend(find_numeric_values_and_keys(f"{k}[{B}]",C))
13
+ elif isinstance(v,(int,float)):A.append((k,v))
14
+ elif isinstance(v,str):
15
+ try:D=float(v);A.append((k,D))
16
+ except ValueError:pass
17
+ return A
18
+ def find_numeric_values(v):
19
+ A=[]
20
+ if isinstance(v,dict):
21
+ for B in v.values():A.extend(find_numeric_values(B))
22
+ elif isinstance(v,list):
23
+ for C in v:A.extend(find_numeric_values(C))
24
+ elif isinstance(v,(int,float)):A.append(v)
25
+ elif isinstance(v,str):
26
+ try:D=float(v);A.append(D)
27
+ except ValueError:pass
28
+ return A
29
+ def filter_numeric_values_by_patterns(numeric_values_with_keys,include_patterns=_A,exclude_patterns=_A):
30
+ E=exclude_patterns;D=include_patterns;F=[]
31
+ for(B,G)in numeric_values_with_keys:
32
+ A=True
33
+ if E:
34
+ for C in E:
35
+ if fnmatch.fnmatch(B,C):A=_B;break
36
+ if A and D:
37
+ A=_B
38
+ for C in D:
39
+ if fnmatch.fnmatch(B,C):A=True;break
40
+ if A:F.append((B,G))
41
+ return F
42
+ class Tree:
43
+ @classmethod
44
+ def data_to_numeric_values(F,data,include_patterns=_A,exclude_patterns=_A):
45
+ E=exclude_patterns;D=include_patterns;logging.debug(f"Extracting numeric values from tree data");A=find_numeric_values_and_keys('',data);logging.debug(f"Found {len(A)} numeric values in tree data, 10 first:")
46
+ for(B,C)in A[:10]:logging.debug(f" {B}: {C}")
47
+ if D or E:
48
+ logging.debug(f"Applying include/exclude patterns");A=filter_numeric_values_by_patterns(A,include_patterns=D,exclude_patterns=E);logging.debug(f"After filtering, {len(A)} numeric values remain, 10 first:")
49
+ for(B,C)in A[:10]:logging.debug(f" {B}: {C}")
50
+ return A
51
+ @classmethod
52
+ def compare(V,compare_floats,test_floats_data,ref_floats_data):
53
+ Q='diff';P='tree';C=ref_floats_data;B=test_floats_data;A=compare_floats;R,S=A.compare_errors.add_group('node','json');R,D=A.compare_errors.add_group(P,P,parent=S);B=sorted(B,key=lambda x:x[0]);C=sorted(C,key=lambda x:x[0]);E=_B;K=len(B);L=len(C);T=max(K,L);F=0;G=0
54
+ for W in range(T):
55
+ H,M=B[F]if F<K else(_A,_A);J,N=C[G]if G<L else(_A,_A)
56
+ if H!=J:
57
+ D.incr(Q)
58
+ if not E:
59
+ if J>H:F+=1;I=f"Test: {H}"
60
+ else:G+=1;I=f"Ref.: {J}"
61
+ E=A.compare_errors.add(D,Compare2ValuesResults(SEVERITY_ERROR,'Different keys for numeric values'),info=I)
62
+ continue
63
+ F+=1;G+=1;I=H;U=M-N
64
+ if U==0:continue
65
+ else:
66
+ D.incr(Q)
67
+ if not E:
68
+ O=A.compare_2_values(M,N)
69
+ if O:E=A.compare_errors.add(D,O,info=I)
@@ -26,6 +26,9 @@
26
26
  <th class="p-2" rowspan="2">x</th>
27
27
  <th class="p-2" rowspan="2">y</th>
28
28
  {% endif %}
29
+ {% if group.type == "tree" %}
30
+ <th class="p-2" colspan="2" rowspan="2">Key</th>
31
+ {% endif %}
29
32
  </tr>
30
33
  <tr>
31
34
  <th class="p-2 test-bg-50">Test</th>
@@ -86,6 +89,10 @@
86
89
  <td class="number">{{ item.info.y }}</td>
87
90
  {% endif %}
88
91
 
92
+ {% if group.type == "tree" %}
93
+ <td>{{ item.info }}</td>
94
+ {% endif %}
95
+
89
96
  </tr>
90
97
  {% endfor %}
91
98
  {% endfor %}
scilens/utils/xml.py ADDED
@@ -0,0 +1,19 @@
1
+ import xml.etree.ElementTree as ET
2
+ def etree_to_dict(t):
3
+ C={t.tag:{}if t.attrib else None};D=list(t)
4
+ if D:
5
+ A={}
6
+ for G in map(etree_to_dict,D):
7
+ for(B,E)in G.items():
8
+ if B in A:
9
+ if isinstance(A[B],list):A[B].append(E)
10
+ else:A[B]=[A[B],E]
11
+ else:A[B]=E
12
+ C={t.tag:A}
13
+ if t.attrib:C[t.tag].update(('@'+A,B)for(A,B)in t.attrib.items())
14
+ if t.text:
15
+ F=t.text.strip()
16
+ if D or t.attrib:
17
+ if F:C[t.tag]['#text']=F
18
+ else:C[t.tag]=F
19
+ return C
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: scilens
3
- Version: 0.4.11
3
+ Version: 0.5.0
4
4
  Summary: A CesGensLaB framework for data collecting and deep analysis
5
5
  Home-page: https://scilens.dev
6
6
  License: Proprietary
@@ -14,11 +14,12 @@ Classifier: Programming Language :: Python :: 3.11
14
14
  Classifier: Programming Language :: Python :: 3.12
15
15
  Classifier: Programming Language :: Python :: 3.13
16
16
  Requires-Dist: coloredlogs (>=15.0.1,<16.0.0)
17
- Requires-Dist: jinja2 (>=3.1.4,<4.0.0)
18
- Requires-Dist: pydantic (>=2.10.2,<3.0.0)
17
+ Requires-Dist: jinja2 (>=3.1.6,<4.0.0)
18
+ Requires-Dist: numpy (>=2.2.6,<3.0.0)
19
+ Requires-Dist: pydantic (>=2.11.7,<3.0.0)
19
20
  Requires-Dist: pyyaml (>=6.0.2,<7.0.0)
20
- Requires-Dist: requests (>=2.32.3,<3.0.0)
21
- Requires-Dist: rich-click (>=1.8.4,<2.0.0)
21
+ Requires-Dist: requests (>=2.32.5,<3.0.0)
22
+ Requires-Dist: rich-click (>=1.8.9,<2.0.0)
22
23
  Project-URL: Documentation, https://scilens.dev/docs
23
24
  Description-Content-Type: text/markdown
24
25
 
@@ -10,30 +10,32 @@ scilens/components/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuF
10
10
  scilens/components/analyse_folder.py,sha256=yqc-dscKaHLZJCYeXGak2v0c3F2aeX0E11AFPfya6r0,208
11
11
  scilens/components/compare_2_files.py,sha256=IlgfAi9GTAa9TlCXXjCkSZut_yJoCoXh31ctEokAjjE,2330
12
12
  scilens/components/compare_errors.py,sha256=vGb4DWP89HMIeBm0dZU2nt-ksppAs_37xtCHaPd0w5Y,1640
13
- scilens/components/compare_floats.py,sha256=_FyB5UjFsmZ8tlg6w5dneSvkUeij4UjzXuQERDxFpW0,6465
13
+ scilens/components/compare_floats.py,sha256=LPbA-l5NBoZ5WbLLU3b2R5XsHlQY9iwcc0BHjqcUhpw,4646
14
14
  scilens/components/compare_folders.py,sha256=s7cgo2JhZi8F7tt3lGbPhkaO2726Lz3c4LYGP2HbWtA,2773
15
- scilens/components/compare_models.py,sha256=zSoH0E7vuvcu3i4vbNTyJvqgzHZh_hfO3mZ6UvBzfAo,937
15
+ scilens/components/compare_models.py,sha256=EvxBZ1hPhqViCiTx7pfVIcwllkHjCjuc0mNEVa0Yqw0,941
16
16
  scilens/components/executor.py,sha256=PLeKolzPd4wPX8e6DdfOb0uHGky3DxTcKN9QtB6oe3Q,3712
17
17
  scilens/components/file_reader.py,sha256=7SbKCqb4Co_pqAKX3wweYhqAcVkU7BDlT903sLd76Kc,1407
18
+ scilens/components/num/vectors.py,sha256=r2FBOzGfAFkLiLRShIp72V3chDvIR0ZJ3f4_p4m7gzY,782
18
19
  scilens/config/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
19
20
  scilens/config/cli_run_options.py,sha256=Ls7yK5QDUPFbk73nbjGuPvuRbBRYw4Miag5ISpu3prg,281
20
21
  scilens/config/env_var.py,sha256=NqNBoIfngJEXaGEm7jGqre5pmkJ9eUjiWzbDrTVfi2c,292
21
22
  scilens/config/load.py,sha256=ltcv90GlsMJR2FE2ZL_jDscL7k5aGoHoMatWw61lrTw,1672
22
- scilens/config/models/__init__.py,sha256=eLCW1OLVINewGFy5GXSrOk8Rab_QsgKAuoErBjphHRs,673
23
+ scilens/config/models/__init__.py,sha256=BO0WVq_VHjjhd7JqK3eiEdqTL6eAA3kdynt1oDcKzD8,755
23
24
  scilens/config/models/app.py,sha256=UCC7Be6gOwvxQpM5Wl1HIf2Xb61CmslFzXvj_50eqsQ,1558
24
25
  scilens/config/models/base.py,sha256=k92CR8TA5L8dZJtg28c8albk16AK9-3umdosA7aYsxw,499
25
26
  scilens/config/models/compare.py,sha256=IiH1wJWYVnPnUJ3BiMeGDy8CFHwPOw1nQS2wfk-0p44,2152
26
- scilens/config/models/compare_float_thresholds.py,sha256=M8flQmu5B-Lc-RStn-kcQJZum_kZxj591w8myyQQuEY,2127
27
+ scilens/config/models/compare_float_thresholds.py,sha256=4l-AMfzpOUnBYU9hsSFAmIL-B6OyfQeVnsiAhRZSYsQ,2153
27
28
  scilens/config/models/execute.py,sha256=yF_q8swd4-s2KyT_RwtSzOW41AY5GiEZaLhGUGJBU0Y,2340
28
29
  scilens/config/models/execute_and_compare.py,sha256=aIWF1NIgdq5USS9ZVWOKgpEyMagCvqYYWYSXWvBBgjg,597
29
30
  scilens/config/models/file_reader.py,sha256=0-ldLt4YVmb2IwdfEHiIqDsioyXwqSkxrlfuEOmcyrA,1191
30
- scilens/config/models/reader_format_cols.py,sha256=-nvPjZImao_RFVAlyvTZG1fCXa3hhkH9th4lOD3ZLT4,3382
31
+ scilens/config/models/reader_format_cols.py,sha256=j1WbmmhigtVU5kE0yfojTji3zmTZZlZHJ1-cc-nTewM,3531
31
32
  scilens/config/models/reader_format_csv.py,sha256=KWEH0c12n6hdaWAKdHXYMT5SvH4UqBFvP7d3ZkJr7r8,1620
32
33
  scilens/config/models/reader_format_netcdf.py,sha256=Skr5lZACqVRrrlvs7R1RVFBpMTDthLJN-Fbs24jtb7o,1271
34
+ scilens/config/models/reader_format_trees.py,sha256=5T9YU0iG5e3bfi7DTjqomT6CCwQJiPhx0wBp3i_Asps,564
33
35
  scilens/config/models/reader_format_txt.py,sha256=35rvhg311DN9miE47QM9NN_gcZHglYG2lBZPLJy4iyg,1462
34
36
  scilens/config/models/reader_format_txt_fixed_cols.py,sha256=XmmFS0LdGR81XCjJIyW4cngivFo_8drckqe_k8fhqJk,1385
35
37
  scilens/config/models/reader_metrics.py,sha256=uLwyd2vE4GRHbArYRv1BRH_acTL1hbFB7HgZRDJiAJg,965
36
- scilens/config/models/readers.py,sha256=NpEjXbLv11k9N8UsnuS55KEYlRijF9C3eOrI0SB9dqM,1723
38
+ scilens/config/models/readers.py,sha256=gCviJLKWjulEDLic0cc_Vyi0pIEs5mkCtJJkslU8KFQ,2581
37
39
  scilens/config/models/report.py,sha256=_4W96v5izWCC_CrMzh3PM0mZIUAa3L26ZQqjV0Mv0f4,1008
38
40
  scilens/config/models/report_html.py,sha256=IsKlmE7QbSTiPrOaxPc48Ne7xPE5yqTcLjxqN_i-unY,3803
39
41
  scilens/config/models/report_output.py,sha256=XfzTsd1G3QjbZFer9dkWa1pa3HKbmK85UcHg6A7loOQ,890
@@ -54,10 +56,14 @@ scilens/readers/exceptions.py,sha256=JzmxcjnR5sH-IOWVeCC5A1bSwxv-jCAtIJvDjzx1CTI
54
56
  scilens/readers/mat_dataset.py,sha256=Z9TYDWaH2aqdniLNDjlpR6VVNHMSARjh52clhdMyOn4,1496
55
57
  scilens/readers/reader_csv.py,sha256=yq2MRHYk3C5NIkFbkl6gM-CFUUPTwgm8W-2-g_WaQ5M,5550
56
58
  scilens/readers/reader_interface.py,sha256=r1pu9LyweTGXU8YfI3FPZy1Em4stzmJb-6j90j1tPQQ,938
57
- scilens/readers/reader_manager.py,sha256=DFinxIk3IIIcB6JxybGcv-mXt3jhXgCwUtzR0TqhB2Q,2684
59
+ scilens/readers/reader_json.py,sha256=V33m4eFWGd2ESIMvt8KPlOXs2OJMeJ7P9uf7MzdINS4,882
60
+ scilens/readers/reader_manager.py,sha256=EaImzzOs4yIvZ6hgGfOf8GT8jwN3TmbxquUxqJbN5-c,2988
58
61
  scilens/readers/reader_txt.py,sha256=U3hGIorj-Nv-jq6zYtvbDv2LQBHTgW52PHbV8A5FMA8,4526
59
- scilens/readers/reader_txt_fixed_cols.py,sha256=uVzcblWlfsdBZzboPXtsWC9H3jSNjfMp87pUkqnW3sE,4617
62
+ scilens/readers/reader_txt_fixed_cols.py,sha256=t7vdRwt7g6-PqGer-kBdtYu7Ou75m_nKpQarBJmKxnk,4921
63
+ scilens/readers/reader_xml.py,sha256=Z8pYL6AEjqc1NkmLWCCZCLgl4spgI2u2qSdGCN-D0LQ,977
64
+ scilens/readers/reader_yaml.py,sha256=yjRZ-wn3hb7d4wVv8nScBl_i1Mzv_XwegcQOTkCKtoc,887
60
65
  scilens/readers/transform.py,sha256=kppfgPkXymF0qtquFivuosLVfF66L9bE-wGx-3bMHv8,307
66
+ scilens/readers/tree.py,sha256=47CtGDK-j09FgPJhKpqyQj4zKTmejErj2OYAHzfi2cg,2755
61
67
  scilens/report/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
62
68
  scilens/report/assets/logo.svg,sha256=W-1OVqcvdBjf-1AHHcV6WciIUqBoVFUh52Tc3o_jqtA,4519
63
69
  scilens/report/assets/logo_cglb.svg,sha256=tEpkSr2h-jjQMecqiHef98Mxod4GD5j5nCQaFloTYso,2411
@@ -78,7 +84,7 @@ scilens/report/templates/compare_12_sections.html,sha256=X0YP_LgpzdIoM2rqEip9uoR
78
84
  scilens/report/templates/compare_13_section_images.html,sha256=RZ2WGpbuW9eCgmY8szNNVPCTtllm8KczfticBIWxZhA,935
79
85
  scilens/report/templates/compare_13_section_numbers copy.html,sha256=0PWK_I2kNX3LjPLkkY4eSYIeB7YFkA28nk-PPLDhnaY,1753
80
86
  scilens/report/templates/compare_13_section_numbers.html,sha256=9etEMSqwrDyJIn_nMbKEVaDgnFL_hBxSjPR-hU2wgDI,851
81
- scilens/report/templates/compare_13_section_numbers_table.html,sha256=pME7vkcPpP2YF0X_jPeD8hEyjA4i-11slfwuQkfUNNI,2927
87
+ scilens/report/templates/compare_13_section_numbers_table.html,sha256=bLh0hBp8lj7iehd0wrgPi_owsX_Aft-aciwWXfQSJhw,3110
82
88
  scilens/report/templates/html_macros.html,sha256=jKatNSn4nX_72_wHl0-0dhxZZZBoGDGpOg7E7TMZSGs,1185
83
89
  scilens/report/templates/html_widget_err.html,sha256=sjbtooSh7RGFs8kcct4_tMi_n8FQiaoqRhUjBzHduZM,336
84
90
  scilens/report/templates/index.html,sha256=02nQg3yqGX69g4W7Zy0EKU_SOrskMd3N4hZhg4uAzu8,6089
@@ -115,7 +121,8 @@ scilens/utils/template.py,sha256=KXBfzeCRQyBT0KNzWvGEVNVqTlRStyx4V3c_N4H29sc,402
115
121
  scilens/utils/time_tracker.py,sha256=DdVBoMpVLXrX0qZZXyLm4g38EwDVLlRcBqcpNex1mYY,545
116
122
  scilens/utils/vectors.py,sha256=4N2BZSC5n3HgZqPujDGF5NdjVmSL1rOHb_qw4OoABQY,103
117
123
  scilens/utils/web.py,sha256=MAFWpIFOKz7QhqDoFh-Qwstvc76KpcxstSgHFT8FOL4,901
118
- scilens-0.4.11.dist-info/METADATA,sha256=podUjjzOmVM9UI_JwIGhiuqoLIOMmpVX3CuQZyKQ_Js,1368
119
- scilens-0.4.11.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
120
- scilens-0.4.11.dist-info/entry_points.txt,sha256=DaKGgxUEUv34GJAoXtta6ecL37ercejep9sCSSRQK2s,48
121
- scilens-0.4.11.dist-info/RECORD,,
124
+ scilens/utils/xml.py,sha256=HcB-ymJy8o4lsczHpXznGrbYahq_3cnnkPOdRfWdHfg,461
125
+ scilens-0.5.0.dist-info/METADATA,sha256=vrmvvRPo0Sm6mXf3Yxl7bsf1RGeHyYlf5EQ3wp4zqA8,1405
126
+ scilens-0.5.0.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
127
+ scilens-0.5.0.dist-info/entry_points.txt,sha256=DaKGgxUEUv34GJAoXtta6ecL37ercejep9sCSSRQK2s,48
128
+ scilens-0.5.0.dist-info/RECORD,,