Coverage for iPokerSummary.py: 0%

187 statements  

« 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 -*- 

3 

4# Copyright 2008-2011 Carl Gherardi 

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. 

17 

18# import L10n 

19# _ = L10n.get_translation() 

20from HandHistoryConverter import FpdbParseError, FpdbHandPartial 

21from decimal import Decimal 

22import re 

23import logging 

24import datetime 

25from TourneySummary import TourneySummary 

26 

27log = logging.getLogger("parser") 

28 

29 

30class iPokerSummary(TourneySummary): 

31 substitutions = { 

32 "LS": "\$|\xe2\x82\xac|\xe2\u201a\xac|\u20ac|\xc2\xa3|\£|RSD|kr|", 

33 "PLYR": r'(?P<PNAME>[^"]+)', 

34 "NUM": r".,0-9", 

35 "NUM2": r"\b((?:\d{1,3}(?:\s\d{3})*)|(?:\d+))\b", # Regex pattern for matching numbers with spaces 

36 } 

37 currencies = {"€": "EUR", "$": "USD", "": "T$", "£": "GBP", "RSD": "RSD", "kr": "SEK"} 

38 

39 months = { 

40 "Jan": 1, 

41 "Feb": 2, 

42 "Mar": 3, 

43 "Apr": 4, 

44 "May": 5, 

45 "Jun": 6, 

46 "Jul": 7, 

47 "Aug": 8, 

48 "Sep": 9, 

49 "Oct": 10, 

50 "Nov": 11, 

51 "Dec": 12, 

52 } 

53 

54 limits = { 

55 "No limit": "nl", 

56 "Pot limit": "pl", 

57 "Limit": "fl", 

58 "NL": "nl", 

59 "SL": "nl", 

60 "БЛ": "nl", 

61 "PL": "pl", 

62 "LP": "pl", 

63 "L": "fl", 

64 "LZ": "fl", 

65 } 

66 games = { # base, category 

67 "7 Card Stud": ("stud", "studhi"), 

68 "7 Card Stud Hi-Lo": ("stud", "studhilo"), 

69 "7 Card Stud HiLow": ("stud", "studhilo"), 

70 "5 Card Stud": ("stud", "5_studhi"), 

71 "Holdem": ("hold", "holdem"), 

72 "Six Plus Holdem": ("hold", "6_holdem"), 

73 "Omaha": ("hold", "omahahi"), 

74 "Omaha Hi-Lo": ("hold", "omahahilo"), 

75 } 

76 

77 re_Identify = re.compile("<game\sgamecode=") 

78 re_client = re.compile(r"<client_version>(?P<CLIENT>.*?)</client_version>") 

79 re_GameType = re.compile( 

80 r""" 

81 <gametype>(?P<GAME>((?P<CATEGORY>(5|7)\sCard\sStud(\sHi\-Lo)?(\sHiLow)?|(Six\sPlus\s)?Holdem|Omaha(\sHi\-Lo)?(\sHiLow)?)?\s?(?P<LIMIT>NL|SL|L|LZ|PL|БЛ|LP|No\slimit|Pot\slimit|Limit))|LH\s(?P<LSB>[%(NUM)s]+)(%(LS)s)?/(?P<LBB>[%(NUM)s]+)(%(LS)s)?.+?) 

82 (\s(%(LS)s)?(?P<SB>[%(NUM)s]+)(%(LS)s)?/(%(LS)s)?(?P<BB>[%(NUM)s]+))?(%(LS)s)?(\sAnte\s(%(LS)s)?(?P<ANTE>[%(NUM)s]+)(%(LS)s)?)?</gametype>\s+? 

83 <tablename>(?P<TABLE>.+)?</tablename>\s+? 

84 (<(tablecurrency|tournamentcurrency)>.*</(tablecurrency|tournamentcurrency)>\s+?)? 

85 (<smallblind>.+</smallblind>\s+?)? 

86 (<bigblind>.+</bigblind>\s+?)? 

87 <duration>.+</duration>\s+? 

88 <gamecount>.+</gamecount>\s+? 

89 <startdate>(?P<DATETIME>.+)</startdate>\s+? 

90 <currency>(?P<CURRENCY>.+)</currency>\s+? 

91 <nickname>(?P<HERO>.+)</nickname> 

92 """ 

93 % substitutions, 

94 re.MULTILINE | re.VERBOSE, 

95 ) 

96 

97 re_GameInfoTrny = re.compile( 

98 r""" 

99 (?:(<tour(?:nament)?code>(?P<TOURNO>\d+)</tour(?:nament)?code>))| 

100 (?:(<tournamentname>(?P<NAME>[^<]*)</tournamentname>))| 

101 (?:(<rewarddrawn>(?P<REWARD>[%(NUM2)s%(LS)s]+)</rewarddrawn>))|  

102 (?:(<place>(?P<PLACE>.+?)</place>))| 

103 (?:(<buyin>(?P<BIAMT>[%(NUM2)s%(LS)s]+)\s\+\s)?(?P<BIRAKE>[%(NUM2)s%(LS)s]+)\s\+\s(?P<BIRAKE2>[%(NUM2)s%(LS)s]+)</buyin>)| 

104 (?:(<totalbuyin>(?P<TOTBUYIN>.*)</totalbuyin>))| 

105 (?:(<win>(%(LS)s)?(?P<WIN>[%(NUM2)s%(LS)s]+)</win>)) 

106 """ 

107 % substitutions, 

108 re.VERBOSE, 

109 ) 

110 re_GameInfoTrny2 = re.compile( 

111 r""" 

112 (?:(<tour(?:nament)?code>(?P<TOURNO>\d+)</tour(?:nament)?code>))| 

113 (?:(<tournamentname>(?P<NAME>[^<]*)</tournamentname>))| 

114 (?:(<place>(?P<PLACE>.+?)</place>))| 

115 (?:(<buyin>(?P<BIAMT>[%(NUM2)s%(LS)s]+)\s\+\s)?(?P<BIRAKE>[%(NUM2)s%(LS)s]+)</buyin>)| 

116 (?:(<totalbuyin>(?P<TOTBUYIN>[%(NUM2)s%(LS)s]+)</totalbuyin>))| 

117 (?:(<win>(%(LS)s)?(?P<WIN>.+?|[%(NUM2)s%(LS)s]+)</win>)) 

118 """ 

119 % substitutions, 

120 re.VERBOSE, 

121 ) 

122 re_Buyin = re.compile(r"""(?P<BUYIN>[%(NUM)s]+)""" % substitutions, re.MULTILINE | re.VERBOSE) 

123 re_TourNo = re.compile(r"(?P<TOURNO>\d+)$", re.MULTILINE) 

124 re_TotalBuyin = re.compile( 

125 r"""(?P<BUYIN>(?P<BIAMT>[%(LS)s%(NUM)s]+)\s\+\s?(?P<BIRAKE>[%(LS)s%(NUM)s]+)?)""" % substitutions, 

126 re.MULTILINE | re.VERBOSE, 

127 ) 

128 re_DateTime1 = re.compile( 

129 """(?P<D>[0-9]{2})\-(?P<M>[a-zA-Z]{3})\-(?P<Y>[0-9]{4})\s+(?P<H>[0-9]+):(?P<MIN>[0-9]+)(:(?P<S>[0-9]+))?""", 

130 re.MULTILINE, 

131 ) 

132 re_DateTime2 = re.compile( 

133 """(?P<D>[0-9]{2})[\/\.](?P<M>[0-9]{2})[\/\.](?P<Y>[0-9]{4})\s+(?P<H>[0-9]+):(?P<MIN>[0-9]+)(:(?P<S>[0-9]+))?""", 

134 re.MULTILINE, 

135 ) 

136 re_DateTime3 = re.compile( 

137 """(?P<Y>[0-9]{4})\/(?P<M>[0-9]{2})\/(?P<D>[0-9]{2})\s+(?P<H>[0-9]+):(?P<MIN>[0-9]+)(:(?P<S>[0-9]+))?""", 

138 re.MULTILINE, 

139 ) 

140 re_Place = re.compile(r"""(?:(<place>(?P<PLACE>.+?)</place>))""" % substitutions, re.VERBOSE) 

141 re_FPP = re.compile(r"Pts\s") 

142 

143 codepage = ["utf8", "cp1252"] 

144 

145 @staticmethod 

146 def getSplitRe(self, head): 

147 re_SplitTourneys = re.compile("PokerStars Tournament ") 

148 return re_SplitTourneys 

149 

150 def parseSummary(self): 

151 m = self.re_GameType.search(self.summaryText) 

152 if not m: 

153 tmp = self.summaryText[0:200] 

154 log.error(("iPokerSummary.determineGameType: '%s'") % tmp) 

155 raise FpdbParseError 

156 

157 mg = m.groupdict() 

158 # print "DEBUG: m.groupdict(): %s" % mg 

159 

160 if "SB" in mg and mg["SB"] is not None: 

161 tmp = self.summaryText[0:200] 

162 log.error(("iPokerSummary.parseSummary: Text does not appear to be a tournament '%s'") % tmp) 

163 raise FpdbParseError 

164 else: 

165 tourney = True 

166 # self.gametype['limitType'] = 

167 if "GAME" in mg: 

168 if mg["CATEGORY"] is None: 

169 (self.info["base"], self.info["category"]) = ("hold", "5_omahahi") 

170 else: 

171 (self.gametype["base"], self.gametype["category"]) = self.games[mg["CATEGORY"]] 

172 if "LIMIT" in mg: 

173 self.gametype["limitType"] = self.limits[mg["LIMIT"]] 

174 

175 m2 = self.re_DateTime1.search(mg["DATETIME"]) 

176 if m2: 

177 month = self.months[m2.group("M")] 

178 sec = m2.group("S") 

179 if m2.group("S") is None: 

180 sec = "00" 

181 datetimestr = "%s/%s/%s %s:%s:%s" % ( 

182 m2.group("Y"), 

183 month, 

184 m2.group("D"), 

185 m2.group("H"), 

186 m2.group("MIN"), 

187 sec, 

188 ) 

189 self.startTime = datetime.datetime.strptime(datetimestr, "%Y/%m/%d %H:%M:%S") 

190 else: 

191 try: 

192 self.startTime = datetime.datetime.strptime(mg["DATETIME"], "%Y-%m-%d %H:%M:%S") 

193 except ValueError: 

194 date_match = self.re_DateTime2.search(mg["DATETIME"]) 

195 if date_match is not None: 

196 datestr = "%d/%m/%Y %H:%M:%S" if "/" in mg["DATETIME"] else "%d.%m.%Y %H:%M:%S" 

197 if date_match.group("S") is None: 

198 datestr = "%d/%m/%Y %H:%M" 

199 else: 

200 date_match1 = self.re_DateTime3.search(mg["DATETIME"]) 

201 datestr = "%Y/%m/%d %H:%M:%S" 

202 if date_match1 is None: 

203 log.error(("iPokerSummary.parseSummary Could not read datetime")) 

204 raise FpdbParseError 

205 if date_match1.group("S") is None: 

206 datestr = "%Y/%m/%d %H:%M" 

207 self.startTime = datetime.datetime.strptime(mg["DATETIME"], datestr) 

208 

209 if not mg["CURRENCY"] or mg["CURRENCY"] == "fun": 

210 self.buyinCurrency = "play" 

211 else: 

212 self.buyinCurrency = mg["CURRENCY"] 

213 self.currency = self.buyinCurrency 

214 

215 mt = self.re_TourNo.search(mg["TABLE"]) 

216 if mt: 

217 self.tourNo = mt.group("TOURNO") 

218 else: 

219 tourNo = mg["TABLE"].split(",")[-1].strip().split(" ")[0] 

220 if tourNo.isdigit(): 

221 self.tourNo = tourNo 

222 

223 if tourney: 

224 re_client_split = ".".join(self.re_client.split(".")[:2]) 

225 if re_client_split == "23.5": # betclic fr 

226 matches = list(self.re_GameInfoTrny.finditer(self.summaryText)) 

227 if len(matches) > 0: 

228 mg2 = { 

229 "TOURNO": None, 

230 "NAME": None, 

231 "REWARD": None, 

232 "PLACE": None, 

233 "BIAMT": None, 

234 "BIRAKE": None, 

235 "BIRAKE2": None, 

236 "TOTBUYIN": None, 

237 "WIN": None, 

238 } 

239 mg2["TOURNO"] = matches[0].group("TOURNO") 

240 mg2["NAME"] = matches[1].group("NAME") 

241 mg2["REWARD"] = matches[2].group("REWARD") 

242 mg2["PLACE"] = matches[3].group("PLACE") 

243 mg2["BIAMT"] = matches[4].group("BIAMT") 

244 mg2["BIRAKE"] = matches[4].group("BIRAKE") 

245 mg2["BIRAKE2"] = matches[4].group("BIRAKE2") 

246 mg2["TOTBUYIN"] = matches[5].group("TOTBUYIN") 

247 mg2["WIN"] = matches[6].group("WIN") 

248 

249 self.buyin = 0 

250 self.fee = 0 

251 self.prizepool = None 

252 self.entries = None 

253 

254 if mg2["TOURNO"]: 

255 self.tourNo = mg2["TOURNO"] 

256 # if mg2['CURRENCY']: 

257 # self.currency = self.currencies[mg2['CURRENCY']] 

258 rank, winnings = None, None 

259 if "PLACE" in mg2 and self.re_Place.search(mg2["PLACE"]): 

260 rank = int(mg2["PLACE"]) 

261 winnings = int(100 * self.convert_to_decimal(mg2["WIN"])) 

262 

263 self.tourneyName = mg2["NAME"].replace(" " + self.tourNo, "") 

264 

265 if not mg2["BIRAKE"] and mg2["TOTBUYIN"]: 

266 m3 = self.re_TotalBuyin.search(mg2["TOTBUYIN"]) 

267 if m3: 

268 mg2 = m3.groupdict() 

269 elif mg2["BIAMT"]: 

270 mg2["BIRAKE"] = "0" 

271 if mg2["BIAMT"] and mg2["BIRAKE"]: 

272 self.buyin = int(100 * self.convert_to_decimal(mg2["BIAMT"])) 

273 self.fee = int(100 * self.convert_to_decimal(mg2["BIRAKE"])) 

274 if "BIRAKE1" in mg2 and mg2["BIRAKE1"]: 

275 self.buyin += int(100 * self.convert_to_decimal(mg2["BIRAKE1"])) 

276 if self.re_FPP.match(mg2["BIAMT"]): 

277 self.buyinCurrency = "FPP" 

278 else: 

279 self.buyin = 0 

280 self.fee = 0 

281 if self.buyin == 0: 

282 self.buyinCurrency = "FREE" 

283 hero = mg["HERO"] 

284 self.addPlayer(rank, hero, winnings, self.currency, None, None, None) 

285 else: 

286 raise FpdbHandPartial(hid=self.tourNo) 

287 if self.tourNo is None: 

288 log.error(("iPokerSummary.parseSummary: Could Not Parse tourNo")) 

289 raise FpdbParseError 

290 

291 else: 

292 matches = list(self.re_GameInfoTrny2.finditer(self.summaryText)) 

293 if len(matches) > 0: 

294 mg2 = { 

295 "TOURNO": None, 

296 "NAME": None, 

297 "PLACE": None, 

298 "BIAMT": None, 

299 "BIRAKE": None, 

300 "TOTBUYIN": None, 

301 "WIN": None, 

302 } 

303 mg2["TOURNO"] = matches[0].group("TOURNO") 

304 mg2["NAME"] = matches[1].group("NAME") 

305 mg2["PLACE"] = matches[2].group("PLACE") 

306 mg2["BIAMT"] = matches[3].group("BIAMT") 

307 mg2["BIRAKE"] = matches[3].group("BIRAKE") 

308 mg2["TOTBUYIN"] = matches[4].group("TOTBUYIN") 

309 mg2["WIN"] = matches[5].group("WIN") 

310 

311 self.buyin = 0 

312 self.fee = 0 

313 self.prizepool = None 

314 self.entries = None 

315 

316 if mg2["TOURNO"]: 

317 self.tourNo = mg2["TOURNO"] 

318 # if mg2['CURRENCY']: 

319 # self.currency = self.currencies[mg2['CURRENCY']] 

320 rank, winnings = None, None 

321 if "PLACE" in mg2 and mg2["PLACE"] != "N/A": 

322 rank = int(mg2["PLACE"]) 

323 if mg2["WIN"] and mg2["WIN"] != "N/A": 

324 winnings = int(100 * self.convert_to_decimal(mg2["WIN"])) 

325 

326 self.tourneyName = mg2["NAME"].replace(" " + self.tourNo, "") 

327 

328 if not mg2["BIRAKE"] and mg2["TOTBUYIN"]: 

329 m3 = self.re_TotalBuyin.search(mg2["TOTBUYIN"]) 

330 if m3: 

331 mg2 = m3.groupdict() 

332 elif mg2["BIAMT"]: 

333 mg2["BIRAKE"] = "0" 

334 if mg2["BIAMT"] and mg2["BIRAKE"]: 

335 self.buyin = int(100 * self.convert_to_decimal(mg2["BIAMT"])) 

336 self.fee = int(100 * self.convert_to_decimal(mg2["BIRAKE"])) 

337 if "BIRAKE1" in mg2 and mg2["BIRAKE1"]: 

338 self.buyin += int(100 * self.convert_to_decimal(mg2["BIRAKE1"])) 

339 if self.re_FPP.match(mg2["BIAMT"]): 

340 self.buyinCurrency = "FPP" 

341 else: 

342 self.buyin = 0 

343 self.fee = 0 

344 if self.buyin == 0: 

345 self.buyinCurrency = "FREE" 

346 hero = mg["HERO"] 

347 self.addPlayer(rank, hero, winnings, self.currency, None, None, None) 

348 else: 

349 raise FpdbHandPartial(hid=self.tourNo) 

350 if self.tourNo is None: 

351 log.error(("iPokerSummary.parseSummary: Could Not Parse tourNo")) 

352 raise FpdbParseError 

353 else: 

354 tmp = self.summaryText[0:200] 

355 log.error(("iPokerSummary.determineGameType: Text does not appear to be a tournament '%s'") % tmp) 

356 raise FpdbParseError 

357 

358 def convert_to_decimal(self, string): 

359 dec = self.clearMoneyString(string) 

360 m = self.re_Buyin.search(dec) 

361 if m: 

362 dec = Decimal(m.group("BUYIN")) 

363 else: 

364 dec = 0 

365 return dec