Carbon Poker offers a 5 card stud game that wasn't listed here. It's not available...
[fpdb-dooglus.git] / pyfpdb / GuiBulkImport.py
blobffd3235862eb95b0d2ed3834baf6078538199834
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
4 #Copyright 2008-2011 Steffen Schaumburg
5 #This program is free software: you can redistribute it and/or modify
6 #it under the terms of the GNU Affero General Public License as published by
7 #the Free Software Foundation, version 3 of the License.
9 #This program is distributed in the hope that it will be useful,
10 #but WITHOUT ANY WARRANTY; without even the implied warranty of
11 #MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 #GNU General Public License for more details.
14 #You should have received a copy of the GNU Affero General Public License
15 #along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #In the "official" distribution you can find the license in agpl-3.0.txt.
18 import L10n
19 _ = L10n.get_translation()
21 # Standard Library modules
22 import os
23 import sys
24 from time import time
25 from optparse import OptionParser
26 import traceback
28 # pyGTK modules
29 import pygtk
30 pygtk.require('2.0')
31 import gtk
32 import gobject
34 # fpdb/FreePokerTools modules
35 import fpdb_import
36 import Configuration
37 import Exceptions
39 import logging
40 # logging has been set up in fpdb.py or HUD_main.py, use their settings:
41 log = logging.getLogger("importer")
43 class GuiBulkImport():
45 # CONFIGURATION - update these as preferred:
46 allowThreads = False # set to True to try out the threads field
48 def dopulse(self):
49 self.progressbar.pulse()
50 return True
52 def load_clicked(self, widget, data=None):
53 if self.cbfilter.get_model()[self.cbfilter.get_active()][0] == (_("Please select site")):
54 self.progressbar.set_text(_("Please select site"))
55 return
56 stored = None
57 dups = None
58 partial = None
59 errs = None
60 ttime = None
61 # Does the lock acquisition need to be more sophisticated for multiple dirs?
62 # (see comment above about what to do if pipe already open)
63 if self.settings['global_lock'].acquire(wait=False, source="GuiBulkImport"): # returns false immediately if lock not acquired
64 #try:
65 print _("\nGlobal lock taken ...")
66 self.progressbar.set_text(_("Importing..."))
67 self.progressbar.pulse()
68 while gtk.events_pending(): # see http://faq.pygtk.org/index.py?req=index for more hints (3.7)
69 gtk.main_iteration(False)
70 self.timer = gobject.timeout_add(100, self.dopulse)
72 # get the dir to import from the chooser
73 selected = self.chooser.get_filenames()
75 # get the import settings from the gui and save in the importer
76 self.importer.setHandCount(int(self.spin_hands.get_text()))
77 self.importer.setQuiet(self.chk_st_st.get_active())
78 self.importer.setThreads(int(self.spin_threads.get_text()))
79 self.importer.setHandsInDB(self.n_hands_in_db)
80 cb_model = self.cb_dropindexes.get_model()
81 cb_index = self.cb_dropindexes.get_active()
82 cb_hmodel = self.cb_drophudcache.get_model()
83 cb_hindex = self.cb_drophudcache.get_active()
85 #self.lab_info.set_markup('<span foreground="blue">Importing ...</span>') # uses pango markup!
87 if cb_index:
88 self.importer.setDropIndexes(cb_model[cb_index][0])
89 else:
90 self.importer.setDropIndexes("auto")
91 if cb_hindex:
92 self.importer.setDropHudCache(cb_hmodel[cb_hindex][0])
93 else:
94 self.importer.setDropHudCache("auto")
95 sitename = self.cbfilter.get_model()[self.cbfilter.get_active()][0]
96 #self.importer.setFailOnError(self.chk_fail.get_active())
97 if self.is_archive.get_active():
98 if sitename == "PokerStars":
99 self.importer.setStarsArchive(True)
100 if sitename == "Full Tilt Poker":
101 self.importer.setFTPArchive(True)
103 for selection in selected:
104 self.importer.addBulkImportImportFileOrDir(selection, site = sitename)
105 self.importer.setCallHud(self.cb_testmode.get_active())
106 self.importer.bHudTest = self.cb_testmode.get_active()
107 starttime = time()
108 # try:
109 (stored, dups, partial, errs, ttime) = self.importer.runImport()
110 # except:
111 # print "*** EXCEPTION DURING BULKIMPORT!!!"
112 # raise Exceptions.FpdbError
113 # finally:
114 gobject.source_remove(self.timer)
116 ttime = time() - starttime
117 if ttime == 0:
118 ttime = 1
120 completionMessage = _('Bulk import done: Stored: %d \tDuplicates: %d \tPartial: %d \tErrors: %d in %s seconds - %.0f/sec')\
121 % (stored, dups, partial, errs, ttime, (stored+0.0) / ttime)
122 print completionMessage
123 log.info(completionMessage)
125 self.importer.clearFileList()
127 if self.n_hands_in_db == 0 and stored > 0:
128 self.cb_dropindexes.set_sensitive(True)
129 self.cb_dropindexes.set_active(0)
130 self.lab_drop.set_sensitive(True)
131 self.cb_drophudcache.set_sensitive(True)
132 self.cb_drophudcache.set_active(0)
133 self.lab_hdrop.set_sensitive(True)
135 self.progressbar.set_text(_("Import Complete"))
136 self.progressbar.set_fraction(0)
137 #except:
138 #err = traceback.extract_tb(sys.exc_info()[2])[-1]
139 #print "*** BulkImport Error: "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1])
140 #self.settings['global_lock'].release()
141 self.settings['global_lock'].release()
142 else:
143 print _("bulk import aborted - global lock not available")
145 def get_vbox(self):
146 """returns the vbox of this thread"""
147 return self.vbox
149 def __init__(self, settings, config, sql = None, parent = None):
150 self.settings = settings
151 self.config = config
152 self.parent = parent
154 self.importer = fpdb_import.Importer(self, self.settings, config, sql, parent)
156 self.vbox = gtk.VBox(False, 0)
157 self.vbox.show()
159 self.chooser = gtk.FileChooserWidget()
160 self.chooser.set_filename(self.settings['bulkImport-defaultPath'])
161 self.chooser.set_select_multiple(True)
162 self.vbox.add(self.chooser)
163 self.chooser.show()
165 # Table widget to hold the settings
166 self.table = gtk.Table(rows=5, columns=5, homogeneous=False)
167 self.vbox.add(self.table)
168 self.table.show()
170 # checkbox - print start/stop?
171 self.chk_st_st = gtk.CheckButton(_('Print Start/Stop Info'))
172 self.table.attach(self.chk_st_st, 0, 1, 0, 1, xpadding=10, ypadding=0,
173 yoptions=gtk.SHRINK)
174 self.chk_st_st.show()
175 self.chk_st_st.set_active(True)
177 # label - status
178 self.lab_status = gtk.Label(_("Hands/status print:"))
179 self.table.attach(self.lab_status, 1, 2, 0, 1, xpadding=0, ypadding=0,
180 yoptions=gtk.SHRINK)
181 self.lab_status.show()
182 self.lab_status.set_justify(gtk.JUSTIFY_RIGHT)
183 self.lab_status.set_alignment(1.0, 0.5)
185 # spin button - status
186 status_adj = gtk.Adjustment(value=100, lower=0, upper=300, step_incr=10,
187 page_incr=1, page_size=0) #not sure what upper value should be!
188 self.spin_status = gtk.SpinButton(adjustment=status_adj, climb_rate=0.0,
189 digits=0)
190 self.table.attach(self.spin_status, 2, 3, 0, 1, xpadding=10, ypadding=0,
191 yoptions=gtk.SHRINK)
192 self.spin_status.show()
194 # label - threads
195 self.lab_threads = gtk.Label(_("Number of threads:"))
196 self.table.attach(self.lab_threads, 3, 4, 0, 1, xpadding=0, ypadding=0,
197 yoptions=gtk.SHRINK)
198 self.lab_threads.show()
199 if not self.allowThreads:
200 self.lab_threads.set_sensitive(False)
201 self.lab_threads.set_justify(gtk.JUSTIFY_RIGHT)
202 self.lab_threads.set_alignment(1.0, 0.5)
204 # spin button - threads
205 threads_adj = gtk.Adjustment(value=0, lower=0, upper=32, step_incr=1,
206 page_incr=1, page_size=0) #not sure what upper value should be!
207 self.spin_threads = gtk.SpinButton(adjustment=threads_adj, climb_rate=0.0, digits=0)
208 self.table.attach(self.spin_threads, 4, 5, 0, 1, xpadding=10, ypadding=0,
209 yoptions=gtk.SHRINK)
210 self.spin_threads.show()
211 if not self.allowThreads:
212 self.spin_threads.set_sensitive(False)
214 # checkbox - archive file?
215 self.is_archive = gtk.CheckButton(_('Archive File'))
216 self.table.attach(self.is_archive, 0, 1, 1, 2, xpadding=10, ypadding=0, yoptions=gtk.SHRINK)
217 self.is_archive.show()
219 # label - hands
220 self.lab_hands = gtk.Label(_("Hands/file:"))
221 self.table.attach(self.lab_hands, 1, 2, 1, 2, xpadding=0, ypadding=0, yoptions=gtk.SHRINK)
222 self.lab_hands.show()
223 self.lab_hands.set_justify(gtk.JUSTIFY_RIGHT)
224 self.lab_hands.set_alignment(1.0, 0.5)
226 # spin button - hands to import
227 hands_adj = gtk.Adjustment(value=0, lower=0, upper=10, step_incr=1,
228 page_incr=1, page_size=0) #not sure what upper value should be!
229 self.spin_hands = gtk.SpinButton(adjustment=hands_adj, climb_rate=0.0, digits=0)
230 self.table.attach(self.spin_hands, 2, 3, 1, 2, xpadding=10, ypadding=0,
231 yoptions=gtk.SHRINK)
232 self.spin_hands.show()
234 # label - drop indexes
235 self.lab_drop = gtk.Label(_("Drop indexes:"))
236 self.table.attach(self.lab_drop, 3, 4, 1, 2, xpadding=0, ypadding=0,
237 yoptions=gtk.SHRINK)
238 self.lab_drop.show()
239 self.lab_drop.set_justify(gtk.JUSTIFY_RIGHT)
240 self.lab_drop.set_alignment(1.0, 0.5)
242 # ComboBox - drop indexes
243 self.cb_dropindexes = gtk.combo_box_new_text()
244 self.cb_dropindexes.append_text(_('auto'))
245 self.cb_dropindexes.append_text(_("don't drop"))
246 self.cb_dropindexes.append_text(_('drop'))
247 self.cb_dropindexes.set_active(0)
248 self.table.attach(self.cb_dropindexes, 4, 5, 1, 2, xpadding=10,
249 ypadding=0, yoptions=gtk.SHRINK)
250 self.cb_dropindexes.show()
252 self.cb_testmode = gtk.CheckButton(_('HUD Test mode'))
253 self.table.attach(self.cb_testmode, 0, 1, 2, 3, xpadding=10, ypadding=0, yoptions=gtk.SHRINK)
254 self.cb_testmode.show()
256 # label - filter
257 self.lab_filter = gtk.Label(_("Site filter:"))
258 self.table.attach(self.lab_filter, 1, 2, 2, 3, xpadding=0, ypadding=0,
259 yoptions=gtk.SHRINK)
260 self.lab_filter.show()
261 self.lab_filter.set_justify(gtk.JUSTIFY_RIGHT)
262 self.lab_filter.set_alignment(1.0, 0.5)
264 # ComboBox - filter
265 self.cbfilter = gtk.combo_box_new_text()
266 disabled_sites = [] # move disabled sites to bottom of list
267 self.cbfilter.append_text(_("Please select site"))
268 for w in self.config.hhcs:
269 try:
270 if self.config.supported_sites[w].enabled: # include enabled ones first
271 print w
272 self.cbfilter.append_text(w)
273 else:
274 disabled_sites.append(w)
275 except: # self.supported_sites[w] may not exist if hud_config is bad
276 disabled_sites.append(w)
277 for w in disabled_sites: # then disabled ones
278 print w
279 self.cbfilter.append_text(w)
280 self.cbfilter.set_active(0)
281 self.table.attach(self.cbfilter, 2, 3, 2, 3, xpadding=10, ypadding=1,
282 yoptions=gtk.SHRINK)
283 self.cbfilter.show()
285 # label - drop hudcache
286 self.lab_hdrop = gtk.Label(_("Drop HudCache:"))
287 self.table.attach(self.lab_hdrop, 3, 4, 2, 3, xpadding=0, ypadding=0,
288 yoptions=gtk.SHRINK)
289 self.lab_hdrop.show()
290 self.lab_hdrop.set_justify(gtk.JUSTIFY_RIGHT)
291 self.lab_hdrop.set_alignment(1.0, 0.5)
293 # ComboBox - drop hudcache
294 self.cb_drophudcache = gtk.combo_box_new_text()
295 self.cb_drophudcache.append_text(_('auto'))
296 self.cb_drophudcache.append_text(_("don't drop"))
297 self.cb_drophudcache.append_text(_('drop'))
298 self.cb_drophudcache.set_active(0)
299 self.table.attach(self.cb_drophudcache, 4, 5, 2, 3, xpadding=10,
300 ypadding=0, yoptions=gtk.SHRINK)
301 self.cb_drophudcache.show()
303 # button - Import
304 self.load_button = gtk.Button(_('_Bulk Import')) # todo: rename variables to import too
305 self.load_button.connect('clicked', self.load_clicked,
306 _('Import clicked'))
307 self.table.attach(self.load_button, 2, 3, 4, 5, xpadding=0, ypadding=0,
308 yoptions=gtk.SHRINK)
309 self.load_button.show()
311 # label - spacer (keeps rows 3 & 5 apart)
312 self.lab_spacer = gtk.Label()
313 self.table.attach(self.lab_spacer, 3, 5, 3, 4, xpadding=0, ypadding=0,
314 yoptions=gtk.SHRINK)
315 self.lab_spacer.show()
317 # label - info
318 # self.lab_info = gtk.Label()
319 # self.table.attach(self.lab_info, 3, 5, 4, 5, xpadding = 0, ypadding = 0, yoptions=gtk.SHRINK)
320 # self.lab_info.show()
321 self.progressbar = gtk.ProgressBar()
322 self.table.attach(self.progressbar, 3, 5, 4, 5, xpadding=0, ypadding=0,
323 yoptions=gtk.SHRINK)
324 self.progressbar.set_text(_("Waiting..."))
325 self.progressbar.set_fraction(0)
326 self.progressbar.show()
328 # see how many hands are in the db and adjust accordingly
329 tcursor = self.importer.database.cursor
330 tcursor.execute("Select count(1) from Hands")
331 row = tcursor.fetchone()
332 tcursor.close()
333 self.importer.database.rollback()
334 self.n_hands_in_db = row[0]
335 if self.n_hands_in_db == 0:
336 self.cb_dropindexes.set_active(2)
337 self.cb_dropindexes.set_sensitive(False)
338 self.lab_drop.set_sensitive(False)
339 self.cb_drophudcache.set_active(2)
340 self.cb_drophudcache.set_sensitive(False)
341 self.lab_hdrop.set_sensitive(False)
343 def main(argv=None):
344 """main can also be called in the python interpreter, by supplying the command line as the argument."""
345 if argv is None:
346 argv = sys.argv[1:]
348 def destroy(*args): # call back for terminating the main eventloop
349 gtk.main_quit()
351 parser = OptionParser()
352 parser.add_option("-f", "--file", dest="filename", metavar="FILE", default=None,
353 help=_("Input file"))
354 parser.add_option("-c", "--convert", dest="filtername", default=None, metavar="FILTER",
355 help=_("Site")+ " (Absolute, Carbon, Everleaf, Full Tilt Poker, PokerStars, ...)") #TODO: dynamically generate list
356 parser.add_option("-x", "--failOnError", action="store_true", default=False,
357 help=_("If this option is used it quits with an extended error message if it encounters any error"))
358 parser.add_option("-u", "--usage", action="store_true", dest="usage", default=False,
359 help=_("Print some useful one liners"))
360 parser.add_option("-s", "--starsarchive", action="store_true", dest="starsArchive", default=False,
361 help=_("Do the required conversion for %s archive format (ie. as provided by support)") % "PokerStars")
362 parser.add_option("-F", "--ftparchive", action="store_true", dest="ftpArchive", default=False,
363 help=_("Do the required conversion for %s archive format (ie. as provided by support)") % "Full Tilt Poker")
364 parser.add_option("-t", "--testdata", action="store_true", dest="testData", default=False,
365 help=_("Generate and print test data for regression testing"))
366 (options, argv) = parser.parse_args(args = argv)
368 if options.usage == True:
369 #Print usage examples and exit
370 print _("USAGE:")
371 print ('PokerStars ' + _('converter') + ': ./GuiBulkImport.py -c PokerStars -f filename')
372 print ('Full Tilt ' + _('converter') + ': ./GuiBulkImport.py -c "Full Tilt Poker" -f filename')
373 print ('Everleaf ' + _('converter') + ': ./GuiBulkImport.py -c Everleaf -f filename')
374 print ('Absolute ' + _('converter') + ': ./GuiBulkImport.py -c Absolute -f filename')
375 print ('PartyPoker ' + _('converter') + ': ./GuiBulkImport.py -c PartyPoker -f filename')
376 sys.exit(0)
378 config = Configuration.Config()
380 settings = {}
381 if os.name == 'nt': settings['os'] = 'windows'
382 else: settings['os'] = 'linuxmac'
384 settings.update(config.get_db_parameters())
385 settings.update(config.get_import_parameters())
386 settings.update(config.get_default_paths())
388 if not options.filename:
389 i = GuiBulkImport(settings, config, None)
390 main_window = gtk.Window()
391 main_window.connect('destroy', destroy)
392 main_window.add(i.vbox)
393 main_window.show()
394 gtk.main()
395 else:
396 if not options.filtername:
397 print _("You have to select a site with the -c parameter. E.g.:"), "Everleaf converter: ./GuiBulkImport.py -c Everleaf -f filename"
398 #Do something useful
399 importer = fpdb_import.Importer(False,settings, config, None)
400 # importer.setDropIndexes("auto")
401 importer.setDropIndexes(_("don't drop"))
402 importer.setFailOnError(options.failOnError)
403 importer.setThreads(-1)
404 importer.addBulkImportImportFileOrDir(os.path.expanduser(options.filename), site=options.filtername)
405 importer.setCallHud(False)
406 if options.starsArchive:
407 importer.setStarsArchive(True)
408 if options.ftpArchive:
409 importer.setFTPArchive(True)
410 if options.testData:
411 importer.setPrintTestData(True)
412 (stored, dups, partial, errs, ttime) = importer.runImport()
413 importer.clearFileList()
414 print _('Bulk import done: Stored: %d \tDuplicates: %d \tPartial: %d \tErrors: %d in %s seconds - %.0f/sec')\
415 % (stored, dups, partial, errs, ttime, (stored+0.0) / ttime)
418 if __name__ == '__main__':
419 sys.exit(main())