<commit_before>import webapp2
import json

from generic_handler import GenericHandler
from google.appengine.api import users
from google.appengine.ext import ndb
from handler_utils import is_int
from handler_utils import GetPairIdFromRequest
from handler_utils import GetTourneyWithIdAndMaybeReturnStatus
from handler_utils import SetErrorStatus
from models import HandScore
from models import PlayerPair
from models import Tournament
from movements import Movement


class MovementHandler(GenericHandler):
  ''' Class to handle requests to /api/tournaments/:id/movement/:pair_no '''

  def get(self, id, pair_no):
    ''' Fetch movement for tournament with id and team pair_no. 

    Args:
      id: String. Tournament id. 
      pair_no: Integer. Pair number for the team whose movement we're getting.

    See api for request and response documentation.
    '''
    tourney = GetTourneyWithIdAndMaybeReturnStatus(self.response, id)
    if not tourney:
      return

    if not self._CheckValidPairMaybeSetStatus(tourney, pair_no):
      return

    player_pair = PlayerPair.GetByPairNo(tourney, int(pair_no))
    if not player_pair:
      SetErrorStatus(self.response, 404, "Invalid Request",
                     "Player pair {} not in tournament".format(pair_no))
      return

    if not self._CheckUserAllowedToSeeMovementMaybeSetStatus(
        tourney, player_pair):
      return

    no_hands_per_round, no_rounds = Movement.NumBoardsPerRoundFromTotal(
        tourney.no_pairs, tourney.no_boards)
    try:
      movement = Movement.CreateMovement(
          tourney.no_pairs, no_hands_per_round, no_rounds).GetMovement(
              int(pair_no))
    except ValueError:
      SetErrorStatus(self.response, 500, "Corrupted Data",
                     "No valid movement for this tourney's config")
      return

    movement_list = []
    for round in movement:
      movement_list.append(
          self._GetJsonRoundWithScore(round, tourney, int(pair_no)))

    combined_dict = {
      'name' : tourney.name,
      'players' : player_pair.player_list(),
      'movement': movement_list
    }

    self.response.headers['Content-Type'] = 'application/json'
    self.response.set_status(200)
    self.response.out.write(json.dumps(combined_dict, indent=2))

  def _GetJsonRoundWithScore(self, round, tourney, pair_no):
    ''' Converts round information to a json interpretable string adding 
    scored hands if any exist.

    Args:
      round: MovementRound. Contains all player/hand information about a specific
        matchup from the point of view of Pair pair_no. 
      tourney: Tournament. Tournament in which this is happening.
      pair_no: Pair from whose point of view this movement is seen.

    Returns:
      Dict as expected by api. Includes any scores that have already been added.
    '''
    hands = round.hands
    round_str = round.to_dict()
    if hands:
      del round_str['hands']
    for h in hands:
      if round.is_north:
        hand_score = HandScore.GetByHandParams(tourney, h, pair_no, 
                                               round.opponent)
      else:
        hand_score = HandScore.GetByHandParams(tourney, h, round.opponent,
                                               pair_no)
      if hand_score:
        round_str.setdefault('hands', []).append({
          'hand_no' : h,
          'score': {
              'calls' : hand_score.calls_dict(),
              'ns_score' : hand_score.ns_score,
              'ew_score' : hand_score.ew_score,
              'notes' : hand_score.notes,
        }})
      else:
        round_str.setdefault('hands', []).append({ 'hand_no' : h })
    return round_str

  def _CheckValidPairMaybeSetStatus(self, tourney, pair_no):
    ''' Test if the provided pair number is valid for tourney. 

    Args:
      tourney: Tournament. Tournament the pair number is being validated for.
      pair_no: Integer. Pair number for the team we are validating.
    '''
    error = "Invalid Input"
    if (not is_int(pair_no)) or int(pair_no) < 1 or int(pair_no) > tourney.no_pairs:
      SetErrorStatus(self.response, 404, error,
                     "Pair number {} is invalid".format(pair_no))
      return False<commit_msg>Fix E positioning in movements page<commit_after>import webapp2
import json

from generic_handler import GenericHandler
from google.appengine.api import users
from google.appengine.ext import ndb
from handler_utils import is_int
from handler_utils import GetPairIdFromRequest
from handler_utils import GetTourneyWithIdAndMaybeReturnStatus
from handler_utils import SetErrorStatus
from models import HandScore
from models import PlayerPair
from models import Tournament
from movements import Movement


class MovementHandler(GenericHandler):
  ''' Class to handle requests to /api/tournaments/:id/movement/:pair_no '''

  def get(self, id, pair_no):
    ''' Fetch movement for tournament with id and team pair_no. 

    Args:
      id: String. Tournament id. 
      pair_no: Integer. Pair number for the team whose movement we're getting.

    See api for request and response documentation.
    '''
    tourney = GetTourneyWithIdAndMaybeReturnStatus(self.response, id)
    if not tourney:
      return

    if not self._CheckValidPairMaybeSetStatus(tourney, pair_no):
      return

    player_pair = PlayerPair.GetByPairNo(tourney, int(pair_no))
    if not player_pair:
      SetErrorStatus(self.response, 404, "Invalid Request",
                     "Player pair {} not in tournament".format(pair_no))
      return

    if not self._CheckUserAllowedToSeeMovementMaybeSetStatus(
        tourney, player_pair):
      return

    no_hands_per_round, no_rounds = Movement.NumBoardsPerRoundFromTotal(
        tourney.no_pairs, tourney.no_boards)
    try:
      movement = Movement.CreateMovement(
          tourney.no_pairs, no_hands_per_round, no_rounds).GetMovement(
              int(pair_no))
    except ValueError:
      SetErrorStatus(self.response, 500, "Corrupted Data",
                     "No valid movement for this tourney's config")
      return

    movement_list = []
    for round in movement:
      movement_list.append(
          self._GetJsonRoundWithScore(round, tourney, int(pair_no)))

    combined_dict = {
      'name' : tourney.name,
      'players' : player_pair.player_list(),
      'movement': movement_list
    }

    self.response.headers['Content-Type'] = 'application/json'
    self.response.set_status(200)
    self.response.out.write(json.dumps(combined_dict, indent=2))

  def _GetJsonRoundWithScore(self, round, tourney, pair_no):
    ''' Converts round information to a json interpretable string adding 
    scored hands if any exist.

    Args:
      round: MovementRound. Contains all player/hand information about a specific
        matchup from the point of view of Pair pair_no. 
      tourney: Tournament. Tournament in which this is happening.
      pair_no: Pair from whose point of view this movement is seen.

    Returns:
      Dict as expected by api. Includes any scores that have already been added.
    '''
    hands = round.hands
    round_str = round.to_dict()
    if hands:
      del round_str['hands']
    for h in hands:
      if round.is_north:
        hand_score = HandScore.GetByHandParams(tourney, h, pair_no, 
                                               round.opponent)
      else:
        hand_score = HandScore.GetByHandParams(tourney, h, round.opponent,
                                               pair_no)
      if hand_score:
        round_str.setdefault('hands', []).append({
          'hand_no' : h,
          'score': {
              'calls' : hand_score.calls_dict(),
              'ns_score' : hand_score.get_ns_score(),
              'ew_score' : hand_score.get_ew_score(),
              'notes' : hand_score.notes,
        }})
      else:
        round_str.setdefault('hands', []).append({ 'hand_no' : h })
    return round_str

  def _CheckValidPairMaybeSetStatus(self, tourney, pair_no):
    ''' Test if the provided pair number is valid for tourney. 

    Args:
      tourney: Tournament. Tournament the pair number is being validated for.
      pair_no: Integer. Pair number for the team we are validating.
    '''
    error = "Invalid Input"
    if (not is_int(pair_no)) or int(pair_no) < 1 or int(pair_no) > tourney.no_pairs:
      SetErrorStatus(self.response, 404, error,
                     "Pair number {} is invalid".format(pair_no))
      return False
{'fraction_non_alphanumeric': 0.08072916666666667, 'fraction_numerical': 0.0035511363636363635, 'mean_word_length': 2.7517761989342806, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 8, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '785756', 'n_tokens_mistral': 2483, 'n_tokens_neox': 2369, 'n_words': 698}