scilens 0.3.6__py3-none-any.whl → 0.3.8__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.
scilens/cli/main.py CHANGED
@@ -1,6 +1,6 @@
1
1
  _B='green'
2
2
  _A=True
3
- import logging,os,coloredlogs,rich_click as click
3
+ import logging,os,webbrowser,coloredlogs,rich_click as click
4
4
  from scilens.app import pkg_name,pkg_version
5
5
  from scilens.readers.reader_manager import ReaderManager
6
6
  from scilens.run.tasks_collector import TasksCollector
@@ -52,25 +52,31 @@ def config_json():config_print('envvars')
52
52
  @click.option('--export-json',is_flag=_A,help=f"Generate JSON report(s).")
53
53
  @click.option('--export-yaml',is_flag=_A,help=f"Generate YAML report(s).")
54
54
  @click.option('--export-html-add-index',is_flag=_A,help=f"Generate an index for generated HTML reports.")
55
- def run(path,config,collect_discover,collect_depth,processor,tag,collect_only,report_title,export_html,export_json,export_yaml,export_html_add_index):
56
- R='datetime';K=processor;J=collect_discover;I=config;E=collect_depth;echo_separator('Info');echo_info();echo_separator('System Info');echo_system_info();S=list(tag);B=os.path.abspath(path)
55
+ @click.option('--export-html-open',is_flag=_A,help=f"Open all generated HTML reports in the default browser.")
56
+ def run(path,config,collect_discover,collect_depth,processor,tag,collect_only,report_title,export_html,export_json,export_yaml,export_html_add_index,export_html_open):
57
+ V='datetime';M=export_html_open;L=export_html_add_index;K=processor;J=collect_discover;I=config;E=collect_depth;echo_separator('Info');echo_info();echo_separator('System Info');echo_system_info();W=list(tag);B=os.path.abspath(path)
57
58
  if not os.path.isdir(B):logging.error(f"Dir '{B}' does not exist.");exit(1)
58
59
  if not bool(I)+J+(bool(E)or E==0)+bool(K)in[0,1]:logging.error(f"Options --config, --collect-discover, --collect-depth and --processor are mutually exclusive.");exit(1)
59
60
  echo_separator('Collecting tasks');F=[]
60
- try:F=TasksCollector(B,I,J,E,S,K).process(get_vars(report_title,export_html,export_json,export_yaml))
61
+ try:F=TasksCollector(B,I,J,E,W,K).process(get_vars(report_title,export_html,export_json,export_yaml))
61
62
  except Exception as D:logging.error(D);exit(1)
62
63
  if collect_only:echo_separator();logging.info('Collecting tasks only - End');echo_separator();exit(0)
63
64
  else:
64
- L=TimeTracker();A=len(F);M=0;N=0;O=0;P=[]
65
- for(T,U)in enumerate(F):
66
- echo_separator(f"Running task {T+1}/{A}")
67
- try:C=U.process()
65
+ N=TimeTracker();A=len(F);O=0;P=0;Q=0;R=[]
66
+ for(X,Y)in enumerate(F):
67
+ echo_separator(f"Running task {X+1}/{A}")
68
+ try:C=Y.process()
68
69
  except Exception as D:echo_task_error();logging.error(D);C=TaskResults(error=str(D))
69
- if C.report_results:P+=C.report_results.files_created
70
- if C.error:M+=1
70
+ if C.report_results:R+=C.report_results.files_created
71
+ if C.error:O+=1
71
72
  G=C.processor_results
72
73
  if G:
73
- if G.warnings:O+=1
74
- if G.errors:N+=1
75
- if export_html_add_index:echo_separator(f"Post Actions");logging.info(f"Generate HTML Index for the HTML reports");V=[A for A in P if A.endswith('.html')];Q=os.path.join(B,'index.html');SearchAndIndex().create_html_index(SearchAndIndex().file_list_info_from_origin(V,B),Q,title='Index of Reports');logging.info(f"HTML Index generated at '{Q}'")
76
- echo_separator(f"End Running tasks ({A}/{A})");L.stop();H=L.get_data();logging.info(f"Tasks with errors ............... {M}/{A}");logging.info(f"Tasks with processor errors ..... {N}/{A}");logging.info(f"Tasks with processor warnings ... {O}/{A}");logging.info(f"Start ........................... {H['start'][R]} utc");logging.info(f"End ............................. {H['end'][R]} utc");logging.info(f"Duration......................... {H['duration_seconds']} seconds");echo_separator()
74
+ if G.warnings:Q+=1
75
+ if G.errors:P+=1
76
+ if L or M:
77
+ echo_separator(f"Post Actions");S=[A for A in R if A.endswith('.html')]
78
+ if L:logging.info(f"Generate HTML Index for the HTML reports");T=os.path.join(B,'index.html');SearchAndIndex().create_html_index(SearchAndIndex().file_list_info_from_origin(S,B),T,title='Index of Reports');logging.info(f"HTML Index generated at '{T}'")
79
+ if M:
80
+ logging.info(f"Open HTML reports in the default browser")
81
+ for U in S:logging.info(f"Open '{U}'");Z=f"file://{U}";webbrowser.open(Z)
82
+ echo_separator(f"End Running tasks ({A}/{A})");N.stop();H=N.get_data();logging.info(f"Tasks with errors ............... {O}/{A}");logging.info(f"Tasks with processor errors ..... {P}/{A}");logging.info(f"Tasks with processor warnings ... {Q}/{A}");logging.info(f"Start ........................... {H['start'][V]} utc");logging.info(f"End ............................. {H['end'][V]} utc");logging.info(f"Duration......................... {H['duration_seconds']} seconds");echo_separator()
@@ -1,6 +1,7 @@
1
1
  _C='amplitude'
2
2
  _B=False
3
3
  _A=None
4
+ import logging
4
5
  from scilens.components.compare_models import SEVERITY_ERROR,SEVERITY_WARNING,CompareGroup,CompareFloatsErr,Compare2ValuesResults
5
6
  from scilens.components.compare_errors import CompareErrors
6
7
  from scilens.config.models import CompareFloatThresholdsConfig
@@ -26,14 +27,17 @@ class CompareFloats:
26
27
  if len(test_vector)!=len(reference_vector):raise Exception('Vectors have different lengths')
27
28
  diffs_count=0;err_limit_reached=_B;ponderation_method=self.thresholds.vectors.ponderation_method if self.thresholds.vectors else _A
28
29
  if ponderation_method=='RIAE':ponderation_method=A
30
+ if ponderation_method:logging.debug(f"Using ponderation method: {ponderation_method} with reduction_method {self.thresholds.vectors.reduction_method}")
29
31
  amplitude_compare=_A
30
32
  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
31
33
  RIAE_force_severity=_A
32
34
  if self.thresholds.vectors and ponderation_method in[A,'RIAE_midpoint']:
33
- RIAE_force_severity=self.thresholds.vectors.reduction_method
34
35
  if'CheckVectors'not in globals():raise Exception('scilens_compare not found. Please install scilens-compare package with `pip install scilens-compare`.')
35
36
  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)
37
+ if riae_error is _A:logging.warning('RIAE calculation returned None. This may indicate an issue with the vectors.')
38
+ else:
39
+ RIAE_force_severity=self.thresholds.vectors.reduction_method
40
+ 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)
37
41
  nb=len(test_vector)
38
42
  for idx in range(nb):
39
43
  diff=test_vector[idx]-reference_vector[idx]
@@ -1,4 +1,10 @@
1
1
  _A=None
2
- from pydantic import BaseModel,Field
3
- class CompareFloatVectorsConfig(BaseModel):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.")
2
+ from pydantic import BaseModel,Field,model_validator
3
+ class CompareFloatVectorsConfig(BaseModel):
4
+ 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
+ @model_validator(mode='after')
6
+ def check_value_required(self):
7
+ A=self
8
+ if A.ponderation_method.startswith('RIAE')and not A.riae_threshold:raise ValueError('riae_threshold is required when ponderation_method is "RIAE"')
9
+ return A
4
10
  class CompareFloatThresholdsConfig(BaseModel):relative_vs_absolute_min:float=Field(default=1e-12,description="Si la valeur de test est inférieure à ce seuil, calcul de l'erreur absolue.");relative_error_min:float=Field(default=.001,description="Si l'erreur relative est supérieure à ce seuil, génère une erreur de sévérité `warning`.");relative_error_max:float=Field(default=.01,description="Si l'erreur relative est supérieure à ce seuil, génère une erreur de sévérité `error`.");absolute_error_min:float=Field(default=1e-07,description="Si l'erreur absolue est supérieure à ce seuil, génère une erreur de sévérité `warning`.");absolute_error_max:float=Field(default=1e-06,description="Si l'erreur absolue est supérieure à ce seuil, génère une erreur de sévérité `error`.");vectors:CompareFloatVectorsConfig|_A=Field(default=_A,description='Paramètres pour la comparaison de vecteurs de flottants (csv, nc, ...).')
@@ -3,4 +3,4 @@ from pydantic import BaseModel,Field
3
3
  from scilens.app import product_name
4
4
  from scilens.config.models.report_html import ReportHtmlConfig
5
5
  from scilens.config.models.report_output import ReportOutputConfig
6
- class ReportConfig(BaseModel):debug:bool=Field(default=False,description='If `true` the report will be more verbose and displays template input data.');title:str=Field(default=_A,description='Titre du rapport');title_prefix:str=Field(default=f"{product_name} Report",description='Préfixe au Titre du rapport');logo:str|_A=Field(default=_A,description="Source d'une image logo. Peut être une url ou une url data image encodée base64 (exclusif avec `logo_file`).");logo_file:str|_A=Field(default=_A,description="Source fichier d'une image logo (exclusif avec `logo`).");output:ReportOutputConfig=ReportOutputConfig();html:ReportHtmlConfig=ReportHtmlConfig()
6
+ class ReportConfig(BaseModel):debug:bool=Field(default=False,description='If `true` the report will be more verbose and displays template input data.');title:str=Field(default=_A,description='Titre du rapport');title_prefix:str=Field(default=f"{product_name} Report",description='Préfixe au Titre du rapport');description:str|_A=Field(default=_A,description='Description inclu dans une section spécifique description des rapports');logo:str|_A=Field(default=_A,description="Source d'une image logo. Peut être une url ou une url data image encodée base64 (exclusif avec `logo_file`).");logo_file:str|_A=Field(default=_A,description="Source fichier d'une image logo (exclusif avec `logo`).");output:ReportOutputConfig=ReportOutputConfig();html:ReportHtmlConfig=ReportHtmlConfig()
@@ -1,6 +1,8 @@
1
- _A="Paramètre modifiable par l'utilisateur"
1
+ _C="Paramètre modifiable par l'utilisateur"
2
+ _B=True
3
+ _A=None
2
4
  from pydantic import BaseModel,Field
3
- class ReportParameterPageModeConfig(BaseModel):is_user_preference:bool=Field(default=True,description=_A);default_value:str=Field(default='onepage',description='`tabs` ou `onepage`')
4
- class ReportParameterOpenFileInConfig(BaseModel):is_user_preference:bool=Field(default=True,description=_A);default_value:str=Field(default='browser',description='`browser` ou `vscode`')
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):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()
5
+ class ReportParameterPageModeConfig(BaseModel):is_user_preference:bool=Field(default=_B,description=_C);default_value:str=Field(default='onepage',description='`tabs` ou `onepage`')
6
+ class ReportParameterOpenFileInConfig(BaseModel):is_user_preference:bool=Field(default=_B,description=_C);default_value:str=Field(default='browser',description='`browser` ou `vscode`')
7
+ class ReportHtmlCurvesConfig(BaseModel):display_on_load:bool=Field(default=False,description="Si `true`, affiche tous les graphiques courbes à l'ouverture du rapport.");init_width:int=Field(default=600,description='Largeur initiale des graphiques courbes.');init_height:int=Field(default=400,description='Hauteur initiale des graphiques courbes.');compare_vs_values:bool=Field(default=_B,description='Dans le chart de comparaison, affiche les valeurs de référence et de test.');compare_vs_difference:bool=Field(default=_B,description='Dans le chart de comparaison, affiche la différence entre les valeurs de référence et de test.')
8
+ class ReportHtmlConfig(BaseModel):custom_style:str|_A=Field(default=_A,description='CSS personnalisé.');custom_script_head:str|_A=Field(default=_A,description='Script personnalisé dans le `<head>`.');custom_script_body:str|_A=Field(default=_A,description='Script personnalisé en fin de `<body>`.');extra_html_start:str|_A=Field(default=_A,description='HTML personnalisé en début de rapport.');extra_html_summary:str|_A=Field(default=_A,description='HTML personnalisé dans la section `Summary`.');extra_html_end:str|_A=Field(default=_A,description='HTML personnalisé en fin de rapport.');logo_height:int=Field(default=40,description='Hauteur du logo dans le titre.');compare_color_test:str=Field(default='1982c4',description='Couleur pour les données de test.');compare_color_reference:str=Field(default='6a4c93',description='Couleur pour les données de référence.');collapse_if_successful:bool=Field(default=_B,description="N'affiche par défaut les sections de comparaison sans erreur.");parameter_page_mode:ReportParameterPageModeConfig=ReportParameterPageModeConfig();parameter_open_file_in:ReportParameterOpenFileInConfig=ReportParameterOpenFileInConfig();curves:ReportHtmlCurvesConfig=ReportHtmlCurvesConfig()
@@ -22,6 +22,6 @@ class HtmlReport:
22
22
  E=os.path.join(L,D)
23
23
  if os.path.isfile(E):C=E;break
24
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
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,'description':A.config.description,'image':K or get_logo_image_src(C),'config':A.config.html,'config_json':A.config.html.model_dump_json()};G=None
26
26
  if A.config.debug:G=A.config.model_dump_json(indent=4)
27
27
  return template_render_infolder('index.html',{I:N,'task':data.get(I),'data':{'files':data.get('processor_results')},'debug':G})
@@ -47,15 +47,3 @@
47
47
  </table>
48
48
 
49
49
  </div>
50
-
51
-
52
-
53
- <div id="tabs" class="tabs noselect" style="display: none;">
54
- <div class="tab active" onclick="actions.click_tab(event, 0)">Summary</div>
55
- {% for file in data.files %}
56
- {% if not file.skipped %}
57
- <div class="tab {{ ns.statuses[loop.index] }}" onclick="actions.click_tab(event, {{ loop.index }})"><span class="">{{ file.name }}</span></div>
58
- {% endif %}
59
- {% endfor %}
60
- <div class="tabend"></div>
61
- </div>
@@ -0,0 +1,9 @@
1
+ <div id="tabs" class="tabs noselect" style="display: none;">
2
+ <div class="tab active" onclick="actions.click_tab(event, 0)">Summary</div>
3
+ {% for file in data.files %}
4
+ {% if not file.skipped %}
5
+ <div class="tab {{ ns.statuses[loop.index] }}" onclick="actions.click_tab(event, {{ loop.index }})"><span class="">{{ file.name }}</span></div>
6
+ {% endif %}
7
+ {% endfor %}
8
+ <div class="tabend"></div>
9
+ </div>
@@ -2,7 +2,18 @@
2
2
 
3
3
  <h2>Summary</h2>
4
4
 
5
- <!-- FILES -->
5
+ <!-- DESCRIPTION -->
6
+ {% if meta.description %}
7
+ <!-- <h3>Description</h3> -->
8
+ <div id="section_summary_description" class="description">
9
+ {{ meta.description }}
10
+ </div>
11
+ {% endif %}
12
+
13
+ <!-- EXTRA HTML -->
14
+ {% if meta.config.extra_html_summary %}{{ meta.config.extra_html_summary }}{% endif %}
15
+
16
+ <!-- DATASETS -->
6
17
  <h3>
7
18
  Datasets <action data-command="toogle" data-args="section_summary_datasets"></action>
8
19
  </h3>
@@ -133,11 +133,16 @@
133
133
  <div id="framesseries_{{ file_index }}" ></div>
134
134
  {% endif %}
135
135
 
136
- {% for item in [{"id": "spectrograms", "label": "Spectrograms"}, {"id": "frameseries", "label": "Frameseries"}] %}
137
136
 
137
+ <!-- MATRICES -->
138
+ {% if file.test.matrices %}
139
+ {% for item in [{"id": "spectrograms", "label": "Spectrograms"}, {"id": "frameseries", "label": "Frameseries"}] %}
140
+ {% if file.test.matrices[item.id] %}
138
141
  <h3>{{ item.label }} <action data-command="toogle" data-args="{{ item.id }}_{{ file_index|string }}"></action></h3>
139
142
  <div id="{{ item.id }}_{{ file_index }}" ></div>
143
+ {% endif %}
140
144
  {% endfor %}
145
+ {% endif %}
141
146
 
142
147
 
143
148
  <!--COMPARISONS ERRORS AND WARNINGS-->
@@ -26,19 +26,21 @@
26
26
  <script src="https://cdn.plot.ly/plotly-2.34.0.min.js" charset="utf-8"></script>
27
27
 
28
28
  <script>
29
+
29
30
  ((w_1, undef) => { w_1.None = undef; })(window); // for Python None = undef when templating
30
31
  {% include 'js_dom.js' %}
31
32
  {% include 'js_palette.js' %}
32
- </script>
33
- <script>{% include 'js_com_page.js' with context %}</script>
34
- <script>{% include 'js_chartlibs_plotly.js' %}</script>
35
- <script>{% include 'js_chartlibs_echarts.js' %}</script>
36
- <script>{% include 'js_curvemgr.js' %}</script>
37
- <script>{% include 'utils_compare_report_anim.js' %}</script>
38
- <script>{% include 'utils_compare_report_framesseries.js' %}</script>
39
- <script>
33
+
34
+ {% include 'js_com_page.js' with context %}
35
+ {% include 'js_chartlibs_plotly.js' %}
36
+ {% include 'js_chartlibs_echarts.js' %}
37
+ {% include 'js_curvemgr.js' %}
38
+ {% include 'utils_compare_report_anim.js' %}
39
+ {% include 'utils_compare_report_framesseries.js' %}
40
+
40
41
  {% if ns.has_spectrograms %}{% include 'uti_spectrograms.js' %}{% endif %}
41
42
  {% if ns.has_matrices %}{% include 'uti_matrix.js' %}{% endif %}
43
+
42
44
  </script>
43
45
  <script>
44
46
  function load_animations(){
@@ -89,13 +91,16 @@ function load_file_section(global_var, section_prefix, cls) {
89
91
  user-select: none; /* Standard syntax */
90
92
  }
91
93
  </style>
94
+ {% if meta.config.custom_style %}<style type="text/css">{{ meta.config.custom_style }}</style>{% endif %}
95
+ {% if meta.config.custom_script_head %}<script>{{ meta.config.custom_script_head }}</script>{% endif %}
92
96
  </head>
93
97
  <body>
94
98
  {% include 'body_01_title.html' with context %}
95
-
99
+ {% if meta.config.extra_html_start %}{{ meta.config.extra_html_start }}{% endif %}
100
+ {% include 'body_02_tabs.html' with context %}
96
101
  {% include 'compare_11_summary.html' with context %}
97
102
  {% include 'compare_12_sections.html' with context %}
98
-
103
+ {% if meta.config.extra_html_end %}{{ meta.config.extra_html_end }}{% endif %}
99
104
  {% include 'body_99_footer.html' with context %}
100
105
  <script type="text/javascript">
101
106
  const GLOBAL_VARS = {};
@@ -125,5 +130,6 @@ function load_file_section(global_var, section_prefix, cls) {
125
130
  MatrixMgmt.loadGlobal();
126
131
  </script>
127
132
  {% endif %}
133
+ {% if meta.config.custom_script_body %}<script>{{ meta.config.custom_script_body }}</script>{% endif %}
128
134
  </body>
129
135
  </html>
@@ -3,40 +3,58 @@
3
3
  const plotly = {
4
4
  add: function(elt, meta, items) {
5
5
  const series = []
6
+ let yaxis2 = null;
7
+
8
+ //
9
+
6
10
  items.forEach(item => {
7
- series.push({
11
+ const serie = {
8
12
  name: item.name,
9
13
  x: item.x_data,
10
14
  y: item.y_data,
15
+ // yaxis : 'y1', // required if there are multiple y axes
11
16
  // mode: 'lines+markers',
12
17
  mode: 'lines',
13
18
  line: { color: item.color, width: 3 },
14
- marker: { color: item.color, size: 6 },
15
- })
16
- });
17
- Plotly.newPlot(
18
- elt,
19
- series,
20
- {
21
- title: { text: meta.title, font: { weight: 800 } },
22
- xaxis: { title: meta.xaxis },
23
- yaxis: { title: meta.yaxis },
24
- autosize: true,
25
- // showlegend: false,
26
- // legend: {
27
- // x: 1,
28
- // xanchor: 'right',
29
- // y: 1
30
- // }
31
- // margin: {
32
- // l: 10,
33
- // r: 10,
34
- // b: 10,
35
- // t: 10,
36
- // pad: 0,
37
- // },
19
+ // marker: { color: item.color, size: 6 },
20
+ }
21
+ if (item.special) {
22
+ switch (item.special) {
23
+ case 'diff':
24
+ yaxis2 = {title: 'Difference',overlaying: 'y',side: 'right'}
25
+ serie.line.color = 'rgba(255, 0, 0, 0.5)';
26
+ serie.yaxis = 'y2';
27
+ serie.fill = 'tozeroy';
28
+ serie.fillcolor = 'rgba(255, 0, 0, 0.2)';
29
+ break;
30
+ }
38
31
  }
39
- );
32
+ // item.special
33
+ series.push(serie)
34
+ });
35
+
36
+ const layout = {
37
+ title: { text: meta.title, font: { weight: 800 } },
38
+ xaxis: { title: meta.xaxis },
39
+ yaxis: { title: meta.yaxis },
40
+ autosize: true,
41
+ // showlegend: false,
42
+ // legend: {
43
+ // x: 1,
44
+ // xanchor: 'right',
45
+ // y: 1
46
+ // }
47
+ // margin: {
48
+ // l: 10,
49
+ // r: 10,
50
+ // b: 10,
51
+ // t: 10,
52
+ // pad: 0,
53
+ // },
54
+ };
55
+ if (yaxis2) {layout.yaxis2 = yaxis2;}
56
+
57
+ Plotly.newPlot(elt,series,layout);
40
58
  },
41
59
  add_ys: function(elt, meta, x_data, y_items) {
42
60
  this.add(elt, meta, y_items.map((item) => {return {name: item.name, color: item.color, x_data: x_data, y_data: item.data} } ))
@@ -60,6 +60,8 @@ const CONFIG = {
60
60
  display_on_load: false,
61
61
  init_width: 600,
62
62
  init_height: 400,
63
+ compare_vs_values: true,
64
+ compare_vs_difference: true,
63
65
  }
64
66
 
65
67
 
@@ -79,10 +81,11 @@ const curve_add_chart = function(element_parent, data, zoom) {
79
81
  div,
80
82
  { title: data.title, xaxis: data.xaxis , yaxis: data.yaxis },
81
83
  data.series.map((item) => {return {
82
- name: item.name,
83
- color: item.color,
84
- x_data: item.data.map((e) => e[0]),
85
- y_data: item.data.map((e) => e[1]),
84
+ name: item.name,
85
+ color: item.color,
86
+ x_data: item.data.map((e) => e[0]),
87
+ y_data: item.data.map((e) => e[1]),
88
+ special: item.special,
86
89
  }}),
87
90
  )
88
91
  };
@@ -198,29 +201,63 @@ CurvesChart.prototype = {
198
201
 
199
202
  }
200
203
  // display each curve test vs reference
201
- for (index_curve in chart.curves) {
202
- real_index = chart.curves[index_curve]
204
+ if (CONFIG.compare_vs_values || CONFIG.compare_vs_difference) {
205
+ for (index_curve in chart.curves) {
206
+ real_index = chart.curves[index_curve]
203
207
 
204
- const series = [
205
- {
206
- name: "Test",
207
- data: this.curves["test"].curves[real_index].series,
208
- color: '#1982c4',
209
- },
210
- {
211
- name: "Reference",
212
- data: this.curves["reference"].curves[real_index].series,
213
- color: '#6a4c93',
214
- },
215
- ]
216
- const data = {
217
- title: this.curves["test"].curves[real_index].title + " [Test vs Reference]",
218
- xaxis: chart.xaxis,
219
- yaxis: chart.yaxis,
220
- series : series,
208
+ const series = [];
209
+ if (CONFIG.compare_vs_values) {
210
+ series.push({
211
+ name: "Test",
212
+ data: this.curves["test"].curves[real_index].series,
213
+ color: '#1982c4',
214
+ });
215
+ series.push({
216
+ name: "Reference",
217
+ data: this.curves["reference"].curves[real_index].series,
218
+ color: '#6a4c93',
219
+ });
220
+ }
221
+ if (CONFIG.compare_vs_difference) {
222
+ series.push({
223
+ name: "Difference",
224
+ data: this.curves["test"].curves[real_index].series.map((e, i) => {
225
+ return [e[0], e[1] - this.curves["reference"].curves[real_index].series[i][1]]
226
+ }),
227
+ color: '#ffcc00',
228
+ special: 'diff',
229
+ });
230
+ }
231
+
232
+ // {
233
+ // name: "Test",
234
+ // data: this.curves["test"].curves[real_index].series,
235
+ // color: '#1982c4',
236
+ // },
237
+ // {
238
+ // name: "Reference",
239
+ // data: this.curves["reference"].curves[real_index].series,
240
+ // color: '#6a4c93',
241
+ // },
242
+ // {
243
+ // name: "Difference",
244
+ // data: this.curves["test"].curves[real_index].series.map((e, i) => {
245
+ // return [e[0], e[1] - this.curves["reference"].curves[real_index].series[i][1]]
246
+ // }),
247
+ // color: '#ffcc00',
248
+ // special: 'diff',
249
+ // },
250
+ //
251
+ const data = {
252
+ title: this.curves["test"].curves[real_index].title + " [Test vs Reference]",
253
+ xaxis: chart.xaxis,
254
+ yaxis: chart.yaxis,
255
+ series : series,
256
+ }
257
+ curve_add_chart((chart.curves.length > 1) ? out.row_2 : out.row_1, data, this.curve_block.zoom);
221
258
  }
222
- curve_add_chart((chart.curves.length > 1) ? out.row_2 : out.row_1, data, this.curve_block.zoom);
223
259
  }
260
+
224
261
  }
225
262
  },
226
263
  }
@@ -309,6 +346,7 @@ w_1.curvemgr = {
309
346
  }
310
347
  },
311
348
  init(config) {
349
+ console.log(config)
312
350
  for (const k in CONFIG) {
313
351
  if (config[k] != undef) {CONFIG[k] = config[k];}
314
352
  }
@@ -37,6 +37,15 @@ padding:15px;
37
37
  background-color: #fafafa;
38
38
  }
39
39
 
40
+ .description {
41
+ background-color: #eef2f7;
42
+ border-left: 6px solid #4a90e2;
43
+ padding: 20px;
44
+ margin-bottom: 30px;
45
+ border-radius: 8px;
46
+
47
+ }
48
+
40
49
 
41
50
  .ERROR { background-color:#c52a0f20;color:#c52a0f; }
42
51
  .WARNING { background-color:#bcbc0620;color:#bcbc06; }
@@ -4,6 +4,6 @@ from scilens.run.task_context import TaskContext
4
4
  from scilens.run.run_task import RunTask
5
5
  from scilens.config.models import AppConfig
6
6
  class StandaloneTaskRunner:
7
- config_path=None
7
+ config:AppConfig;config_path=None
8
8
  def __init__(A,config):A.config=config_load(config)
9
9
  def process(A,working_dir,origin_working_dir=None):B=TaskContext(config=A.config,config_file=A.config_path,working_dir=working_dir,origin_working_dir=origin_working_dir);C=RunTask(B);D=C.process();return D
scilens/utils/file.py CHANGED
@@ -26,6 +26,8 @@ def json_load(path):
26
26
  with open(path)as A:return json.load(A)
27
27
  def yaml_write(path,data):
28
28
  with open(path,'w')as A:yaml.dump(data,A,default_flow_style=False)
29
+ def yaml_load(path):
30
+ with open(path)as A:return yaml.safe_load(A)
29
31
  def move(source,target):shutil.move(source,target)
30
32
  def list_paths_at_depth(root_dir,depth):
31
33
  B=depth;A=root_dir;C=[]
@@ -0,0 +1,16 @@
1
+ from pathlib import Path
2
+ from scilens.utils.file import json_load,yaml_load
3
+ def load_model_from_file(cls,path,json=True,yaml=True):
4
+ C=yaml;B=json;A=path
5
+ if isinstance(A,str):A=Path(A)
6
+ if not A.exists():raise FileNotFoundError(f"File {A} does not exist.")
7
+ if B:
8
+ try:D=json_load(A)
9
+ except Exception:
10
+ if not C:raise ValueError(f"Error during loading JSON file: {A}.")
11
+ if C:
12
+ try:D=yaml_load(A)
13
+ except Exception:
14
+ if not B:raise ValueError(f"Error during loading YAML file: {A}.")
15
+ if B and C and not D:raise ValueError(f"Unsupported file format: Supported formats are YAML and JSON.")
16
+ E=cls(**D);return E
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: scilens
3
- Version: 0.3.6
3
+ Version: 0.3.8
4
4
  Summary: A CesGensLaB framework for data collecting and deep analysis
5
5
  Home-page: https://scilens.dev
6
6
  License: Proprietary
@@ -5,12 +5,12 @@ scilens/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
5
  scilens/cli/cglb.py,sha256=R0377H5H193DJ_h4hj32m6qvrZrMnSFOxSGVl2FItiU,443
6
6
  scilens/cli/config.py,sha256=XVY6q5E9fb6MZzPct4-X7m6e45erpt5MCIuzKTBKPAI,965
7
7
  scilens/cli/info.py,sha256=xE7q9epjrCQRL6Agi3nhKsG6Mr3B8HSUFMti-epMoXA,1929
8
- scilens/cli/main.py,sha256=LljcS0s2E35y4YZpV01GhMhMK9HyRRHYmxc_q_kSurI,6004
8
+ scilens/cli/main.py,sha256=C8EWm6JfTBBH74pR3J-O2ZuPX78VcQ5MWC5iqNUFN6Y,6332
9
9
  scilens/components/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
10
  scilens/components/analyse_folder.py,sha256=yqc-dscKaHLZJCYeXGak2v0c3F2aeX0E11AFPfya6r0,208
11
11
  scilens/components/compare_2_files.py,sha256=jbZNLbRj3x8TxUADM5QC2u_TGl4I7u5OdaEMh-gMBUk,1713
12
12
  scilens/components/compare_errors.py,sha256=vGb4DWP89HMIeBm0dZU2nt-ksppAs_37xtCHaPd0w5Y,1640
13
- scilens/components/compare_floats.py,sha256=p1lnnwkGJXIsb6Y5psQc_5FcOuB2vP_cIQHXhZjWPXc,5617
13
+ scilens/components/compare_floats.py,sha256=yYJZ_QpAZUhP1uwNtGshXQLIzKtki9ifCN3hd9AFj2U,5916
14
14
  scilens/components/compare_folders.py,sha256=LZ1AuYxLVHMNbtXWXQrdms4vZgOQthvDy-8NFD_EFjc,2617
15
15
  scilens/components/compare_models.py,sha256=SCPd747h_nd4ewZsqLB6CFr27v6q99NELJb-gpkdj0o,918
16
16
  scilens/components/executor.py,sha256=j5xejkCaaPyl3V38Q4HxxXcAx4Tnj8CILAjSJ1G7OIE,3417
@@ -22,7 +22,7 @@ scilens/config/load.py,sha256=4U51o4cJfqhSuRIHKUDIsDQA0C4wv6SzTkVmInGDJdI,1647
22
22
  scilens/config/models/__init__.py,sha256=eLCW1OLVINewGFy5GXSrOk8Rab_QsgKAuoErBjphHRs,673
23
23
  scilens/config/models/app.py,sha256=JltWRjjqXYkH6rg3OHYhMfkBqHFhZEZdthqES3LxvzY,1453
24
24
  scilens/config/models/compare.py,sha256=esRqW3PNVOqkA_mt4_qbS7dVCLulUrZTBUhANQOHoqE,1847
25
- scilens/config/models/compare_float_thresholds.py,sha256=J5XBK1dAnmU-i2uA2bsaHnTM_m07_i17wsO8UiCw46o,1844
25
+ scilens/config/models/compare_float_thresholds.py,sha256=mHu48-70i3o_qUw6x-1A7XeRwFUNAO6WP6qNPGwAew0,2097
26
26
  scilens/config/models/execute.py,sha256=8issd_hg49SdVkDq2TLDB1vBJY4M1t279XERNUd3VVs,2142
27
27
  scilens/config/models/execute_and_compare.py,sha256=TWL6yXGvQSaaV6nhHqWLvtr3v396APIoDNt0U1TbMro,582
28
28
  scilens/config/models/file_reader.py,sha256=c18vKhVcBX4ufpbnCBJyVyAsQtlxpwx0lGVuf1i8EGA,1176
@@ -32,8 +32,8 @@ scilens/config/models/reader_format_netcdf.py,sha256=k-AMdm239T6I42R8jzyRlPKKJ8z
32
32
  scilens/config/models/reader_format_txt.py,sha256=eHg90gwEI_VpqwqEjMRhwlS8dHcl5G4ow-37HjQq_zY,1168
33
33
  scilens/config/models/reader_format_txt_fixed_cols.py,sha256=xHD1_JOoRZow8lSNaDSYFeNckojctkT4C61mbBcjeKg,1079
34
34
  scilens/config/models/readers.py,sha256=Pq5kOGW3b6g1x5cp_BbwUF7LUB_P3m9bHDYLSTVXNBY,1769
35
- scilens/config/models/report.py,sha256=nTmP2nIwL2Ku5IH9QMwYLPKmfsK2ttu9UK0GnzPUHeM,870
36
- scilens/config/models/report_html.py,sha256=WiUPD38NCmBYHQdYyMb1-713kVNq7dm5pe8chlhuoyM,1468
35
+ scilens/config/models/report.py,sha256=6mzqZMJnS_z5Rs01ISo8L8HRcWvmiQrK0dYqu8a58vM,993
36
+ scilens/config/models/report_html.py,sha256=W4ATubdtxnW-vSOPXBZ6PNKMPcexpB9jeFi7c6b5VOc,2327
37
37
  scilens/config/models/report_output.py,sha256=XoqUe-t-y8GRbUR3_bDwwaWf6hif-rZ-5pKDGdCMugw,875
38
38
  scilens/helpers/assets.py,sha256=XphDA3-yE1PPKw4XFZhDrlLQjMZfGMlpOBXa8uy_xX0,1552
39
39
  scilens/helpers/search_and_index.py,sha256=kXZ7124ra_SGAdKUZ7msy55UOWQ9dCSuPuNoU-NdUyM,1522
@@ -60,24 +60,25 @@ 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=ajNDTfEu06fs2h1SF4nTP1MvZmYwMcLieeSngyuH-qE,1905
63
+ scilens/report/html_report.py,sha256=ml_paRkzI81irpeWNtEkBOHkK0W7veNU6RbVM6RLM6E,1940
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=0mrMM62TSBdPOpPNCcam0bZsZtM0GjoMQ-jrSqI8HCw,2173
66
+ scilens/report/templates/body_01_title.html,sha256=LJOWO6ImNPW9cg3tCDlgdllVTwnFGWcb2qvA3yv6wNk,1758
67
+ scilens/report/templates/body_02_tabs.html,sha256=oOFslWcfNsWpCX12GECZDzdR5uAHE54HPP6IYUf7y0U,412
67
68
  scilens/report/templates/body_99_footer.html,sha256=8cWebeWfZwZ-9bYAMZkZj8rbCWq3BLIMjKQThWQxoQM,362
68
- scilens/report/templates/compare_11_summary.html,sha256=4rxBlOxTcn59ztYtqDbi6SRQXlaz30HkVl7dJpzCmZE,3776
69
- scilens/report/templates/compare_12_sections.html,sha256=Sm5NtOkGhkm0Eo-H2R-97mNDjuuw84NLdcZntevzEVQ,6304
69
+ scilens/report/templates/compare_11_summary.html,sha256=qVvFydtAvAYyVOOTqjTN3LUj5Lh_Cl680EYL5SCZkd4,4086
70
+ scilens/report/templates/compare_12_sections.html,sha256=8hCQRvdD_xhv8PGqT3WcfKxakWdCfGUFbv9HPBrNCro,6431
70
71
  scilens/report/templates/compare_13_section_numbers copy.html,sha256=0PWK_I2kNX3LjPLkkY4eSYIeB7YFkA28nk-PPLDhnaY,1753
71
72
  scilens/report/templates/compare_13_section_numbers.html,sha256=9etEMSqwrDyJIn_nMbKEVaDgnFL_hBxSjPR-hU2wgDI,851
72
73
  scilens/report/templates/compare_13_section_numbers_table.html,sha256=sJy6ZYtjl80vM1b3oqZSXawZWp7KNIwLI_wCnvBwYPE,3270
73
- scilens/report/templates/index.html,sha256=2xR6htGfpYwCxRDzXzQJflrnl9lp7r0AkJRnm16liM8,4954
74
+ scilens/report/templates/index.html,sha256=NwIjcv_h_xu2tY7y2DNZup5UwohmSuejz2AF1EmgPxI,5370
74
75
  scilens/report/templates/js_chartlibs_echarts.js,sha256=6YicVhTNIBmmBpV31XCVN5oBeiD0t29JIosJZRUv01M,907
75
- scilens/report/templates/js_chartlibs_plotly.js,sha256=uVAOKUB5XE33-r04phR-LlRkFoaHEIXyQ3jXT5r97Rc,1521
76
+ scilens/report/templates/js_chartlibs_plotly.js,sha256=mDf4O1pHqK69IqwGe6Irw8xLV-cnL7WZZ5ZEfUI2DZ4,2082
76
77
  scilens/report/templates/js_com_page.js,sha256=ZxYHR-KGQRH726rPOXrEgyzBKM9NtGH3_APvcawKxQw,6862
77
- scilens/report/templates/js_curvemgr.js,sha256=Kmn2o9mKctKEXkIYOzWxqh2IVRtrpKcZvdBl8QmzdJ0,10798
78
+ scilens/report/templates/js_curvemgr.js,sha256=9t5ZDogVJTiI0oullrZ2IT7_qXG73CH_m2gNUpuY4oY,12199
78
79
  scilens/report/templates/js_dom.js,sha256=XnxgdB0x-Xtt0eQFrwjcFO1cb_KPsTImpJBB6m_y8FI,1229
79
80
  scilens/report/templates/js_palette.js,sha256=HeewAmkR67QiqXSanJS3cCgp6IPKomlULUTKt55F6es,218
80
- scilens/report/templates/style.css,sha256=thZ_LZonmY9qH9oBie1BcK2H2FPPqik11YFr1hyo6ng,4071
81
+ scilens/report/templates/style.css,sha256=SOKxdCqoj0yBt2zt3g1RkYx4ZV0_9PhGtO-TDWjmSHE,4217
81
82
  scilens/report/templates/uti_matrix.js,sha256=L2NqR9fu1075JGStWy6yS7EX4pHGAcBrhfR_cAL4VYw,2675
82
83
  scilens/report/templates/uti_spectrograms.js,sha256=EoZtBUYbup0KOvmcZRpnUGNrIZVbveqQK0aoIqkq94E,3066
83
84
  scilens/report/templates/utils_compare_report_anim.js,sha256=a7FHRco17BmgOAHb9kiDsFcSoxbmTGqjBbXBprf3hnU,2923
@@ -88,18 +89,19 @@ scilens/run/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
88
89
  scilens/run/models/task_results.py,sha256=hdr_QEwMnjdfdawpfuBRMGqCHWQvsF61G39CVEMXKl8,284
89
90
  scilens/run/models/task_runtime.py,sha256=VNbMPS1ocl6WUDG5ipUxp3RSAST2OZ5DqGcfJWFEed8,114
90
91
  scilens/run/run_task.py,sha256=suCnACK2RmcwGdmOUAxnb0UD3LC_VT8RH9S525rsr14,2828
91
- scilens/run/standalone_task_runner.py,sha256=XhbwoUdjdfM2m2CfWHym05HyvPB5xK2A9M-o5zMu8dA,498
92
+ scilens/run/standalone_task_runner.py,sha256=D3SUgVzoYtFvfDRacX286gXswuyN4z37et_qxfly4Rs,515
92
93
  scilens/run/task_context.py,sha256=NnujvpwnxY-YEzivYPYWaX-YChcZlEXt9y0_DXLqZkk,659
93
94
  scilens/run/tasks_collector.py,sha256=m_FQaJdQRi4fCLW17ryJxU0TvGNJN54JTw2Mg6XPojY,3174
94
95
  scilens/utils/dict.py,sha256=1MVQc8vZCs8_gQJMBkBSXO828wMe2eIWFiraLVmcjqk,214
95
- scilens/utils/file.py,sha256=3JkynZORUWah-dwaVpUDzyOSlOQkub1d9R3QqCkNYXE,1597
96
+ scilens/utils/file.py,sha256=ljtTHCvT7vfDSbHA-5aKDl9885SVce3TBXWRIA-aRx0,1664
97
+ scilens/utils/load_model_from_file.py,sha256=k5I-B6s5nVZu90MgzKSM0_IRj9oNL-4oJJRTwEvOyw8,619
96
98
  scilens/utils/php.py,sha256=VBJxpzwwRPNcr3379f6ViwhpTzjGc4BKlSXHv4lnor8,444
97
99
  scilens/utils/system.py,sha256=drXp_Vdv2dP9wFQoEQZIhxyCJhFliBLFPylGwv89FF4,182
98
100
  scilens/utils/template.py,sha256=9dlXX3nmfzDRUwzPJOkoxk15UXivZ2SW-McdCwokFa4,443
99
101
  scilens/utils/time_tracker.py,sha256=DdVBoMpVLXrX0qZZXyLm4g38EwDVLlRcBqcpNex1mYY,545
100
102
  scilens/utils/vectors.py,sha256=4N2BZSC5n3HgZqPujDGF5NdjVmSL1rOHb_qw4OoABQY,103
101
103
  scilens/utils/web.py,sha256=MAFWpIFOKz7QhqDoFh-Qwstvc76KpcxstSgHFT8FOL4,901
102
- scilens-0.3.6.dist-info/METADATA,sha256=m6niWTXoKAI_Ean-zkDhQmYvGQvSEM_mI3K7Le22tBM,1367
103
- scilens-0.3.6.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
104
- scilens-0.3.6.dist-info/entry_points.txt,sha256=DaKGgxUEUv34GJAoXtta6ecL37ercejep9sCSSRQK2s,48
105
- scilens-0.3.6.dist-info/RECORD,,
104
+ scilens-0.3.8.dist-info/METADATA,sha256=RTctyV618MmgiLWuaf1NfysYdqN1CC6SZKpCEFTpTzY,1367
105
+ scilens-0.3.8.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
106
+ scilens-0.3.8.dist-info/entry_points.txt,sha256=DaKGgxUEUv34GJAoXtta6ecL37ercejep9sCSSRQK2s,48
107
+ scilens-0.3.8.dist-info/RECORD,,