Bonjour,
connaissez-vous des tutos ou des vidéos, éventuellement en anglais, montrant comment utiliser PyInstaller ?
Toute info. est la bienvenue.
Bonjour,
connaissez-vous des tutos ou des vidéos, éventuellement en anglais, montrant comment utiliser PyInstaller ?
Toute info. est la bienvenue.
J'ai fait ceci pour obtenir ce mini-tuto.
Question à la con mais je la pose quand même : si je veux faire un EXE pour Windows, il faudra que j'utilise PyInstaller sous Windows. Non ?
Sous Mac, peut-on utiliser PyInstaller sans passer par Mac Port que j'évite autant que possible ?
Bonjour,
Je suppose que le manuel de pyinstaller ne t'a pas échappé (http://www.pyinstaller.org/export/la...pdf?format=raw)
Sinon, je n'ai pas trouvé de tuto intéressant sur le sujet, mais ça m'intéresse beaucoup. Jusqu'à présent, je n'utilise que py2exe sur Win, mais j'aimerais faire cela en multiplateforme.
Je trouve que cette fonction est importante, et je suis étonnée qu'elle ne soit pas intégrée dans les modules python officiels. En effet, Python est de plus en plus utilisé sur nos machines (et c'est très bien!), mais en contrepartie, quand on diffuse un logiciel en Python, on ne devrait pas être soumis à l'existence d'un python installé, ou à sa version: il faut donc que le logiciel diffusé intègre son propre interpréteur Python ainsi que les modules et bibliothèques utilisés. Le fait que le tout soit dans un seul fichier exécutable ma semble secondaire.
En multiplateforme, il y a aussi cx_freeze, mais je ne sais pas m'en servir non plus et je ne sais pas s'il faut choisir cx_freeze ou pyinstaller aujourd'hui (sur Python 2.6 et, plus tard Python 3).
Mais peut-être y a-t-il d'autres solutions?
Tyrtamos
Bonjour,
je me suis arrêté sur PyInstaller car il semble bien supporter PyQt que j'utiliserais dans un avenir presque proche pour mon application.
Je vais essayer de faire mumuse avec PyInstaller dès que possible.
Je me suis mis aussi à PyQt4 pour un projet assez gros, et je suis intéressé aussi pour cela.
Tyrtamos
Bonjour,
Merci pour l'info, j'ai un peu testé pyinstaller et il est intéressant.
Mais, je suis tomber sur un petit soucis, j'ai "compilé" (si vous permettez l'expression) un petit helloworld sur mon opensuse 11.2 et je n'ai pas réussi à exécuter le binaire sur une autre distrib (même sur une suse 11.3) ! :/
Après quelques recherches il semblerait que cela provienne de la manière dont est compilé le bootloader et que cela devrait être corrigé dans une prochaine version.
Dans un ticket, ils parlent de compiler le bootloader avec lsbcc, mais là cela devient un peu trop ardu pour ma part.
Maintenant, si quelqu'un à une solution pour réellement obtenir un binaire cross-distrib linux en attendant la version qui corrigera le blème, je suis preneur.
Pour Mac, j'ai utilisé un machine virtuelle avec VirtualBox. Voici la doc que j'ai utilisée pour créer ma machine virtuelle: http://www.takwing.idv.hk/tech/virtual/index.php
Salutations.
Tu nous prépares quoi tyrtamos...
Merci à aepli pour tes compléments.
Au sein de mon photo-club, nous organisons tous les ans un salon photographique important (exposition de 1000 photos, ateliers, conférences, etc...) avec un concours international (http://www.spr-photo.fr/).
Ce concours reçoit environ 3000 photos (papier et jpg) proposées par plus de 400 auteurs issus d'environ 40 pays. Je suis responsable de la partie informatique de ce traitement, et le logiciel actuel, écrit en delphi, est obsolète. J'ai donc entrepris de le réécrire, avec Python + sqlite3 + PyQt4 + reportlab. Si sqlite3 ne suffit pas, j'ai déjà testé Postgresql + psycopg2 en dépannage, qui marche très bien (son seul inconvénient est de compliquer un peu l'installation).
Le traitement comporte: la création des étiquettes code barre, la saisie des bordereaux, la saisie des notes du jugement, l'édition de nombreux états de sortie: statistiques, notifications aux auteurs (papier et email), liste des photos à exposer pour le site web, liste et palmarès pour le catalogue, étiquettes pour l'exposition des photos, étiquettes pour les colis de retour, liste de colisage, etc... Ainsi que de nombreuses vérifications/rectifications à toutes les étapes.
La base de données comportera une dizaine de tables avec des contraintes d'intégrité référentielles pour empêcher d'introduire des infos erronées (ex: une photo appartient forcément à un auteur), ou pour faciliter des modifications (ex: la suppression d'un auteur entraine la suppression de ses photos). Le choix de SQL permettra de sortir facilement des états non prévus au départ, sans modifier le code. On devrait même pouvoir faire ça avec openoffice-base.
Ce projet pose des problèmes qu'on ne voit pas tout de suite. Prenons 2 exemples:
- Dans la saisie des adresses, on ne prend pas les adresses des pays cités par les auteurs, mais une liste prédéfinie de pays. Sinon, on ne peut plus sortir de statistiques par pays. Je prenais jusqu'à présent la liste des 192 membres de l'ONU, et je prendrai désormais la liste des 246 pays de l'iso 3166 (avec quelques corrections). On voit tout de suite qu'il y aura un combobox dans la page de saisie.
- Si on veut envoyer par mail les résultats du concours à chaque auteur, il faut pouvoir envoyer 400 emails avec la bonne pièce jointe pour chacun des auteurs. J'arrive à faire ça avec mon code (http://python.jpvweb.com/mesrecettes...xpedition_mail), mais j'ai découvert avec surprise que les FAI coupaient rapidement ce genre d'expédition en masse pour lutter contre les spams...
Pour le reste, à part les bases de Python, tout est nouveau pour moi: PyQt4, Sqlite, reportlab, etc ... Mais c'est ça qui est intéressant! Je pense qu'une bonne partie de ce que j'aurai fait se retrouvera sur mon site.
Et j'ai 6 mois pour faire ça...
Tyrtamos
Bonjour à tous,
J'avais fait un interface sous wx de pyinstaller.
Cela m'évite de rechercher la syntaxe..., à voir si cela vous intéresse.
Alex
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318 #!/usr/bin/env python # -*- coding: iso-8859-1 -*- # Version : # Pyintasllerg40 Ecriture et récup du fichier ini par ConfigParter,heure de création du .exe import wx,os,shutil,ConfigParser import os,os.path,time def recup_ini(ficonf,lst_recup): #Récupération du fichier de configuration #Syntaxe self.lreturn=recup_ini("pyinstallerg40.ini",["fsource","ficone","fpyinstaller","fpythonw"]) lst_return=[] if os.path.exists(ficonf) : config = ConfigParser.ConfigParser() config.read(ficonf) s='local' #Section lst_return=[] for param in lst_recup : lst_return.append(config.get(s, param)) return lst_return else : for param in lst_recup : lst_return.append('') return lst_return def ecrit_ini(ficonf,lst_param,lst_valeur): #Ecriture du fichier de configuration #Syntaxe d'appel : #ecrit_ini("pyinstallerg40.ini",["fsource","ficone","fpyinstaller","fpythonw"],[fsource,ficone,fpyinstaller,fpythonw]) config = ConfigParser.ConfigParser() s='local' #Section config.add_section(s) for i in range(len(lst_param )): config.set(s,lst_param[i], lst_valeur[i]) config.write(open(ficonf,'w')) #------------------------------------------- # La Frame principale - #------------------------------------------- # generated by wxGlade class MyFrame(wx.Frame): def __init__(self, *args, **kwds): # begin wxGlade: MyFrame.__init__ kwds["style"] = wx.DEFAULT_FRAME_STYLE wx.Frame.__init__(self, *args, **kwds) self.panel_1 = wx.Panel(self, -1) self.label_01 = wx.StaticText(self.panel_1, -1, " Nécessite PyInstaller, il est à l'adresse :") self.label_02 = wx.StaticText(self.panel_1, -1, " ") self.label_03 = wx.TextCtrl(self.panel_1, -1, "http://pyinstaller.python-hosting.com/",style=wx.TE_READONLY) self.label_01.SetForegroundColour(wx.Colour(0, 0, 255)) self.label_01.SetFont(wx.Font(10, wx.DEFAULT, wx.SLANT, wx.NORMAL, 0, "")) self.label_03.SetForegroundColour(wx.Colour(0, 0, 255)) self.label_03.SetFont(wx.Font(10, wx.DEFAULT, wx.SLANT, wx.NORMAL, 0, "")) self.label_1 = wx.StaticText(self.panel_1, -1, " Fichier source") self.button_1 = wx.Button(self.panel_1, -1, "Parcourir") self.text_ctrl_1 = wx.TextCtrl(self.panel_1, -1, "") self.label_2 = wx.StaticText(self.panel_1, -1, " Fichier icone (Nécessite pywin32)") self.button_2 = wx.Button(self.panel_1, -1, "Parcourir") self.text_ctrl_2 = wx.TextCtrl(self.panel_1, -1, "") self.label_4 = wx.StaticText(self.panel_1, -1, " Emplacement ....pyinstaller-1.3\\configure.py") self.button_4 = wx.Button(self.panel_1, -1, "Parcourir") self.text_ctrl_4 = wx.TextCtrl(self.panel_1, -1, "") self.label_5 = wx.StaticText(self.panel_1, -1, " Emplacement Pythonw.exe") self.button_5 = wx.Button(self.panel_1, -1, "Parcourir") self.text_ctrl_5 = wx.TextCtrl(self.panel_1, -1, "") self.label_6 = wx.StaticText(self.panel_1, -1, " Effacement des fichiers temporaires") self.button_6 = wx.Button(self.panel_1, -1, "Efface !!") self.text_ctrl_6 = wx.StaticText(self.panel_1, -1, "") self.label_3 = wx.StaticText(self.panel_1, -1, " Création .exe") self.button_3 = wx.Button(self.panel_1, -1, "Go !") self.text_ctrl_3 = wx.StaticText(self.panel_1, -1, "pyinstallerg") self.__set_properties() self.__do_layout() # Les événements self.Bind(wx.EVT_BUTTON, self.parcourir_s, self.button_1) # Boutton Recherche du fichier source self.Bind(wx.EVT_BUTTON, self.parcourir_i, self.button_2) # Boutton Recherche du fichier icone self.Bind(wx.EVT_BUTTON, self.parcourir_pyi, self.button_4) # Boutton Recherchedu fichier ....pyinstaller-1.3\Configure.py self.Bind(wx.EVT_BUTTON, self.parcourir_pywexe, self.button_5) # Boutton Recherche du fichier pythonw.exe self.Bind(wx.EVT_BUTTON, self.bouton_efface, self.button_6) self.Bind(wx.EVT_BUTTON, self.go, self.button_3) # Boutton Création du .exe self.Bind(wx.EVT_CLOSE, self.onclose) # Quit #--------------------------- # Récup de pyinstallerg.ini - #--------------------------- self.lreturn=recup_ini("pyinstallerg40.ini",["fsource","ficone","fpyinstaller","fpythonw"]) self.text_ctrl_1.SetValue(self.lreturn[0]) self.text_ctrl_2.SetValue(self.lreturn[1]) self.text_ctrl_4.SetValue(self.lreturn[2]) self.text_ctrl_5.SetValue(self.lreturn[3]) # end wxGlade def __set_properties(self): # begin wxGlade: MyFrame.__set_properties self.SetTitle("Pynstallerg") self.text_ctrl_1.SetMinSize((500, 24)) self.text_ctrl_2.SetMinSize((500,24)) self.label_03.SetMinSize((500,24)) self.text_ctrl_4.SetMinSize((500,24)) self.text_ctrl_5.SetMinSize((500,24)) self.button_1.SetBackgroundColour(wx.Colour(255, 127, 0)) self.button_3.SetBackgroundColour(wx.Colour(255, 0, 0)) # end wxGlade def __do_layout(self): # begin wxGlade: MyFrame.__do_layout sizer_1 = wx.BoxSizer(wx.VERTICAL) grid_sizer_1 = wx.FlexGridSizer(6, 3, 3, 3) grid_sizer_1.Add(self.label_01, 0, 0, 0) grid_sizer_1.Add(self.label_02, 0, 0, 0) grid_sizer_1.Add(self.label_03, 0, 0, 0) grid_sizer_1.Add(self.label_1, 0, 0, 0) grid_sizer_1.Add(self.button_1, 0, 0, 0) grid_sizer_1.Add(self.text_ctrl_1, 0, 0, 0) grid_sizer_1.Add(self.label_2, 0, 0, 0) grid_sizer_1.Add(self.button_2, 0, 0, 0) grid_sizer_1.Add(self.text_ctrl_2, 0, 0, 0) grid_sizer_1.Add(self.label_4, 0, 0, 0) grid_sizer_1.Add(self.button_4, 0, 0, 0) grid_sizer_1.Add(self.text_ctrl_4, 0, 0, 0) grid_sizer_1.Add(self.label_5, 0, 0, 0) grid_sizer_1.Add(self.button_5, 0, 0, 0) grid_sizer_1.Add(self.text_ctrl_5, 0, 0, 0) grid_sizer_1.Add(self.label_6, 0, 0, 0) grid_sizer_1.Add(self.button_6, 0, 0, 0) grid_sizer_1.Add(self.text_ctrl_6, 0, 0, 0) grid_sizer_1.Add(self.label_3, 0, 0, 0) grid_sizer_1.Add(self.button_3, 0, 0, 0) grid_sizer_1.Add(self.text_ctrl_3, 0, 0, 0) self.panel_1.SetSizer(grid_sizer_1) sizer_1.Add(self.panel_1, 1, wx.EXPAND, 0) self.SetSizer(sizer_1) sizer_1.Fit(self) self.Layout() # end wxGlade def parcourir_s(self, event): # wxGlade: MyFrame1.<event_handler> wildcard = "All files (*.*)|*.*|" \ "Fichiers textes (*.txt)|*.txt" dialog = wx.FileDialog(None, "Choose a file", os.getcwd(), "", wildcard, wx.OPEN) if dialog.ShowModal() == wx.ID_OK: self.text_ctrl_1.SetValue(dialog.GetPath()) event.Skip() def parcourir_i(self, event): # wxGlade: MyFrame1.<event_handler> wildcard = "All files (*.*)|*.*|" \ "Fichiers textes (*.txt)|*.txt" dialog = wx.FileDialog(None, "Choose a file", os.getcwd(), "", wildcard, wx.OPEN) if dialog.ShowModal() == wx.ID_OK: self.text_ctrl_2.SetValue(dialog.GetPath()) event.Skip() def parcourir_pyi(self, event): # wxGlade: MyFrame1.<event_handler> wildcard = "All files (*.*)|*.*|" \ "Fichiers textes (*.txt)|*.txt" dialog = wx.FileDialog(None, "Choose a file", os.getcwd(), "", wildcard, wx.OPEN) if dialog.ShowModal() == wx.ID_OK: self.text_ctrl_4.SetValue(dialog.GetPath()) event.Skip() def parcourir_pywexe(self, event): # wxGlade: MyFrame1.<event_handler> wildcard = "All files (*.*)|*.*|" \ "Fichiers textes (*.txt)|*.txt" dialog = wx.FileDialog(None, "Choose a file", os.getcwd(), "", wildcard, wx.OPEN) if dialog.ShowModal() == wx.ID_OK: self.text_ctrl_5.SetValue(dialog.GetPath()) def bouton_efface(self, event): # wxGlade: MyFrame1.<event_handler> fsource=self.text_ctrl_1.GetValue() ficone=self.text_ctrl_2.GetValue() cheminpyi=self.text_ctrl_4.GetValue() cheminpywexe=self.text_ctrl_5.GetValue() fsansfin=fsource[:len(fsource)-3] if fsource[len(fsource)-3:]=="pyw": fsansfin=fsource[:len(fsource)-4] fseul=fsansfin.split(os.sep) # Sans les / frep=os.sep.join(fseul[:len(fseul)-1])+os.sep # Rep du fichier source fwarn=frep+"warn"+fseul[len(fseul)-1]+".txt" fbuild=frep+"build"+fseul[len(fseul)-1]+os.sep bilan_eff="Ont été effacés : " if os.path.exists(fsansfin+".bat") : os.remove(fsansfin+".bat") bilan_eff+=" .bat" if os.path.exists(fsansfin+".spec") : os.remove(fsansfin+".spec") bilan_eff+=" .spec" if os.path.exists(fwarn) : os.remove(fwarn) bilan_eff+=" warnX.txt" if os.path.exists(fbuild) : shutil.rmtree(fbuild) bilan_eff+=" buildX\\" self.text_ctrl_6.SetLabel(bilan_eff) #----------------------------------------------------- # Go = > Création du fihier - #----------------------------------------------------- def go(self, event): # wxGlade: MyFrame1.<event_handler> fsource=self.text_ctrl_1.GetValue() ficone=self.text_ctrl_2.GetValue() cheminpyi=self.text_ctrl_4.GetValue() cheminpywexe=self.text_ctrl_5.GetValue() fsansfin=fsource[:len(fsource)-3] if fsource[len(fsource)-3:]=="pyw": fsansfin=fsource[:len(fsource)-4] fseul=fsansfin.split(os.sep) # sans slash frep=os.sep.join(fseul[:len(fseul)-1])+os.sep chempyiseul=cheminpyi.split(os.sep) reppyi=os.sep.join(chempyiseul[:len(chempyiseul)-1])+os.sep #Création du nouveau fichier os.chdir(frep) #mettre le bon rep fichierobjetsortie=open(fsansfin+".bat",'w') fichierobjetsortie.write(cheminpywexe+" "+reppyi+os.sep+"configure.py"+'\n') if ficone!="" : fichierobjetsortie.write(cheminpywexe+" "+reppyi+'Makespec.py -F -w --icon='+ficone+' "'+fsource+'"'+'\n') else: fichierobjetsortie.write(cheminpywexe+" "+reppyi+'Makespec.py -F -w "'+fsource+'"'+'\n') fichierobjetsortie.write(cheminpywexe+" "+reppyi+"build.py "+fsansfin+'.spec'+'\n') fichierobjetsortie.close() os.system(fsansfin+".bat") self.text_ctrl_3.SetLabel("") if fsource!="" and os.path.exists(fsansfin+".exe") : os.system(fsansfin+".bat") self.text_ctrl_3.SetLabel(" Creation OK ! "+fsansfin+".exe : "+time.strftime('%H:%M:%S')) event.Skip() #----------------------------------------------------- # Quit => sauvegarde dans pyinstallerg.ini - #----------------------------------------------------- def onclose(self,event): #try : if os.path.exists('pyinstallerg40.ini') : os.remove('pyinstallerg40.ini') fsource=self.text_ctrl_1.GetValue() ficone=self.text_ctrl_2.GetValue() fpyinstaller=self.text_ctrl_4.GetValue() fpythonw=self.text_ctrl_5.GetValue() ecrit_ini("pyinstallerg40.ini",["fsource","ficone","fpyinstaller","fpythonw"],[fsource,ficone,fpyinstaller,fpythonw]) self.Destroy() # end of class MyFrame if __name__ == "__main__": app = wx.PySimpleApp(0) wx.InitAllImageHandlers() frame_1 = MyFrame(None, -1, "") app.SetTopWindow(frame_1) frame_1.Show() app.MainLoop()
Bonjour,
Merci alexdevl, c'est intéressant.
Malheureusement pour moi, PyInstaller semble ne pas supporter entièrement Python 2.6 sous Windows: http://www.pyinstaller.org/wiki/Python26Win.
C'est bien dommage.
Tyrtamos
Edit: je viens d'essayer cx_freeze avec PyQt4, Python 2.6 et Windows 7: ça marche! De plus, cx_freeze est dispo pour Python 2.7 et 3.
Parmi les différentes méthodes, j'ai utilisé setup.py que je connais un peu grâce à py2exe. Mais comme d'habitude, il faut chercher à taton pour compenser la faiblesse de la doc et la quasi inexistence de tuto. Mais bon. Ça marche...
Par exemple, j'ai un programme PyQt4 test.py qui importe 2 modules (printx.py et bibconcours.py) qui sont dans un répertoire différent ..\..\biblio. Voilà le setup.py:
Avec ce setup, il suffit de faire dans la console cmd et dans le répertoire de test.py:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import sys from cx_Freeze import setup, Executable base = None if sys.platform == "win32": base = "Win32GUI" buildOptions = dict( compressed = True, includes = ["printx", "bibconcours"], path = sys.path + [r"..\..\biblio"] ) setup( name = "simple_PyQt4", version = "0.1", description = "Programme test.py avec PyQt4", executables = [Executable("test.py", base = base)], options = dict(build_exe = buildOptions) )
et l'exécutable test.exe se trouve dans le sous-répertoire "build\exe.win32-2.6", avec les .dll et .pyd nécessaires, ainsi qu'une librairie zippée. Ce qui représente tout de même 25Mo...
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2 python setup.py build
Curieusement, l'opération m'a détecté une petite erreur de programmation que l'exécution habituelle ne m'avait pas détectée: ça, c'est intéressant aussi!
Bref, je suis parti sur cx_freeze. Je re-tenterai PyInstaller quand il aura progressé un peu.
Etant donné le site calamiteux de ce projet, je n'arrive pas à savoir si Mac O$ et Linux sont supportés.
Merci pour ton exemple. Concernant la taille du fichier, as-tu testé l'import réduit de modules PyQt ?
Intéressant... Quelle sera la licence de ce projet ?
Tu peux passer par un timer pour envoyer des mails par petits lots. Ce sera plus long mais c'est l'ordi. qui bossera. A essayer...
La partie BDD reste toujours un grand mystère pour moi.
Pour la partie PDF, as-tu envisagé LaTeX ? Cela demande juste de produire un fichier contenant du code, puis ensuite de lancer quelques commandes que je pourrais te fournir. Inconvénient : il faut installer LaTeX sur la machine, et aussi connaître sa syntaxe.
Quelles sont les avantages de reportlab ? L'installation sosu Mac O$ n'a pas l'air simple...
Il existe une version rpm pour centos ainsi qu'un paquet source rpm et l'ensemble des sources tar.gz. Pour Mac Os x, il n'existe aucune mention dans la doc, mais on en parle dans la mailing list (http://sourceforge.net/mailarchive/f...x-freeze-users).
J'ai vu sur mon ubuntu 10.04 que le paquet cx_freeze existe.
Qu'entends-tu par là?
Jusqu'à présent, le logiciel étant conçu et utilisé au sein du photo-club, le problème de la licence ne se posait pas. Par la suite, si je le mets à disposition, ce sera probablement sous licence gpl comme mes autres logiciels.
C'est ce que je voulais faire aussi: une tempo de 35 secondes entre 2 mails donnera environ 4 heures pour les 400 mails.
Je te suggère de bosser un peu la question. En fait, tout ce qui peut être attribué au système de gestion de BDR décharge d'autant le programme à écrire! C'est donc de la "paresse intelligente", qui est souvent la 1ère motivation des hommes de méthode...![]()
Je veux simplement pouvoir créer des documents pdf comme je veux, à partir des infos de la base de données.
L'année dernière, voilà ce que j'ai fait:
- extraction des données en python à partir d'un fichier dbase III.
- création en python d'un fichier csv avec toutes les données à éditer
- rédaction d'une page de publipostage en openoffice word
- publipostage pour obtenir un fichier unique pdf de 400 pages. Ce qui convient pour un mailing "papier".
- Comme je souhaitais aussi accéder à chaque page séparément pour les envois par email, j'ai utilisé pdfsam sous windows pour éclater le fichier en 400 pages pdf. Puis, j'ai fait un programme en python pour renommer les 400 pages avec le code auteur, pour que chaque email puisse appeller le bon fichier en tant que pièce jointe.
Bref, un sacré bazar... J'aimerais donc que tout cela se fasse tout seul, et reportlab, que j'ai un peu testé, me semble capable de faire ça. Je l'ai utilisé sous Windows, mais il existe aussi sous mon ubuntu 10.04. Sous Mac Os X, je ne sais pas.
J'aurai d'ailleurs à créer aussi des pages html, mais mes besoins sont plus simples, et je sais déjà le faire (avec un modèle html créé par kompozer).
Tyrtamos
Ave Tyrtamos,
Questions de curieux sur votre projet.
En diagonale, QT4 et une BDD çà fleure bon l'architecture client serveur.
Pourquoi ce choix?
Un modèle 3 tiers vous permettrait sans doute d'avoir moins de soucis côté déploiement MultiOS et mises à jour.
Note: Vous pouvez aussi utiliser QT4/Webkit pour avoir des fonctionnalités mixtes (une sorte d'HTML5).
J'adore SQL mais après avoir gouté les ORM Python que sont Elixir et SQLAlchemy, je ne puis résister à vous suggérer d'y jeter un oeil si vous ne l'avez déjà fait - et dans ce cas, pourquoi ne pas les prendre "on board".
La magie des ORM est qu'ils produisent le SQL pour nous.Envoyé par rambc Voir le message
La partie BDD reste toujours un grand mystère pour moi.
On peut donc être relativement mauvais en SQL et réaliser un projet qui utilise une BDD modeste en ayant des connaissances minimale sur SQL.
En plus, on peut commencer le projet avec SQLite3 puis le migrer sur Postgres plus tard sans trop d'effort.
- W
Note: Enfin presque! Je suis en pétard parce
- SQLite3 ne supporte pas des clés auto-incrémentés dans des tables qui ont d'autres clés primaires. Mais on peut s'en accommoder quand même.
- SQLAlchemy rend les traitements SQL presque indépendants de la BDD, mais côté "meta" sorti des tables, snif... mais bon c'est quand même pas banal de créer sa base de donnée on the fly.
Bonjour wiztricks,
En fait, il s'agit d'un process technique, qui a un début (la réception des colis de photos), une fin (le retour des colis de photos), et un déroulement précis basé sur une expérience de 23 ans (3 ans pour moi). On retrouve donc bien les 3 composantes du modèle 3 tiers, y compris la partie métier, et j'en tiens compte de façon implicite.
Dans ce projet, je cherche à satisfaire plusieurs exigences, dont les suivantes qui ont orienté mes choix:
1 - la base de données doit être conçue pour être stable dans le temps, malgré les évolutions inévitables des besoins.
2 - Les IHM doivent être compatibles avec l'utilisation facile par des bénévoles, et empêcher le plus d'erreurs possibles, le plus tôt possible.
3 - le système informatique doit pouvoir être installé et utilisé par un non-informaticien ayant de simples connaissances de bureautique.
4 - On doit pouvoir exploiter les données d'une façon non prévue au départ, et si nécessaire sans passer par le logiciel.
5 - Le développement du projet doit être compatible avec un amateur bénévole (=moi!), et les logiciels utilisés doivent être gratuits.
Une compatibilité multiplateforme n'est pas obligatoire, mais serait un plus.
Le choix de sqlite3 devient alors évident: base de données relationnelle, sans installation de serveur et consultable par openoffice (il y a aussi sqliteExpert). Postgresql est le 2ème choix, plus complexe à installer, plus puissant et consultable "en direct" (sans ODBC) grâce à psycopg2. La solution web/mysql est exclue parce que nous n'avons pas internet sur les lieux du concours.
Le choix de PyQt4 est facile aussi: tkinter est trop limité, je ne vois pas l'évolution de wxpython (python 3?), et je voulais pouvoir dessiner facilement les formulaires (=qtdesigner). J'aurais pu prendre PyGtk si il avait un designer équivalent.
Il ne reste plus que les outils de mise en forme des résultats des requêtes en csv, pdf et html.
J'ai déjà entendu parler de SQLAlchemy et Elixir, mais je n'ai pas encore compris ce que ça faisait. Et ce n'est pas wikipedia qui m'a clarifié le sujet (http://fr.wikipedia.org/wiki/SQLAlchemy). Je vais y jeter un coup d'oeil. Merci!
Tyrtamos
Ave Tyrtamos
Je n'ai toujours pas compris si l'application était multi-poste (plusieurs PC qui partagent des données) ou fonctionnait sur un seul PC... Donc, je ne sais pas quoi dire pour le reste
Pour Elixir voir le tuto
Il y a aussi un tuto pour SQLAlchemy mais il est beaucoup moins vendeur(*) que celui d'Elixir.
-W
(*) Les ORM sont des choses très compliquées. Pas facile pour SQLAlchemy de faire simple alors qu'il veut montrer qu'il est aussi riche que Hibernate...
Elixir est un ORM declaratif de type Active record construit au dessus.
C'est beaucoup moins puissant mais ca rend le monstre beaucoup plus digeste.
Bonjour,
Il n'y a qu'un seul PC et un seul opérateur en même temps. Il n'y a donc pas d'accès concurrents aux mêmes données.
Pour la saisie des notes du jugement (ça dure 2 jours), il y a 3 PC supplémentaires (un par juge) équipés de lecteur de code barre, et les échanges de données avec le PC maitre se font par clés USB. Les tentatives de réseaux n'ont pas donné satisfaction.
Merci pour les liens!
Tyrtamos
Bonjour,
Pour cx_Freeze: voici un petit tuto que j'ai fait pour mon usage:
http://python.jpvweb.com/mesrecettespython/cx_freeze
J'espère qu'il vous sera utile aussi.
Tyrtamos
Très vendeur l'exemple proposé par Elixir. Je ne sais si SQLAlchemy propose le même genre d'exemple. J'ai le souvenir de trucs très abstraits pour un nul comme moi.Envoyé par wiztricks
Petite question : Elixir est-il assez efficace pour une recherche par mots clés ? Je voudrais créer une BDD contenant des chemins de fichiers auxquels seraient associés des mots clés. Le nombre de fichiers ne devrait pas dépasser quelques milliers, et les recherches seraient du type "TROUVER LES FICHIERS AYANT POUR CLEFS ...".
Super.Envoyé par wiztricks
![]()
Salut,
Elixir permet la construction de classe Python associées aux tables de la BDD.
Au dessus de ces tables on des primitives indépendantes de la BDD qui vont permettre de faire des requêtes qui seront traduites en SQL en fonction de ce qu'on veut faire.
Il est clair que cette "facilité" ajoute de l'overhead: effectuer ses requêtes SQL à la "main" via DBAPI sera bien sur plus efficace.
Mais le bourrin qui tourne derrière reste le SGDB et son efficacité relative sera fonction du modèle de données et du type de requêtes qu'on fera dessus.
Dans ton cas, on peut imaginer faire cela avec trois tables: les fichiers, les mots_clés et une association ManytoMany entre les deux.
C'est une structure qui si mes souvenirs sont bons est donnée en exemple.
L'intérêt d'Elixir est la rapidité de mise en oeuvre de la chose.
Après le piège avec les noms de fichiers est lorsqu'on s'amuse à rechercher dans les noms avec des %LIKE, mais là encore Elixir délègue le boulot au SGDB.
- W
Merci pour ces compléments. De toute façon, cette fonctionnalité viendra plus tard dans mon projet. Grâce à toi je peux envisager d'entrer dans le monde des BDD. L'amélioration des performances viendra ensuite si besoin.
Partager