#!/usr/bin/python """ The Blue Alliance Python API: Object Portion This module provides object-oriented data from The Blue Alliance. Specifically, It uses the module "tbaWeb" to actually retrieve the data, and organizes that data into objects. """ import tbaWeb, sys, os, os.path import pickle as cPickle baseDir = os.path.abspath('.') cPickleProtocol=0 def setAPIKey(key): tbaWeb.setAPIKey(key) def setBaseDir(path): global baseDir baseDir = os.path.abspath(path) def getRealDir(path): """Internal functions, maps relative path strings to a proper path""" p = path.split('/') rv = os.path.join(baseDir, *p) return rv class TBAID(object): #TODO: Test this class id = '' type = '' data = None def __init__(self, type, id): self.type, self.id = type, id def __get__(self, instance, owner): if self.data is None: #query for the data func, key = {'match':(tbaWeb.getMatches, 'matchid'), 'event':(tbaWeb.getEvents, 'eventid'), 'team':(tbaWeb.getTeams, 'teamNum') }[self.type] d = func(XML=False, **{key: self.id})[0] cls = {'match':Match, 'event':Event, 'team':Team }[self.type] self.data = cls(d) return self.data def __set__(self, instance, val): raise AttributeError, "This object cannot be set. If you think this data \ is wrong, use an appropriate obj.refresh(), or contact The Blue Alliance" class Team(object): #TODO: Test match retrieval #TODO: Change to accept TBA dictionary __teams = {} teamNumber = 0 __matches = None matches = None name = '' nick = '' state = '' country = '' rookieYear = 0 websiteUrl = '' tbaUrl = '' def __new__(cls, teamNum, autoLoadData=True): teamNum = int(teamNum) if cls.__teams.has_key(teamNum): return cls.__teams[teamNum] else: try: self = cls.load(teamNum) return self except: self = super(Team, cls).__new__(cls) cls.__teams[teamNum] = self self.teamNumber = teamNum if autoLoadData: self.initFromTBA() self.matches = property(self.getMatches) return self def initFromTBA(self): data = tbaWeb.getTeams(self.teamNumber, XML=False)[0] self.__setFromTBADict(data) def __setFromTBADict(self, data): self.name = data['name'] self.nick = data['informalname'] self.state = data['state'] self.country = data['country'] self.rookieYear = int( data['rookieyear'] ) self.websiteUrl = data['website'] self.tbaUrl = data['tba_link'] self.__matches = None def __str__(self): return 'Team %s' % self.teamNumber def __repr__(self): return 'Team(%r)' % self.teamNumber def __hash__(self): return self.teamNumber.__hash__() def __int__(self): return self.teamNumber() def refresh(self): self.initFromTBA() def save(self): p = getRealDir('teams/%s.pkl' % str(self.teamNumber)) #if not os.path.exists(p): # os.mknod(p) f = open(p, 'wb') cPickle.dump(self, f, cPickleProtocol) @staticmethod def load(teamNum): p = getRealDir('teams/%s.pkl' % str(teamNum)) assert os.path.exists(p) f = open(p, 'rb') return cPickle.load(f) def __getnewargs__(self): print '__getnewargs__ called' return (self.teamNumber, False) def __getstate__(self): #matches = [m.id for m in self.matches] #TODO: Finish implementing match saving return (self.teamNumber, self.name, self.nick, self.state, self.country, self.rookieYear, self.websiteUrl, self.tbaUrl, self.matches) @classmethod def __setstate__(cls, state): self = cls.__new__(cls, state[0]) self.teamNumber, self.name, self.nick, self.state, self.country, \ self.rookieYear, self.websiteUrl, self.tbaUrl, self.matches = state def _getMatches(self): if self.__matches is None: data = tbaWeb.getMatches(self.teamNumber, XML=False) self.__matches = tuple(Match(d) for d in data) return self.__matches matches = property(_getMatches) class Match(object): __matches = {} __tbadict = {} id = '' redAlliance = None blueAlliance = None finalScore = {'red':0, 'blue':0} matchNumber = 0 matchType = 'Qualifications' event = None tbaUrl = '' videoUrl = '' #TODO: pickle-ing, testing def __new__(cls, *args): #TODO: Construct Match from TBAID, from event/type/num if len(args) == 1 and hasattr(args[0], 'has_key'): #We were given a dictionary only. Assume data from TBA. return cls.__newFromTbaDict(args[0]) @classmethod def __newFromTbaDict(cls, data): matchID = data['matchid'] if cls.__matches.has_key(matchID): self = cls.__matches[matchID] else: self = super(Match, cls).__new__(cls) cls.__matches[matchID] = self self.__initFromTbaDict(self, data) def __initFromTbaDict(self, data): self.id = matchID self.redAlliance = data['red1' ], data['red2' ], data['red3' ] self.blueAlliance = data['blue1'], data['blue2'], data['blue3'] self.finalScore['red'] = data['redscore'] self.finalScore['blue'] = data['bluescore'] self.matchNumber = int( data['matchnumber'] ) self.matchType = data['complevel'] #self.event = TBAID('event', data['eventid']) self.tbaUrl = data['tba_link'] self.videoUrl = data['video_url'] self.__tbadict = data return self class Event(object): #TODO: Write this object pass #TODO: TBAID class (should be descriptor that auto-constructs objects) #TODO: Convert classes to __new__/refresh/__setFromTBADict/__NewFromTBA