diff --git a/pyfpdb/Configuration.py b/pyfpdb/Configuration.py index 0348bc21..d40f37f9 100755 --- a/pyfpdb/Configuration.py +++ b/pyfpdb/Configuration.py @@ -519,6 +519,9 @@ class Config: file = None return file + def get_doc(self): + return self.doc + def get_site_node(self, site): for site_node in self.doc.getElementsByTagName("site"): if site_node.getAttribute("site_name") == site: @@ -553,11 +556,9 @@ class Config: return location_node def save(self, file = None): - if file is not None: - with open(file, 'w') as f: - self.doc.writexml(f) - else: - shutil.move(self.file, self.file+".backup") + if file is None: + file = self.file + shutil.move(file, file+".backup") with open(file, 'w') as f: self.doc.writexml(f) diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py index dbd7afe1..42cd986c 100755 --- a/pyfpdb/Database.py +++ b/pyfpdb/Database.py @@ -1343,7 +1343,9 @@ class Database: q = q.replace('%s', self.sql.query['placeholder']) - self.cursor.execute(q, ( + c = self.connection.cursor() + + c.execute(q, ( p['tableName'], p['gameTypeId'], p['siteHandNo'], @@ -1374,7 +1376,7 @@ class Database: p['street4Pot'], p['showdownPot'] )) - return self.get_last_insert_id(self.cursor) + return self.get_last_insert_id(c) # def storeHand def storeHandsPlayers(self, hid, pids, pdata): @@ -1393,16 +1395,39 @@ class Database: pdata[p]['card6'], pdata[p]['card7'], pdata[p]['winnings'], + pdata[p]['rake'], + pdata[p]['totalProfit'], pdata[p]['street0VPI'], pdata[p]['street1Seen'], pdata[p]['street2Seen'], pdata[p]['street3Seen'], pdata[p]['street4Seen'], + pdata[p]['sawShowdown'], + pdata[p]['wonAtSD'], pdata[p]['street0Aggr'], pdata[p]['street1Aggr'], pdata[p]['street2Aggr'], pdata[p]['street3Aggr'], - pdata[p]['street4Aggr'] + pdata[p]['street4Aggr'], + pdata[p]['street1CBChance'], + pdata[p]['street2CBChance'], + pdata[p]['street3CBChance'], + pdata[p]['street4CBChance'], + pdata[p]['street1CBDone'], + pdata[p]['street2CBDone'], + pdata[p]['street3CBDone'], + pdata[p]['street4CBDone'], + pdata[p]['wonWhenSeenStreet1'], + pdata[p]['street0Calls'], + pdata[p]['street1Calls'], + pdata[p]['street2Calls'], + pdata[p]['street3Calls'], + pdata[p]['street4Calls'], + pdata[p]['street0Bets'], + pdata[p]['street1Bets'], + pdata[p]['street2Bets'], + pdata[p]['street3Bets'], + pdata[p]['street4Bets'], ) ) q = """INSERT INTO HandsPlayers ( @@ -1418,19 +1443,46 @@ class Database: card6, card7, winnings, + rake, + totalProfit, street0VPI, street1Seen, street2Seen, street3Seen, street4Seen, + sawShowdown, + wonAtSD, street0Aggr, street1Aggr, street2Aggr, street3Aggr, - street4Aggr + street4Aggr, + street1CBChance, + street2CBChance, + street3CBChance, + street4CBChance, + street1CBDone, + street2CBDone, + street3CBDone, + street4CBDone, + wonWhenSeenStreet1, + street0Calls, + street1Calls, + street2Calls, + street3Calls, + street4Calls, + street0Bets, + street1Bets, + street2Bets, + street3Bets, + street4Bets ) VALUES ( - %s, %s, + %s, %s, %s, %s, %s, + %s, %s, %s, %s, %s, + %s, %s, %s, %s, %s, + %s, %s, %s, %s, %s, + %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, @@ -1440,11 +1492,8 @@ class Database: # position, # tourneyTypeId, # startCards, -# rake, -# totalProfit, # street0_3BChance, # street0_3BDone, -# sawShowdown, # otherRaisedStreet1, # otherRaisedStreet2, # otherRaisedStreet3, @@ -1453,22 +1502,12 @@ class Database: # foldToOtherRaisedStreet2, # foldToOtherRaisedStreet3, # foldToOtherRaisedStreet4, -# wonWhenSeenStreet1, -# wonAtSD, # stealAttemptChance, # stealAttempted, # foldBbToStealChance, # foldedBbToSteal, # foldSbToStealChance, # foldedSbToSteal, -# street1CBChance, -# street1CBDone, -# street2CBChance, -# street2CBDone, -# street3CBChance, -# street3CBDone, -# street4CBChance, -# street4CBDone, # foldToStreet1CBChance, # foldToStreet1CBDone, # foldToStreet2CBChance, @@ -1485,21 +1524,13 @@ class Database: # street3CheckCallRaiseDone, # street4CheckCallRaiseChance, # street4CheckCallRaiseDone, -# street0Calls, -# street1Calls, -# street2Calls, -# street3Calls, -# street4Calls, -# street0Bets, -# street1Bets, -# street2Bets, -# street3Bets, -# street4Bets q = q.replace('%s', self.sql.query['placeholder']) #print "DEBUG: inserts: %s" %inserts - self.cursor.executemany(q, inserts) + #print "DEBUG: q: %s" % q + c = self.connection.cursor() + c.executemany(q, inserts) def storeHudCacheNew(self, gid, pid, hc): q = """INSERT INTO HudCache ( @@ -1641,6 +1672,15 @@ class Database: # street4CheckCallRaiseChance, # street4CheckCallRaiseDone) + def isDuplicate(self, gametypeID, siteHandNo): + dup = False + c = self.get_cursor() + c.execute(self.sql.query['isAlreadyInDB'], (gametypeID, siteHandNo)) + result = c.fetchall() + if len(result) > 0: + dup = True + return dup + def getGameTypeId(self, siteid, game): c = self.get_cursor() #FIXME: Fixed for NL at the moment @@ -1680,6 +1720,13 @@ class Database: q = "SELECT name, id FROM Players WHERE siteid=%s and name=%s" q = q.replace('%s', self.sql.query['placeholder']) + #NOTE/FIXME?: MySQL has ON DUPLICATE KEY UPDATE + #Usage: + # INSERT INTO `tags` (`tag`, `count`) + # VALUES ($tag, 1) + # ON DUPLICATE KEY UPDATE `count`=`count`+1; + + #print "DEBUG: name: %s site: %s" %(name, site_id) c.execute (q, (site_id, name)) diff --git a/pyfpdb/DerivedStats.py b/pyfpdb/DerivedStats.py index e4d59336..c5575ddc 100644 --- a/pyfpdb/DerivedStats.py +++ b/pyfpdb/DerivedStats.py @@ -18,7 +18,7 @@ #fpdb modules import Card -DEBUG = True +DEBUG = False if DEBUG: import pprint @@ -39,12 +39,24 @@ class DerivedStats(): #Init vars that may not be used, but still need to be inserted. # All stud street4 need this when importing holdem self.handsplayers[player[1]]['winnings'] = 0 + self.handsplayers[player[1]]['rake'] = 0 + self.handsplayers[player[1]]['totalProfit'] = 0 self.handsplayers[player[1]]['street4Seen'] = False self.handsplayers[player[1]]['street4Aggr'] = False + self.handsplayers[player[1]]['wonWhenSeenStreet1'] = False + self.handsplayers[player[1]]['sawShowdown'] = False + self.handsplayers[player[1]]['wonAtSD'] = False + for i in range(5): + self.handsplayers[player[1]]['street%dCalls' % i] = 0 + self.handsplayers[player[1]]['street%dBets' % i] = 0 + for i in range(1,5): + self.handsplayers[player[1]]['street%dCBChance' %i] = False + self.handsplayers[player[1]]['street%dCBDone' %i] = False self.assembleHands(self.hand) self.assembleHandsPlayers(self.hand) + if DEBUG: print "Hands:" pp.pprint(self.hands) @@ -95,33 +107,56 @@ class DerivedStats(): #print "DEBUG: playersAtStreet 1:'%s' 2:'%s' 3:'%s' 4:'%s'" %(self.hands['playersAtStreet1'],self.hands['playersAtStreet2'],self.hands['playersAtStreet3'],self.hands['playersAtStreet4']) self.streetXRaises(hand) # Empty function currently - # comment TEXT, - # commentTs DATETIME - def assembleHandsPlayers(self, hand): #street0VPI/vpip already called in Hand + # sawShowdown is calculated in playersAtStreetX, as that calculation gives us a convenient list of names + #hand.players = [[seat, name, chips],[seat, name, chips]] for player in hand.players: self.handsplayers[player[1]]['seatNo'] = player[0] self.handsplayers[player[1]]['startCash'] = player[2] - # Winnings is a non-negative value of money collected from the pot, which already includes the - # rake taken out. hand.collectees is Decimal, database requires cents - for player in hand.collectees: - self.handsplayers[player]['winnings'] = int(100 * hand.collectees[player]) - for i, street in enumerate(hand.actionStreets[2:]): self.seen(self.hand, i+1) for i, street in enumerate(hand.actionStreets[1:]): self.aggr(self.hand, i) + self.calls(self.hand, i) + self.bets(self.hand, i) - default_holecards = ["Xx", "Xx", "Xx", "Xx"] + # Winnings is a non-negative value of money collected from the pot, which already includes the + # rake taken out. hand.collectees is Decimal, database requires cents + for player in hand.collectees: + self.handsplayers[player]['winnings'] = int(100 * hand.collectees[player]) + #FIXME: This is pretty dodgy, rake = hand.rake/#collectees + # You can really only pay rake when you collect money, but + # different sites calculate rake differently. + # Should be fine for split-pots, but won't be accurate for multi-way pots + self.handsplayers[player]['rake'] = int(100* hand.rake)/len(hand.collectees) + if self.handsplayers[player]['street1Seen'] == True: + self.handsplayers[player]['wonWhenSeenStreet1'] = True + if self.handsplayers[player]['sawShowdown'] == True: + self.handsplayers[player]['wonAtSD'] = True + + for player in hand.pot.committed: + self.handsplayers[player]['totalProfit'] = int(self.handsplayers[player]['winnings'] - (100*hand.pot.committed[player])) + + self.calcCBets(hand) + + #default_holecards = ["Xx", "Xx", "Xx", "Xx"] + #if hand.gametype['base'] == "hold": + # pass + #elif hand.gametype['base'] == "stud": + # pass + #else: + # # Flop hopefully... + # pass for street in hand.holeStreets: for player in hand.players: for i in range(1,8): self.handsplayers[player[1]]['card%d' % i] = 0 - if player[1] in hand.holecards[street].keys(): + #print "DEBUG: hand.holecards[%s]: %s" % (street, hand.holecards[street]) + if player[1] in hand.holecards[street].keys() and hand.gametype['base'] == "hold": self.handsplayers[player[1]]['card1'] = Card.encodeCard(hand.holecards[street][player[1]][1][0]) self.handsplayers[player[1]]['card2'] = Card.encodeCard(hand.holecards[street][player[1]][1][1]) try: @@ -174,7 +209,11 @@ class DerivedStats(): self.hands['playersAtStreet%d' % (i+1)] = len(set.union(alliners, actors)) actions = hand.actions[hand.actionStreets[-1]] - self.hands['playersAtShowdown'] = len(set.union(self.pfba(actions) - self.pfba(actions, l=('folds',)), alliners)) + pas = set.union(self.pfba(actions) - self.pfba(actions, l=('folds',)), alliners) + self.hands['playersAtShowdown'] = len(pas) + + for player in pas: + self.handsplayers[player]['sawShowdown'] = True def streetXRaises(self, hand): # self.actions[street] is a list of all actions in a tuple, contining the action as the second element @@ -188,6 +227,20 @@ class DerivedStats(): for (i, street) in enumerate(hand.actionStreets[1:]): self.hands['street%dRaises' % i] = len(filter( lambda action: action[1] in ('raises','bets'), hand.actions[street])) + def calcCBets(self, hand): + # Continuation Bet chance, action: + # Had the last bet (initiative) on previous street, got called, close street action + # Then no bets before the player with initiatives first action on current street + # ie. if player on street-1 had initiative + # and no donkbets occurred + for i, street in enumerate(hand.actionStreets[2:], start=1): + name = self.lastBetOrRaiser(hand.actionStreets[i]) + if name: + chance = self.noBetsBefore(hand.actionStreets[i+1], name) + self.handsplayers[name]['street%dCBChance' %i] = True + if chance == True: + self.handsplayers[name]['street%dCBDone' %i] = self.betStreet(hand.actionStreets[i+1], name) + def seen(self, hand, i): pas = set() for act in hand.actions[hand.actionStreets[i+1]]: @@ -211,6 +264,20 @@ class DerivedStats(): else: self.handsplayers[player[1]]['street%sAggr' % i] = False + def calls(self, hand, i): + callers = [] + for act in hand.actions[hand.actionStreets[i+1]]: + if act[1] in ('calls'): + self.handsplayers[act[0]]['street%sCalls' % i] = 1 + self.handsplayers[act[0]]['street%sCalls' % i] + + # CG - I'm sure this stat is wrong + # Best guess is that raise = 2 bets + def bets(self, hand, i): + betters = [] + for act in hand.actions[hand.actionStreets[i+1]]: + if act[1] in ('bets'): + self.handsplayers[act[0]]['street%sBets' % i] = 1 + self.handsplayers[act[0]]['street%sBets' % i] + def countPlayers(self, hand): pass @@ -226,3 +293,35 @@ class DerivedStats(): if f is not None and action[1] in f: continue players.add(action[0]) return players + + def noBetsBefore(self, street, player): + """Returns true if there were no bets before the specified players turn, false otherwise""" + betOrRaise = False + for act in self.hand.actions[street]: + #Must test for player first in case UTG + if act[0] == player: + betOrRaise = True + break + if act[1] in ('bets', 'raises'): + break + return betOrRaise + + def betStreet(self, street, player): + """Returns true if player bet/raised the street as their first action""" + betOrRaise = False + for act in self.hand.actions[street]: + if act[0] == player and act[1] in ('bets', 'raises'): + betOrRaise = True + else: + break + return betOrRaise + + + def lastBetOrRaiser(self, street): + """Returns player name that placed the last bet or raise for that street. + None if there were no bets or raises on that street""" + lastbet = None + for act in self.hand.actions[street]: + if act[1] in ('bets', 'raises'): + lastbet = act[0] + return lastbet diff --git a/pyfpdb/GuiPrefs.py b/pyfpdb/GuiPrefs.py new file mode 100755 index 00000000..ada9cb51 --- /dev/null +++ b/pyfpdb/GuiPrefs.py @@ -0,0 +1,169 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +#Copyright 2008 Carl Gherardi +#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 . +#In the "official" distribution you can find the license in +#agpl-3.0.txt in the docs folder of the package. + + +import xml.dom.minidom +from xml.dom.minidom import Node + +import pygtk +pygtk.require('2.0') +import gtk +import gobject + +import Configuration + + +class GuiPrefs: + + def __init__(self, config, mainwin, dia): + self.config = config + self.main_window = mainwin + self.dialog = dia + + self.tree_box = gtk.ScrolledWindow() + self.tree_box.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) + + self.dialog.add(self.tree_box) + self.dialog.show() + + self.doc = None + self.configStore = None + self.configView = None + + self.fillFrames() + + def fillFrames(self): + self.doc = self.config.get_doc() + + self.configStore = gtk.TreeStore(gobject.TYPE_PYOBJECT, gobject.TYPE_STRING, gobject.TYPE_STRING) + self.configView = gtk.TreeView(self.configStore) + self.configView.set_enable_tree_lines(True) + + configColumn = gtk.TreeViewColumn("Setting") + self.configView.append_column(configColumn) + cRender = gtk.CellRendererText() + configColumn.pack_start(cRender, True) + configColumn.add_attribute(cRender, 'text', 1) + + configColumn = gtk.TreeViewColumn("Value") + self.configView.append_column(configColumn) + cRender = gtk.CellRendererText() + configColumn.pack_start(cRender, True) + configColumn.add_attribute(cRender, 'text', 2) + + if self.doc.documentElement.tagName == 'FreePokerToolsConfig': + self.configStore.clear() + self.root = self.configStore.append( None, [self.doc.documentElement, "fpdb", None] ) + for elem in self.doc.documentElement.childNodes: + iter = self.addTreeRows(self.root, elem) + if self.root != None: + self.configView.expand_row(self.configStore.get_path(self.root), False) + self.configView.connect("row-activated", self.rowChosen) + self.configView.show() + self.tree_box.add(self.configView) + self.tree_box.show() + self.dialog.show() + + def addTreeRows(self, parent, node): + if (node.nodeType == node.ELEMENT_NODE): + (setting, value) = (node.nodeName, None) + elif (node.nodeType == node.TEXT_NODE): + # text nodes hold the whitespace (or whatever) between the xml elements, not used here + (setting, value) = ("TEXT: ["+node.nodeValue+"|"+node.nodeValue+"]", node.data) + else: + (setting, value) = ("?? "+node.nodeValue, "type="+str(node.nodeType)) + + #iter = self.configStore.append( parent, [node.nodeValue, None] ) + iter = None + if node.nodeType != node.TEXT_NODE and node.nodeType != node.COMMENT_NODE: + iter = self.configStore.append( parent, [node, setting, value] ) + if node.hasAttributes(): + for i in xrange(node.attributes.length): + self.configStore.append( iter, [node, node.attributes.item(i).localName, node.attributes.item(i).value] ) + if node.hasChildNodes(): + for elem in node.childNodes: + self.addTreeRows(iter, elem) + return iter + + def rowChosen(self, tview, path, something2, data=None): + # tview should= self.configStore + tmodel = tview.get_model() + iter = tmodel.get_iter(path) + if tmodel.iter_has_child(iter): + # toggle children display + if tview.row_expanded(path): + tview.collapse_row(tmodel.get_path(iter)) + else: + tview.expand_row(tmodel.get_path(iter), False) + else: + # display value and allow edit + name = tmodel.get_value( iter, 1 ) + val = tmodel.get_value( iter, 2 ) + dia_edit = gtk.Dialog(name, + self.main_window, + gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, + (gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT, + gtk.STOCK_OK, gtk.RESPONSE_ACCEPT)) + #dia_edit.set_default_size(350, 100) + entry = gtk.Entry() + if val: + entry.set_text(val) + entry.set_width_chars(40) + dia_edit.vbox.pack_start(entry, False, False, 0) + entry.show() + entry.connect("activate", self.__set_entry, dia_edit) + response = dia_edit.run() + if response == gtk.RESPONSE_ACCEPT: + # update configStore + new_val = entry.get_text() + tmodel.set_value(iter, 2, new_val) + tmodel.get_value(iter, 0).setAttribute(name, new_val) + dia_edit.destroy() + + def __set_entry(self, w, dia=None): + if dia is not None: + dia.response(gtk.RESPONSE_ACCEPT) + + + +if __name__=="__main__": + + config = Configuration.Config() + + win = gtk.Window(gtk.WINDOW_TOPLEVEL) + win.set_title("Test Preferences Dialog") + win.set_border_width(1) + win.set_default_size(600, 500) + win.set_resizable(True) + + dia = gtk.Dialog("Preferences", + win, + gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, + (gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT, + gtk.STOCK_SAVE, gtk.RESPONSE_ACCEPT)) + dia.set_default_size(500, 500) + prefs = GuiPrefs(config, win, dia.vbox) + response = dia.run() + if response == gtk.RESPONSE_ACCEPT: + # save updated config + config.save() + dia.destroy() + + + + diff --git a/pyfpdb/Hand.py b/pyfpdb/Hand.py index a5ea87ec..f6fa478e 100644 --- a/pyfpdb/Hand.py +++ b/pyfpdb/Hand.py @@ -210,24 +210,24 @@ db: a connected fpdb_db object""" ##### # End prep functions ##### - - # HandsActions - all actions for all players for all streets - self.actions - # HudCache data can be generated from HandsActions (HandsPlayers?) - - # Hands - Summary information of hand indexed by handId - gameinfo hh = self.stats.getHands() - hh['gameTypeId'] = gtid - # seats TINYINT NOT NULL, - hh['seats'] = len(sqlids) - #print hh - handid = db.storeHand(hh) - # HandsPlayers - ? ... Do we fix winnings? - db.storeHandsPlayers(handid, sqlids, self.stats.getHandsPlayers()) - # Tourneys ? - # TourneysPlayers + if not db.isDuplicate(gtid, hh['siteHandNo']): + # Hands - Summary information of hand indexed by handId - gameinfo + hh['gameTypeId'] = gtid + # seats TINYINT NOT NULL, + hh['seats'] = len(sqlids) - pass + handid = db.storeHand(hh) + db.storeHandsPlayers(handid, sqlids, self.stats.getHandsPlayers()) + # HandsActions - all actions for all players for all streets - self.actions + # HudCache data can be generated from HandsActions (HandsPlayers?) + # Tourneys ? + # TourneysPlayers + else: + log.info("Hand.insert(): hid #: %s is a duplicate" % hh['siteHandNo']) + #Raise Duplicate exception? + pass def select(self, handId): """ Function to create Hand object from database """ diff --git a/pyfpdb/HandHistoryConverter.py b/pyfpdb/HandHistoryConverter.py index a662ca79..804b3534 100644 --- a/pyfpdb/HandHistoryConverter.py +++ b/pyfpdb/HandHistoryConverter.py @@ -94,7 +94,7 @@ follow : whether to tail -f the input""" else: log.info("Created directory '%s'" % out_dir) try: - self.out_fh = codecs.open(self.out_path, 'w', 'cp1252') + self.out_fh = codecs.open(self.out_path, 'w', 'utf8') except: log.error("out_path %s couldn't be opened" % (self.out_path)) else: diff --git a/pyfpdb/fpdb.py b/pyfpdb/fpdb.py index d0a5b815..80d3fb93 100755 --- a/pyfpdb/fpdb.py +++ b/pyfpdb/fpdb.py @@ -69,6 +69,7 @@ import gtk import interlocks +import GuiPrefs import GuiBulkImport import GuiPlayerStats import GuiPositionalStats @@ -146,6 +147,20 @@ class fpdb: dia.run() dia.destroy() + def dia_preferences(self, widget, data=None): + dia = gtk.Dialog("Preferences", + self.window, + gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, + (gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT, + gtk.STOCK_SAVE, gtk.RESPONSE_ACCEPT)) + dia.set_default_size(500, 500) + prefs = GuiPrefs.GuiPrefs(self.config, self.window, dia.vbox) + response = dia.run() + if response == gtk.RESPONSE_ACCEPT: + # save updated config + self.config.save() + dia.destroy() + def dia_create_del_database(self, widget, data=None): self.warning_box("Unimplemented: Create/Delete Database") self.obtain_global_lock() @@ -350,6 +365,7 @@ class fpdb: + @@ -396,6 +412,7 @@ class fpdb: ('LoadProf', None, '_Load Profile (broken)', 'L', 'Load your profile', self.dia_load_profile), ('EditProf', None, '_Edit Profile (todo)', 'E', 'Edit your profile', self.dia_edit_profile), ('SaveProf', None, '_Save Profile (todo)', 'S', 'Save your profile', self.dia_save_profile), + ('Preferences', None, '_Preferences', None, 'Edit your preferences', self.dia_preferences), ('import', None, '_Import'), ('sethharchive', None, '_Set HandHistory Archive Directory', None, 'Set HandHistory Archive Directory', self.select_hhArchiveBase), ('bulkimp', None, '_Bulk Import', 'B', 'Bulk Import', self.tab_bulk_import), diff --git a/pyfpdb/test_Database.py b/pyfpdb/test_Database.py index b348f741..25bd6dbc 100644 --- a/pyfpdb/test_Database.py +++ b/pyfpdb/test_Database.py @@ -64,5 +64,4 @@ def testSQLiteModFunction(): assert vars[idx]%13 == int(i[0]) idx = idx+1 - assert 0 == 1 cur.execute("DROP TABLE test")