def __unicode__(self): """ Returns a string representation """ if self.end_time is not None: return self.place.name + u" du " + self.start_time.astimezone(tz()).strftime(u"%d/%m/%Y %H:%M") + u" au " + self.end_time.astimezone(tz()).strftime(u"%d/%m/%Y %H:%M") else: return self.place.name + u" du " + self.start_time.astimezone(tz()).strftime(u"%d/%m/%Y %H:%M") + u" à maintenant"
def current_opening(self): """ Return the current opening if any, or None """ now = datetime.now(tz()) try: return self.openings.get(Q(start_time__lte=now, end_time__gt=now) | Q(start_time__lte=now, end_time=None)) except PlaceOpening.DoesNotExist: return None
def process_match_row(row, tournament): try: # Some of them store in decimal (% of day passed). days = int(float(row[1])) seconds = (float(row[1]) % 1) * 86400 # 86400 in 1 day. # hour, minute, second, microsecond time = datetime.time(seconds // 3600, seconds // 60, seconds // 1, seconds % 1) except ValueError: # Otherwise attempt to match "(Day 1 )11:03(:00) AM". strtime = re.match( "^(Day (?P<day>\d+) )?" "(?P<hour>((0?|1)[0-9])|(2[0-3])):(?P<minute>[0-5][0-9])" "(:(?P<second>[0-5][0-9]))? (?P<meridiem>[AP]M)$", row[1], re.IGNORECASE) if strtime: def getint(group): # Helper function: make integer from regex group. val = strtime.group(group) if val is None: return 0 return int(val) # Days are 1-indexed (subtract 1), but None -> 0. # By using max(0, day-1), it can't fall below 0. days = max(0, getint('day') - 1) # Calculate hour before instantiating immutable time(). hour = getint('hour') if strtime.group('meridiem').upper() == "PM" and hour < 12: hour += 12 # No microsecond value available here. time = datetime.time(hour, getint('minute'), getint('second')) else: raise ValueError( _("Couldn't parse timestamp {!r}.").format( row[1])) from None # We can't simply add a timedelta to the start date. # e.g. 11am on the day where daylight savings starts, hours=11 will # actually result in 12pm (2am-3am does not exist). time = datetime.datetime.combine( date + datetime.timedelta(days=days), time) time = tz().localize(time) players = defaultdict(dict) # Each field column is `(field * station) - 1` (zero-indexed). # e.g. A1,A2,B1,B2, etc. (works for any number of stations/fields). for col, team in enumerate(row[3:]): if not team: continue # No team, skip. team = int(team) field = col // len(STATIONS) if field > len(FIELDS): # (Avoids FIELDS[field] IndexError, more details this way.) raise ValueError( _("Field number {0} too large (max {1}) (time {2})."). format(field, len(FIELDS), time.isoformat())) players[field][col % len(STATIONS)] = team if not players: players[0] = {} # Default to first field (no players). elif len(players) > 1: # Warn, but not a breaking error, even if extra supplied. self.stdout.write( self.style.WARNING( _("Splitting simultaneous match (time {}).").format( time.isoformat()))) for field in players: # Now save the objects to the database. number = 1 round = 1 last = Match.objects.filter( tournament=tournament).order_by('number').last() if last is not None: number = last.number + 1 round = last.round # Enum value by index for field. match = Match(tournament=tournament, number=number, round=round, field=FIELDS[field], schedule=time, actual=None) match.full_clean() # Ensure friendly errors. match.save() # Find players that fail full_clean() (duplicate team/round). clean_players = [] dirty_players = [] # "Clean failed." for stn, team in players[field].items(): team = Team.objects.get(number=team) # Get station enum value by index. player = Player(team=team, match=match, station=STATIONS[stn], surrogate=False) try: player.full_clean() # No exceptions, so it's clean. clean_players.append(player) except ValidationError: # Too difficult to ensure correct ValidationError, so # just assume it is. Presumably any db constraints will # restrict all the important things anyway. dirty_players.append(player) # If (players exist, and) all are repeats, then next round. if dirty_players and not clean_players: match.round += 1 match.save() # During setup, no race condition F(...). # Else, make the extras surrogates. else: for p in dirty_players: p.surrogate = True # Finally, save all. clean_players.extend(dirty_players) for p in clean_players: p.full_clean() # Ensure friendly errors. p.save()