scilens 0.2.1__py3-none-any.whl → 0.3.1__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,22 +1,26 @@
1
1
  import os
2
2
  from scilens.run.task_context import TaskContext
3
+ from scilens.readers.reader_interface import ReaderInterface
3
4
  from scilens.components.file_reader import FileReader
4
- from scilens.components.compare_errors import CompareErrors,SEVERITY_ERROR
5
+ from scilens.components.compare_models import SEVERITY_ERROR
6
+ from scilens.components.compare_errors import CompareErrors
5
7
  from scilens.components.compare_floats import CompareFloats
6
8
  class Compare2Files:
7
9
  def __init__(A,context):A.context=context
8
10
  def compare(B,path_test,path_ref):
9
- Q='comparison_errors';P='comparison';M='reader';J='error';I='ref';H='test';E='path';A={H:{},I:{},P:None,Q:None};D={H:{E:path_test},I:{E:path_ref}}
10
- for(K,F)in D.items():
11
- if not F.get(E)or not os.path.exists(F[E]):A[J]=f"file {K} does not exist";return A
12
- R=FileReader(B.context.working_dir,B.context.config.file_reader,B.context.config.readers,config_alternate_path=B.context.origin_working_dir)
13
- for(K,F)in D.items():D[K][M]=R.read(F[E])
14
- C=D[H][M];G=D[I][M]
15
- if not C or not G:A['skipped']=True;return A
16
- A[H]=C.info();A[I]=G.info()
17
- if C.read_error:A[J]=C.read_error;return A
18
- L=CompareErrors(B.context.config.compare.errors_limit,B.context.config.compare.ignore_warnings);N,S=C.compare(CompareFloats(L,B.context.config.compare.float_thresholds),G,param_is_ref=True);A[P]=S;A[Q]=L.get_data()
19
- if N:A[J]=N;return A
20
- C.close();G.close();O=len(L.errors[SEVERITY_ERROR])
21
- if O>0:T=f"{O} comparison errors";A[J]=T
11
+ R='comparison_errors';Q='comparison';N='reader';L='error';K='ref';J='test';F='path';A={J:{},K:{},Q:None,R:None};D={J:{F:path_test},K:{F:path_ref}}
12
+ for(M,G)in D.items():
13
+ if not G.get(F)or not os.path.exists(G[F]):A[L]=f"file {M} does not exist";return A
14
+ S=FileReader(B.context.working_dir,B.context.config.file_reader,B.context.config.readers,config_alternate_path=B.context.origin_working_dir)
15
+ for(M,G)in D.items():D[M][N]=S.read(G[F])
16
+ C=D[J][N];H=D[K][N]
17
+ if not C or not H:A['skipped']=True;return A
18
+ A[J]=C.info();A[K]=H.info()
19
+ if C.read_error:A[L]=C.read_error;return A
20
+ I=CompareErrors(B.context.config.compare.errors_limit,B.context.config.compare.ignore_warnings);T=CompareFloats(I,B.context.config.compare.float_thresholds);C.compare(T,H,param_is_ref=True);E=I.root_group;O={'total_diffs':E.total_diffs}
21
+ if E.info:O.update(E.info)
22
+ A[Q]=O;A[R]=I.get_data()
23
+ if E.error:A[L]=E.error;return A
24
+ C.close();H.close();P=len(I.errors[SEVERITY_ERROR])
25
+ if P>0:U=f"{P} comparison errors";A[L]=U
22
26
  return A
@@ -1,22 +1,23 @@
1
1
  _B=False
2
2
  _A=None
3
- from pydantic import BaseModel
4
- class CompareGroup(BaseModel):name:str;data:dict|_A
5
- class CompareErrFloats(BaseModel):is_relative:bool;value:float;test:float;reference:float
6
- class CompareErr(BaseModel):err:CompareErrFloats|_A;msg:int;group:int|_A=_A;info:dict|_A=_A
7
- SEVERITY_ERROR='error'
8
- SEVERITY_WARNING='warning'
3
+ from dataclasses import asdict
4
+ from.compare_models import SEVERITY_ERROR,SEVERITY_WARNING,COMPARE_GROUP_TYPE,CompareGroup,CompareFloatsErr,CompareErr,Compare2ValuesResults
9
5
  class CompareErrors:
10
- def __init__(A,nb_max,ignore_warnings=_B):A.nb_max=nb_max;A.ignore_warnings=ignore_warnings;A.errors={SEVERITY_ERROR:[],SEVERITY_WARNING:[]};A.count=0;A.limit_reached=_B;A.messages=[];A.messages_map={};A.groups=[]
11
- def add_group(A,name,data=_A):B=len(A.groups);A.groups.append(CompareGroup(name=name,data=data));return B
12
- def add(A,severity,message,comp_err,group_idx=_A,info=_A):
13
- D=severity;C=message
6
+ def __init__(A,nb_max,ignore_warnings=_B):A.nb_max=nb_max;A.ignore_warnings=ignore_warnings;A.errors={SEVERITY_ERROR:[],SEVERITY_WARNING:[]};A.count=0;A.limit_reached=_B;A.root_group=_A;A.messages=[];A._messages_map={};A.groups=[]
7
+ def add_group(A,type,name,parent=_A,data=_A):
8
+ B=parent
9
+ if not A.root_group and B:raise Exception('No root group defined')
10
+ id=len(A.groups);C=CompareGroup(id=id,type=type,name=name,parent=B,data=data)
11
+ if not B:A.root_group=C
12
+ A.groups.append(C);return id,C
13
+ def add(A,group,comp_res,info=_A):
14
+ F=group;C=comp_res;D=C.severity;E=C.message;G=C.comp_err
14
15
  if A.ignore_warnings and D==SEVERITY_WARNING:return _B
15
- A.count+=1;B=A.messages_map.get(C)
16
- if B is _A:B=len(A.messages);A.messages.append(C);A.messages_map[C]=B
17
- A.errors[D].append(CompareErr(err=comp_err,msg=B,group=group_idx,info=info))
16
+ A.count+=1;B=A._messages_map.get(E)
17
+ if B is _A:B=len(A.messages);A.messages.append(E);A._messages_map[E]=B
18
+ A.errors[D].append(CompareErr(err=G,msg=B,group=F.id,info=info));F.incr(D)
18
19
  if A.count>=A.nb_max:A.limit_reached=True;return True
19
20
  def get_data(B):
20
- A={'messages':B.messages,'groups':[A.model_dump()for A in B.groups]}
21
- for(C,D)in B.errors.items():A[C]=[A.model_dump()for A in D];A[C+'_nb']=len(A[C])
21
+ D=[{'id':A.id,'type':A.type,'name':A.name,'error':A.error,'total_diffs':A.total_diffs,'total_warnings':A.total_warnings,'total_errors':A.total_errors,'data':A.data,'info':A.info,'parent_id':A.parent.id if A.parent else _A}for A in B.groups];A={'messages':B.messages,'groups':D}
22
+ for(C,E)in B.errors.items():A[C]=[A.model_dump()for A in E];A[C+'_nb']=len(A[C])
22
23
  return A
@@ -1,50 +1,72 @@
1
- _B='amplitude'
1
+ _C='amplitude'
2
+ _B=False
2
3
  _A=None
3
- from scilens.components.compare_errors import CompareErrors,SEVERITY_ERROR,SEVERITY_WARNING,CompareErrFloats
4
+ from scilens.components.compare_models import SEVERITY_ERROR,SEVERITY_WARNING,CompareFloatsErr,Compare2ValuesResults
5
+ from scilens.components.compare_errors import CompareErrors
4
6
  from scilens.config.models import CompareFloatThresholdsConfig
5
7
  try:from scilens_compare import vectors as CheckVectors
6
8
  except ModuleNotFoundError:pass
7
- def vector_get_amplitude(vector):min_val=min(vector);max_val=max(vector);return{'min':min_val,'max':max_val,_B:abs(max_val-min_val)}
9
+ def vector_get_amplitude(vector):min_val=min(vector);max_val=max(vector);return{'min':min_val,'max':max_val,_C:abs(max_val-min_val)}
8
10
  class CompareFloats:
9
11
  def __init__(self,compare_errors,config):self.compare_errors=compare_errors;self.thresholds=config
10
- def compare_vectors(self,test_vector,reference_vector,group_idx=_A,info_vector=_A):
11
- A='ignore';diffs_count=0;counts={SEVERITY_ERROR:0,SEVERITY_WARNING:0};err_limit_reached=False;amplitude_compare=_A
12
- if self.thresholds.vectors and self.thresholds.vectors.ponderation_method=='amplitude_moderation':amplitude=vector_get_amplitude(test_vector)[_B];amplitude_compare=amplitude*self.thresholds.vectors.amplitude_moderation_multiplier;reduction_method=self.thresholds.vectors.reduction_method
12
+ def compare_2_values(self,test,reference):
13
+ thr=self.thresholds;sign=-1 if test-reference<0 else 1
14
+ if abs(test)>thr.relative_vs_absolute_min and reference!=0:
15
+ err=abs(test-reference)/abs(reference);comp_err=CompareFloatsErr(is_relative=True,value=sign*err,test=test,reference=reference)
16
+ if err<thr.relative_error_max:
17
+ if err>thr.relative_error_min:return Compare2ValuesResults(SEVERITY_WARNING,f"Rel. err. > {thr.relative_error_min} and < {thr.relative_error_max}",comp_err)
18
+ else:return Compare2ValuesResults(SEVERITY_ERROR,f"Rel. err. > {thr.relative_error_max}",comp_err)
19
+ else:
20
+ err=abs(test-reference);comp_err=CompareFloatsErr(is_relative=_B,value=sign*err,test=test,reference=reference)
21
+ if err<thr.absolute_error_max:
22
+ if err>thr.absolute_error_min:return Compare2ValuesResults(SEVERITY_WARNING,f"Abs. err. > {thr.absolute_error_min} and < {thr.absolute_error_max}",comp_err)
23
+ else:return Compare2ValuesResults(SEVERITY_ERROR,f"Abs. err. > {thr.absolute_error_max}",comp_err)
24
+ def compare_vectors(self,test_vector,reference_vector,group_id,info_vector=_A):
25
+ B='ignore';A='RIAE_trapezoid';group=self.compare_errors.groups[group_id]
26
+ if len(test_vector)!=len(reference_vector):raise Exception('Vectors have different lengths')
27
+ diffs_count=0;err_limit_reached=_B;ponderation_method=self.thresholds.vectors.ponderation_method if self.thresholds.vectors else _A
28
+ if ponderation_method=='RIAE':ponderation_method=A
29
+ amplitude_compare=_A
30
+ if self.thresholds.vectors and ponderation_method=='amplitude_moderation':amplitude=vector_get_amplitude(test_vector)[_C];amplitude_compare=amplitude*self.thresholds.vectors.amplitude_moderation_multiplier;reduction_method=self.thresholds.vectors.reduction_method
13
31
  RIAE_force_severity=_A
14
- if self.thresholds.vectors and self.thresholds.vectors.ponderation_method in['RIAE','RIAE_trapezoid','RIAE_midpoint']:
32
+ if self.thresholds.vectors and ponderation_method in[A,'RIAE_midpoint']:
15
33
  RIAE_force_severity=self.thresholds.vectors.reduction_method
16
34
  if'CheckVectors'not in globals():raise Exception('scilens_compare not found. Please install scilens-compare package with `pip install scilens-compare`.')
17
- riae_error=CheckVectors.relative_integral_absolute_error_trapezoid(reference_vector,test_vector,range(len(test_vector)));riae_error=CheckVectors.relative_integral_absolute_error_midpoint(reference_vector,test_vector,range(len(test_vector)));print('riae_error');print(riae_error)
18
- if riae_error<self.thresholds.vectors.riae_threshold:RIAE_force_severity=self.thresholds.vectors.reduction_method
19
- else:0
35
+ 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)))
36
+ 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)
20
37
  nb=len(test_vector)
21
38
  for idx in range(nb):
22
39
  diff=test_vector[idx]-reference_vector[idx]
23
40
  if diff==0:continue
24
- else:diffs_count+=1
41
+ else:diffs_count+=1;group.incr('diff')
25
42
  if err_limit_reached:continue
26
- if RIAE_force_severity==A:continue
43
+ if RIAE_force_severity==B:continue
27
44
  if amplitude_compare is not _A and abs(diff)<amplitude_compare:
28
- if reduction_method==A:continue
29
- elif reduction_method=='soften':severity,message,comp_err=self.compare_2_values(test_vector[idx],reference_vector[idx]);severity=SEVERITY_WARNING
45
+ if reduction_method==B:continue
46
+ elif reduction_method=='soften':
47
+ res_compare=self.compare_2_values(test_vector[idx],reference_vector[idx])
48
+ if res_compare:res_compare.severity=SEVERITY_WARNING
30
49
  else:
31
- severity,message,comp_err=self.compare_2_values(test_vector[idx],reference_vector[idx])
32
- if RIAE_force_severity:severity=SEVERITY_WARNING
33
- if comp_err:
34
- counts[severity]+=1;info={'index':idx}
50
+ res_compare=self.compare_2_values(test_vector[idx],reference_vector[idx])
51
+ if res_compare and RIAE_force_severity:res_compare.severity=SEVERITY_WARNING
52
+ if res_compare:
53
+ info={'index':idx}
35
54
  if info_vector:info['info']=info_vector[idx]
36
- err_limit_reached=self.compare_errors.add(severity,message,comp_err,group_idx=group_idx,info=info)
37
- return err_limit_reached,diffs_count,counts
38
- def compare_2_values(self,test,reference):
39
- thr=self.thresholds;sign=-1 if test-reference<0 else 1
40
- if abs(test)>thr.relative_vs_absolute_min and reference!=0:
41
- err=abs(test-reference)/abs(reference);comp_err=CompareErrFloats(is_relative=True,value=sign*err,test=test,reference=reference)
42
- if err<thr.relative_error_max:
43
- if err>thr.relative_error_min:return SEVERITY_WARNING,f"Rel. err. > {thr.relative_error_min} and < {thr.relative_error_max}",comp_err
44
- else:return SEVERITY_ERROR,f"Rel. err. > {thr.relative_error_max}",comp_err
45
- else:
46
- err=abs(test-reference);comp_err=CompareErrFloats(is_relative=False,value=sign*err,test=test,reference=reference)
47
- if err<thr.absolute_error_max:
48
- if err>thr.absolute_error_min:return SEVERITY_WARNING,f"Abs. err. > {thr.absolute_error_min} and < {thr.absolute_error_max}",comp_err
49
- else:return SEVERITY_ERROR,f"Abs. err. > {thr.absolute_error_max}",comp_err
50
- return _A,_A,_A
55
+ err_limit_reached=self.compare_errors.add(group,res_compare,info=info)
56
+ return err_limit_reached,diffs_count
57
+ def compare_matrices(self,test_mat,ref_mat,group_id,x_vector=_A,y_vector=_A):
58
+ group=self.compare_errors.groups[group_id];info={};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
59
+ if test_nb_lines!=ref_nb_lines or test_nb_columns!=ref_nb_columns:raise Exception('Matrices have different dimensions')
60
+ for i in range(test_nb_lines):
61
+ for j in range(test_nb_columns):
62
+ diff=test_mat[i][j]-ref_mat[i][j]
63
+ if diff==0:continue
64
+ else:diffs_count+=1
65
+ if err_limit_reached:continue
66
+ res_compare=self.compare_2_values(test_mat[i][j],ref_mat[i][j])
67
+ if res_compare:
68
+ info={'i':i+1,'j':j+1}
69
+ if x_vector:info['x']=x_vector[j]
70
+ if y_vector:info['y']=y_vector[i]
71
+ err_limit_reached=self.compare_errors.add(group,res_compare,info=info)
72
+ return err_limit_reached,diffs_count
@@ -0,0 +1,20 @@
1
+ _A=None
2
+ from dataclasses import dataclass
3
+ from typing import Literal,Optional
4
+ from pydantic import BaseModel
5
+ SEVERITY_ERROR='error'
6
+ SEVERITY_WARNING='warning'
7
+ @dataclass
8
+ class CompareFloatsErr:is_relative:bool;value:float;test:float|_A=_A;reference:float|_A=_A
9
+ @dataclass
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
12
+ COMPARE_GROUP_TYPE=Literal['node','lines','vectors',' matrix']
13
+ @dataclass
14
+ class CompareGroup:
15
+ id:int;type:COMPARE_GROUP_TYPE;name:str;parent:Optional['CompareGroup']=_A;error:str|_A=_A;total_diffs:int=0;total_warnings:int=0;total_errors:int=0;data:dict|_A=_A;info:dict|_A=_A
16
+ def incr(A,type):
17
+ if type==SEVERITY_ERROR:A.total_errors+=1
18
+ elif type==SEVERITY_WARNING:A.total_warnings+=1
19
+ elif type=='diff':A.total_diffs+=1
20
+ if A.parent is not _A:A.parent.incr(type)
@@ -5,23 +5,30 @@ from scilens.utils.web import Web
5
5
  def unzip_file(zip_file_path,extract_to_path):
6
6
  with zipfile.ZipFile(zip_file_path,'r')as A:A.extractall(extract_to_path)
7
7
  def find_command(command_path,working_dirs,guess_os_extension=False):
8
- F='.bash';E='.sh';A=[]
8
+ J='.bash';I='.sh';G=working_dirs;A=command_path;H=os.path.isabs(A);C=[]
9
9
  if guess_os_extension:
10
- B=platform.system().lower()
11
- if B=='windows':A=['.exe','.bat','.cmd']
12
- elif B=='linux':A=[E,F,'.bin']
13
- elif B=='darwin':A=[E,F]
14
- else:logging.warning(f"Unknown system {B}")
15
- for G in working_dirs:
16
- C=os.path.join(G,command_path)
17
- if os.path.exists(C):return C
10
+ D=platform.system().lower()
11
+ if D=='windows':C=['.exe','.bat','.cmd']
12
+ elif D=='linux':C=[I,J,'.bin']
13
+ elif D=='darwin':C=[I,J]
14
+ else:logging.warning(f"Unknown system {D}")
15
+ if H:
16
+ if os.path.exists(A):return A
17
+ else:
18
+ for E in G:
19
+ B=os.path.join(E,A)
20
+ if os.path.exists(B):return B
21
+ for K in C:
22
+ F=A+K
23
+ if H:
24
+ if os.path.exists(F):return F
18
25
  else:
19
- for H in A:
20
- D=C+H
21
- if os.path.exists(D):return D
26
+ for E in G:
27
+ B=os.path.join(E,F)
28
+ if os.path.exists(B):return B
22
29
  class Executor:
23
30
  def __init__(A,absolute_working_dir,config,alternative_working_dir=None):
24
- B=config;A.working_dir=absolute_working_dir;A.config=B;A.alternative_working_dir=alternative_working_dir;A.command_path=None;A.temp_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
25
32
  if B.exe_url and B.exe_path:raise ValueError('Executable URL and Path are defined. Only one can be defined.')
26
33
  if not B.exe_url and not B.exe_path:raise ValueError('Executable URL and Path are not defined. One must be defined.')
27
34
  if not os.path.exists(A.working_dir):logging.info(f"Creating working directory {A.working_dir}");dir_create(A.working_dir)
@@ -33,26 +40,16 @@ class Executor:
33
40
  for dir in A.config.pre_folder_delete or[]:dir_remove(os.path.join(A.working_dir,dir))
34
41
  logging.info(f"Folders creation")
35
42
  for dir in A.config.pre_folder_creation or[]:dir_create(os.path.join(A.working_dir,dir))
36
- if A.config.exe_url:logging.info(f"Download executable {A.config.exe_url}");A.temp_dir=tempfile.mkdtemp();E='executable';B=os.path.join(A.temp_dir,E);Web().download_progress(A.config.exe_url,B,headers=A.config.exe_url_headers,callback100=lambda percentage:logging.info(f"Downloaded {percentage}%"));logging.info(f"Download completed")
43
+ if A.config.exe_url:
44
+ logging.info(f"Download executable {A.config.exe_url}");A.temp_dir=tempfile.mkdtemp();E='executable';B=os.path.join(A.temp_dir,E)
45
+ try:Web().download_progress(A.config.exe_url,B,headers=A.config.exe_url_headers,callback100=lambda percentage:logging.info(f"Downloaded {percentage}%"))
46
+ except Exception as F:raise ValueError(f"Error downloading executable: {F}")
47
+ logging.info(f"Download completed")
37
48
  else:B=A.config.exe_path
38
- if A.config.exe_unzip_and_use:logging.info(f"Unzip archive");C=os.path.dirname(B);unzip_file(B,C);B=os.path.join(C,A.config.exe_unzip_and_use);print(f"executable_path {B}");logging.info(f"Unzip completed")
39
- if not os.path.exists(B):
40
- if not A.config.exe_guess_os_extension:raise FileNotFoundError(f"Command not found: {B}")
41
- else:
42
- logging.info(f"Guess OS extension");D=[A.working_dir]
43
- if A.alternative_working_dir:D.append(A.alternative_working_dir)
44
- B=find_command(B,D,guess_os_extension=True)
45
- if not B:raise FileNotFoundError(f"Command not found: {B}")
46
- logging.info(f"Add executable permissions");F=os.stat(B).st_mode;os.chmod(B,F|stat.S_IXUSR|stat.S_IXGRP|stat.S_IXOTH);A.command_path=B
49
+ 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")
50
+ C=find_command(B,A.dirs,guess_os_extension=A.config.exe_guess_os_extension)
51
+ if not C:raise FileNotFoundError(f"Command not found: {B}")
52
+ 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);A.command_path=C
47
53
  def _post_operations(A):logging.info(f"Execute - Post Operations")
48
- def _run_command(A):
49
- logging.info(f"Execute - Run Command");C=A.command_path;B=C
50
- if os.path.isabs(B):
51
- if not os.path.exists(B):raise FileNotFoundError(f"Command not found: {B}")
52
- else:
53
- D=[A.working_dir]
54
- if A.alternative_working_dir:D.append(A.alternative_working_dir)
55
- B=find_command(C,D,guess_os_extension=A.config.exe_guess_os_extension)
56
- if not B:raise FileNotFoundError(f"Command not found: {C}")
57
- E=f"{B}{A.config.command_suffix or''}";logging.info(f"RUN COMMAND {E} in {A.working_dir}");subprocess.run(E,shell=True,check=True,cwd=A.working_dir)
54
+ def _run_command(A):logging.info(f"Execute - Run Command");C=A.command_path;B=f"{C}{A.config.command_suffix or''}";logging.info(f"RUN COMMAND {B} in {A.working_dir}");subprocess.run(B,shell=True,check=True,cwd=A.working_dir)
58
55
  def process(A):logging.info(f"Execute");A._pre_operations();A._run_command();A._post_operations();A._cleanup()
@@ -3,6 +3,7 @@ import logging,importlib,os
3
3
  from scilens.config.models import FileReaderConfig
4
4
  from scilens.config.models.readers import ReadersConfig
5
5
  from scilens.readers.reader_manager import ReaderManager
6
+ from scilens.readers.reader_interface import ReaderInterface
6
7
  from scilens.readers.exceptions import NoReaderFound
7
8
  class FileReader:
8
9
  def __init__(A,absolute_working_dir,config,readers_config,config_alternate_path=_A):A.path=absolute_working_dir;A.config_alternate_path=config_alternate_path;A.reader_mgmr=ReaderManager();A.config=config;A.readers_config=readers_config
@@ -1,4 +1,5 @@
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 ReaderCsvConfig(BaseModel):ignore_columns:list[str]|_A=Field(default=_A,description='Liste des noms des colonnes à ignorer. (Valide seulement si la première ligne est les en-têtes)');delimiter:str|_A=Field(default=',',description='Délimiteur de colonnes.');quotechar:str|_A=Field(default='"',description='Délimiteur de texte.');curve_parser:ReaderColsCurveParserConfig|_A=Field(default=_A,description='Parseur de courbe à utiliser.')
4
+ 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=False,description='Indique si la première colonne est ma colonne des valeurs y.')
5
+ 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=False,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)')
@@ -3,4 +3,4 @@ from pydantic import BaseModel,Field
3
3
  class ReportParameterPageModeConfig(BaseModel):is_user_preference:bool=Field(default=True,description=_A);default_value:str=Field(default='onepage',description='`tabs` ou `onepage`')
4
4
  class ReportParameterOpenFileInConfig(BaseModel):is_user_preference:bool=Field(default=True,description=_A);default_value:str=Field(default='browser',description='`browser` ou `vscode`')
5
5
  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.')
6
- class ReportHtmlConfig(BaseModel):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=True,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()
6
+ class ReportHtmlConfig(BaseModel):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=True,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()
@@ -3,7 +3,9 @@ _D='x_index'
3
3
  _C='csv_col_index'
4
4
  _B='curves'
5
5
  _A=None
6
+ import logging
6
7
  from dataclasses import dataclass,field
8
+ from scilens.components.compare_models import CompareGroup
7
9
  from scilens.components.compare_floats import CompareFloats
8
10
  from scilens.config.models.reader_format_cols_curve import ReaderCurveParserNameConfig
9
11
  @dataclass
@@ -23,23 +25,23 @@ def cols_dataset_get_curves_col_x(cols_dataset,col_x):
23
25
  E[_D]=C;J=[B for(A,B)in enumerate(A.numeric_col_indexes)if A!=C];F=[];H=[]
24
26
  for D in J:B=A.data[C];K=A.data[D];L={I:A.names[D],'short_title':A.names[D],'series':[[B[A],K[A]]for A in range(A.rows_count)],_C:D};F+=[L];M={I:A.names[D],'type':'simple','xaxis':A.names[C],'yaxis':A.names[D],_B:[len(F)-1]};H+=[M]
25
27
  return{_B:F,_E:H},E
26
- def compare(compare_floats,reader_test,reader_ref,cols_curve):
27
- Q='error';J=compare_floats;I='Errors limit reached';E=reader_ref;C=cols_curve;A=reader_test
28
- if len(A.numeric_col_indexes)!=len(E.numeric_col_indexes):R=f"Number Float columns indexes are different: {len(A.numeric_col_indexes)} != {len(E.numeric_col_indexes)}";return R,_A
29
- K=0;D=[''for A in range(A.cols_count)];L=_A;F=_A
30
- if C and C.type==ReaderCurveParserNameConfig.COL_X:M=C.info[_D];L=A.data[M];F=A.names[M]
31
- G=False
28
+ def compare(group,compare_floats,reader_test,reader_ref,cols_curve):
29
+ L=compare_floats;K='Errors limit reached';G=reader_ref;E=group;C=cols_curve;A=reader_test;logging.debug(f"compare cols: {E.name}")
30
+ if len(A.numeric_col_indexes)!=len(G.numeric_col_indexes):E.error=f"Number Float columns indexes are different: {len(A.numeric_col_indexes)} != {len(G.numeric_col_indexes)}";return
31
+ D=[''for A in range(A.cols_count)];M=_A;H=_A
32
+ if C and C.type==ReaderCurveParserNameConfig.COL_X:N=C.info[_D];M=A.data[N];H=A.names[N]
33
+ I=False
32
34
  for B in range(A.cols_count):
33
35
  if B not in A.numeric_col_indexes:continue
34
- if G:D[B]=I;continue
35
- S=A.data[B];T=E.data[B];U=J.compare_errors.add_group(A.names[B],data={'info_prefix':F}if F else _A);V,W,N=J.compare_vectors(S,T,group_idx=U,info_vector=L);K+=W
36
- if V:G=True;D[B]=I;continue
37
- if N[Q]>0:D[B]=f"{N[Q]} comparison errors"
36
+ if I:D[B]=K;continue
37
+ Q=A.data[B];R=G.data[B];U,F=L.compare_errors.add_group('vectors',A.names[B],parent=E,data={'info_prefix':H}if H else _A);logging.debug(f"compare cols: {F.name}");S,V=L.compare_vectors(Q,R,group_id=F.id,info_vector=M)
38
+ if S:I=True;D[B]=K;continue
39
+ if F.total_errors>0:D[B]=f"{F.total_errors} comparison errors"
38
40
  if C:
39
41
  for O in C.curves[_E]:
40
42
  P=0
41
- for X in O[_B]:
42
- H=C.curves[_B][X]
43
- if D[H[_C]]:H['comparison_error']=D[H[_C]];P+=1
43
+ for T in O[_B]:
44
+ J=C.curves[_B][T]
45
+ if D[J[_C]]:J['comparison_error']=D[J[_C]];P+=1
44
46
  O['comparison']={'curves_nb_with_error':P}
45
- Y=I if G else _A;return Y,{'type':'vectors','total_diffs':K,'cols_has_error':D}
47
+ E.error=K if I else _A;E.info={'cols_has_error':D}
@@ -0,0 +1,22 @@
1
+ _A=None
2
+ import csv
3
+ from collections.abc import Iterator
4
+ from dataclasses import dataclass,field
5
+ from scilens.components.compare_models import CompareGroup
6
+ from scilens.components.compare_floats import CompareFloats
7
+ @dataclass
8
+ 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
9
+ def from_reader(reader,x_value_line=_A,has_header=False,has_y=False):
10
+ E=has_y;D=x_value_line;B=reader;H=_A;I=[]if E else _A;A=[];F=0
11
+ if D:
12
+ J=1 if E else 0
13
+ for M in range(0,D):
14
+ K=next(B);F+=1
15
+ if F==D:H=[float(A)for A in K[J:]]
16
+ if F==0 and has_header:next(B)
17
+ if E:
18
+ for C in B:L=float(C[0]);G=[float(A)for A in C[1:]];I.append(L);A.append(G)
19
+ else:
20
+ for C in B:G=[float(A)for A in C];A.append(G)
21
+ 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)
22
+ def compare(parent_group,compare_floats,test,ref,group_name=''):C=compare_floats;B=parent_group;A=test;F,D=C.compare_errors.add_group('matrix',group_name,parent=B);E,G=C.compare_matrices(A.data,ref.data,D.id,x_vector=A.x_values,y_vector=A.y_values);B.error='Errors limit reached'if E else _A
@@ -1,8 +1,11 @@
1
+ _A=None
1
2
  import logging,csv
2
3
  from scilens.readers.reader_interface import ReaderInterface
3
- from scilens.readers.cols_dataset import ColsDataset,ColsCurves,cols_dataset_get_curves_col_x,compare
4
- from scilens.config.models import ReaderCsvConfig
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
6
+ from scilens.config.models.reader_format_csv import ReaderCsvConfig,ReaderCsvMatrixConfig
5
7
  from scilens.config.models.reader_format_cols_curve import ReaderCurveParserNameConfig
8
+ from scilens.components.compare_models import CompareGroup
6
9
  from scilens.components.compare_floats import CompareFloats
7
10
  def is_num(x):
8
11
  try:return float(x)
@@ -11,30 +14,36 @@ def csv_row_detect_header(first_row):
11
14
  A=first_row
12
15
  if all(not A.isdigit()for A in A):return True,A
13
16
  else:return False,[f"Column {A}"for(A,B)in enumerate(A)]
14
- def csv_row_detect_cols_num(row):return[A for(A,B)in enumerate(row)if is_num(B)!=None]
15
- def csv_detect(path,delimiter,quotechar):
16
- with open(path,'r')as B:A=csv.reader(B,delimiter=delimiter,quotechar=quotechar);C=next(A);D,E=csv_row_detect_header(C);F=next(A);G=csv_row_detect_cols_num(F);return D,E,G
17
+ def csv_row_detect_cols_num(row):return[A for(A,B)in enumerate(row)if is_num(B)!=_A]
18
+ def csv_detect(path,delimiter,quotechar,encoding):
19
+ with open(path,'r',encoding=encoding)as B:A=csv.reader(B,delimiter=delimiter,quotechar=quotechar);C=next(A);D,E=csv_row_detect_header(C);F=next(A);G=csv_row_detect_cols_num(F);return D,E,G
17
20
  class ReaderCsv(ReaderInterface):
18
21
  configuration_type_code='csv';category='datalines';extensions=['CSV']
19
22
  def read(A,reader_options):
20
- C=reader_options;A.reader_options=C;D,E,K=csv_detect(A.origin.path,A.reader_options.delimiter,A.reader_options.quotechar);A.has_header=D;A.cols=E;A.numeric_col_indexes=K
21
- if C.ignore_columns:
22
- if not D:raise Exception('Ignore columns is not supported without header.')
23
- A.numeric_col_indexes=[B for B in A.numeric_col_indexes if A.cols[B]not in C.ignore_columns]
24
- H=len(E);B=ColsDataset(cols_count=H,names=E,numeric_col_indexes=A.numeric_col_indexes,data=[[]for A in range(H)]);I=open(A.origin.path,'r',encoding=A.encoding);L=csv.reader(I,delimiter=A.reader_options.delimiter,quotechar=A.reader_options.quotechar);F=0
25
- for M in L:
26
- F+=1
27
- if D and F==1:continue
28
- for(J,G)in enumerate(M):
29
- if J in B.numeric_col_indexes:G=float(G)
30
- B.data[J].append(G)
31
- B.origin_line_nb.append(F)
32
- B.rows_count=len(B.origin_line_nb);I.close();A.cols_dataset=B;A.raw_lines_number=B.rows_count+(1 if D else 0);A.curves=None
33
- if C.curve_parser:
34
- if C.curve_parser.name==ReaderCurveParserNameConfig.COL_X:
35
- A.curves,N=cols_dataset_get_curves_col_x(B,C.curve_parser.parameters.x)
36
- if A.curves:A.cols_curve=ColsCurves(type=ReaderCurveParserNameConfig.COL_X,info=N,curves=A.curves)
37
- elif C.curve_parser.name==ReaderCurveParserNameConfig.COLS_COUPLE:raise NotImplementedError('cols_couple not implemented')
38
- else:raise Exception('Curve parser not supported.')
39
- def compare(A,compare_floats,param_reader,param_is_ref=True):C=param_is_ref;B=param_reader;D=A.cols_dataset if C else B.cols_dataset;E=A.cols_dataset if not C else B.cols_dataset;F=A.cols_curve;return compare(compare_floats,D,E,F)
23
+ B=reader_options;A.reader_options=B;A.raw_lines_number=_A;A.curves=_A;D,E,M=csv_detect(A.origin.path,A.reader_options.delimiter,A.reader_options.quotechar,encoding=A.encoding);A.has_header=D;A.cols=E;A.numeric_col_indexes=M;H=open(A.origin.path,'r',encoding=A.encoding);I=csv.reader(H,delimiter=A.reader_options.delimiter,quotechar=A.reader_options.quotechar)
24
+ if B.is_matrix:J=B.matrix or ReaderCsvMatrixConfig();N=mat_from_reader(I,has_header=D,x_value_line=J.x_value_line,has_y=J.has_y);A.mat_dataset=N
25
+ else:
26
+ if B.ignore_columns:
27
+ if not D:raise Exception('Ignore columns is not supported without header.')
28
+ A.numeric_col_indexes=[C for C in A.numeric_col_indexes if A.cols[C]not in B.ignore_columns]
29
+ K=len(E);C=ColsDataset(cols_count=K,names=E,numeric_col_indexes=A.numeric_col_indexes,data=[[]for A in range(K)]);F=0
30
+ for O in I:
31
+ F+=1
32
+ if D and F==1:continue
33
+ for(L,G)in enumerate(O):
34
+ if L in C.numeric_col_indexes:G=float(G)
35
+ C.data[L].append(G)
36
+ C.origin_line_nb.append(F)
37
+ C.rows_count=len(C.origin_line_nb);A.cols_dataset=C;A.raw_lines_number=C.rows_count+(1 if D else 0)
38
+ if B.curve_parser:
39
+ if B.curve_parser.name==ReaderCurveParserNameConfig.COL_X:
40
+ A.curves,P=cols_dataset_get_curves_col_x(C,B.curve_parser.parameters.x)
41
+ if A.curves:A.cols_curve=ColsCurves(type=ReaderCurveParserNameConfig.COL_X,info=P,curves=A.curves)
42
+ elif B.curve_parser.name==ReaderCurveParserNameConfig.COLS_COUPLE:raise NotImplementedError('cols_couple not implemented')
43
+ else:raise Exception('Curve parser not supported.')
44
+ H.close()
45
+ def compare(A,compare_floats,param_reader,param_is_ref=True):
46
+ H='node';D=param_is_ref;C=param_reader;B=compare_floats;I=A.reader_options
47
+ 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)
48
+ else:E=A.cols_dataset if D else C.cols_dataset;F=A.cols_dataset if not D else C.cols_dataset;K=A.cols_curve if hasattr(A,'cols_curve')else _A;J,G=B.compare_errors.add_group(H,'csv cols');cols_compare(G,B,E,F,K)
40
49
  def class_info(A):return{'cols':A.cols,'raw_lines_number':A.raw_lines_number,'curves':A.curves}
@@ -7,7 +7,7 @@ _A=None
7
7
  from scilens.readers.reader_interface import ReaderInterface
8
8
  from scilens.readers.transform import string_2_floats
9
9
  from scilens.config.models import ReaderTxtConfig
10
- from scilens.components.compare_errors import SEVERITY_ERROR
10
+ from scilens.components.compare_models import SEVERITY_ERROR,Compare2ValuesResults
11
11
  from scilens.components.compare_floats import CompareFloats
12
12
  class ReaderTxt(ReaderInterface):
13
13
  configuration_type_code='txt';category='datalines';extensions=['TXT']
@@ -42,23 +42,22 @@ class ReaderTxt(ReaderInterface):
42
42
  C,S=A.find_patterns_lines_nb(B.error_rule_patterns);A.read_data['error_rule_patterns']={'found':C,'data':S}
43
43
  if C:A.read_error='String error pattern found'
44
44
  def compare(I,compare_floats,param_reader,param_is_ref=_D):
45
- K=param_is_ref;J=param_reader;D=compare_floats;A=I if K else J;B=I if not K else J;E=0;C=_C;Y=[]
46
- if A.floats_lines_number!=B.floats_lines_number:T=f"Nb number lines 1: {A.floats_lines_number} 2: {B.floats_lines_number} different";return T,_A
47
- L=A.floats_lines;U=B.floats_lines
48
- for M in range(len(L)):
49
- F=L[M];G=U[M];H=F[_F];N=G[_F];O={'line_nb_1':F[_B],'line_nb_2':G[_B],'line_1':A.get_raw_lines(F[_B]),'line_2':B.get_raw_lines(G[_B])}
50
- if len(H)!=len(N):
51
- if not C:E+=1;C=D.compare_errors.add(SEVERITY_ERROR,'Not same numbers number in the lines',_A,info=O)
45
+ U='diff';K=param_is_ref;J=param_reader;A=compare_floats;V,L=A.compare_errors.add_group('node','txt');V,B=A.compare_errors.add_group(_E,_E,parent=L);C=I if K else J;D=I if not K else J;E=_C
46
+ if C.floats_lines_number!=D.floats_lines_number:L.error=f"Nb number lines 1: {C.floats_lines_number} 2: {D.floats_lines_number} different"
47
+ M=C.floats_lines;W=D.floats_lines
48
+ for N in range(len(M)):
49
+ F=M[N];G=W[N];H=F[_F];O=G[_F];P={'line_nb_1':F[_B],'line_nb_2':G[_B],'line_1':C.get_raw_lines(F[_B]),'line_2':D.get_raw_lines(G[_B])}
50
+ if len(H)!=len(O):
51
+ if not E:B.incr(U);E=A.compare_errors.add(B,Compare2ValuesResults(SEVERITY_ERROR,'Not same numbers number in the lines'),info=P)
52
52
  continue
53
- for P in range(len(H)):
54
- Q=H[P];R=N[P];V=Q-R
55
- if V==0:continue
53
+ for Q in range(len(H)):
54
+ R=H[Q];S=O[Q];X=R-S
55
+ if X==0:continue
56
56
  else:
57
- E+=1
58
- if not C:
59
- W,X,S=D.compare_2_values(Q,R)
60
- if S:C=D.compare_errors.add(W,X,S,info=O)
61
- return _A,{'type':_E,'total_diffs':E}
57
+ B.incr(U)
58
+ if not E:
59
+ T=A.compare_2_values(R,S)
60
+ if T:E=A.compare_errors.add(B,T,info=P)
62
61
  def find_patterns_lines_nb(D,patterns):
63
62
  A=patterns;B=_C;map={A:[]for A in A}
64
63
  for(E,F)in enumerate(D.raw_lines):
@@ -34,5 +34,5 @@ class ReaderTxtFixedCols(ReaderInterface):
34
34
  if B.curves:B.cols_curve=ColsCurves(type=ReaderCurveParserNameConfig.COL_X,info=T,curves=B.curves)
35
35
  elif A.curve_parser.name==ReaderCurveParserNameConfig.COLS_COUPLE:raise NotImplementedError('cols_couple not implemented')
36
36
  else:raise Exception('Curve parser not supported.')
37
- def compare(A,compare_floats,param_reader,param_is_ref=True):C=param_is_ref;B=param_reader;D=A.cols_dataset if C else B.cols_dataset;E=A.cols_dataset if not C else B.cols_dataset;F=A.cols_curve;return compare(compare_floats,D,E,F)
37
+ 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
38
  def class_info(A):return{'cols':A.cols_dataset.names,'raw_lines_number':A.raw_lines_number,'curves':A.curves}
@@ -8,19 +8,20 @@ from scilens.utils.time_tracker import TimeTracker
8
8
  class HtmlReport:
9
9
  def __init__(A,config,alt_config_dirs,working_dir=None):A.config=config;A.alt_config_dirs=alt_config_dirs;A.working_dir=working_dir
10
10
  def process(A,processor,data,task_name):
11
- G='meta';F='date';logging.info(f"Processing html report");H=TimeTracker();C=H.get_data()['start']
11
+ I='meta';H='date';logging.info(f"Processing html report");J=TimeTracker();B=J.get_data()['start']
12
12
  if A.config.logo and A.config.logo_file:raise ValueError('logo and logo_file are exclusive.')
13
- I=A.config.logo;B=None
13
+ K=A.config.logo;C=None
14
14
  if A.config.logo_file:
15
15
  D=A.config.logo_file
16
- if os.path.isabs(D):B=D
16
+ if os.path.isabs(D):
17
+ C=D
18
+ if not os.path.isfile(E):raise FileNotFoundError(f"Logo file '{A.config.logo_file}' not found.")
17
19
  else:
18
- B=os.path.join(A.working_dir,D)
19
- if not os.path.isfile(B):
20
- for J in A.alt_config_dirs:
21
- B=os.path.join(J,D)
22
- if os.path.isfile(B):break
23
- if not os.path.isfile(B):raise FileNotFoundError(f"Derived Logo file '{A.config.logo_file}' not found.")
24
- K=A.config.title if A.config.title else A.config.title_prefix+' '+task_name;L={'app_name':product_name,'app_version':pkg_version,'app_homepage':pkg_homepage,'app_copyright':f"© {C[F][:4]} {powered_by['name']}. All rights reserved",'app_powered_by':powered_by,'execution_utc_datetime':C['datetime'],'execution_utc_date':C[F],'execution_utc_time':C['time'],'execution_dir':A.working_dir,'title':K,'image':I or get_logo_image_src(B),'config':A.config.html,'config_json':A.config.html.model_dump_json()};E=None
25
- if A.config.debug:E=A.config.model_dump_json(indent=4)
26
- return template_render_infolder('index.html',{G:L,'task':data.get(G),'data':{'files':data.get('processor_results')},'debug':E})
20
+ F=list(set([A.working_dir]+A.alt_config_dirs))
21
+ for L in F:
22
+ E=os.path.join(L,D)
23
+ if os.path.isfile(E):C=E;break
24
+ if not C:raise FileNotFoundError(f"Logo file '{A.config.logo_file}' not found in {F}.")
25
+ M=A.config.title if A.config.title else A.config.title_prefix+' '+task_name;N={'app_name':product_name,'app_version':pkg_version,'app_homepage':pkg_homepage,'app_copyright':f"© {B[H][:4]} {powered_by['name']}. All rights reserved",'app_powered_by':powered_by,'execution_utc_datetime':B['datetime'],'execution_utc_date':B[H],'execution_utc_time':B['time'],'execution_dir':A.working_dir,'title':M,'image':K or get_logo_image_src(C),'config':A.config.html,'config_json':A.config.html.model_dump_json()};G=None
26
+ if A.config.debug:G=A.config.model_dump_json(indent=4)
27
+ return template_render_infolder('index.html',{I:N,'task':data.get(I),'data':{'files':data.get('processor_results')},'debug':G})
@@ -1,6 +1,6 @@
1
1
  <!-- TITLE -->
2
2
  <h1>
3
- {% if meta.image %}<img height="40" src="{{ meta.image }}"/>{% endif %}
3
+ {% if meta.image %}<img height="{{ meta.config.logo_height }}" src="{{ meta.image }}"/>{% endif %}
4
4
  {{ meta.title }}
5
5
  {{ data.name }}
6
6
  </h1>
@@ -1,93 +1,12 @@
1
1
  {% if file.comparison_errors %}
2
- {% set errs = file.comparison_errors %}
3
- {% set c_type = file.comparison.type %}
4
- <table>
5
- <tr>
6
- <th class="p-2" colspan="6">Error</th>
7
- <th class="p-2" colspan="99">Source</th>
8
- </tr>
9
- <tr>
10
- <th class="p-2" rowspan="2">Severity</th>
11
- <th class="p-2" rowspan="2">Message</th>
12
- <th class="p-2" colspan="2">Value</th>
13
- <th class="p-2" rowspan="2">Error</th>
14
- <th class="p-2" rowspan="2">Visu</th>
2
+ {% for group in file.comparison_errors.groups if group.type != 'node' %}
15
3
 
16
- {% if c_type == "lines" %}
17
- <th class="p-2" colspan="2">Line Number</th>
18
- <th class="p-2" colspan="2">Line(s)</th>
19
- {% endif %}
4
+ {% if group.total_warnings or group.total_errors %}
20
5
 
21
- {% if c_type == "vectors" %}
22
- <th class="p-2" rowspan="2">Column</th>
23
- <th class="p-2" rowspan="2">Index</th>
24
- <th class="p-2" rowspan="2">Info</th>
25
- {% endif %}
6
+ <h4>{{ group.name }}</h4>
7
+ {% include 'compare_13_section_numbers_table.html' with context %}
26
8
 
27
- </tr>
28
- <tr>
29
- <th class="p-2 test-bg-50">Test</th>
30
- <th class="p-2 refe-bg-50">Ref.</th>
31
-
32
- {% if c_type == "lines" %}
33
- <th class="p-2 test-bg-50">Test</th>
34
- <th class="p-2 refe-bg-50">Ref.</th>
35
- <th class="p-2 test-bg-50">Test</th>
36
- <th class="p-2 refe-bg-50">Ref.</th>
37
- {% endif %}
38
-
39
- </tr>
40
-
41
-
42
- {% for error_type in [{"data_key": "error", "class": "ERROR"}, {"data_key": "warning", "class": "WARNING"}] %}
43
- {% for item in errs[error_type.data_key] %}
44
- <tr>
45
-
46
- <td class="{{error_type.class}}">{{error_type.class}}</td>
47
- <td>{{ errs.messages[item.msg] }}</td>
48
-
49
- <!-- COMPARISON -->
50
-
51
- <td class="number test-bg-20">{{ item.err.test }}</td>
52
- <td class="number refe-bg-20">{{ item.err.reference }}</td>
53
- <td class="number">
54
- {% if item.err.is_relative %}
55
- {{ '%0.2f' % (item.err.value*100)|float}}%
56
- {% else %}
57
- {{ item.err.value }}
58
- {% endif %}
59
- </td>
60
- <td>
61
- {% if item.err.test and item.err.reference %}
62
- <div style="width:200px;height:20px">
63
- <div class="test-bg-80" style="width:{{100*(item.err.test|abs)/([(item.err.test|abs), (item.err.reference|abs)]|max)}}%;height:10px"></div>
64
- <div class="refe-bg-80" style="width:{{100*(item.err.reference|abs)/([(item.err.test|abs), (item.err.reference|abs)]|max)}}%; height:10px"></div>
65
- </div>
66
- {% endif %}
67
- </td>
68
-
69
-
70
- {% if c_type == "vectors" %}
71
- {% set group = errs.groups[item.group] %}
72
- <td>{{ group.name }}</td>
73
- <td>{{ item.info.index }}</td>
74
- <td>
75
- {% if group.data %}
76
- {{ group.data.info_prefix + ": " + item.info.info|string }}
77
- {% endif %}
78
- </td>
79
- {% endif %}
80
-
81
- {% if c_type == "lines" %}
82
- <td class="test-bg-20 number">{{ item.info.line_nb_1 }}</td>
83
- <td class="refe-bg-20 number">{{ item.info.line_nb_2 }}</td>
84
- <td class="test-bg-20"><pre>{{ item.info.line_1 }}</pre></td>
85
- <td class="refe-bg-20"><pre>{{ item.info.line_2 }}</pre></td>
86
- {% endif %}
9
+ {% endif %}
87
10
 
88
- </tr>
89
- {% endfor %}
90
- {% endfor %}
91
-
92
- </table>
11
+ {% endfor %}
93
12
  {% endif %}
@@ -0,0 +1,99 @@
1
+ {% set comp_errs = file.comparison_errors %}
2
+ <table>
3
+ <!-- HEADERS -->
4
+ <tr>
5
+ <th class="p-2" colspan="6">Error</th>
6
+ <th class="p-2" colspan="99">Source</th>
7
+ </tr>
8
+ <tr>
9
+ <th class="p-2" rowspan="2">Severity</th>
10
+ <th class="p-2" rowspan="2">Message</th>
11
+ <th class="p-2" colspan="2">Value</th>
12
+ <th class="p-2" rowspan="2">Error</th>
13
+ <th class="p-2" rowspan="2">Visu</th>
14
+ {% if group.type == "lines" %}
15
+ <th class="p-2" colspan="2">Line Number</th>
16
+ <th class="p-2" colspan="2">Line(s)</th>
17
+ {% endif %}
18
+ {% if group.type == "vectors" %}
19
+ <th class="p-2" rowspan="2">Column</th>
20
+ <th class="p-2" rowspan="2">Index</th>
21
+ <th class="p-2" rowspan="2">Info</th>
22
+ {% endif %}
23
+ {% if group.type == "matrix" %}
24
+ <th class="p-2" rowspan="2">i</th>
25
+ <th class="p-2" rowspan="2">j</th>
26
+ <th class="p-2" rowspan="2">x</th>
27
+ <th class="p-2" rowspan="2">y</th>
28
+ {% endif %}
29
+ </tr>
30
+ <tr>
31
+ <th class="p-2 test-bg-50">Test</th>
32
+ <th class="p-2 refe-bg-50">Ref.</th>
33
+ {% if group.type == "lines" %}
34
+ <th class="p-2 test-bg-50">Test</th>
35
+ <th class="p-2 refe-bg-50">Ref.</th>
36
+ <th class="p-2 test-bg-50">Test</th>
37
+ <th class="p-2 refe-bg-50">Ref.</th>
38
+ {% endif %}
39
+ </tr>
40
+ <!-- BODY -->
41
+ {% for error_type in [{"data_key": "error", "class": "ERROR"}, {"data_key": "warning", "class": "WARNING"}] %}
42
+ {% for item in comp_errs[error_type.data_key] if item.group == group.id %}
43
+ <tr>
44
+
45
+ <td class="{{error_type.class}}">{{error_type.class}}</td>
46
+ <td>{{ comp_errs.messages[item.msg] }}</td>
47
+
48
+ <!-- COMPARISON -->
49
+
50
+ <td class="number test-bg-20">{{ item.err.test }}</td>
51
+ <td class="number refe-bg-20">{{ item.err.reference }}</td>
52
+ <td class="number">
53
+ {% if item.err.is_relative %}
54
+ {{ '%0.2f' % (item.err.value*100)|float}}%
55
+ {% else %}
56
+ {{ item.err.value }}
57
+ {% endif %}
58
+ </td>
59
+ <td>
60
+ {% if item.err.test and item.err.reference %}
61
+ <div style="width:200px;height:20px">
62
+ <div class="test-bg-80" style="width:{{100*(item.err.test|abs)/([(item.err.test|abs), (item.err.reference|abs)]|max)}}%;height:10px"></div>
63
+ <div class="refe-bg-80" style="width:{{100*(item.err.reference|abs)/([(item.err.test|abs), (item.err.reference|abs)]|max)}}%; height:10px"></div>
64
+ </div>
65
+ {% endif %}
66
+ </td>
67
+
68
+
69
+ {% if group.type == "vectors" %}
70
+ {% set group = comp_errs.groups[item.group] %}
71
+ <td>{{ group.name }}</td>
72
+ <td>{{ item.info.index }}</td>
73
+ <td>
74
+ {% if group.data %}
75
+ {{ group.data.info_prefix + ": " + item.info.info|string }}
76
+ {% endif %}
77
+ </td>
78
+ {% endif %}
79
+
80
+ {% if group.type == "lines" %}
81
+ <td class="test-bg-20 number">{{ item.info.line_nb_1 }}</td>
82
+ <td class="refe-bg-20 number">{{ item.info.line_nb_2 }}</td>
83
+ <td class="test-bg-20"><pre>{{ item.info.line_1 }}</pre></td>
84
+ <td class="refe-bg-20"><pre>{{ item.info.line_2 }}</pre></td>
85
+ {% endif %}
86
+
87
+ {% if group.type == "matrix" %}
88
+ <td class="number">{{ item.info.i }}</td>
89
+ <td class="number">{{ item.info.j }}</td>
90
+ <td class="number">{{ item.info.x }}</td>
91
+ <td class="number">{{ item.info.y }}</td>
92
+ {% endif %}
93
+
94
+ </tr>
95
+ {% endfor %}
96
+ {% endfor %}
97
+
98
+ </table>
99
+
scilens/utils/web.py CHANGED
@@ -8,13 +8,15 @@ class Web:
8
8
  C=requests.get(url,headers=B);C.raise_for_status()
9
9
  with open(filename,'wb')as D:D.write(C.content)
10
10
  def download_progress(L,url,filename,headers=None,callback100=None):
11
- D=callback100;C=headers;E=BASE_HEADERS.copy()
12
- if C:E.update(C)
13
- F=requests.get(url,headers=E,stream=True);I=int(F.headers.get('Content-Length',0));G=0;J=I//100;A=0
11
+ E=callback100;D=headers;F=BASE_HEADERS.copy()
12
+ if D:F.update(D)
13
+ A=requests.get(url,headers=F,stream=True)
14
+ if A.status_code>299:raise ValueError(f"Error downloading file: {A.status_code} - {A.text}")
15
+ I=int(A.headers.get('Content-Length',0));G=0;J=I//100;B=0
14
16
  with open(filename,'wb')as K:
15
- for B in F.iter_content(chunk_size=1024):
16
- if B:
17
- K.write(B);G+=len(B);H=G//J
18
- if H>A:
19
- A=H
20
- if D:D(A)
17
+ for C in A.iter_content(chunk_size=1024):
18
+ if C:
19
+ K.write(C);G+=len(C);H=G//J
20
+ if H>B:
21
+ B=H
22
+ if E:E(B)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: scilens
3
- Version: 0.2.1
3
+ Version: 0.3.1
4
4
  Summary: A CesGensLaB framework for data collecting and deep analysis
5
5
  Home-page: https://scilens.dev
6
6
  License: Proprietary
@@ -8,12 +8,13 @@ scilens/cli/info.py,sha256=xE7q9epjrCQRL6Agi3nhKsG6Mr3B8HSUFMti-epMoXA,1929
8
8
  scilens/cli/main.py,sha256=LljcS0s2E35y4YZpV01GhMhMK9HyRRHYmxc_q_kSurI,6004
9
9
  scilens/components/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
10
  scilens/components/analyse_folder.py,sha256=yqc-dscKaHLZJCYeXGak2v0c3F2aeX0E11AFPfya6r0,208
11
- scilens/components/compare_2_files.py,sha256=oQ5p9JwB1r_HhfCb29mv1kkkrUd0EdrVug9T-1fQshY,1286
12
- scilens/components/compare_errors.py,sha256=_n9uWwLVZyPn99mwsAF8WBfcYppVQCsMwj0xuOrlhkU,1241
13
- scilens/components/compare_floats.py,sha256=UGUJF-WEZJSCpHZUAvVhkWY-mWiQZ8RqYnkTjFdRp1Y,3617
11
+ scilens/components/compare_2_files.py,sha256=U4xumE28ijFbnrTPH8FgRyR_b5f04jOjaCmegJvCvSE,1483
12
+ scilens/components/compare_errors.py,sha256=Kw_zpVmA3Fb7yVDXog2poLaTsV_K81eLqv-z-b73Nlw,1495
13
+ scilens/components/compare_floats.py,sha256=tmHwS4ivzdA9iJBePHDQrDlnA9zxqjLhIjxuvwPxIKc,5063
14
14
  scilens/components/compare_folders.py,sha256=LZ1AuYxLVHMNbtXWXQrdms4vZgOQthvDy-8NFD_EFjc,2617
15
- scilens/components/executor.py,sha256=8ZZq9wwoiMr7ys9LXv1pEg5Zc06QatT9PGIigMsDAB8,3620
16
- scilens/components/file_reader.py,sha256=2xvBoiJSb0KUihLzRK_o-DdGSRqEBu0-QwT1i9CCWRM,1346
15
+ scilens/components/compare_models.py,sha256=SCPd747h_nd4ewZsqLB6CFr27v6q99NELJb-gpkdj0o,918
16
+ scilens/components/executor.py,sha256=LaT6QnWk8Xf2qdFqBSa58iDh-cUfu_uMIvllpLHmLCk,3314
17
+ scilens/components/file_reader.py,sha256=7SbKCqb4Co_pqAKX3wweYhqAcVkU7BDlT903sLd76Kc,1407
17
18
  scilens/config/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
18
19
  scilens/config/cli_run_options.py,sha256=Ls7yK5QDUPFbk73nbjGuPvuRbBRYw4Miag5ISpu3prg,281
19
20
  scilens/config/env_var.py,sha256=NqNBoIfngJEXaGEm7jGqre5pmkJ9eUjiWzbDrTVfi2c,292
@@ -26,13 +27,13 @@ scilens/config/models/execute.py,sha256=pFY-gZuBvLbcjTEcoNhPPO7FMFmKa6_TU5IXyKaf
26
27
  scilens/config/models/execute_and_compare.py,sha256=TWL6yXGvQSaaV6nhHqWLvtr3v396APIoDNt0U1TbMro,582
27
28
  scilens/config/models/file_reader.py,sha256=c18vKhVcBX4ufpbnCBJyVyAsQtlxpwx0lGVuf1i8EGA,1176
28
29
  scilens/config/models/reader_format_cols_curve.py,sha256=eKLvifq1xuN8sPds9ijfru3vgMZ3Odv5tGfeiK4Sfk4,1860
29
- scilens/config/models/reader_format_csv.py,sha256=XWZTr6s0PPfcOMRrsNeOZGtExC1uyXb67A158MMWzC4,577
30
+ scilens/config/models/reader_format_csv.py,sha256=cxvkVbBF5DtrbRCIppjDUC2EIkb-GIe9qou3TGrihxU,1265
30
31
  scilens/config/models/reader_format_netcdf.py,sha256=nbfTB3avO0DidbNa1dCZGFZmmQvzTYhpe6mqfAanaOA,1025
31
32
  scilens/config/models/reader_format_txt.py,sha256=eHg90gwEI_VpqwqEjMRhwlS8dHcl5G4ow-37HjQq_zY,1168
32
33
  scilens/config/models/reader_format_txt_fixed_cols.py,sha256=xHD1_JOoRZow8lSNaDSYFeNckojctkT4C61mbBcjeKg,1079
33
34
  scilens/config/models/readers.py,sha256=Pq5kOGW3b6g1x5cp_BbwUF7LUB_P3m9bHDYLSTVXNBY,1769
34
35
  scilens/config/models/report.py,sha256=nTmP2nIwL2Ku5IH9QMwYLPKmfsK2ttu9UK0GnzPUHeM,870
35
- scilens/config/models/report_html.py,sha256=9I9iKRDOoLMZRBY0lQV4UFtg5-D-VDfYiFGF1VFAnQ8,1389
36
+ scilens/config/models/report_html.py,sha256=WiUPD38NCmBYHQdYyMb1-713kVNq7dm5pe8chlhuoyM,1468
36
37
  scilens/config/models/report_output.py,sha256=XoqUe-t-y8GRbUR3_bDwwaWf6hif-rZ-5pKDGdCMugw,875
37
38
  scilens/helpers/assets.py,sha256=XphDA3-yE1PPKw4XFZhDrlLQjMZfGMlpOBXa8uy_xX0,1552
38
39
  scilens/helpers/search_and_index.py,sha256=kXZ7124ra_SGAdKUZ7msy55UOWQ9dCSuPuNoU-NdUyM,1522
@@ -46,29 +47,29 @@ scilens/processors/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJW
46
47
  scilens/processors/models/results.py,sha256=KoWxh13Zgi7PuPql8hkf4VjCis42ZxAuzIgJxBWVaX8,119
47
48
  scilens/processors/processor_interface.py,sha256=jzMp1529JXnMGTJijVy6b_1zmARAMNv70f2lgys7vn4,452
48
49
  scilens/readers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
49
- scilens/readers/cols_dataset.py,sha256=suEttRHfj9UhHndchAKazLD2z_YY9dFEVLjlodRJS44,2363
50
+ scilens/readers/cols_dataset.py,sha256=JIfPBzQZml6VlykbrMcCanR12eEnjY1A-ECgXs8wtZ4,2527
50
51
  scilens/readers/exceptions.py,sha256=JzmxcjnR5sH-IOWVeCC5A1bSwxv-jCAtIJvDjzx1CTI,32
51
- scilens/readers/reader_com_txt_lines.py,sha256=zsCumTD0sv06OQNvRKPMuv94De_6KGMvN904-E1Uqeg,91
52
- scilens/readers/reader_csv copy.py,sha256=eFWQvMt4Ot7KgUIDsed1QymMbPblgboUclvQj6viVGs,4069
53
- scilens/readers/reader_csv.py,sha256=oLbA4wU6rlzL1cIrW-AzWifP-RvmG3yHKWQQqITYQ1U,2732
52
+ scilens/readers/mat_dataset.py,sha256=vUEjAK6nuY7miLJvjSkiHAU64KaNa1VCx7EhGPazp-U,1190
53
+ scilens/readers/reader_csv.py,sha256=aPd2IxFiUXYmH_EpNZkCHV1oMWctZW7YSPwC8q75SIo,3490
54
54
  scilens/readers/reader_interface.py,sha256=nnttHL7wt4MOXpi-SBkk8DYxVWscOPG8JFl_z12mIAo,922
55
55
  scilens/readers/reader_manager.py,sha256=DFinxIk3IIIcB6JxybGcv-mXt3jhXgCwUtzR0TqhB2Q,2684
56
- scilens/readers/reader_txt.py,sha256=xeiQNrWSr-jRnb0KoYya8Y_gdjT-0L_iXS4TW_bfqQc,3774
57
- scilens/readers/reader_txt_fixed_cols.py,sha256=KuZd62_cmV9vHRlar2K-acFVVLf28bAqRSbpRRNjblI,2258
56
+ scilens/readers/reader_txt.py,sha256=WPsFunEA_idzAKkD3UJQbLnaOzG2U03P3gY4gphuIw0,3868
57
+ scilens/readers/reader_txt_fixed_cols.py,sha256=vIA6e38_3nkFeCT835eSyCufCXQNGav8Iy7VgHlT_EE,2314
58
58
  scilens/readers/transform.py,sha256=kppfgPkXymF0qtquFivuosLVfF66L9bE-wGx-3bMHv8,307
59
59
  scilens/report/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
60
60
  scilens/report/assets/logo.svg,sha256=W-1OVqcvdBjf-1AHHcV6WciIUqBoVFUh52Tc3o_jqtA,4519
61
61
  scilens/report/assets/logo_cglb.svg,sha256=tEpkSr2h-jjQMecqiHef98Mxod4GD5j5nCQaFloTYso,2411
62
62
  scilens/report/assets.py,sha256=CcfGc9NNGnPVinkHZkEyN2S_BGKNIyMFvVdA__-M6-0,532
63
- scilens/report/html_report.py,sha256=PGbaar0UTUsHrH9HxSibLi7lEv6cean0-yKEhmSAKzQ,1845
63
+ scilens/report/html_report.py,sha256=ajNDTfEu06fs2h1SF4nTP1MvZmYwMcLieeSngyuH-qE,1905
64
64
  scilens/report/report.py,sha256=aS7ktJ2u0IAMMk-HwqqSsRkr77ZBQyYT4wXJ7djQvAk,1811
65
65
  scilens/report/template.py,sha256=cPs5gd3uEwb-6JgitGQD_i4IiUxigBTlZLNRS9KVuos,581
66
- scilens/report/templates/body_01_title.html,sha256=59BmETKHqRO1T_xYp0XLKx3Vha9hU9bu7yaUTVt2p9Y,2146
66
+ scilens/report/templates/body_01_title.html,sha256=0mrMM62TSBdPOpPNCcam0bZsZtM0GjoMQ-jrSqI8HCw,2173
67
67
  scilens/report/templates/body_99_footer.html,sha256=8cWebeWfZwZ-9bYAMZkZj8rbCWq3BLIMjKQThWQxoQM,362
68
68
  scilens/report/templates/compare_11_summary.html,sha256=4rxBlOxTcn59ztYtqDbi6SRQXlaz30HkVl7dJpzCmZE,3776
69
69
  scilens/report/templates/compare_12_sections.html,sha256=HWsfCmfdleyRK6IHJeMEheenOuyA0mLzOZ-0qLcuzJU,5952
70
70
  scilens/report/templates/compare_13_section_numbers copy.html,sha256=0PWK_I2kNX3LjPLkkY4eSYIeB7YFkA28nk-PPLDhnaY,1753
71
- scilens/report/templates/compare_13_section_numbers.html,sha256=JjD20F6X2RjzJIgAAF431JOdmUyNNOHJOufdH21iUsM,2820
71
+ scilens/report/templates/compare_13_section_numbers.html,sha256=FpIYAVXRiWf2zrJtjy2fWPdit_RNbHP2zQLQYScIrtY,291
72
+ scilens/report/templates/compare_13_section_numbers_table.html,sha256=sJy6ZYtjl80vM1b3oqZSXawZWp7KNIwLI_wCnvBwYPE,3270
72
73
  scilens/report/templates/index.html,sha256=mNTu-CAzEJ2rhz81cHAdmT_KcQeOQ3b_FSC73NPEi0U,3670
73
74
  scilens/report/templates/js_chartlibs_echarts.js,sha256=6YicVhTNIBmmBpV31XCVN5oBeiD0t29JIosJZRUv01M,907
74
75
  scilens/report/templates/js_chartlibs_plotly.js,sha256=uVAOKUB5XE33-r04phR-LlRkFoaHEIXyQ3jXT5r97Rc,1521
@@ -95,8 +96,8 @@ scilens/utils/system.py,sha256=drXp_Vdv2dP9wFQoEQZIhxyCJhFliBLFPylGwv89FF4,182
95
96
  scilens/utils/template.py,sha256=9dlXX3nmfzDRUwzPJOkoxk15UXivZ2SW-McdCwokFa4,443
96
97
  scilens/utils/time_tracker.py,sha256=DdVBoMpVLXrX0qZZXyLm4g38EwDVLlRcBqcpNex1mYY,545
97
98
  scilens/utils/vectors.py,sha256=4N2BZSC5n3HgZqPujDGF5NdjVmSL1rOHb_qw4OoABQY,103
98
- scilens/utils/web.py,sha256=E4T8Fra65u9g_BpcFANPk4ORvsYavAeiSgWA3vRca2E,804
99
- scilens-0.2.1.dist-info/METADATA,sha256=QYXvNkOg3U3JDqKslGVMo1OCq3bCM6yT7eCzAS4onX4,1367
100
- scilens-0.2.1.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
101
- scilens-0.2.1.dist-info/entry_points.txt,sha256=DaKGgxUEUv34GJAoXtta6ecL37ercejep9sCSSRQK2s,48
102
- scilens-0.2.1.dist-info/RECORD,,
99
+ scilens/utils/web.py,sha256=MAFWpIFOKz7QhqDoFh-Qwstvc76KpcxstSgHFT8FOL4,901
100
+ scilens-0.3.1.dist-info/METADATA,sha256=AmSUTNHDOlrHTmC0Qp60jHaju--5SiGbDR-EG-uNKm4,1367
101
+ scilens-0.3.1.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
102
+ scilens-0.3.1.dist-info/entry_points.txt,sha256=DaKGgxUEUv34GJAoXtta6ecL37ercejep9sCSSRQK2s,48
103
+ scilens-0.3.1.dist-info/RECORD,,
@@ -1,2 +0,0 @@
1
- class ReaderComTxtLines:
2
- def __init__(A,raw_lines):A.raw_lines=raw_lines;A.ignore_lines=[]
@@ -1,74 +0,0 @@
1
- _E='charts'
2
- _D='x_index'
3
- _C='csv_col_index'
4
- _B='curves'
5
- _A=None
6
- import logging,csv
7
- from scilens.readers.reader_interface import ReaderInterface
8
- from scilens.config.models import ReaderCsvConfig
9
- from scilens.config.models.reader_format_cols_curve import ReaderCurveParserNameConfig
10
- from scilens.components.compare_floats import CompareFloats
11
- def is_num(x):
12
- try:return float(x)
13
- except ValueError:return
14
- def csv_row_detect_header(first_row):
15
- A=first_row
16
- if all(not A.isdigit()for A in A):return True,A
17
- else:return False,[f"Column {A}"for(A,B)in enumerate(A)]
18
- def csv_row_detect_cols_num(row):return[A for(A,B)in enumerate(row)if is_num(B)!=_A]
19
- def csv_detect(path,delimiter,quotechar):
20
- with open(path,'r')as B:A=csv.reader(B,delimiter=delimiter,quotechar=quotechar);C=next(A);D,E=csv_row_detect_header(C);F=next(A);G=csv_row_detect_cols_num(F);return D,E,G
21
- class ReaderCsv(ReaderInterface):
22
- category='datalines';extensions=['CSV']
23
- def read(A,reader_options):
24
- B=reader_options;A.reader_options=B;C,G,H=csv_detect(A.origin.path,A.reader_options.delimiter,A.reader_options.quotechar);A.has_header=C;A.cols=G;A.numeric_col_indexes=H
25
- if B.ignore_columns:
26
- if not C:raise Exception('Ignore columns is not supported without header.')
27
- A.numeric_col_indexes=[C for C in A.numeric_col_indexes if A.cols[C]not in B.ignore_columns]
28
- E=open(A.origin.path,'r',encoding=A.encoding);I=csv.reader(E,delimiter=A.reader_options.delimiter,quotechar=A.reader_options.quotechar);D=[]
29
- for J in I:D+=[J]
30
- if C:D.pop(0)
31
- E.close();A.data_rows=D;A.raw_lines_number=len(A.data_rows)+(1 if C else 0);A.curves=_A
32
- if B.curve_parser:
33
- if B.curve_parser.name==ReaderCurveParserNameConfig.COL_X:
34
- A.curves,K=A._get_curves_col_x(B.curve_parser.parameters.x)
35
- if A.curves:A.curves_parser_type=B.curve_parser.name;A.curves_info=K
36
- elif B.curve_parser.name==ReaderCurveParserNameConfig.COLS_COUPLE:raise NotImplementedError('cols_couple not implemented')
37
- else:raise Exception('Curve parser not supported.')
38
- A.cols_data=[_A]*len(A.cols)
39
- for F in A.numeric_col_indexes:A.cols_data[F]=[float(A[F])for A in D]
40
- def compare(A,compare_floats,param_reader,param_is_ref=True):
41
- U='error';M=param_is_ref;L=param_reader;K=compare_floats;J='Errors limit reached';C=A if M else L;E=A if not M else L
42
- if len(C.numeric_col_indexes)!=len(E.numeric_col_indexes):V=f"Number Float columns indexes are different: {len(C.numeric_col_indexes)} != {len(E.numeric_col_indexes)}";return V,_A
43
- N=0;D=[''for A in C.cols];O=_A;F=_A
44
- if A.curves and A.curves_parser_type==ReaderCurveParserNameConfig.COL_X:P=A.curves_info[_D];O=C.cols_data[P];F=A.cols[P]
45
- G=False
46
- for B in range(len(C.cols_data)):
47
- if C.cols_data[B]==_A:continue
48
- logging.debug(f"Comparing {A.cols[B]}")
49
- if G:D[B]=J;continue
50
- W=C.cols_data[B];X=E.cols_data[B];Y=K.compare_errors.add_group(A.cols[B],data={'info_prefix':F}if F else _A);Q,R,H=K.compare_vectors(W,X,group_idx=Y,info_vector=O);N+=R;logging.debug(f"limit_reached, diffs_count, counts: {Q}, {R}, {H}")
51
- if Q:G=True;D[B]=J;continue
52
- if H[U]>0:D[B]=f"{H[U]} comparison errors"
53
- if A.curves:
54
- for S in A.curves[_E]:
55
- T=0
56
- for Z in S[_B]:
57
- I=A.curves[_B][Z]
58
- if D[I[_C]]:I['comparison_error']=D[I[_C]];T+=1
59
- S['comparison']={'curves_nb_with_error':T}
60
- a=J if G else _A;return a,{'type':'vectors','total_diffs':N,'cols_has_error':D}
61
- def class_info(A):return{'cols':A.cols,'raw_lines_number':A.raw_lines_number,_B:A.curves}
62
- def _get_curves_col_x(E,col_x):
63
- J='title';A=col_x;F={};B=E.cols
64
- if isinstance(A,int):
65
- C=A-1
66
- if C<0 or C>=len(B):raise Exception('curve parser col_x: col_index is out of range.')
67
- if isinstance(A,str):A=[A]
68
- if isinstance(A,list):
69
- H=[B for(B,C)in enumerate(B)if C in A]
70
- if len(H)==0:return _A,F
71
- C=H[0]
72
- F[_D]=C;K=[B for(A,B)in enumerate(E.numeric_col_indexes)if A!=C];G=[];I=[]
73
- for D in K:L={J:B[D],'short_title':B[D],'series':[[float(A[C]),float(A[D])]for A in E.data_rows],_C:D};G+=[L];M={J:B[D],'type':'simple','xaxis':B[C],'yaxis':B[D],_B:[len(G)-1]};I+=[M]
74
- return{_B:G,_E:I},F