wolfhece 2.1.8__py3-none-any.whl → 2.1.10__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
wolfhece/PyDraw.py CHANGED
@@ -2055,7 +2055,8 @@ class WolfMapViewer(wx.Frame):
2055
2055
  """
2056
2056
  Récupère un graphique matplotlib sur base de la fenêtre OpenGL et de la palette de la matrice active
2057
2057
  """
2058
- self.zoom_on(center=center, width=width, height= height, canvas_height=self.canvasheight)
2058
+ self.zoom_on(center=center, width=width, height= height, canvas_height=self.canvasheight, forceupdate=True)
2059
+
2059
2060
 
2060
2061
  fig,axes = plt.subplots(1,2, gridspec_kw={'width_ratios': [20, 1]})
2061
2062
  self.display_canvasogl(fig=fig,ax=axes[0])
@@ -2188,7 +2189,7 @@ class WolfMapViewer(wx.Frame):
2188
2189
  ax=ax[0],
2189
2190
  title=_('Current time {:0>8} s'.format(el_time)))
2190
2191
 
2191
- def get_canvas_as_impage(self) -> Image.Image:
2192
+ def get_canvas_as_image(self) -> Image.Image:
2192
2193
  """
2193
2194
  Récupère la fenêtre OpenGL sous forme d'image
2194
2195
  """
@@ -3326,7 +3327,7 @@ class WolfMapViewer(wx.Frame):
3326
3327
  for cur in self.linkedList:
3327
3328
  if cur is not self:
3328
3329
  cur.update()
3329
-
3330
+
3330
3331
  def zoom_on_active_profile(self, size:float=500., forceupdate:bool=True):
3331
3332
  """ Zoom on active profile """
3332
3333
 
@@ -8515,7 +8516,8 @@ class WolfMapViewer(wx.Frame):
8515
8516
  curarray.updatepalette(onzoom=[self.xmin, self.xmax, self.ymin, self.ymax])
8516
8517
  curarray.delete_lists()
8517
8518
 
8518
- self.Refresh()
8519
+ self.Paint()
8520
+ # self.Refresh()
8519
8521
 
8520
8522
  def _plotting(self, drawing_type: draw_type, checked_state: bool = True):
8521
8523
  """ Drawing objets on canvas"""
@@ -8875,7 +8877,7 @@ class WolfMapViewer(wx.Frame):
8875
8877
  curobj.uncheck_plot()
8876
8878
 
8877
8879
  curitem = self.gettreeitem(curobj)
8878
- self.treelist.CheckItem(curitem, False)
8880
+ self.treelist.UncheckItem(curitem)
8879
8881
 
8880
8882
  def get_current_zoom(self):
8881
8883
  """
wolfhece/PyParams.py CHANGED
@@ -1029,6 +1029,9 @@ class Wolf_Param(wx.Frame):
1029
1029
  page.Append(pg.FontProperty(label = param_name, name = locname, value = locvalue))
1030
1030
 
1031
1031
  else:
1032
+ if locvalue is None:
1033
+ locvalue = ""
1034
+
1032
1035
  page.Append(pg.StringProperty(label = param_name, name = locname, value = locvalue))
1033
1036
 
1034
1037
  def _add_elem_to_page(self, page:pg.PropertyGridPage, group:str, param:dict, param_def:dict = None, prefix:str=''):
wolfhece/apps/version.py CHANGED
@@ -5,7 +5,7 @@ class WolfVersion():
5
5
 
6
6
  self.major = 2
7
7
  self.minor = 1
8
- self.patch = 8
8
+ self.patch = 10
9
9
 
10
10
  def __str__(self):
11
11
 
wolfhece/multiprojects.py CHANGED
@@ -26,8 +26,21 @@ class Project(Wolf_Param):
26
26
  Il s'agit d'une surcharge d'un objet Wolf_Param qui est organisé en groupes de paramètres
27
27
  Chaque paramètre peut être défini par une clé, une valeur et un commentaire (+ éventuellement une chaîne JSON)
28
28
  """
29
- def __init__(self, wdir='', parent=None, title="Default Title", w=500, h=800, ontop=False, to_read=True, filename='', withbuttons=True, DestroyAtClosing=True, toShow=True):
30
- super().__init__(parent, title, w, h, ontop, to_read, filename, withbuttons, DestroyAtClosing, toShow)
29
+ def __init__(self,
30
+ wdir='',
31
+ parent=None,
32
+ title="Default Title",
33
+ w=500, h=800,
34
+ ontop=False,
35
+ to_read=True,
36
+ filename='',
37
+ withbuttons=True,
38
+ DestroyAtClosing=True,
39
+ toShow=True,
40
+ init_GUI:bool = False,
41
+ force_even_if_same_default:bool = False):
42
+
43
+ super().__init__(parent, title, w, h, ontop, to_read, filename, withbuttons, DestroyAtClosing, toShow, init_GUI, force_even_if_same_default)
31
44
  self.wdir = wdir
32
45
 
33
46
  class Wolf2D_Project(Project):
@@ -73,6 +86,7 @@ class Wolf2D_Project(Project):
73
86
  super().__init__(wdir, parent, title, w, h, ontop, to_read, filename, withbuttons, DestroyAtClosing, toShow)
74
87
 
75
88
  self.mysims:dict[str,Union[Wolfresults_2D, wolfres2DGPU]]={}
89
+
76
90
  self.mycontours={}
77
91
  self.mycolormaps={}
78
92
  self.epsilon=5e-4
File without changes
@@ -0,0 +1,516 @@
1
+
2
+ from docx import Document
3
+ from docx.shared import Pt
4
+ from docx.oxml.ns import qn
5
+ from docx.shared import Inches
6
+ from docx.shared import RGBColor
7
+ from pathlib import Path
8
+ from typing import Union, List, Tuple,Literal
9
+ from docx.enum.text import WD_PARAGRAPH_ALIGNMENT
10
+ from PIL import Image
11
+ import pandas as pd
12
+ from tempfile import NamedTemporaryFile, TemporaryDirectory
13
+ import logging
14
+ import matplotlib.pyplot as plt
15
+ from matplotlib.figure import Figure
16
+ from datetime import datetime
17
+ import os
18
+ import socket
19
+ import hashlib
20
+ import re
21
+
22
+ from gettext import gettext as _
23
+
24
+ class RapidReport:
25
+ """
26
+ Class for creating a report 'quickly'.
27
+
28
+ It can be used in Jupyter notebooks or in scripts to create a simple report in Word format.
29
+
30
+ Word document is created with the following structure:
31
+
32
+ - Main page with title, author, date and hash of the document
33
+ - Summary (automatically generated)
34
+ - Title
35
+ - Paragraph
36
+ - Figure (numbered automatically with caption)
37
+ - Bullet list
38
+ - Table
39
+
40
+ It is not a full-fledged reporting tool with advanced functionnalities but a simple way to create a report quickly 'on-the-fly'.
41
+
42
+
43
+ Example:
44
+
45
+ ```
46
+ rapport = RapidReport('Rapport de Projet', 'Alice')
47
+
48
+ rapport.add_title('Titre Principal', level=0)
49
+ rapport.add_paragraph('Ceci est un **paragraphe** introductif avec des mots en *italique* et en **gras**.')
50
+
51
+ rapport += "Tentative d'ajout de figure vie un lien incorrect.\nPassage à la ligne"
52
+ rapport.add_figure('/path/to/image.png', 'Légende de la figure.')
53
+
54
+ rapport.add_bullet_list(['Premier élément', 'Deuxième élément', 'Troisième élément'])
55
+
56
+ rapport.add_table_from_listoflists([['Nom', 'Âge'], ['Alice', '25'], ['Bob', '30']])
57
+
58
+ rapport.save('rapport.docx')
59
+ ```
60
+
61
+ """
62
+
63
+ def __init__(self, main_title:str, author:str):
64
+
65
+ self._main_title = main_title
66
+ self._author = author
67
+ self._date = None
68
+
69
+ self._content = []
70
+ self._document = None
71
+
72
+ self._filename = None
73
+
74
+ self._idx_figure = 0
75
+
76
+ self._styles={}
77
+
78
+ self._has_first_page = False
79
+
80
+ def _define_default_styles(self):
81
+
82
+ # Définir le style de titre
83
+ self._title_style = self._document.styles.add_style('TitleStyle', 1)
84
+ self._title_style.font.name = 'Arial'
85
+ self._title_style.font.size = Pt(20)
86
+ self._title_style.font.bold = True
87
+ self._title_style._element.rPr.rFonts.set(qn('w:eastAsia'), 'Arial')
88
+
89
+ # Définir le style de légende
90
+ self._caption_style = self._document.styles.add_style('CaptionStyle', 1)
91
+ self._caption_style.font.name = 'Arial'
92
+ self._caption_style.font.size = Pt(9)
93
+ self._caption_style.font.italic = True
94
+ self._caption_style._element.rPr.rFonts.set(qn('w:eastAsia'), 'Arial')
95
+ self._caption_style.paragraph_format.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER
96
+
97
+ # Définir le style de corps de texte
98
+ self._body_text_style = self._document.styles.add_style('BodyTextStyle', 1)
99
+ self._body_text_style.font.name = 'Arial'
100
+ self._body_text_style.font.size = Pt(11)
101
+ self._body_text_style._element.rPr.rFonts.set(qn('w:eastAsia'), 'Arial')
102
+ self._body_text_style.paragraph_format.alignment = WD_PARAGRAPH_ALIGNMENT.JUSTIFY
103
+
104
+ # Définir le style de liste à puce
105
+ self._bullet_list_style = self._document.styles.add_style('BulletListStyle', 1)
106
+ self._bullet_list_style.font.name = 'Arial'
107
+ self._bullet_list_style.font.size = Pt(9)
108
+ self._bullet_list_style._element.rPr.rFonts.set(qn('w:eastAsia'), 'Arial')
109
+ self._bullet_list_style.paragraph_format.alignment = WD_PARAGRAPH_ALIGNMENT.LEFT
110
+ self._bullet_list_style.paragraph_format.left_indent = Inches(0.25)
111
+
112
+ self._table_grid_style = self._document.styles.add_style('TableGrid', 3)
113
+ self._table_grid_style.font.name = 'Arial'
114
+ self._table_grid_style.font.size = Pt(9)
115
+ self._table_grid_style._element.rPr.rFonts.set(qn('w:eastAsia'), 'Arial')
116
+ self._table_grid_style.paragraph_format.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER
117
+
118
+ self._figure_style = self._document.styles.add_style('FigureStyle', 1)
119
+ self._figure_style.font.name = 'Arial'
120
+ self._figure_style.font.size = Pt(9)
121
+ self._figure_style._element.rPr.rFonts.set(qn('w:eastAsia'), 'Arial')
122
+ self._figure_style.paragraph_format.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER
123
+
124
+ self._styles['TitleStyle'] = self._title_style
125
+ self._styles['CaptionStyle'] = self._caption_style
126
+ self._styles['BodyTextStyle'] = self._body_text_style
127
+ self._styles['BulletListStyle'] = self._bullet_list_style
128
+ self._styles['TableGrid'] = self._table_grid_style
129
+ self._styles['FigureStyle'] = self._figure_style
130
+
131
+ def set_font(self, fontname:str='Arial', fontsize:int=12):
132
+ """ Définir la police et la taille de la police pour les styles de texte. """
133
+
134
+ for style in self._styles.values():
135
+ style.font.name = fontname
136
+ style.font.size = Pt(fontsize)
137
+
138
+ def fill_first_page(self, main_title:str, author:str):
139
+ """
140
+ Remplir la première page du document.
141
+
142
+ Ajouter le titre, l'auteur et la date.
143
+
144
+ """
145
+ if self._has_first_page:
146
+ return
147
+
148
+ # Récupérer le nom de l'utilisateur
149
+ user_name = os.getlogin()
150
+
151
+ # Récupérer le nom de l'ordinateur
152
+ computer_name = socket.gethostname()
153
+
154
+ logo_path = Path(__file__).parent / 'wolf_report.png'
155
+
156
+ self._main_title = main_title
157
+ self._author = author
158
+ self._date = datetime.now().strftime('%d/%m/%Y')
159
+
160
+ self._insert_title(self._main_title, level=0, index=0)
161
+ self._insert_figure(logo_path,caption=None, width=2.0, index=1)
162
+
163
+ self._insert_paragraph('Ce document a été généré automatiquement par le paquet Python "wolfhece".', index =2)
164
+ self._insert_paragraph(' ', index=3)
165
+ self._insert_paragraph(f'Auteur : {self._author}', index=4)
166
+ self._insert_paragraph(f'Date : {self._date}', index=5)
167
+ self._insert_paragraph(' ', index=6)
168
+ self._insert_paragraph(f'Utilisateur : {user_name}', index=7)
169
+ self._insert_paragraph(f'Ordinateur : {computer_name}', index=8)
170
+ self._insert_paragraph(' ', index=9)
171
+
172
+ chain_hash = hashlib.md5(self._main_title.encode() +
173
+ self._author.encode() +
174
+ user_name.encode() +
175
+ computer_name.encode()+
176
+ self._date.encode()).hexdigest()
177
+
178
+ self._insert_paragraph('Hash du document : ' + chain_hash, index=10)
179
+
180
+ self._insert_new_page(index=11)
181
+
182
+ self._insert_paragraph('summary', index=12)
183
+
184
+ self._has_first_page = True
185
+
186
+ def _insert_title(self, title:str, level:int=1, index:int = 0):
187
+ """ Insère un titre dans le document. """
188
+
189
+ self._content.insert(index, ('title', title, level))
190
+
191
+ def _insert_paragraph(self, paragraph_text:str, style:str='BodyTextStyle', index:int = 0):
192
+ """ Insère un paragraphe dans le document. """
193
+
194
+ self._content.insert(index, ('paragraph', paragraph_text, style))
195
+
196
+ def _insert_figure(self, image_path:Union[str, Path, Image.Image, Figure], caption:str, width:float=7.0, index:int = 0):
197
+ """ Insère une figure dans le document. """
198
+
199
+ self._content.insert(index, ('figure', image_path, caption, width, self._idx_figure))
200
+
201
+ def add_title(self, title:str, level:int=1):
202
+ """ Ajoute un titre au document. """
203
+
204
+ self._content.append(('title', title, level))
205
+
206
+ def _list_titles(self, level:int=None):
207
+ """ Renvoie la liste des titres du document. """
208
+
209
+ if level is None:
210
+ return [item[1] for item in self._content if item[0] == 'title']
211
+ else:
212
+ return [item[1] for item in self._content if item[0] == 'title' and item[2] == level]
213
+
214
+ def _list_captions(self):
215
+ """ Renvoie la liste des légendes de figures du document. """
216
+
217
+ return [item[2] for item in self._content if item[0] == 'figure' if item[2]]
218
+
219
+ def _list_figures(self):
220
+ """ Renvoie la liste des figures du document. """
221
+
222
+ return [item[1] for item in self._content if item[0] == 'figure' if item[1] and item[2]]
223
+
224
+ def _list_index(self):
225
+ """ Renvoie la liste des index de figures du document. """
226
+
227
+ return [item[3] for item in self._content if item[0] == 'figure' if item[3]]
228
+
229
+ def fig_exists(self, fig_name:str):
230
+ """ Vérifie si une figure existe dans le document. """
231
+
232
+ return fig_name in self._list_figures()
233
+
234
+ def get_fig_index(self, fig_name_caption:str):
235
+ """ Renvoie la légende d'une figure. """
236
+
237
+ list_figures = self._list_figures()
238
+ list_captions = self._list_captions()
239
+
240
+ if fig_name_caption in list_figures:
241
+ idx = self._list_figures().index(fig_name_caption)+1
242
+ elif fig_name_caption in list_captions:
243
+ idx = self._list_captions().index(fig_name_caption)+1
244
+ else:
245
+ idx = None
246
+
247
+ return idx
248
+
249
+ def _add_summary(self):
250
+ """ Ajoute un sommaire au document. """
251
+
252
+ titles = self._list_titles()
253
+
254
+ self._document.add_heading(_('Summary'), level=1).style = 'TitleStyle'
255
+
256
+ for cur_title in titles:
257
+ p = self._document.add_paragraph(cur_title, style='BodyTextStyle')
258
+ run = p.add_run()
259
+ run.add_tab()
260
+ run.bold = True
261
+ p.style = 'BodyTextStyle'
262
+
263
+ self._document.add_heading(_('List of figures'), level=1).style = 'TitleStyle'
264
+ figures = self._list_captions()
265
+ for i, cur_figure in enumerate(figures):
266
+ p = self._document.add_paragraph(f'Fig. {i+1} : {cur_figure}', style='BodyTextStyle')
267
+ run = p.add_run()
268
+ run.add_tab()
269
+ run.bold = True
270
+ p.style = 'BodyTextStyle'
271
+
272
+ self._document.add_page_break()
273
+
274
+ def add_paragraph(self, paragraph_text:str, style:str='BodyTextStyle'):
275
+ """ Ajoute un paragraphe au document. """
276
+
277
+ self._content.append(('paragraph', paragraph_text, style))
278
+
279
+ def add(self, paragraph_text:str, style:str='BodyTextStyle'):
280
+ """ Ajoute un paragraphe au document. """
281
+
282
+ self.add_paragraph(paragraph_text, style=style)
283
+
284
+ def __add__(self, paragraph_text:str):
285
+ """ Surcharge de l'opérateur + pour ajouter un paragraphe. """
286
+
287
+ self.add_paragraph(paragraph_text)
288
+
289
+ return self
290
+
291
+ def add_figure(self, image_path:Union[str, Path, Image.Image, Figure], caption:str, width:float=7.0):
292
+ """ Ajoute une figure au document avec une légende. """
293
+
294
+ if caption:
295
+ self._idx_figure += 1
296
+
297
+ self._content.append(('figure', image_path, caption, width, self._idx_figure))
298
+
299
+ def add_bullet_list(self, bullet_list: List[str], style:str='BulletListStyle'):
300
+ """ Ajoute une liste à puce au document. """
301
+
302
+ for item in bullet_list:
303
+ self.add_paragraph('- ' + item, style=style)
304
+
305
+ def add_new_page(self):
306
+ """ Ajoute une nouvelle page au document. """
307
+
308
+ self._content.append(('newpage', '', None))
309
+
310
+ def _insert_new_page(self, index:int = 0):
311
+ """ Insère une nouvelle page au document. """
312
+
313
+ self._content.insert(index, ('newpage', '', None))
314
+
315
+ def add_table_from_listoflists(self, data:List[List[str]], style:str='TableGrid'):
316
+ """
317
+ Ajoute un tableau au document.
318
+
319
+ :param data: Liste de listes contenant les données du tableau. Chaque liste est une ligne du tableau.
320
+
321
+ """
322
+
323
+ self._content.append(('table', data, style))
324
+
325
+ def add_table_from_dict(self, data:dict, style:str='TableGrid'):
326
+ """
327
+ Ajoute un tableau au document.
328
+
329
+ :param data: Dictionnaire contenant les données du tableau. Les clés sont les en-têtes de colonnes.
330
+
331
+ """
332
+
333
+ table_data = [list(data.keys())]
334
+ table_data += [list(data.values())]
335
+ self.add_table_from_listoflists(table_data, style=style)
336
+
337
+ def add_table_as_picture(self, data:Union[List[List[str]], dict, pd.DataFrame, Figure], caption:str=None):
338
+ """ Ajoute un tableau au document sous forme d'image. """
339
+
340
+ def fig2img(fig):
341
+ """Convert a Matplotlib figure to a PIL Image and return it"""
342
+ import io
343
+ buf = io.BytesIO()
344
+
345
+ fig.savefig(buf, bbox_inches='tight')
346
+ buf.seek(0)
347
+ img = Image.open(buf)
348
+ return img
349
+
350
+ if isinstance(data, Figure):
351
+ tmp_image = fig2img(data)
352
+ self.add_figure(tmp_image, caption)
353
+ return
354
+
355
+ if isinstance(data, dict):
356
+ data = pd.DataFrame(data)
357
+ elif isinstance(data, list):
358
+ data = pd.DataFrame(data)
359
+
360
+ fig, ax = plt.subplots()
361
+
362
+ ax.axis('off')
363
+ ax.table(cellText=data.values,
364
+ colLabels=data.columns,
365
+ loc='center',
366
+ cellLoc='center',
367
+ colColours=['#f3f3f3']*len(data.columns))
368
+
369
+ fig.tight_layout()
370
+
371
+ tmp_image = fig2img(fig)
372
+
373
+ self.add_figure(tmp_image, caption, width=4.0)
374
+
375
+ def _apply_text_styles(self, paragraph, text):
376
+ """ Search for bold and italic styles in the text and apply them."""
377
+
378
+ text = text.replace('\n\n', 'DOUBLE_NEWLINE')
379
+ text = text.replace('\n', ' ')
380
+ text = text.replace('DOUBLE_NEWLINE', '\n')
381
+
382
+ def split_bold(text):
383
+ return text.split('**')
384
+
385
+ def split_italic(text):
386
+ return text.split('*')
387
+
388
+ splitted_bold = split_bold(text)
389
+
390
+ bold = False
391
+ for cur_text in splitted_bold:
392
+ if cur_text != '':
393
+ italic = False
394
+ spliited_italic = split_italic(cur_text)
395
+ for cur_text2 in spliited_italic:
396
+ if cur_text2 != '':
397
+ run = paragraph.add_run(cur_text2)
398
+ run.bold = bold
399
+ run .italic = italic
400
+
401
+ italic = not italic
402
+ bold = not bold
403
+
404
+ def parse_content(self):
405
+ """ Parse le contenu du document et l'ajoute au document Word. """
406
+
407
+ # tmp_dir = TemporaryDirectory()
408
+
409
+ for item in self._content:
410
+
411
+ if item[0] == 'title':
412
+ self._document.add_heading(item[1], level=item[2]).style = 'TitleStyle'
413
+
414
+ elif item[0] == 'paragraph':
415
+
416
+ if item[1] == 'summary':
417
+ self._add_summary()
418
+ continue
419
+ else:
420
+ p = self._document.add_paragraph()
421
+ self._apply_text_styles(p, item[1])
422
+ p.style = item[2] if item[2] else 'BodyTextStyle'
423
+
424
+ elif item[0] == 'figure':
425
+
426
+ if isinstance(item[1], Image.Image):
427
+
428
+ tmp_name = NamedTemporaryFile(suffix='.png').name
429
+ item[1].save(tmp_name)
430
+
431
+ elif isinstance(item[1], str):
432
+ tmp_name = item[1]
433
+
434
+ elif isinstance(item[1], Path):
435
+ tmp_name = str(item[1])
436
+
437
+ elif isinstance(item[1], Figure):
438
+ item[1].tight_layout()
439
+ tmp_name = NamedTemporaryFile(suffix='.png').name
440
+ item[1].savefig(tmp_name)
441
+
442
+ if Path(tmp_name).exists():
443
+ self._document.add_picture(tmp_name, width=Inches(item[3]) if item[3] else Inches(7.0))
444
+ self._document.paragraphs[-1].style = 'FigureStyle'
445
+ else:
446
+ logging.error(f"File {tmp_name} not found.")
447
+ p = self._document.add_paragraph()
448
+ run = p.add_run(f'Error: Image not found. {tmp_name}')
449
+ run.font.color.rgb = RGBColor(255, 0, 0)
450
+ p.style = 'BodyTextStyle'
451
+
452
+ if item[2]:
453
+ caption = self._document.add_paragraph(f'Fig. {item[4]} :' + item[2])
454
+ caption.style = 'CaptionStyle'
455
+
456
+ elif item[0] == 'table':
457
+
458
+ data = item[1]
459
+ style = item[2]
460
+ table = self._document.add_table(rows=len(data), cols=len(data[0]))
461
+ table.style = style
462
+
463
+ for i, row in enumerate(data):
464
+ for j, cell in enumerate(row):
465
+ table.cell(i, j).text = cell
466
+
467
+ elif item[0] == 'newpage':
468
+ self._document.add_page_break()
469
+
470
+ def save(self, file_path:Union[str,Path]=None):
471
+ """ Sauvegarde le document Word. """
472
+
473
+ if file_path is None:
474
+ file_path = self._filename
475
+
476
+ if file_path is None:
477
+ raise ValueError("Le chemin du fichier n'a pas été spécifié.")
478
+
479
+ self._document = Document()
480
+
481
+ self._define_default_styles()
482
+
483
+ self.fill_first_page(self._main_title, self._author)
484
+
485
+ self.parse_content()
486
+ try:
487
+ self._document.save(str(file_path))
488
+ except Exception as e:
489
+ logging.error(f"Error saving file: {e}")
490
+
491
+ if __name__ == '__main__':
492
+
493
+ # Exemple d'utilisation
494
+ rapport = RapidReport('Rapport de Projet', 'Alice')
495
+
496
+ rapport.add_title('Titre Principal', level=0)
497
+ rapport.add_paragraph('Ceci est un **paragraphe** introductif avec des mots en *italique* et en **gras**.')
498
+
499
+ rapport += "Tentative d'ajout de figure vie un lien incorrect.\nPassage à la ligne"
500
+ rapport.add_figure('/path/to/image.png', 'Légende de la figure.')
501
+ rapport+="""
502
+ Commentraire sur la figure multilignes
503
+ ligne 2
504
+ ligne3"""
505
+
506
+ rapport.add_bullet_list(['Premier élément', 'Deuxième élément', 'Troisième élément'])
507
+
508
+ rapport.add_table_from_listoflists([['Nom', 'Âge'], ['Alice', '25'], ['Bob', '30']])
509
+ rapport.add_table_from_dict({'Nom': ['Alice', 'Bob'], 'Âge': ['25', '30']})
510
+ rapport.add_table_as_picture({'Nom': ['Alice', 'Bob'], 'Âge': ['25', '30']}, caption='Tableau de données')
511
+
512
+ rapport.save('rapport.docx')
513
+
514
+ assert rapport.get_fig_index('/path/to/image.png') == 1
515
+ assert rapport.get_fig_index('Tableau de données') == 2
516
+
Binary file
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: wolfhece
3
- Version: 2.1.8
3
+ Version: 2.1.10
4
4
  Author-email: Pierre Archambeau <pierre.archambeau@uliege.be>
5
5
  License: AGPL-v3 License
6
6
  Project-URL: Homepage, https://uee.uliege.be/hece
@@ -6,12 +6,12 @@ wolfhece/ManageParams.py,sha256=Wgt5Zh7QBtyiwTAltPHunSLqt4XuVuRH76GTUrXabS4,219
6
6
  wolfhece/Model1D.py,sha256=-cMz-ePSYzrKVVDidiDOz6cojEZ3y6u9gIb7RPwT6Y8,476593
7
7
  wolfhece/PyConfig.py,sha256=oGSL1WsLM9uinlNP4zGBLK3uHPmBfduUi7R-VtWuRFA,8034
8
8
  wolfhece/PyCrosssections.py,sha256=f4dNYRUGZKePruaaBiTcn5vlrw8TFTj9XwTDrdiF_uU,112450
9
- wolfhece/PyDraw.py,sha256=WJDGhaD7N6udY5WUynS9f-26FQ6Uj0bJZFM2gxkzuWU,378354
9
+ wolfhece/PyDraw.py,sha256=eYv0X1NFCWlgOgiRaIjW0SPlR_uVLdZhFpztY1jX6Lo,378408
10
10
  wolfhece/PyGui.py,sha256=VKE785z9XLIWNbxqpyEceLK_wtmPJyq6A_M_qX_94Lg,104772
11
11
  wolfhece/PyGuiHydrology.py,sha256=wKhR-KthPRyzJ887NmsozmUpm2CIQIwO3IbYORCYjrE,7290
12
12
  wolfhece/PyHydrographs.py,sha256=GKK8U0byI45H9O_e4LAOOi7Aw0Tg7Q0Lx322stPg5IQ,3453
13
13
  wolfhece/PyPalette.py,sha256=_Nm2Lc4UxYlZgK8ifZDioG8a0at8oiteYC0x_4XugFc,24384
14
- wolfhece/PyParams.py,sha256=963fkDSEadlLLxe7WM4Nl6nLOeZsOWSFmfg7hIsWPU4,96785
14
+ wolfhece/PyParams.py,sha256=xUmtwna4rhTCqa3-fpq7bG5pxMpoa4PFRi5hEjxOxPw,96868
15
15
  wolfhece/PyPictures.py,sha256=-mJB0JL2YYiEK3D7_ssDkvYiMWK4ve9kXhozQXNeSx8,2216
16
16
  wolfhece/PyTranslate.py,sha256=4appkmNeHHZLFmUtaA_k5_5QL-5ymxnbVN4R2OblmtE,622
17
17
  wolfhece/PyVertex.py,sha256=dHTjyYYTn0F_NWerlAOBKHV79RUzEEtMJMldQtVc1Cs,40092
@@ -34,7 +34,7 @@ wolfhece/import_ascfiles.py,sha256=jg4urcLdSgFS1Knvh7AVGJqM44qc_uYDNrR568tMh-A,4
34
34
  wolfhece/ins.py,sha256=0aU1mo4tYbw64Gwzrqbh-NCTH1tukmk0mpPHjRPHZXU,12661
35
35
  wolfhece/irm_qdf.py,sha256=749SlAXiN1oXp5tfBJoPNJWxydQlY55K0qvIM5YexlM,15436
36
36
  wolfhece/ismember.py,sha256=fkLvaH9fhx-p0QrlEzqa6ySO-ios3ysjAgXVXzLgSpY,2482
37
- wolfhece/multiprojects.py,sha256=tHrAdOBoEEsuNS8hV7udbvduOZLj_NqF3ee5hSDBhN8,20903
37
+ wolfhece/multiprojects.py,sha256=K40kM09xNkQSjiwANTsA4CpaW7KEkawpBkpoiehk9yo,21251
38
38
  wolfhece/picc.py,sha256=KKPNk1BEe7QBzo2icIsdsxUopJ1LXYTomfdfeG2gCeA,7419
39
39
  wolfhece/pyGui1D.py,sha256=pzLWXQ_w3Y_yI846w1GklFO9h5lWZOqiUzg1BUPkuRI,121616
40
40
  wolfhece/pybridges.py,sha256=4PRSsWngDmQnlVuN2tJj0C_HT1h47ExH9QTUPs_Wxlg,57215
@@ -66,7 +66,7 @@ wolfhece/apps/check_install.py,sha256=jrKR-njqnpIh6ZJqvP6KbDUPVCfwTNQj4glQhcyzs9
66
66
  wolfhece/apps/curvedigitizer.py,sha256=avWERHuVxPnJBOD_ibczwW_XG4vAenqWS8W1zjhBox8,4898
67
67
  wolfhece/apps/isocurrent.py,sha256=4XnNWPa8mYUK7V4zdDRFrHFIXNG2AN2og3TqWKKcqjY,3811
68
68
  wolfhece/apps/splashscreen.py,sha256=LkEVMK0eCc84NeCWD3CGja7fuQ_k1PrZdyqD3GQk_8c,2118
69
- wolfhece/apps/version.py,sha256=PDHOsWyysK2-MjO9X84FVTmdBAJq_uSXODfI01muO7E,387
69
+ wolfhece/apps/version.py,sha256=p7F6qFk_CdXhKrAOXaQdIRVqeFmOEFL0SsGEAojsQgo,388
70
70
  wolfhece/apps/wolf.py,sha256=gqfm-ZaUJqNsfCzmdtemSeqLw-GVdSVix-evg5WArJI,293
71
71
  wolfhece/apps/wolf2D.py,sha256=gWD9ee2-1pw_nUxjgRaJMuSe4kUT-RWhOeoTt_Lh1mM,267
72
72
  wolfhece/apps/wolf_logo.bmp,sha256=ruJ4MA51CpGO_AYUp_dB4SWKHelvhOvd7Q8NrVOjDJk,3126
@@ -241,6 +241,9 @@ wolfhece/radar/wolfradar.py,sha256=ylyz8hNAGq92WXnMO8hVe6Nk-a7g--fL-xOcjfhFEtk,9
241
241
  wolfhece/rem/REMMaker.py,sha256=kffClHHpf8P4ruZpEb9EB__HBzg9rFAkiVCh-GFtIHU,30790
242
242
  wolfhece/rem/RasterViz.py,sha256=TDhWyMppcYBL71HfhpZuMgYKhz7faZg-MEOQJo_3Ivo,29128
243
243
  wolfhece/rem/__init__.py,sha256=S2-J5uEGK_VaMFjRUYFIdSScJjZyuXH4RmMmnG3OG7I,19
244
+ wolfhece/report/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
245
+ wolfhece/report/reporting.py,sha256=LrOUI7j1vPefsGhqag1f2KpKRXR-5cH7SyGIsf6nOG0,19196
246
+ wolfhece/report/wolf_report.png,sha256=NoSV58LSwb-oxCcZScRiJno-kxDwRdm_bK-fiMsKJdA,592485
244
247
  wolfhece/scenario/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
245
248
  wolfhece/scenario/check_scenario.py,sha256=nFiCscEGHyz1YvjmZoKlYrfmW03-nLiDTDdRoeE6MUs,4619
246
249
  wolfhece/scenario/config_manager.py,sha256=SValpikuNt_XaJXt8P7kAu6iN_N5YlohyL8ry3iT380,77389
@@ -264,8 +267,8 @@ wolfhece/sounds/sonsw2.wav,sha256=pFLVt6By0_EPQNt_3KfEZ9a1uSuYTgQSX1I_Zurv9Rc,11
264
267
  wolfhece/ui/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
265
268
  wolfhece/ui/wolf_multiselection_collapsiblepane.py,sha256=yGbU_JsF56jsmms0gh7mxa7tbNQ_SxqhpAZxhm-mTy4,14860
266
269
  wolfhece/ui/wolf_times_selection_comparison_models.py,sha256=wCxGRnE3kzEkWlWA6-3X8ADOFux_B0a5QWJ2GnXTgJw,4709
267
- wolfhece-2.1.8.dist-info/METADATA,sha256=na4Fmpn_XCY_8wAgiMs1m3YfEMKwUNC7mZ33W2JzU70,2281
268
- wolfhece-2.1.8.dist-info/WHEEL,sha256=cpQTJ5IWu9CdaPViMhC9YzF8gZuS5-vlfoFihTBC86A,91
269
- wolfhece-2.1.8.dist-info/entry_points.txt,sha256=AIu1KMswrdsqNq_2jPtrRIU4tLjuTnj2dCY-pxIlshw,276
270
- wolfhece-2.1.8.dist-info/top_level.txt,sha256=EfqZXMVCn7eILUzx9xsEu2oBbSo9liWPFWjIHik0iCI,9
271
- wolfhece-2.1.8.dist-info/RECORD,,
270
+ wolfhece-2.1.10.dist-info/METADATA,sha256=Zzg2Nmd6IpZTLHVQohBtHfLxq6TwzEOzad-ue6QTJJk,2282
271
+ wolfhece-2.1.10.dist-info/WHEEL,sha256=cpQTJ5IWu9CdaPViMhC9YzF8gZuS5-vlfoFihTBC86A,91
272
+ wolfhece-2.1.10.dist-info/entry_points.txt,sha256=AIu1KMswrdsqNq_2jPtrRIU4tLjuTnj2dCY-pxIlshw,276
273
+ wolfhece-2.1.10.dist-info/top_level.txt,sha256=EfqZXMVCn7eILUzx9xsEu2oBbSo9liWPFWjIHik0iCI,9
274
+ wolfhece-2.1.10.dist-info/RECORD,,