2008-08-04 05:44:28 +02:00
#!/usr/bin/python
#Copyright 2008 Steffen Jobbagy-Felso
#This program is free software: you can redistribute it and/or modify
#it under the terms of the GNU Affero General Public License as published by
#the Free Software Foundation, version 3 of the License.
#
#This program is distributed in the hope that it will be useful,
#but WITHOUT ANY WARRANTY; without even the implied warranty of
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
#GNU General Public License for more details.
#
#You should have received a copy of the GNU Affero General Public License
#along with this program. If not, see <http://www.gnu.org/licenses/>.
#In the "official" distribution you can find the license in
#agpl-3.0.txt in the docs folder of the package.
#see status.txt for site/games support info
import sys
2008-09-16 23:19:50 +02:00
try :
import MySQLdb
mysqlLibFound = True
except :
pass
try :
import psycopg2
pgsqlLibFound = True
except :
pass
2008-08-04 05:44:28 +02:00
import math
import os
import datetime
import fpdb_simple
import fpdb_parse_logic
2008-10-16 21:15:28 +02:00
from optparse import OptionParser
2008-10-09 20:18:54 +02:00
from time import time
2008-08-04 05:44:28 +02:00
2008-10-08 19:36:08 +02:00
class Importer :
2008-08-04 05:44:28 +02:00
2008-10-16 21:15:28 +02:00
def __init__ ( self ) :
2008-10-08 19:36:08 +02:00
""" Constructor """
2008-10-16 21:15:28 +02:00
self . settings = { ' imp-callFpdbHud ' : False }
2008-10-09 18:13:56 +02:00
self . db = None
self . cursor = None
2008-10-16 21:15:28 +02:00
self . options = None
2008-10-09 19:21:01 +02:00
self . callHud = False
2008-10-09 20:18:54 +02:00
self . lines = None
2008-10-10 19:42:09 +02:00
self . pos_in_file = { } # dict to remember how far we have read in the file
2008-10-08 19:36:08 +02:00
2008-10-16 21:15:28 +02:00
def dbConnect ( self , options , settings ) :
2008-08-04 05:44:28 +02:00
#connect to DB
2008-10-16 21:15:28 +02:00
if settings [ ' db-backend ' ] == 2 :
2008-09-16 23:19:50 +02:00
if not mysqlLibFound :
raise fpdb_simple . FpdbError ( " interface library MySQLdb not found but MySQL selected as backend - please install the library or change the config file " )
2008-10-16 21:15:28 +02:00
self . db = MySQLdb . connect ( host = options . server , user = options . user ,
passwd = options . password , db = options . database )
elif settings [ ' db-backend ' ] == 3 :
2008-09-16 23:19:50 +02:00
if not pgsqlLibFound :
raise fpdb_simple . FpdbError ( " interface library psycopg2 not found but PostgreSQL selected as backend - please install the library or change the config file " )
2008-10-16 21:15:28 +02:00
self . db = psycopg2 . connect ( host = options . server , user = options . user ,
password = options . password , database = options . database )
elif settings [ ' db-backend ' ] == 4 :
2008-09-15 22:31:55 +02:00
pass
else :
pass
2008-10-09 18:13:56 +02:00
self . cursor = self . db . cursor ( )
2008-10-09 19:21:01 +02:00
def setCallHud ( self , value ) :
self . callHud = value
2008-10-16 21:15:28 +02:00
def import_file_dict ( self , options , settings ) :
2008-10-09 20:18:54 +02:00
starttime = time ( )
2008-10-09 18:13:56 +02:00
last_read_hand = 0
2008-10-10 19:42:09 +02:00
loc = 0
2008-10-16 21:15:28 +02:00
if ( options . inputFile == " stdin " ) :
2008-10-09 18:13:56 +02:00
inputFile = sys . stdin
else :
2008-10-16 21:15:28 +02:00
inputFile = open ( options . inputFile , " rU " )
try : loc = self . pos_in_file [ options . inputFile ]
2008-10-10 19:42:09 +02:00
except : pass
2008-10-09 18:13:56 +02:00
2008-10-16 21:15:28 +02:00
self . dbConnect ( options , settings )
2008-10-09 20:18:54 +02:00
# Read input file into class and close file
2008-10-10 19:42:09 +02:00
inputFile . seek ( loc )
2008-10-09 20:18:54 +02:00
self . lines = fpdb_simple . removeTrailingEOL ( inputFile . readlines ( ) )
2008-10-16 21:15:28 +02:00
self . pos_in_file [ options . inputFile ] = inputFile . tell ( )
2008-10-09 20:18:54 +02:00
inputFile . close ( )
firstline = self . lines [ 0 ]
if firstline . find ( " Tournament Summary " ) != - 1 :
2008-09-22 23:48:12 +02:00
print " TODO: implement importing tournament summaries "
2008-10-16 21:15:28 +02:00
self . cursor . close ( )
self . db . close ( )
2008-09-22 23:48:12 +02:00
return 0
2008-10-09 20:18:54 +02:00
site = fpdb_simple . recogniseSite ( firstline )
category = fpdb_simple . recogniseCategory ( firstline )
2008-08-04 05:44:28 +02:00
startpos = 0
stored = 0 #counter
duplicates = 0 #counter
partial = 0 #counter
errors = 0 #counter
2008-10-09 20:18:54 +02:00
for i in range ( len ( self . lines ) ) : #main loop, iterates through the lines of a file and calls the appropriate parser method
if ( len ( self . lines [ i ] ) < 2 ) :
2008-08-04 05:44:28 +02:00
endpos = i
2008-10-09 20:18:54 +02:00
hand = self . lines [ startpos : endpos ]
2008-08-04 05:44:28 +02:00
if ( len ( hand [ 0 ] ) < 2 ) :
hand = hand [ 1 : ]
cancelled = False
damaged = False
if ( site == " ftp " ) :
for i in range ( len ( hand ) ) :
if ( hand [ i ] . endswith ( " has been canceled " ) ) : #this is their typo. this is a typo, right?
cancelled = True
seat1 = hand [ i ] . find ( " Seat " ) #todo: make this recover by skipping this line
if ( seat1 != - 1 ) :
if ( hand [ i ] . find ( " Seat " , seat1 + 3 ) != - 1 ) :
damaged = True
if ( len ( hand ) < 3 ) :
pass
2008-10-09 20:53:57 +02:00
#todo: the above 2 lines are kind of a dirty hack, the mentioned circumstances should be handled elsewhere but that doesnt work with DOS/Win EOL. actually this doesnt work.
2008-08-04 05:44:28 +02:00
elif ( hand [ 0 ] . endswith ( " (partial) " ) ) : #partial hand - do nothing
partial + = 1
elif ( hand [ 1 ] . find ( " Seat " ) == - 1 and hand [ 2 ] . find ( " Seat " ) == - 1 and hand [ 3 ] . find ( " Seat " ) == - 1 ) : #todo: should this be or instead of and?
partial + = 1
elif ( cancelled or damaged ) :
partial + = 1
else : #normal processing
2008-08-18 08:43:05 +02:00
isTourney = fpdb_simple . isTourney ( hand [ 0 ] )
if not isTourney :
fpdb_simple . filterAnteBlindFold ( site , hand )
hand = fpdb_simple . filterCrap ( site , hand , isTourney )
2008-10-16 21:15:28 +02:00
2008-08-04 05:44:28 +02:00
try :
2008-10-09 18:13:56 +02:00
handsId = fpdb_parse_logic . mainParser ( self . db , self . cursor , site , category , hand )
self . db . commit ( )
2008-08-18 16:41:34 +02:00
2008-08-04 05:44:28 +02:00
stored + = 1
2008-10-09 18:13:56 +02:00
self . db . commit ( )
2008-10-09 19:21:01 +02:00
# if settings['imp-callFpdbHud'] and self.callHud and os.sep=='/':
2008-10-16 21:15:28 +02:00
if settings [ ' imp-callFpdbHud ' ] and self . callHud :
2008-08-22 22:10:32 +02:00
#print "call to HUD here. handsId:",handsId
2008-08-31 04:06:24 +02:00
#pipe the Hands.id out to the HUD
2008-10-16 21:15:28 +02:00
# options.pipe_to_hud.write("%s" % (handsId) + os.linesep)
print " handsID = " , handsID
options . pipe_to_hud . stdin . write ( " %s " % ( handsId ) + os . linesep )
2008-08-04 05:44:28 +02:00
except fpdb_simple . DuplicateError :
duplicates + = 1
except ( ValueError ) , fe :
errors + = 1
2008-10-16 21:15:28 +02:00
self . printEmailErrorMessage ( errors , options . inputFile , hand [ 0 ] )
2008-10-09 20:36:12 +02:00
2008-10-16 21:15:28 +02:00
if ( options . failOnError ) :
self . db . commit ( ) #dont remove this, in case hand processing was cancelled this ties up any open ends.
self . cursor . close ( )
self . db . close ( )
2008-08-04 05:44:28 +02:00
raise
except ( fpdb_simple . FpdbError ) , fe :
errors + = 1
2008-10-16 21:15:28 +02:00
self . printEmailErrorMessage ( errors , options . inputFile , hand [ 0 ] )
2008-10-09 20:36:12 +02:00
2008-08-04 05:44:28 +02:00
#fe.printStackTrace() #todo: get stacktrace
2008-10-09 18:13:56 +02:00
self . db . rollback ( )
2008-08-04 05:44:28 +02:00
2008-10-16 21:15:28 +02:00
if ( options . failOnError ) :
self . db . commit ( ) #dont remove this, in case hand processing was cancelled this ties up any open ends.
self . cursor . close ( )
self . db . close ( )
2008-08-04 05:44:28 +02:00
raise
2008-10-16 21:15:28 +02:00
if ( options . minPrint != 0 ) :
if ( ( stored + duplicates + partial + errors ) % options . minPrint == 0 ) :
2008-08-04 05:44:28 +02:00
print " stored: " , stored , " duplicates: " , duplicates , " partial: " , partial , " errors: " , errors
2008-10-16 21:15:28 +02:00
if ( options . handCount != 0 ) :
if ( ( stored + duplicates + partial + errors ) > = options . handCount ) :
if ( not options . quiet ) :
2008-08-04 05:44:28 +02:00
print " quitting due to reaching the amount of hands to be imported "
2008-10-09 20:18:54 +02:00
print " Total stored: " , stored , " duplicates: " , duplicates , " partial/damaged: " , partial , " errors: " , errors , " time: " , ( time ( ) - starttime )
2008-08-04 05:44:28 +02:00
sys . exit ( 0 )
startpos = endpos
2008-10-09 20:18:54 +02:00
print " Total stored: " , stored , " duplicates: " , duplicates , " partial: " , partial , " errors: " , errors , " time: " , ( time ( ) - starttime )
2008-08-04 05:44:28 +02:00
2008-10-09 08:17:18 +02:00
if stored == 0 :
if duplicates > 0 :
2008-10-09 20:18:54 +02:00
for line_no in range ( len ( self . lines ) ) :
if self . lines [ line_no ] . find ( " Game # " ) != - 1 :
final_game_line = self . lines [ line_no ]
2008-10-09 08:17:18 +02:00
handsId = fpdb_simple . parseSiteHandNo ( final_game_line )
else :
print " failed to read a single hand from file: " , inputFile
handsId = 0
#todo: this will cause return of an unstored hand number if the last hand was error or partial
2008-10-09 18:13:56 +02:00
self . db . commit ( )
2008-10-16 21:15:28 +02:00
self . cursor . close ( )
self . db . close ( )
2008-08-19 00:53:25 +02:00
return handsId
2008-10-09 08:17:18 +02:00
#end def import_file_dict
2008-08-04 05:44:28 +02:00
2008-10-09 20:36:12 +02:00
def printEmailErrorMessage ( self , errors , filename , line ) :
print " Error No. " , errors , " , please send the hand causing this to steffen@sycamoretest.info so I can fix it. "
2008-10-16 21:15:28 +02:00
print " Filename: " , options . inputFile
2008-10-09 20:36:12 +02:00
print " Here is the first line so you can identify it. Please mention that the error was a ValueError: "
2008-10-16 21:15:28 +02:00
print hand [ 0 ]
2008-10-09 20:36:12 +02:00
2008-08-04 05:44:28 +02:00
if __name__ == " __main__ " :
2008-10-08 19:48:16 +02:00
print " CLI for fpdb_import is currently on vacation please check in later "