Coverage for TourneySummary.py: 0%
206 statements
« prev ^ index » next coverage.py v7.6.3, created at 2024-10-14 11:07 +0000
« prev ^ index » next coverage.py v7.6.3, created at 2024-10-14 11:07 +0000
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
4# Copyright 2009-2011 Stephane Alessio
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.
8#
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.
13#
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"""parses and stores summary sections from e.g. eMail or summary files"""
20# import L10n
21# _ = L10n.get_translation()
23# TODO: check to keep only the needed modules
25import sys
26import logging
28import codecs
30import pprint
31import Database
32from HandHistoryConverter import HandHistoryConverter
35try:
36 import xlrd
37except ImportError:
38 xlrd = None
41log = logging.getLogger("parser")
44class TourneySummary(object):
45 ################################################################
46 # Class Variables
47 UPS = {"a": "A", "t": "T", "j": "J", "q": "Q", "k": "K", "S": "s", "C": "c", "H": "h", "D": "d"} # SAL- TO KEEP ??
48 LCS = {"H": "h", "D": "d", "C": "c", "S": "s"} # SAL- TO KEEP ??
49 SYMBOL = {"USD": "$", "EUR": "$", "T$": "", "play": ""}
50 MS = {"horse": "HORSE", "8game": "8-Game", "hose": "HOSE", "ha": "HA"}
51 SITEIDS = {
52 "Fulltilt": 1,
53 "Full Tilt Poker": 1,
54 "PokerStars": 2,
55 "Everleaf": 3,
56 "Boss": 4,
57 "OnGame": 5,
58 "UltimateBet": 6,
59 "Betfair": 7,
60 "Absolute": 8,
61 "PartyPoker": 9,
62 "PacificPoker": 10,
63 "Partouche": 11,
64 "Merge": 12,
65 "PKR": 13,
66 "iPoker": 14,
67 "Winamax": 15,
68 "Everest": 16,
69 "Cake": 17,
70 "Entraction": 18,
71 "BetOnline": 19,
72 "Microgaming": 20,
73 "Bovada": 21,
74 "Enet": 22,
75 "SealsWithClubs": 23,
76 "WinningPoker": 24,
77 "Run It Once Poker": 26,
78 }
80 def __init__(self, db, config, siteName, summaryText, in_path="-", builtFrom="HHC", header=""):
81 self.db = db
82 self.config = config
83 self.import_parameters = self.config.get_import_parameters()
84 self.siteName = siteName
85 self.siteId = None
86 if siteName in self.SITEIDS:
87 self.siteId = self.SITEIDS[siteName]
88 self.in_path = in_path
89 self.header = header
91 self.summaryText = summaryText
92 self.tourneyName = None
93 self.tourneyTypeId = None
94 self.tourneyId = None
95 self.startTime = None
96 self.endTime = None
97 self.tourNo = None
98 self.currency = None
99 self.buyinCurrency = None
100 self.buyin = 0
101 self.fee = 0
102 self.hero = None
103 self.maxseats = 0
104 self.entries = 0
105 self.speed = "Normal"
106 self.prizepool = 0 # Make it a dict in order to deal (eventually later) with non-money winnings : {'MONEY' : amount, 'OTHER' : Value ??}
107 self.buyInChips = 0
108 self.mixed = None
109 self.isRebuy = False
110 self.isAddOn = False
111 self.isKO = False
112 self.isProgressive = False
113 self.isMatrix = False
114 self.isShootout = False
115 self.isFast = False
116 self.rebuyChips = None
117 self.addOnChips = None
118 self.rebuyCost = 0
119 self.addOnCost = 0
120 self.totalRebuyCount = None
121 self.totalAddOnCount = None
122 self.koBounty = 0
123 self.isSng = False
124 self.stack = "Regular"
125 self.isStep = False
126 self.stepNo = 0
127 self.isChance = False
128 self.chanceCount = 0
129 self.isMultiEntry = False
130 self.isReEntry = False
131 self.isNewToGame = False
132 self.isHomeGame = False
133 self.isSplit = False
134 self.isFifty50 = False
135 self.isTime = False
136 self.timeAmt = 0
137 self.isSatellite = False
138 self.isDoubleOrNothing = False
139 self.isCashOut = False
140 self.isOnDemand = False
141 self.isFlighted = False
142 self.isGuarantee = False
143 self.guaranteeAmt = 0
144 self.added = None
145 self.addedCurrency = None
146 self.gametype = {"category": None, "limitType": None, "mix": "none"}
147 self.players = {}
148 self.comment = None
149 self.commentTs = None
151 # Collections indexed by player names
152 self.playerIds = {}
153 self.tourneysPlayersIds = {}
154 self.ranks = {}
155 self.winnings = {}
156 self.winningsCurrency = {}
157 self.rebuyCounts = {}
158 self.addOnCounts = {}
159 self.koCounts = {}
161 # currency symbol for this summary
162 self.sym = None
164 if builtFrom == "IMAP":
165 # Fix line endings?
166 pass
167 if self.db is None:
168 self.db = Database.Database(config)
170 self.parseSummary()
172 # end def __init__
174 def __str__(self):
175 # TODO : Update
176 vars = (
177 (("SITE"), self.siteName),
178 (("START TIME"), self.startTime),
179 (("END TIME"), self.endTime),
180 (("TOURNEY NAME"), self.tourneyName),
181 (("TOURNEY NO"), self.tourNo),
182 (("TOURNEY TYPE ID"), self.tourneyTypeId),
183 (("TOURNEY ID"), self.tourneyId),
184 (("BUYIN"), self.buyin),
185 (("FEE"), self.fee),
186 (("CURRENCY"), self.currency),
187 (("HERO"), self.hero),
188 (("MAX SEATS"), self.maxseats),
189 (("ENTRIES"), self.entries),
190 (("SPEED"), self.speed),
191 (("PRIZE POOL"), self.prizepool),
192 (("STARTING CHIP COUNT"), self.buyInChips),
193 (("MIXED"), self.mixed),
194 (("REBUY"), self.isRebuy),
195 (("ADDON"), self.isAddOn),
196 (("KO"), self.isKO),
197 (("MATRIX"), self.isMatrix),
198 (("SHOOTOUT"), self.isShootout),
199 (("REBUY CHIPS"), self.rebuyChips),
200 (("ADDON CHIPS"), self.addOnChips),
201 (("REBUY COST"), self.rebuyCost),
202 (("ADDON COST"), self.addOnCost),
203 (("TOTAL REBUYS"), self.totalRebuyCount),
204 (("TOTAL ADDONS"), self.totalAddOnCount),
205 (("KO BOUNTY"), self.koBounty),
206 (("SNG"), self.isSng),
207 (("SATELLITE"), self.isSatellite),
208 (("DOUBLE OR NOTHING"), self.isDoubleOrNothing),
209 (("GUARANTEEAMT"), self.guaranteeAmt),
210 (("ADDED"), self.added),
211 (("ADDED CURRENCY"), self.addedCurrency),
212 (("COMMENT"), self.comment),
213 (("COMMENT TIMESTAMP"), self.commentTs),
214 )
216 structs = (
217 (("PLAYER IDS"), self.playerIds),
218 (("PLAYERS"), self.players),
219 (("TOURNEYS PLAYERS IDS"), self.tourneysPlayersIds),
220 (("RANKS"), self.ranks),
221 (("WINNINGS"), self.winnings),
222 (("WINNINGS CURRENCY"), self.winningsCurrency),
223 (("COUNT REBUYS"), self.rebuyCounts),
224 (("COUNT ADDONS"), self.addOnCounts),
225 (("COUNT KO"), self.koCounts),
226 )
227 str = ""
228 for name, var in vars:
229 str = str + "\n%s = " % name + pprint.pformat(var)
231 for name, struct in structs:
232 str = str + "\n%s =\n" % name + pprint.pformat(struct, 4)
233 return str
235 # end def __str__
237 def getSplitRe(self, head):
238 pass
240 """Function to return a re object to split the summary text into separate tourneys, based on head of file"""
242 def parseSummary(self):
243 pass
245 """should fill the class variables with the parsed information"""
247 def getSummaryText(self):
248 return self.summaryText
250 @staticmethod
251 def clearMoneyString(money):
252 "Renders 'numbers' like '1 200' and '2,000'"
253 money = money.strip("€€\u20ac$ ")
254 return HandHistoryConverter.clearMoneyString(money)
256 def insertOrUpdate(self, printtest=False):
257 # First : check all needed info is filled in the object, especially for the initial select
259 # Notes on DB Insert
260 # Some identified issues for tourneys already in the DB (which occurs when the HH file is parsed and inserted before the Summary)
261 # Be careful on updates that could make the HH import not match the tourney inserted from a previous summary import !!
262 # BuyIn/Fee can be at 0/0 => match may not be easy
263 # Only one existinf Tourney entry for Matrix Tourneys, but multiple Summary files
264 # Starttime may not match the one in the Summary file : HH = time of the first Hand / could be slighltly different from the one in the summary file
265 # Note: If the TourneyNo could be a unique id .... this would really be a relief to deal with matrix matches ==> Ask on the IRC / Ask Fulltilt ??
266 self.db.set_printdata(printtest)
268 self.playerIds = self.db.getSqlPlayerIDs(self.players.keys(), self.siteId, self.hero)
269 # for player in self.players:
270 # id=self.db.get_player_id(self.config, self.siteName, player)
271 # if not id:
272 # id=self.db.insertPlayer(unicode(player), self.siteId)
273 # self.playerIds.update({player:id})
275 # print "TS.insert players",self.players,"playerIds",self.playerIds
276 self.dbid_pids = self.playerIds # TODO:rename this field in Hand so this silly renaming can be removed
278 # print "TS.self before starting insert",self
279 self.tourneyTypeId = self.db.createOrUpdateTourneyType(self)
280 self.tourneyId = self.db.createOrUpdateTourney(self)
281 self.db.createOrUpdateTourneysPlayers(self)
282 self.db.commit()
284 logging.debug(("Tourney Insert/Update done"))
286 # TO DO : Return what has been done (tourney created, updated, nothing)
287 # ?? stored = 1 if tourney is fully created / duplicates = 1, if everything was already here and correct / partial=1 if some things were already here (between tourney, tourneysPlayers and handsPlayers)
288 # if so, prototypes may need changes to know what has been done or make some kind of dict in Tourney object that could be updated during the insert process to store that information
289 stored = 0
290 duplicates = 0
291 partial = 0
292 errors = 0
293 ttime = 0
294 return (stored, duplicates, partial, errors, ttime)
296 def addPlayer(self, rank, name, winnings, winningsCurrency, rebuyCount, addOnCount, koCount, entryId=None):
297 """\
298Adds a player to the tourney, and initialises data structures indexed by player.
299rank (int) indicating the finishing rank (can be -1 if unknown)
300name (string) player name
301winnings (int) the money the player ended the tourney with (can be 0, or -1 if unknown)
302"""
303 log.debug("addPlayer: rank:%s - name : '%s' - Winnings (%s)" % (rank, name, winnings))
304 if self.players.get(name) is not None:
305 if entryId is None:
306 entries = self.players[name][-1]
307 self.players[name].append(entries + 1)
308 elif entryId in self.players[name]:
309 return None
310 else:
311 self.players[name].append(entryId)
312 if rank:
313 self.ranks[name].append(rank)
314 self.winnings[name].append(winnings)
315 self.winningsCurrency[name].append(winningsCurrency)
316 else:
317 self.ranks[name].append(None)
318 self.winnings[name].append(None)
319 self.winningsCurrency[name].append(None)
320 self.rebuyCounts[name].append(None)
321 self.addOnCounts[name].append(None)
322 self.koCounts[name].append(None)
323 else:
324 self.players[name] = [entryId if entryId is not None else 1]
325 if rank:
326 self.ranks.update({name: [rank]})
327 self.winnings.update({name: [winnings]})
328 self.winningsCurrency.update({name: [winningsCurrency]})
329 else:
330 self.ranks.update({name: [None]})
331 self.winnings.update({name: [None]})
332 self.winningsCurrency.update({name: [None]})
333 self.rebuyCounts.update({name: [rebuyCount]})
334 self.addOnCounts.update({name: [addOnCount]})
335 self.koCounts.update({name: [koCount]})
337 # end def addPlayer
339 def writeSummary(self, fh=sys.__stdout__):
340 print("Override me", file=fh)
342 def printSummary(self):
343 self.writeSummary(sys.stdout)
345 @staticmethod
346 def summaries_from_excel(filenameXLS, tourNoField):
347 wb = xlrd.open_workbook(filenameXLS)
348 sh = wb.sheet_by_index(0)
349 summaryTexts, rows, header, keys, entries = [], [], None, None, {}
350 for rownum in range(sh.nrows):
351 if rownum == 0:
352 header = sh.row_values(rownum)[0]
353 elif tourNoField in sh.row_values(rownum):
354 keys = [str(c).encode("utf-8") for c in sh.row_values(rownum)]
355 elif keys is not None:
356 rows.append([str(c).encode("utf-8") for c in sh.row_values(rownum)])
357 for row in rows:
358 data = dict(zip(keys, row))
359 data["header"] = header
360 if len(data[tourNoField]) > 0:
361 if entries.get(data[tourNoField]) is None:
362 entries[data[tourNoField]] = []
363 entries[data[tourNoField]].append(data)
364 for k, item in entries.iteritems():
365 summaryTexts.append(item)
366 return summaryTexts
368 @staticmethod
369 def readFile(self, filename):
370 whole_file = None
371 for kodec in self.codepage:
372 try:
373 in_fh = codecs.open(filename, "r", kodec)
374 whole_file = in_fh.read()
375 in_fh.close()
376 break
377 except UnicodeDecodeError as e:
378 log.warning("TS.readFile: '%s' : '%s'" % (filename, e))
379 except UnicodeError as e:
380 log.warning("TS.readFile: '%s' : '%s'" % (filename, e))
382 return whole_file