<commit_before># This is a very simple implementation of the UCT Monte Carlo Tree Search algorithm in Python 2.7.
# The function UCT(rootstate, itermax, verbose = False) is towards the bottom of the code.
# It aims to have the clearest and simplest possible code, and for the sake of clarity, the code
# is orders of magnitude less efficient than it could be made, particularly by using a
# state.GetRandomMove() or state.DoRandomRollout() function.
#
# Example GameState classes for Nim, OXO and Othello are included to give some idea of how you
# can write your own GameState use UCT in your 2-player game. Change the game to be played in
# the UCTPlayGame() function at the bottom of the code.
#
# Written by Peter Cowling, Ed Powley, Daniel Whitehouse (University of York, UK) September 2012.
#
# Licence is granted to freely use and distribute for any sensible/legal purpose so long as this comment
# remains in any distributed code.
#
# For more information about Monte Carlo Tree Search check out our web site at www.mcts.ai

from math import *
import random
import time
from tests.testing_utils import generate_game_for
from hearthbreaker.cards import *
from hearthbreaker.agents.basic_agents import DoNothingBot
from hearthbreaker.game_objects import *

class HearthState:
    """ A state of the game, i.e. the game board.
    """
    def __init__(self):
        self.playerJustMoved = 2 # At the root pretend the player just moved is p2 - p1 has the first move
        #deck1 = [GoldshireFootman, GoldshireFootman, MurlocRaider, MurlocRaider, BloodfenRaptor, BloodfenRaptor,
        #         FrostwolfGrunt, FrostwolfGrunt, RiverCrocolisk, RiverCrocolisk, IronfurGrizzly, IronfurGrizzly,
        #         MagmaRager, MagmaRager, SilverbackPatriarch, SilverbackPatriarch, ChillwindYeti, ChillwindYeti,
        #         OasisSnapjaw, OasisSnapjaw, SenjinShieldmasta, SenjinShieldmasta, BootyBayBodyguard, BootyBayBodyguard,
        #         FenCreeper, FenCreeper, BoulderfistOgre, BoulderfistOgre, WarGolem, WarGolem]
        #deck2 = [GoldshireFootman, GoldshireFootman, MurlocRaider, MurlocRaider, BloodfenRaptor, BloodfenRaptor,
        #         FrostwolfGrunt, FrostwolfGrunt, RiverCrocolisk, RiverCrocolisk, IronfurGrizzly, IronfurGrizzly,
        #         MagmaRager, MagmaRager, SilverbackPatriarch, SilverbackPatriarch, ChillwindYeti, ChillwindYeti,
        #         OasisSnapjaw, OasisSnapjaw, SenjinShieldmasta, SenjinShieldmasta, BootyBayBodyguard, BootyBayBodyguard,
        #         FenCreeper, FenCreeper, BoulderfistOgre, BoulderfistOgre, WarGolem, WarGolem]
        deck1 = RiverCrocolisk
        #deck1 = [Innervate, Innervate, WildGrowth, WildGrowth, Wrath, Wrath]
        #deck1 = Soulfire
        #deck1 = [Soulfire, Soulfire, MortalCoil, MortalCoil]
        deck2 = RiverCrocolisk
        game = generate_game_for(deck1, deck2, DoNothingBot, DoNothingBot)
        game._start_turn()
        self.game = game

    def Clone(self):
        """ Create a deep clone of this game state.
        """
        st = HearthState()
        st.playerJustMoved = self.playerJustMoved
        #st.game = self.game.copy()
        #st.game = copy.copy(self.game.copy())
        st.game = copy.deepcopy(self.game.copy())
        return st

    def DoMove(self, move):
        """ Update a state by carrying out the given move.
            Must update playerJustMoved if end_turn.
        """
        assert self.game.players[0].hero.health > 0 and self.game.players[1].hero.health > 0 and not self.game.game_ended

        def _choose_target(targets):
            return targets[move[4]]

        def _choose_index(targets, player):
            return move[4]

        def _choose_option(*options):
            return options[move[4]]

        if self.game.current_player.name == "one":
            self.playerJustMoved = 1
        else:
            self.playerJustMoved = 2

        # print(str(self.game.current_player.mana) + "/" + str(self.game.current_player.max_mana))
        if move[0] == "end_turn":
            self.game._end_turn()
            self.game._start_turn()
        elif move[0] == "hero_power":
            self.game.current_player.agent.choose_target = _choose_target
            self.game.current_player.hero.power.use()
        elif move[0] == "summon_minion":
            self.game.current_player.agent.choose_index = _choose_index
            self.game.play_card(self.game.current_player.hand[move[3]])
        elif move[2] is None:  # Passing index rather than object, hopefully the game copy fix will help with this
            self.game.play_card(self.game.current_player.hand[move[3]])
        elif move[0] == "minion_attack" or move[0] == "hero_attack" or move[0] == "mage_power":
            self.game.current_player.agent.choose_target = _choose_target
            m = self.game.current_player.minions[move[3]]
            m.attack()
        elif move[0] == "targeted_spell":
            self.game.current_player.agent.choose_target = _choose_target
            self.game.play_card(self.game.current_player.hand[move[3]])
        else:
            raise NameError("DoMove ran into unclassified card", move)

    def GetMoves(self):
        """ Get all possible moves from this state.
        """
        if self.game.game_ended or self.game.players[0].hero.health <= 0 or self.game.players[1].hero.health <= 0:
            return []
        valid_moves = []  # Move format is [string, attacker/card, target, attacker/card index, target index]

        for card in self.game.current_player.hand:
            dupe = False
            for i in range(len(valid_moves)):
                if valid_moves[i][1].name == card.name:
                    dupe = True
                    break
            if not dupe:
                if card.can_use(self.game.current_player, self.game) and isinstance(card, MinionCard):
                    valid_moves.append(["summon_minion", card, None, self.game.current_player.hand.index(card), 0])
                elif card.can_use(self.game.current_player, self.game) and isinstance(card, WeaponCard):
                    valid_moves.append(["equip_weapon", card, None, self.game.current_player.hand.index(card), 0])
                elif card.can_use(self.game.current_player, self.game) and isinstance(card, SecretCard):
                    valid_moves.append(["played_secret", card, None, self.game.current_player.hand.index(card), 0])
                elif card.can_use(self.game.current_player, self.game) and not card.targetable:
                    valid_moves.append(["untargeted_spell", card, None, self.game.current_player.hand.index(card), 0])
                elif card.can_use(self.game.current_player, self.game) and card.targetable:
                    for i in range(len(card.targets)):
                        valid_moves.append(["targeted_spell", card, card.targets[i],
                                            self.game.current_player.hand.index(card), i])

        found_taunt = False
        targets = []
        for enemy in copy.copy(self.game.other_player.minions):
            if enemy.taunt and enemy.can_be_attacked():
                found_taunt = True
            if enemy.can_be_attacked():
                targets.append(enemy)

        if found_taunt:
            targets = [target for target in targets if target.taunt]
        else:
            targets.append(self.game.other_player.hero)

        for minion in copy.copy(self.game.current_player.minions):
            if minion.can_attack():
                for i in range(len(targets)):
                    valid_moves.append(["minion_attack", minion, targets[i],
                                        self.game.current_player.minions.index(minion), i])

        if self.game.current_player.hero.can_attack():
            for i in range(len(targets)):
                valid_moves.append(["hero_attack", self.game.current_player.hero, targets[i],
                                    self.game.current_player.hand.index(card), i])

        valid_moves.append(["end_turn", None, None])
        return valid_moves

    def GetResult(self, playerjm):
        """ Get the game result from the viewpoint of playerjm.
        """
        if self.game.players[0].hero.health <= 0 and self.game.players[1].hero.health <= 0:
            return 0.5
        elif self.game.players[playerjm - 1].hero.health <= 0:
            return 0
        elif self.game.players[2 - playerjm].hero.health <= 0:
            return 1
        else:  # Should not be possible to get here...
            return 0.5

    def __repr__(self):
        s = "Turn: " + str(self.game.turn)
        s += "\n[" + str(self.game.players[0].hero.health) + " hp:" + str(len(self.game.players[0].hand)) + " in hand:" + str(self.game.players[0].deck.left) + " in deck:" + str(self.game.players[0].mana) + "/" + str(self.game.players[0].max_mana) + " mana] "
        for minion in copy.copy(self.game.players[0].minions):
            s += str(minion.calculate_attack()) + "/" + str(minion.health) + ":"
        s += "\n[" + str(self.game.players[1].hero.health) + " hp:" + str(len(self.game.players[1].hand)) + " in hand:" + str(self.game.players[1].deck.left) + " in deck:" + str(self.game.players[1].mana) + "/" + str(self.game.players[1].max_mana) + " mana] "
        for minion in copy.copy(self.game.players[1].minions):
            s += str(minion.calculate_attack()) + "/" + str(minion.health) + ":"
        s += "\n" + "Current Player: " + str(self.game.current_player.name)
        return s

class Node:
    """ A node in the game tree. Note wins is always from the viewpoint of playerJustMoved.
        Crashes if state not specified.
    """
    def __init__(self, move = None, parent = None, state = None):
        self.move = move # the move that got us to this node - "None" for the root node
        self.parentNode = parent # "None" for the root node
        self.childNodes = []
        self.wins = 0
        self.visits = 0
        self.untriedMoves = state.GetMoves() # future child nodes
        self.playerJustMoved = state.playerJustMoved # the only part of the state that the Node needs later

    def UCTSelectChild(self):
        """ Use the UCB1 formula to select a child node. Often a constant UCTK is applied so we have
            lambda c: c.wins/c.visits + UCTK * sqrt(2*log(self.visits)/c.visits to vary the amount of
            exploration versus exploitation.
        """
        s = sorted(self.childNodes, key = lambda c: c.wins/c.visits + sqrt(2*log(self.visits)/c.visits))[-1]
        return s

    def AddChild(self, m, s):
        """ Remove m from untriedMoves and add a new child node for this move.
            Return the added child node
        """
        n = Node(move = m, parent = self, state = s)
        self.untriedMoves.remove(m)
        self.childNodes.append(n)
        return n

    def Update(self, result):
        """ Update this node - one additional visit and result additional wins. result must be from the viewpoint of playerJustmoved.
        """
        self.visits += 1
        self.wins += result

    def __repr__(self):
        return "[M:" + str(self.move) + " W/V:" + str(self.wins) + "/" + str(self.visits) + " U:" + str(self.untriedMoves) + "]"

    def TreeToString(self, indent):
        s = self.IndentString(indent) + str(self)
        for c in self.childNodes:
             s += c.TreeToString(indent+1)
        return s

    def IndentString(self,indent):
        s = "\n"
        for i in range (1,indent+1):
            s += "| "
        return s

    def ChildrenToString(self):
        s = ""
        for c in self.childNodes:
             s += str(c) + "\n"
        return s[:-2]

def UCT(rootstate, seconds, verbose = False):
    """ Conduct a UCT search for seconds starting from rootstate.
        Return the best move from the rootstate.
        Assumes 2 alternating players (player 1 starts), with game results in the range [0.0, 1.0]."""

    rootnode = Node(state = rootstate)

    future = time.time() + seconds
    while time.time() < future:
        node = rootnode
        state = rootstate.Clone()

        # Select
        while node.untriedMoves == [] and node.childNodes != []: # node is fully expanded and non-terminal
            node = node.UCTSelectChild()
            state.DoMove(node.move)

        # Expand
        if node.untriedMoves != []: # if we can expand (i.e. state/node is non-terminal)
            m = random.choice(node.untriedMoves)
            state.DoMove(m)
            node = node.AddChild(m,state) # add child and descend tree

        # Rollout - this can often be made orders of magnitude quicker using a state.GetRandomMove() function
        while state.GetMoves() != []: # while state is non-terminal
            state.DoMove(random.choice(state.GetMoves()))

        # Backpropagate
        while node != None: # backpropagate from the expanded node and work back to the root node
            #node.Update(state.GetResult(node.playerJustMoved)) # state is terminal. Update node with result from POV of node.playerJustMoved
            node.Update(state.GetResult(node.playerJustMoved)) # state is terminal. Update node with result from POV of node.activePlayer
            node = node.parentNode

    # Output some information about the tree - can be omitted
    if (verbose): print(rootnode.TreeToString(0))
    else: print(rootnode.ChildrenToString())

    return sorted(rootnode.childNodes, key = lambda c: c.visits)[-1].move # return the move that was most visited

def UCTPlayGame():
    """ Play a sample game between two UCT players where each player gets a different number
        of UCT iterations (= simulations = tree nodes).
    """
    state = HearthState()
    while (state.GetMoves() != []):
        print(str(state))
        m = UCT(rootstate = state, seconds = 5, verbose = False)
        print("Best Move: " + str(m) + "\n")
        state.DoMove(m)
    if state.GetResult(state.playerJustMoved) == 1.0:
        print("Player " + str(state.playerJustMoved) + " wins!")
    elif state.GetResult(state.playerJustMoved) == 0.0:
        print("Player " + str(3 - state.playerJustMoved) + " wins!")
    else: print("Nobody wins!")

if __name__ == "__main__":
    """ Play a single game to the end using UCT for both players.
    """
    UCTPlayGame()<commit_msg>Added a seed to random<commit_after># This is a very simple implementation of the UCT Monte Carlo Tree Search algorithm in Python 2.7.
# The function UCT(rootstate, itermax, verbose = False) is towards the bottom of the code.
# It aims to have the clearest and simplest possible code, and for the sake of clarity, the code
# is orders of magnitude less efficient than it could be made, particularly by using a
# state.GetRandomMove() or state.DoRandomRollout() function.
#
# Example GameState classes for Nim, OXO and Othello are included to give some idea of how you
# can write your own GameState use UCT in your 2-player game. Change the game to be played in
# the UCTPlayGame() function at the bottom of the code.
#
# Written by Peter Cowling, Ed Powley, Daniel Whitehouse (University of York, UK) September 2012.
#
# Licence is granted to freely use and distribute for any sensible/legal purpose so long as this comment
# remains in any distributed code.
#
# For more information about Monte Carlo Tree Search check out our web site at www.mcts.ai

from math import *
import random
import time
from tests.testing_utils import generate_game_for
from hearthbreaker.cards import *
from hearthbreaker.agents.basic_agents import DoNothingBot
from hearthbreaker.game_objects import *

class HearthState:
    """ A state of the game, i.e. the game board.
    """
    def __init__(self):
        self.playerJustMoved = 2 # At the root pretend the player just moved is p2 - p1 has the first move
        #deck1 = [GoldshireFootman, GoldshireFootman, MurlocRaider, MurlocRaider, BloodfenRaptor, BloodfenRaptor,
        #         FrostwolfGrunt, FrostwolfGrunt, RiverCrocolisk, RiverCrocolisk, IronfurGrizzly, IronfurGrizzly,
        #         MagmaRager, MagmaRager, SilverbackPatriarch, SilverbackPatriarch, ChillwindYeti, ChillwindYeti,
        #         OasisSnapjaw, OasisSnapjaw, SenjinShieldmasta, SenjinShieldmasta, BootyBayBodyguard, BootyBayBodyguard,
        #         FenCreeper, FenCreeper, BoulderfistOgre, BoulderfistOgre, WarGolem, WarGolem]
        #deck2 = [GoldshireFootman, GoldshireFootman, MurlocRaider, MurlocRaider, BloodfenRaptor, BloodfenRaptor,
        #         FrostwolfGrunt, FrostwolfGrunt, RiverCrocolisk, RiverCrocolisk, IronfurGrizzly, IronfurGrizzly,
        #         MagmaRager, MagmaRager, SilverbackPatriarch, SilverbackPatriarch, ChillwindYeti, ChillwindYeti,
        #         OasisSnapjaw, OasisSnapjaw, SenjinShieldmasta, SenjinShieldmasta, BootyBayBodyguard, BootyBayBodyguard,
        #         FenCreeper, FenCreeper, BoulderfistOgre, BoulderfistOgre, WarGolem, WarGolem]
        #deck1 = RiverCrocolisk
        #deck1 = [Innervate, Innervate, WildGrowth, WildGrowth, Wrath, Wrath]
        deck1 = [Soulfire, Soulfire]
        #deck1 = [Soulfire, Soulfire, MortalCoil, MortalCoil]
        deck2 = RiverCrocolisk
        random.seed(1857)
        game = generate_game_for(deck1, deck2, DoNothingBot, DoNothingBot)
        game._start_turn()
        self.game = game

    def Clone(self):
        """ Create a deep clone of this game state.
        """
        st = HearthState()
        st.playerJustMoved = self.playerJustMoved
        #st.game = self.game.copy()
        #st.game = copy.copy(self.game.copy())
        st.game = copy.deepcopy(self.game.copy())
        return st

    def DoMove(self, move):
        """ Update a state by carrying out the given move.
            Must update playerJustMoved if end_turn.
        """
        assert self.game.players[0].hero.health > 0 and self.game.players[1].hero.health > 0 and not self.game.game_ended

        def _choose_target(targets):
            return targets[move[4]]

        def _choose_index(targets, player):
            return move[4]

        def _choose_option(*options):
            return options[move[4]]

        if self.game.current_player.name == "one":
            self.playerJustMoved = 1
        else:
            self.playerJustMoved = 2

        # print(str(self.game.current_player.mana) + "/" + str(self.game.current_player.max_mana))
        if move[0] == "end_turn":
            self.game._end_turn()
            self.game._start_turn()
        elif move[0] == "hero_power":
            self.game.current_player.agent.choose_target = _choose_target
            self.game.current_player.hero.power.use()
        elif move[0] == "summon_minion":
            self.game.current_player.agent.choose_index = _choose_index
            self.game.play_card(self.game.current_player.hand[move[3]])
        elif move[2] is None:  # Passing index rather than object, hopefully the game copy fix will help with this
            self.game.play_card(self.game.current_player.hand[move[3]])
        elif move[0] == "minion_attack" or move[0] == "hero_attack" or move[0] == "mage_power":
            self.game.current_player.agent.choose_target = _choose_target
            m = self.game.current_player.minions[move[3]]
            m.attack()
        elif move[0] == "targeted_spell":
            self.game.current_player.agent.choose_target = _choose_target
            self.game.play_card(self.game.current_player.hand[move[3]])
        else:
            raise NameError("DoMove ran into unclassified card", move)

    def GetMoves(self):
        """ Get all possible moves from this state.
        """
        if self.game.game_ended or self.game.players[0].hero.health <= 0 or self.game.players[1].hero.health <= 0:
            return []
        valid_moves = []  # Move format is [string, attacker/card, target, attacker/card index, target index]

        for card in self.game.current_player.hand:
            dupe = False
            for i in range(len(valid_moves)):
                if valid_moves[i][1].name == card.name:
                    dupe = True
                    break
            if not dupe:
                if card.can_use(self.game.current_player, self.game) and isinstance(card, MinionCard):
                    valid_moves.append(["summon_minion", card, None, self.game.current_player.hand.index(card), 0])
                elif card.can_use(self.game.current_player, self.game) and isinstance(card, WeaponCard):
                    valid_moves.append(["equip_weapon", card, None, self.game.current_player.hand.index(card), 0])
                elif card.can_use(self.game.current_player, self.game) and isinstance(card, SecretCard):
                    valid_moves.append(["played_secret", card, None, self.game.current_player.hand.index(card), 0])
                elif card.can_use(self.game.current_player, self.game) and not card.targetable:
                    valid_moves.append(["untargeted_spell", card, None, self.game.current_player.hand.index(card), 0])
                elif card.can_use(self.game.current_player, self.game) and card.targetable:
                    for i in range(len(card.targets)):
                        valid_moves.append(["targeted_spell", card, card.targets[i],
                                            self.game.current_player.hand.index(card), i])

        found_taunt = False
        targets = []
        for enemy in copy.copy(self.game.other_player.minions):
            if enemy.taunt and enemy.can_be_attacked():
                found_taunt = True
            if enemy.can_be_attacked():
                targets.append(enemy)

        if found_taunt:
            targets = [target for target in targets if target.taunt]
        else:
            targets.append(self.game.other_player.hero)

        for minion in copy.copy(self.game.current_player.minions):
            if minion.can_attack():
                for i in range(len(targets)):
                    valid_moves.append(["minion_attack", minion, targets[i],
                                        self.game.current_player.minions.index(minion), i])

        if self.game.current_player.hero.can_attack():
            for i in range(len(targets)):
                valid_moves.append(["hero_attack", self.game.current_player.hero, targets[i],
                                    self.game.current_player.hand.index(card), i])

        valid_moves.append(["end_turn", None, None])
        return valid_moves

    def GetResult(self, playerjm):
        """ Get the game result from the viewpoint of playerjm.
        """
        if self.game.players[0].hero.health <= 0 and self.game.players[1].hero.health <= 0:
            return 0.5
        elif self.game.players[playerjm - 1].hero.health <= 0:
            return 0
        elif self.game.players[2 - playerjm].hero.health <= 0:
            return 1
        else:  # Should not be possible to get here...
            return 0.5

    def __repr__(self):
        s = "Turn: " + str(self.game.turn)
        s += "\n[" + str(self.game.players[0].hero.health) + " hp:" + str(len(self.game.players[0].hand)) + " in hand:" + str(self.game.players[0].deck.left) + " in deck:" + str(self.game.players[0].mana) + "/" + str(self.game.players[0].max_mana) + " mana] "
        for minion in copy.copy(self.game.players[0].minions):
            s += str(minion.calculate_attack()) + "/" + str(minion.health) + ":"
        s += "\n[" + str(self.game.players[1].hero.health) + " hp:" + str(len(self.game.players[1].hand)) + " in hand:" + str(self.game.players[1].deck.left) + " in deck:" + str(self.game.players[1].mana) + "/" + str(self.game.players[1].max_mana) + " mana] "
        for minion in copy.copy(self.game.players[1].minions):
            s += str(minion.calculate_attack()) + "/" + str(minion.health) + ":"
        s += "\n" + "Current Player: " + str(self.game.current_player.name)
        return s

class Node:
    """ A node in the game tree. Note wins is always from the viewpoint of playerJustMoved.
        Crashes if state not specified.
    """
    def __init__(self, move = None, parent = None, state = None):
        self.move = move # the move that got us to this node - "None" for the root node
        self.parentNode = parent # "None" for the root node
        self.childNodes = []
        self.wins = 0
        self.visits = 0
        self.untriedMoves = state.GetMoves() # future child nodes
        self.playerJustMoved = state.playerJustMoved # the only part of the state that the Node needs later

    def UCTSelectChild(self):
        """ Use the UCB1 formula to select a child node. Often a constant UCTK is applied so we have
            lambda c: c.wins/c.visits + UCTK * sqrt(2*log(self.visits)/c.visits to vary the amount of
            exploration versus exploitation.
        """
        s = sorted(self.childNodes, key = lambda c: c.wins/c.visits + sqrt(2*log(self.visits)/c.visits))[-1]
        return s

    def AddChild(self, m, s):
        """ Remove m from untriedMoves and add a new child node for this move.
            Return the added child node
        """
        n = Node(move = m, parent = self, state = s)
        self.untriedMoves.remove(m)
        self.childNodes.append(n)
        return n

    def Update(self, result):
        """ Update this node - one additional visit and result additional wins. result must be from the viewpoint of playerJustmoved.
        """
        self.visits += 1
        self.wins += result

    def __repr__(self):
        return "[M:" + str(self.move) + " W/V:" + str(self.wins) + "/" + str(self.visits) + " U:" + str(self.untriedMoves) + "]"

    def TreeToString(self, indent):
        s = self.IndentString(indent) + str(self)
        for c in self.childNodes:
             s += c.TreeToString(indent+1)
        return s

    def IndentString(self,indent):
        s = "\n"
        for i in range (1,indent+1):
            s += "| "
        return s

    def ChildrenToString(self):
        s = ""
        for c in self.childNodes:
             s += str(c) + "\n"
        return s[:-2]

def UCT(rootstate, seconds, verbose = False):
    """ Conduct a UCT search for seconds starting from rootstate.
        Return the best move from the rootstate.
        Assumes 2 alternating players (player 1 starts), with game results in the range [0.0, 1.0]."""
    rootnode = Node(state = rootstate)

    future = time.time() + seconds
    while time.time() < future:
        node = rootnode
        state = rootstate.Clone()

        # Select
        while node.untriedMoves == [] and node.childNodes != []: # node is fully expanded and non-terminal
            node = node.UCTSelectChild()
            state.DoMove(node.move)

        # Expand
        if node.untriedMoves != []: # if we can expand (i.e. state/node is non-terminal)
            m = random.choice(node.untriedMoves)
            state.DoMove(m)
            node = node.AddChild(m, state) # add child and descend tree

        # Rollout - this can often be made orders of magnitude quicker using a state.GetRandomMove() function
        while state.GetMoves() != []: # while state is non-terminal
            state.DoMove(random.choice(state.GetMoves()))

        # Backpropagate
        while node != None: # backpropagate from the expanded node and work back to the root node
            #node.Update(state.GetResult(node.playerJustMoved)) # state is terminal. Update node with result from POV of node.playerJustMoved
            node.Update(state.GetResult(node.playerJustMoved)) # state is terminal. Update node with result from POV of node.activePlayer
            node = node.parentNode

    # Output some information about the tree - can be omitted
    if (verbose): print(rootnode.TreeToString(0))
    else: print(rootnode.ChildrenToString())

    return sorted(rootnode.childNodes, key = lambda c: c.visits)[-1].move # return the move that was most visited

def UCTPlayGame():
    """ Play a sample game between two UCT players where each player gets a different number
        of UCT iterations (= simulations = tree nodes).
    """
    state = HearthState()
    while (state.GetMoves() != []):
        print(str(state))
        m = UCT(rootstate = state, seconds = 5, verbose = False)
        print("Best Move: " + str(m) + "\n")
        state.DoMove(m)
    if state.GetResult(state.playerJustMoved) == 1.0:
        print("Player " + str(state.playerJustMoved) + " wins!")
    elif state.GetResult(state.playerJustMoved) == 0.0:
        print("Player " + str(3 - state.playerJustMoved) + " wins!")
    else: print("Nobody wins!")

if __name__ == "__main__":
    """ Play a single game to the end using UCT for both players.
    """
    UCTPlayGame()
<|endoftext|>


<commit_before>#!/usr/bin/env python3

'''
description:    Unified Post Precession (UPP) part of wrfpy
license:        APACHE 2.0
author:         Ronald van Haren, NLeSC (r.vanharen@esciencecenter.nl)
'''

import utils
import glob
import subprocess
import os
import errno

class upp:
  '''
  Runs the Universal Post Processor (UPP) for requested time steps in
  a wrfout file
  '''
  def __init__(self):
    #self.logger = utils.get_logger()
    logger.info('*** RUNNING UNIVERSAL POST PROCESSOR ***')
    self._set_variables()
    self._initialize()
    self._prepare_post_dir()
    self._set_environment_variables()

  def _set_variables(self):
    '''
    Define control variables for the unipost.exe tool, inherit from
    global config. Variables are stored in a dictionary called config
    '''
    # hardcode for now for testing purposes.
    global config
    config = {}
    config['upp_archive_dir'] = '/home/WUR/haren009/sources/upp_archive'
    config['upp_dir'] = '/home/WUR/haren009/sources/UPPV3.0'
    config['crtm_dir'] = os.path.join(config['upp_dir'],
                                     'src/lib/crtm2/src/fix')
    config['upp_domain_dir'] = '/home/WUR/haren009/sources/test/DOMAINS/test_case'
    config['post_dir'] = os.path.join(config['upp_domain_dir'], 'postprd')
    config['wrf_run_dir'] = '/home/WUR/haren009/sources/WRFV3/run'

  def _initialize(self):
    '''
    Check if archive dir exists, create if not.
    The archive dir is used to ...
    '''
    if not os.path.exists(config['upp_archive_dir']):
      os.makedirs(config['upp_archive_dir'])  # create archive dir
    # create post_dir (remove old one if needed)
    utils.silentremove(config['post_dir'])
    os.makedirs(config['post_dir'])

  def _prepare_post_dir(self):
    '''
    Create and prepare post_dir
    '''
    logger.debug('Preparing postprd directory: %s' %config['post_dir'])

    # create config['post_dir'] if it does not exist yet
    try:
      os.makedirs(config['post_dir'])
    except OSError as e:
      if e.errno != errno.EEXIST:  # directory already exists
        raise # re-raise exception if a different error occured

    # Link all the relevant files need to compute various diagnostics
    relpath_to_link = ['EmisCoeff/Big_Endian/EmisCoeff.bin',
                       'AerosolCoeff/Big_Endian/AerosolCoeff.bin',
                       'CloudCoeff/Big_Endian/CloudCoeff.bin',
                       'SpcCoeff/Big_Endian/imgr_g11.SpcCoeff.bin',
                       'TauCoeff/ODPS/Big_Endian/imgr_g11.TauCoeff.bin',
                       'SpcCoeff/Big_Endian/imgr_g12.SpcCoeff.bin',
                       'TauCoeff/ODPS/Big_Endian/imgr_g12.TauCoeff.bin',
                       'SpcCoeff/Big_Endian/imgr_g13.SpcCoeff.bin',
                       'TauCoeff/ODPS/Big_Endian/imgr_g13.TauCoeff.bin',
                       'SpcCoeff/Big_Endian/imgr_g15.SpcCoeff.bin',
                       'TauCoeff/ODPS/Big_Endian/imgr_g15.TauCoeff.bin',
                       'SpcCoeff/Big_Endian/imgr_mt1r.SpcCoeff.bin',
                       'TauCoeff/ODPS/Big_Endian/imgr_mt1r.TauCoeff.bin',
                       'SpcCoeff/Big_Endian/imgr_mt2.SpcCoeff.bin',
                       'TauCoeff/ODPS/Big_Endian/imgr_mt2.TauCoeff.bin',
                       'SpcCoeff/Big_Endian/imgr_insat3d.SpcCoeff.bin',
                       'TauCoeff/ODPS/Big_Endian/imgr_insat3d.TauCoeff.bin',
                       'SpcCoeff/Big_Endian/amsre_aqua.SpcCoeff.bin',
                       'TauCoeff/ODPS/Big_Endian/amsre_aqua.TauCoeff.bin',
                       'SpcCoeff/Big_Endian/tmi_trmm.SpcCoeff.bin',
                       'TauCoeff/ODPS/Big_Endian/tmi_trmm.TauCoeff.bin',
                       'SpcCoeff/Big_Endian/ssmi_f13.SpcCoeff.bin',
                       'TauCoeff/ODPS/Big_Endian/ssmi_f13.TauCoeff.bin',
                       'SpcCoeff/Big_Endian/ssmi_f14.SpcCoeff.bin',
                       'TauCoeff/ODPS/Big_Endian/ssmi_f14.TauCoeff.bin',
                       'SpcCoeff/Big_Endian/ssmi_f15.SpcCoeff.bin',
                       'TauCoeff/ODPS/Big_Endian/ssmi_f15.TauCoeff.bin',
                       'SpcCoeff/Big_Endian/ssmis_f16.SpcCoeff.bin',
                       'TauCoeff/ODPS/Big_Endian/ssmis_f16.TauCoeff.bin',
                       'SpcCoeff/Big_Endian/ssmis_f17.SpcCoeff.bin',
                       'TauCoeff/ODPS/Big_Endian/ssmis_f17.TauCoeff.bin',
                       'SpcCoeff/Big_Endian/ssmis_f18.SpcCoeff.bin',
                       'TauCoeff/ODPS/Big_Endian/ssmis_f18.TauCoeff.bin',
                       'SpcCoeff/Big_Endian/ssmis_f19.SpcCoeff.bin',
                       'TauCoeff/ODPS/Big_Endian/ssmis_f19.TauCoeff.bin',
                       'SpcCoeff/Big_Endian/ssmis_f20.SpcCoeff.bin',
                       'TauCoeff/ODPS/Big_Endian/ssmis_f20.TauCoeff.bin',
                       'SpcCoeff/Big_Endian/seviri_m10.SpcCoeff.bin',
                       'TauCoeff/ODPS/Big_Endian/seviri_m10.TauCoeff.bin',
                       'SpcCoeff/Big_Endian/v.seviri_m10.SpcCoeff.bin']

    # abspath coefficients for crtm2 (simulated synthetic satellites)
    abspath_coeff= [os.path.join(config['crtm_dir'], relpath) for relpath in
                    relpath_to_link ]
    # abspath wrf_cntrl param file
    abspath_pf = os.path.join(config['upp_domain_dir'], 'parm',
                              'wrf_cntrl.parm')
    # concatenate lists of paths
    abspath_to_link = abspath_coeff + [abspath_pf]
    # create a symlink for every file in abspath_to_link
    for fl in abspath_to_link:
      utils.check_file_exists(fl)  # check if file exist and is readable
      os.symlink(fl, os.path.join(config['post_dir'], os.path.basename(fl)))
    # symlink wrf_cntrl.parm to config['post_dir']/fort.14
    os.symlink(abspath_pf, os.path.join(config['post_dir'], 'fort.14'))
    # symlink microphysic's tables - code used is based on mp_physics option
    # used in the wrfout file
    os.symlink(os.path.join(config['wrf_run_dir'], 'ETAMPNEW_DATA'),
               os.path.join(config['post_dir'], 'nam_micro_lookup.dat'))
    os.symlink(os.path.join(config['wrf_run_dir'],
                            'ETAMPNEW_DATA.expanded_rain'
                            ), os.path.join(config['post_dir'],
                                            'hires_micro_lookup.dat'))

  def _set_environment_variables(self):
    '''
    Set environment variables
    '''
    logger.debug('Enter set_environment_variables')
    os.environ['MP_SHARED_MEMORY'] = 'yes'
    os.environ['MP_LABELIO'] = 'yes'
    os.environ['tmmark'] = 'tm00'
    logger.debug('Leave set_environment_variables')

  def _cleanup_output_files(self):
    '''
    Clean up old output files in post_dir
    '''
    logger.debug('Enter cleanup_output_files')
    file_ext = [ '*.out', '*.tm00', 'fort.110', 'itag']
    files_found = [ f for files in [
      glob.glob(os.path.join(config['post_dir'], ext))
      for ext in file_ext ] for f in files]
    # try to remove files, raise exception if needed
    [ utils.silentremove(fl) for fl in files_found ]
    logger.debug('Leave cleanup_output_files')

  def _write_itag(self, wrfout, current_time):
    '''
    Create input file for unipost
      --------content itag file ---------------------------------------
      First line is location of wrfout data
      Second line is required format
      Third line is the modeltime to process
      Fourth line is the model identifier (WRF, NMM)
      -----------------------------------------------------------------
    '''
    logger.debug('Enter write_itag')
    logger.debug('Time in itag file is: %s' %current_time)
    # set itag filename and cleanup
    filename = os.path.join(config['post_dir'], 'itag')
    utils.silentremove(filename)
    # template of itag file
    template = """{wrfout}
netcdf
{current_time}:00:00
NCAR
"""
    # context variables in template
    context = {
      "wrfout":wrfout,
      "current_time":current_time
      }
    # create the itag file and write content to it based on the template
    try:
      with open(filename, 'w') as itag:
        itag.write(template.format(**context))
    except IOError as e:
      logger.error('Unable to write itag file: %s' %filename)
      raise  # re-raise exception
    logger.debug('Leave write_itag')

  def _run_unipost_step(self, wrfout, current_time, thours):
    '''
    Input variables for the function are:
      - full path to a wrfout file (regular wrfout naming)
      - time to run unipost for in format YYYY-MM-DD_HH
      - thours: TODO add description
    The following functionality is provided by the function:
      - validate input parameters
      - write itag file
      - run unipost.exe command
      - rename output
      - archive output
      - cleanup output
    '''
    # see if current_time is in wrfout AND validate time format
    utils.validate_time_wrfout(wrfout, current_time)
    # extract domain information from wrfout filename
    domain = int(wrfout[-22:-20])
    # write itag file
    self._write_itag(wrfout, current_time)
    # run unipost.exe
    # TODO: should be a call directly to uniposte.exe instead of a script uni.exe
    # TODO: uni.exe load ifort modules, calls unipost.exe and reloads gfort modules
    # TODO: should fix compilation of numpy/netCDF4 with intel compiler
    subprocess.check_call(os.path.join(config['upp_dir'], 'bin', 'uni.exe'),
                          cwd=config['post_dir'], stdout=utils.devnull(),
                          stderr=utils.devnull())
    # rename and archive output
    self._archive_output(current_time, thours, domain)
    # cleanup output files
    self._cleanup_output_files()

  def run_unipost_file(self, wrfout, frequency=2, use_t0=False):
    '''
    Input variables for the function are:
      - wrfout: full path to a wrfout file (regular wrfout naming)
      - (optional) frequency: time interval in hours at which processing should
        take place
      - (optional) use_t0: boolean, process time step 0
    The function provides the following functionality:
      description
    '''
    time_steps = utils.timesteps_wrfout(wrfout)
    # convert to hours since timestep 0
    td = [int((t - time_steps[0]).total_seconds()/3600) for t in time_steps]
    # modulo  should be zero
    if not td[-1]%frequency==0:
      message = ''  # TODO: add error message
      logger.error(message)
      raise IOError(message)
    else:
      # create list of booleans where module is 0
      modulo = [tdi%frequency==0 for tdi in td]
    for idx, tstep in enumerate(time_steps):
      if (not use_t0 and idx==0) or (modulo[idx] is False):
        continue
      # convert time step to time string
      current_time = utils.datetime_to_string(tstep)
      # run unipost step
      self._run_unipost_step(wrfout, current_time, td[idx])

  def _archive_output(self, current_time, thours, domain):
    '''
    rename unipost.exe output to wrfpost_d0${domain}_time.grb and archive
    '''
    import shutil
    # verify that domain is an int
    if not isinstance(domain, int):
      message = 'domain id should be an integer'
      logger.error(message)
      raise IOError(message)
    # define original and destination filename
    origname = 'WRFPRS%02d.tm00' %thours
    outname = 'wrfpost_d%02d_%s.grb' %(domain, current_time)
    # rename file and move to archive dir
    shutil.move(os.path.join(config['post_dir'], origname),
                os.path.join(config['upp_archive_dir'], outname))
    # check if file is indeed archived
    utils.check_file_exists(os.path.join(config['upp_archive_dir'], outname))

if __name__ == "__main__":
  logger = utils.start_logging('test.log')
  postprocess = upp()
  postprocess.run_unipost_file(
    '/home/WUR/haren009/sources/WRFV3/run/wrfout_d01_2014-07-16_00:00:00')<commit_msg>use multiple files for testing now<commit_after>#!/usr/bin/env python3

'''
description:    Unified Post Precession (UPP) part of wrfpy
license:        APACHE 2.0
author:         Ronald van Haren, NLeSC (r.vanharen@esciencecenter.nl)
'''

import utils
import glob
import subprocess
import os
import errno

class upp:
  '''
  Runs the Universal Post Processor (UPP) for requested time steps in
  a wrfout file
  '''
  def __init__(self):
    #self.logger = utils.get_logger()
    logger.info('*** RUNNING UNIVERSAL POST PROCESSOR ***')
    self._set_variables()
    self._initialize()
    self._prepare_post_dir()
    self._set_environment_variables()

  def _set_variables(self):
    '''
    Define control variables for the unipost.exe tool, inherit from
    global config. Variables are stored in a dictionary called config
    '''
    # hardcode for now for testing purposes.
    global config
    config = {}
    config['upp_archive_dir'] = '/home/WUR/haren009/sources/upp_archive'
    config['upp_dir'] = '/home/WUR/haren009/sources/UPPV3.0'
    config['crtm_dir'] = os.path.join(config['upp_dir'],
                                     'src/lib/crtm2/src/fix')
    config['upp_domain_dir'] = '/home/WUR/haren009/sources/test/DOMAINS/test_case'
    config['post_dir'] = os.path.join(config['upp_domain_dir'], 'postprd')
    config['wrf_run_dir'] = '/home/WUR/haren009/sources/WRFV3/run'

  def _initialize(self):
    '''
    Check if archive dir exists, create if not.
    The archive dir is used to ...
    '''
    if not os.path.exists(config['upp_archive_dir']):
      os.makedirs(config['upp_archive_dir'])  # create archive dir
    # create post_dir (remove old one if needed)
    utils.silentremove(config['post_dir'])
    os.makedirs(config['post_dir'])

  def _prepare_post_dir(self):
    '''
    Create and prepare post_dir
    '''
    logger.debug('Preparing postprd directory: %s' %config['post_dir'])

    # create config['post_dir'] if it does not exist yet
    try:
      os.makedirs(config['post_dir'])
    except OSError as e:
      if e.errno != errno.EEXIST:  # directory already exists
        raise # re-raise exception if a different error occured

    # Link all the relevant files need to compute various diagnostics
    relpath_to_link = ['EmisCoeff/Big_Endian/EmisCoeff.bin',
                       'AerosolCoeff/Big_Endian/AerosolCoeff.bin',
                       'CloudCoeff/Big_Endian/CloudCoeff.bin',
                       'SpcCoeff/Big_Endian/imgr_g11.SpcCoeff.bin',
                       'TauCoeff/ODPS/Big_Endian/imgr_g11.TauCoeff.bin',
                       'SpcCoeff/Big_Endian/imgr_g12.SpcCoeff.bin',
                       'TauCoeff/ODPS/Big_Endian/imgr_g12.TauCoeff.bin',
                       'SpcCoeff/Big_Endian/imgr_g13.SpcCoeff.bin',
                       'TauCoeff/ODPS/Big_Endian/imgr_g13.TauCoeff.bin',
                       'SpcCoeff/Big_Endian/imgr_g15.SpcCoeff.bin',
                       'TauCoeff/ODPS/Big_Endian/imgr_g15.TauCoeff.bin',
                       'SpcCoeff/Big_Endian/imgr_mt1r.SpcCoeff.bin',
                       'TauCoeff/ODPS/Big_Endian/imgr_mt1r.TauCoeff.bin',
                       'SpcCoeff/Big_Endian/imgr_mt2.SpcCoeff.bin',
                       'TauCoeff/ODPS/Big_Endian/imgr_mt2.TauCoeff.bin',
                       'SpcCoeff/Big_Endian/imgr_insat3d.SpcCoeff.bin',
                       'TauCoeff/ODPS/Big_Endian/imgr_insat3d.TauCoeff.bin',
                       'SpcCoeff/Big_Endian/amsre_aqua.SpcCoeff.bin',
                       'TauCoeff/ODPS/Big_Endian/amsre_aqua.TauCoeff.bin',
                       'SpcCoeff/Big_Endian/tmi_trmm.SpcCoeff.bin',
                       'TauCoeff/ODPS/Big_Endian/tmi_trmm.TauCoeff.bin',
                       'SpcCoeff/Big_Endian/ssmi_f13.SpcCoeff.bin',
                       'TauCoeff/ODPS/Big_Endian/ssmi_f13.TauCoeff.bin',
                       'SpcCoeff/Big_Endian/ssmi_f14.SpcCoeff.bin',
                       'TauCoeff/ODPS/Big_Endian/ssmi_f14.TauCoeff.bin',
                       'SpcCoeff/Big_Endian/ssmi_f15.SpcCoeff.bin',
                       'TauCoeff/ODPS/Big_Endian/ssmi_f15.TauCoeff.bin',
                       'SpcCoeff/Big_Endian/ssmis_f16.SpcCoeff.bin',
                       'TauCoeff/ODPS/Big_Endian/ssmis_f16.TauCoeff.bin',
                       'SpcCoeff/Big_Endian/ssmis_f17.SpcCoeff.bin',
                       'TauCoeff/ODPS/Big_Endian/ssmis_f17.TauCoeff.bin',
                       'SpcCoeff/Big_Endian/ssmis_f18.SpcCoeff.bin',
                       'TauCoeff/ODPS/Big_Endian/ssmis_f18.TauCoeff.bin',
                       'SpcCoeff/Big_Endian/ssmis_f19.SpcCoeff.bin',
                       'TauCoeff/ODPS/Big_Endian/ssmis_f19.TauCoeff.bin',
                       'SpcCoeff/Big_Endian/ssmis_f20.SpcCoeff.bin',
                       'TauCoeff/ODPS/Big_Endian/ssmis_f20.TauCoeff.bin',
                       'SpcCoeff/Big_Endian/seviri_m10.SpcCoeff.bin',
                       'TauCoeff/ODPS/Big_Endian/seviri_m10.TauCoeff.bin',
                       'SpcCoeff/Big_Endian/v.seviri_m10.SpcCoeff.bin']

    # abspath coefficients for crtm2 (simulated synthetic satellites)
    abspath_coeff= [os.path.join(config['crtm_dir'], relpath) for relpath in
                    relpath_to_link ]
    # abspath wrf_cntrl param file
    abspath_pf = os.path.join(config['upp_domain_dir'], 'parm',
                              'wrf_cntrl.parm')
    # concatenate lists of paths
    abspath_to_link = abspath_coeff + [abspath_pf]
    # create a symlink for every file in abspath_to_link
    for fl in abspath_to_link:
      utils.check_file_exists(fl)  # check if file exist and is readable
      os.symlink(fl, os.path.join(config['post_dir'], os.path.basename(fl)))
    # symlink wrf_cntrl.parm to config['post_dir']/fort.14
    os.symlink(abspath_pf, os.path.join(config['post_dir'], 'fort.14'))
    # symlink microphysic's tables - code used is based on mp_physics option
    # used in the wrfout file
    os.symlink(os.path.join(config['wrf_run_dir'], 'ETAMPNEW_DATA'),
               os.path.join(config['post_dir'], 'nam_micro_lookup.dat'))
    os.symlink(os.path.join(config['wrf_run_dir'],
                            'ETAMPNEW_DATA.expanded_rain'
                            ), os.path.join(config['post_dir'],
                                            'hires_micro_lookup.dat'))

  def _set_environment_variables(self):
    '''
    Set environment variables
    '''
    logger.debug('Enter set_environment_variables')
    os.environ['MP_SHARED_MEMORY'] = 'yes'
    os.environ['MP_LABELIO'] = 'yes'
    os.environ['tmmark'] = 'tm00'
    logger.debug('Leave set_environment_variables')

  def _cleanup_output_files(self):
    '''
    Clean up old output files in post_dir
    '''
    logger.debug('Enter cleanup_output_files')
    file_ext = [ '*.out', '*.tm00', 'fort.110', 'itag']
    files_found = [ f for files in [
      glob.glob(os.path.join(config['post_dir'], ext))
      for ext in file_ext ] for f in files]
    # try to remove files, raise exception if needed
    [ utils.silentremove(fl) for fl in files_found ]
    logger.debug('Leave cleanup_output_files')

  def _write_itag(self, wrfout, current_time):
    '''
    Create input file for unipost
      --------content itag file ---------------------------------------
      First line is location of wrfout data
      Second line is required format
      Third line is the modeltime to process
      Fourth line is the model identifier (WRF, NMM)
      -----------------------------------------------------------------
    '''
    logger.debug('Enter write_itag')
    logger.debug('Time in itag file is: %s' %current_time)
    # set itag filename and cleanup
    filename = os.path.join(config['post_dir'], 'itag')
    utils.silentremove(filename)
    # template of itag file
    template = """{wrfout}
netcdf
{current_time}:00:00
NCAR
"""
    # context variables in template
    context = {
      "wrfout":wrfout,
      "current_time":current_time
      }
    # create the itag file and write content to it based on the template
    try:
      with open(filename, 'w') as itag:
        itag.write(template.format(**context))
    except IOError as e:
      logger.error('Unable to write itag file: %s' %filename)
      raise  # re-raise exception
    logger.debug('Leave write_itag')

  def _run_unipost_step(self, wrfout, current_time, thours):
    '''
    Input variables for the function are:
      - full path to a wrfout file (regular wrfout naming)
      - time to run unipost for in format YYYY-MM-DD_HH
      - thours: TODO add description
    The following functionality is provided by the function:
      - validate input parameters
      - write itag file
      - run unipost.exe command
      - rename output
      - archive output
      - cleanup output
    '''
    # see if current_time is in wrfout AND validate time format
    utils.validate_time_wrfout(wrfout, current_time)
    # extract domain information from wrfout filename
    domain = int(wrfout[-22:-20])
    # write itag file
    self._write_itag(wrfout, current_time)
    # run unipost.exe
    # TODO: should be a call directly to uniposte.exe instead of a script uni.exe
    # TODO: uni.exe load ifort modules, calls unipost.exe and reloads gfort modules
    # TODO: should fix compilation of numpy/netCDF4 with intel compiler
    subprocess.check_call(os.path.join(config['upp_dir'], 'bin', 'uni.exe'),
                          cwd=config['post_dir'], stdout=utils.devnull(),
                          stderr=utils.devnull())
    # rename and archive output
    self._archive_output(current_time, thours, domain)
    # cleanup output files
    self._cleanup_output_files()

  def run_unipost_file(self, wrfout, frequency=2, use_t0=False):
    '''
    Input variables for the function are:
      - wrfout: full path to a wrfout file (regular wrfout naming)
      - (optional) frequency: time interval in hours at which processing should
        take place
      - (optional) use_t0: boolean, process time step 0
    The function provides the following functionality:
      description
    '''
    time_steps = utils.timesteps_wrfout(wrfout)
    # convert to hours since timestep 0
    td = [int((t - time_steps[0]).total_seconds()/3600) for t in time_steps]
    # modulo  should be zero
    if not td[-1]%frequency==0:
      message = ''  # TODO: add error message
      logger.error(message)
      raise IOError(message)
    else:
      # create list of booleans where module is 0
      modulo = [tdi%frequency==0 for tdi in td]
    for idx, tstep in enumerate(time_steps):
      if (not use_t0 and idx==0) or (modulo[idx] is False):
        continue
      # convert time step to time string
      current_time = utils.datetime_to_string(tstep)
      # run unipost step
      self._run_unipost_step(wrfout, current_time, td[idx])

  def _archive_output(self, current_time, thours, domain):
    '''
    rename unipost.exe output to wrfpost_d0${domain}_time.grb and archive
    '''
    import shutil
    # verify that domain is an int
    if not isinstance(domain, int):
      message = 'domain id should be an integer'
      logger.error(message)
      raise IOError(message)
    # define original and destination filename
    origname = 'WRFPRS%02d.tm00' %thours
    outname = 'wrfpost_d%02d_%s.grb' %(domain, current_time)
    # rename file and move to archive dir
    shutil.move(os.path.join(config['post_dir'], origname),
                os.path.join(config['upp_archive_dir'], outname))
    # check if file is indeed archived
    utils.check_file_exists(os.path.join(config['upp_archive_dir'], outname))

if __name__ == "__main__":
  logger = utils.start_logging('test.log')
  postprocess = upp()
  wrfout_files = glob.glob(os.path.join(config['wrf_run_dir'], 'wrfout_d01*'))
  postprocess.run_unipost_file(wrfout_files[0], use_t0=True)
  [postprocess.run_unipost_file(f) for f in wrfout_files[1:]]

  #postprocess.run_unipost_file(
  #  '/home/WUR/haren009/sources/WRFV3/run/wrfout_d01_2014-07-16_00:00:00')<|endoftext|>


<commit_before>#!/usr/bin/env python
#
# Copyright (c) 2012-2013 SEOmoz, Inc.
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

'''This is a module for dealing with urls. In particular, sanitizing them.'''

import re
try:
    from urllib import quote as urlquote
    from urllib import unquote as urlunquote
    from urlparse import urlparse, urlunparse, urljoin
except ImportError:  # pragma: no cover
    # Python 3 support
    from urllib.parse import quote as urlquote
    from urllib.parse import unquote as urlunquote
    from urllib.parse import urlparse, urlunparse, urljoin

# For publicsuffix utilities
from publicsuffix import PublicSuffixList
psl = PublicSuffixList()

# The default ports associated with each scheme
PORTS = {
    'http': 80,
    'https': 443
}

def parse(url, encoding='utf-8'):
    '''Parse the provided url string and return an URL object'''
    return URL.parse(url, encoding)

class URL(object):
    '''
    For more information on how and what we parse / sanitize:
        http://tools.ietf.org/html/rfc1808.html
    The more up-to-date RFC is this one:
        http://www.ietf.org/rfc/rfc3986.txt
    '''

    # Via http://www.ietf.org/rfc/rfc3986.txt
    GEN_DELIMS = ":/?#[]@"
    SUB_DELIMS = "!$&'()*+,;="
    ALPHA = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
    DIGIT = "0123456789"
    UNRESERVED = ALPHA + DIGIT + "-._~"
    RESERVED = GEN_DELIMS + SUB_DELIMS
    PCHAR = UNRESERVED + SUB_DELIMS + ":@"
    PATH = PCHAR + "/"
    QUERY = PCHAR + "/?"
    FRAGMENT = PCHAR + "/?"
    USERINFO = UNRESERVED + SUB_DELIMS + ":"

    PERCENT_ESCAPING_RE = re.compile('(%([a-fA-F0-9]{2})|.)', re.S)

    @classmethod
    def parse(cls, url, encoding):
        '''Parse the provided url, and return a URL instance'''
        if isinstance(url, str):
            parsed = urlparse(url.decode(encoding).encode('utf-8'))
        else:
            parsed = urlparse(url.encode('utf-8'))

        try:
            port = parsed.port
        except ValueError:
            port = None

        userinfo = parsed.username
        if userinfo and parsed.password:
            userinfo += ':%s' % parsed.password

        return cls(parsed.scheme, parsed.hostname, port,
            parsed.path, parsed.params, parsed.query, parsed.fragment, userinfo)

    def __init__(self, scheme, host, port, path, params, query, fragment, userinfo=None):
        self._scheme = scheme
        self._host = host
        self._port = port
        self._path = path or '/'
        self._params = re.sub(r'^;+', '', str(params))
        self._params = re.sub(r'^;|;$', '', re.sub(r';{2,}', ';', self._params))
        # Strip off extra leading ?'s
        self._query = re.sub(r'^\?+', '', str(query))
        self._query = re.sub(r'^&|&$', '', re.sub(r'&{2,}', '&', self._query))
        self._fragment = fragment
        self._userinfo = userinfo

    def equiv(self, other):
        '''Return true if this url is equivalent to another'''
        if isinstance(other, basestring):
            _other = self.parse(other, 'utf-8')
        else:
            _other = self.parse(other.utf8(), 'utf-8')

        _self = self.parse(self.utf8(), 'utf-8')
        _self.canonical().defrag().abspath().escape().punycode()
        _other.canonical().defrag().abspath().escape().punycode()

        result = (
            _self._scheme   == _other._scheme   and
            _self._host     == _other._host     and
            _self._path     == _other._path     and
            _self._params   == _other._params   and
            _self._query    == _other._query)

        if result:
            if _self._port and not _other._port:
                # Make sure _self._port is the default for the scheme
                return _self._port == PORTS.get(_self._scheme, None)
            elif _other._port and not _self._port:
                # Make sure _other._port is the default for the scheme
                return _other._port == PORTS.get(_other._scheme, None)
            else:
                return _self._port == _other._port
        else:
            return False

    def __eq__(self, other):
        '''Return true if this url is /exactly/ equal to another'''
        if isinstance(other, basestring):
            return self.__eq__(self.parse(other, 'utf-8'))
        return (
            self._scheme   == other._scheme   and
            self._host     == other._host     and
            self._path     == other._path     and
            self._port     == other._port     and
            self._params   == other._params   and
            self._query    == other._query    and
            self._fragment == other._fragment and
            self._userinfo == other._userinfo)

    def __ne__(self, other):
        return not self.__eq__(other)

    def __str__(self):
        return self.utf8()

    def __repr__(self):
        return '<url.URL object "%s" >' % self.utf8()

    def canonical(self):
        '''Canonicalize this url. This includes reordering parameters and args
        to have a consistent ordering'''
        self._query = '&'.join(sorted([q for q in self._query.split('&')]))
        self._params = ';'.join(sorted([q for q in self._params.split(';')]))
        return self

    def defrag(self):
        '''Remove the fragment from this url'''
        self._fragment = None
        return self

    def deparam(self, params):
        '''Strip any of the provided parameters out of the url'''
        lowered = set([p.lower() for p in params])
        def function(name, _):
            return name.lower() in lowered
        return self.filter_params(function)

    def filter_params(self, function):
        '''Remove parameters if function(name, value)'''
        def keep(query):
            name, _, value = query.partition('=')
            return not function(name, value)
        self._query = '&'.join(q for q in self._query.split('&') if q and keep(q))
        self._params = ';'.join(q for q in self._params.split(';') if q and keep(q))
        return self

    def deuserinfo(self):
        '''Remove any userinfo'''
        self._userinfo = None
        return self

    def abspath(self):
        '''Clear out any '..' and excessive slashes from the path'''
        # Remove double forward-slashes from the path
        path = re.sub(r'\/{2,}', '/', self._path)
        # With that done, go through and remove all the relative references
        unsplit = []
        directory = False
        for part in path.split('/'):
            # If we encounter the parent directory, and there's
            # a segment to pop off, then we should pop it off.
            if part == '..' and (not unsplit or unsplit.pop() != None):
                directory = True
            elif part != '.':
                unsplit.append(part)
                directory = False
            else:
                directory = True

        # With all these pieces, assemble!
        if directory:
            # If the path ends with a period, then it refers to a directory,
            # not a file path
            self._path = '/'.join(unsplit) + '/'
        else:
            self._path = '/'.join(unsplit)
        return self

    def sanitize(self):
        '''A shortcut to abspath and escape'''
        return self.abspath().escape()

    @staticmethod
    def percent_encode(raw, safe):
        if isinstance(raw, unicode):
            raw = raw.encode('utf-8')

        def replacement(match):
            string = match.group(1)
            if len(string) == 1:
                if string in safe:
                    return string
                else:
                    return '%%%02X' % ord(string)
            else:
                # Replace any escaped entities with their equivalent if needed.
                character = chr(int(match.group(2), 16))
                if (character in safe) and not (character in URL.RESERVED):
                    return character
                return string.upper()

        return URL.PERCENT_ESCAPING_RE.sub(replacement, raw)

    def escape(self, strict=False):
        '''Make sure that the path is correctly escaped'''
        if strict:
            self._path = self.percent_encode(self._path, URL.PATH)
            self._query = self.percent_encode(self._query, URL.QUERY)
            self._params = self.percent_encode(self._params, URL.QUERY)
            if self._userinfo:
                self._userinfo = self.percent_encode(self._userinfo, URL.USERINFO)
            return self
        else:
            self._path = urlquote(urlunquote(self._path), safe=URL.PATH)
            # Safe characters taken from:
            #    http://tools.ietf.org/html/rfc3986#page-50
            self._query = urlquote(urlunquote(self._query), safe=URL.QUERY)
            # The safe characters for URL parameters seemed a little more vague.
            # They are interpreted here as *pchar despite this page, since the
            # updated RFC seems to offer no replacement
            #    http://tools.ietf.org/html/rfc3986#page-54
            self._params = urlquote(urlunquote(self._params), safe=URL.QUERY)
            if self._userinfo:
                self._userinfo = urlquote(urlunquote(self._userinfo),
                    safe=URL.USERINFO)
            return self

    def unescape(self):
        '''Unescape the path'''
        self._path = urlunquote(self._path)
        return self

    def encode(self, encoding):
        '''Return the url in an arbitrary encoding'''
        netloc = self._host or ''
        if self._port:
            netloc += (':' + str(self._port))

        if self._userinfo is not None:
            netloc = '%s@%s' % (self._userinfo, netloc)

        result = urlunparse((str(self._scheme), str(netloc),
            str(self._path), str(self._params), str(self._query),
            self._fragment))
        return result.decode('utf-8').encode(encoding)

    def relative(self, path, encoding='utf-8'):
        '''Evaluate the new path relative to the current url'''
        if not isinstance(path, str):
            newurl = urljoin(self.utf8(),
                str(path).decode(encoding).encode('utf-8'))
        else:
            newurl = urljoin(self.utf8(), path.encode('utf-8'))
        return URL.parse(newurl, 'utf-8')

    def punycode(self):
        '''Convert to punycode hostname'''
        if self._host:
            self._host = self._host.decode('utf-8').encode('idna')
            return self
        raise TypeError('Cannot punycode a relative url (%s)' % repr(self))

    def unpunycode(self):
        '''Convert to an unpunycoded hostname'''
        if self._host:
            self._host = self._host.decode('utf-8').decode('idna').encode('utf-8')
            return self
        raise TypeError('Cannot unpunycode a relative url (%s)' % repr(self))

    ###########################################################################
    # Information about the domain
    ###########################################################################
    def pld(self):
        '''Return the 'pay-level domain' of the url
            (http://moz.com/blog/what-the-heck-should-we-call-domaincom)'''
        if self._host:
            return psl.get_public_suffix(self._host)
        return ''

    def tld(self):
        '''Return the top-level domain of a url'''
        if self._host:
            return '.'.join(self.pld().split('.')[1:])
        return ''

    ###########################################################################
    # Information about the type of url it is
    ###########################################################################
    def absolute(self):
        '''Return True if this is a fully-qualified URL with a hostname and
        everything'''
        return bool(self._host)

    ###########################################################################
    # Get a string representation. These methods can't be chained, as they
    # return strings
    ###########################################################################
    def unicode(self):
        '''Return a unicode version of this url'''
        return self.encode('utf-8').decode('utf-8')

    def utf8(self):
        '''Return a utf-8 version of this url'''
        return self.encode('utf-8')
<commit_msg>Avoid reencoding<commit_after>#!/usr/bin/env python
#
# Copyright (c) 2012-2013 SEOmoz, Inc.
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

'''This is a module for dealing with urls. In particular, sanitizing them.'''

import re
try:
    from urllib import quote as urlquote
    from urllib import unquote as urlunquote
    from urlparse import urlparse, urlunparse, urljoin
except ImportError:  # pragma: no cover
    # Python 3 support
    from urllib.parse import quote as urlquote
    from urllib.parse import unquote as urlunquote
    from urllib.parse import urlparse, urlunparse, urljoin

# For publicsuffix utilities
from publicsuffix import PublicSuffixList
psl = PublicSuffixList()

# The default ports associated with each scheme
PORTS = {
    'http': 80,
    'https': 443
}

def parse(url, encoding='utf-8'):
    '''Parse the provided url string and return an URL object'''
    return URL.parse(url, encoding)

class URL(object):
    '''
    For more information on how and what we parse / sanitize:
        http://tools.ietf.org/html/rfc1808.html
    The more up-to-date RFC is this one:
        http://www.ietf.org/rfc/rfc3986.txt
    '''

    # Via http://www.ietf.org/rfc/rfc3986.txt
    GEN_DELIMS = ":/?#[]@"
    SUB_DELIMS = "!$&'()*+,;="
    ALPHA = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
    DIGIT = "0123456789"
    UNRESERVED = ALPHA + DIGIT + "-._~"
    RESERVED = GEN_DELIMS + SUB_DELIMS
    PCHAR = UNRESERVED + SUB_DELIMS + ":@"
    PATH = PCHAR + "/"
    QUERY = PCHAR + "/?"
    FRAGMENT = PCHAR + "/?"
    USERINFO = UNRESERVED + SUB_DELIMS + ":"

    PERCENT_ESCAPING_RE = re.compile('(%([a-fA-F0-9]{2})|.)', re.S)

    @classmethod
    def parse(cls, url, encoding):
        '''Parse the provided url, and return a URL instance'''
        if isinstance(url, str):
            if encoding != 'utf-8':
                url = url.decode(encoding).encode('utf-8')
        else:
            url = url.encode('utf-8')

        parsed = urlparse(url)

        try:
            port = parsed.port
        except ValueError:
            port = None

        userinfo = parsed.username
        if userinfo and parsed.password:
            userinfo += ':%s' % parsed.password

        return cls(parsed.scheme, parsed.hostname, port,
            parsed.path, parsed.params, parsed.query, parsed.fragment, userinfo)

    def __init__(self, scheme, host, port, path, params, query, fragment, userinfo=None):
        self._scheme = scheme
        self._host = host
        self._port = port
        self._path = path or '/'
        self._params = re.sub(r'^;+', '', str(params))
        self._params = re.sub(r'^;|;$', '', re.sub(r';{2,}', ';', self._params))
        # Strip off extra leading ?'s
        self._query = re.sub(r'^\?+', '', str(query))
        self._query = re.sub(r'^&|&$', '', re.sub(r'&{2,}', '&', self._query))
        self._fragment = fragment
        self._userinfo = userinfo

    def equiv(self, other):
        '''Return true if this url is equivalent to another'''
        if isinstance(other, basestring):
            _other = self.parse(other, 'utf-8')
        else:
            _other = self.parse(other.utf8(), 'utf-8')

        _self = self.parse(self.utf8(), 'utf-8')
        _self.canonical().defrag().abspath().escape().punycode()
        _other.canonical().defrag().abspath().escape().punycode()

        result = (
            _self._scheme   == _other._scheme   and
            _self._host     == _other._host     and
            _self._path     == _other._path     and
            _self._params   == _other._params   and
            _self._query    == _other._query)

        if result:
            if _self._port and not _other._port:
                # Make sure _self._port is the default for the scheme
                return _self._port == PORTS.get(_self._scheme, None)
            elif _other._port and not _self._port:
                # Make sure _other._port is the default for the scheme
                return _other._port == PORTS.get(_other._scheme, None)
            else:
                return _self._port == _other._port
        else:
            return False

    def __eq__(self, other):
        '''Return true if this url is /exactly/ equal to another'''
        if isinstance(other, basestring):
            return self.__eq__(self.parse(other, 'utf-8'))
        return (
            self._scheme   == other._scheme   and
            self._host     == other._host     and
            self._path     == other._path     and
            self._port     == other._port     and
            self._params   == other._params   and
            self._query    == other._query    and
            self._fragment == other._fragment and
            self._userinfo == other._userinfo)

    def __ne__(self, other):
        return not self.__eq__(other)

    def __str__(self):
        return self.utf8()

    def __repr__(self):
        return '<url.URL object "%s" >' % self.utf8()

    def canonical(self):
        '''Canonicalize this url. This includes reordering parameters and args
        to have a consistent ordering'''
        self._query = '&'.join(sorted([q for q in self._query.split('&')]))
        self._params = ';'.join(sorted([q for q in self._params.split(';')]))
        return self

    def defrag(self):
        '''Remove the fragment from this url'''
        self._fragment = None
        return self

    def deparam(self, params):
        '''Strip any of the provided parameters out of the url'''
        lowered = set([p.lower() for p in params])
        def function(name, _):
            return name.lower() in lowered
        return self.filter_params(function)

    def filter_params(self, function):
        '''Remove parameters if function(name, value)'''
        def keep(query):
            name, _, value = query.partition('=')
            return not function(name, value)
        self._query = '&'.join(q for q in self._query.split('&') if q and keep(q))
        self._params = ';'.join(q for q in self._params.split(';') if q and keep(q))
        return self

    def deuserinfo(self):
        '''Remove any userinfo'''
        self._userinfo = None
        return self

    def abspath(self):
        '''Clear out any '..' and excessive slashes from the path'''
        # Remove double forward-slashes from the path
        path = re.sub(r'\/{2,}', '/', self._path)
        # With that done, go through and remove all the relative references
        unsplit = []
        directory = False
        for part in path.split('/'):
            # If we encounter the parent directory, and there's
            # a segment to pop off, then we should pop it off.
            if part == '..' and (not unsplit or unsplit.pop() != None):
                directory = True
            elif part != '.':
                unsplit.append(part)
                directory = False
            else:
                directory = True

        # With all these pieces, assemble!
        if directory:
            # If the path ends with a period, then it refers to a directory,
            # not a file path
            self._path = '/'.join(unsplit) + '/'
        else:
            self._path = '/'.join(unsplit)
        return self

    def sanitize(self):
        '''A shortcut to abspath and escape'''
        return self.abspath().escape()

    @staticmethod
    def percent_encode(raw, safe):
        if isinstance(raw, unicode):
            raw = raw.encode('utf-8')

        def replacement(match):
            string = match.group(1)
            if len(string) == 1:
                if string in safe:
                    return string
                else:
                    return '%%%02X' % ord(string)
            else:
                # Replace any escaped entities with their equivalent if needed.
                character = chr(int(match.group(2), 16))
                if (character in safe) and not (character in URL.RESERVED):
                    return character
                return string.upper()

        return URL.PERCENT_ESCAPING_RE.sub(replacement, raw)

    def escape(self, strict=False):
        '''Make sure that the path is correctly escaped'''
        if strict:
            self._path = self.percent_encode(self._path, URL.PATH)
            self._query = self.percent_encode(self._query, URL.QUERY)
            self._params = self.percent_encode(self._params, URL.QUERY)
            if self._userinfo:
                self._userinfo = self.percent_encode(self._userinfo, URL.USERINFO)
            return self
        else:
            self._path = urlquote(urlunquote(self._path), safe=URL.PATH)
            # Safe characters taken from:
            #    http://tools.ietf.org/html/rfc3986#page-50
            self._query = urlquote(urlunquote(self._query), safe=URL.QUERY)
            # The safe characters for URL parameters seemed a little more vague.
            # They are interpreted here as *pchar despite this page, since the
            # updated RFC seems to offer no replacement
            #    http://tools.ietf.org/html/rfc3986#page-54
            self._params = urlquote(urlunquote(self._params), safe=URL.QUERY)
            if self._userinfo:
                self._userinfo = urlquote(urlunquote(self._userinfo),
                    safe=URL.USERINFO)
            return self

    def unescape(self):
        '''Unescape the path'''
        self._path = urlunquote(self._path)
        return self

    def encode(self, encoding):
        '''Return the url in an arbitrary encoding'''
        netloc = self._host or ''
        if self._port:
            netloc += (':' + str(self._port))

        if self._userinfo is not None:
            netloc = '%s@%s' % (self._userinfo, netloc)

        result = urlunparse((str(self._scheme), str(netloc),
            str(self._path), str(self._params), str(self._query),
            self._fragment))
        if encoding != 'utf-8':
            result = result.decode('utf-8').encode(encoding)

        return result

    def relative(self, path, encoding='utf-8'):
        '''Evaluate the new path relative to the current url'''
        if isinstance(path, str):
            if encoding != 'utf-8':
                path = path.decode(encoding).encode('utf-8')
        else:
            path = path.encode('utf-8')

        newurl = urljoin(self.utf8(), path)

        return URL.parse(newurl, 'utf-8')

    def punycode(self):
        '''Convert to punycode hostname'''
        if self._host:
            self._host = self._host.decode('utf-8').encode('idna')
            return self
        raise TypeError('Cannot punycode a relative url (%s)' % repr(self))

    def unpunycode(self):
        '''Convert to an unpunycoded hostname'''
        if self._host:
            self._host = self._host.decode('utf-8').decode('idna').encode('utf-8')
            return self
        raise TypeError('Cannot unpunycode a relative url (%s)' % repr(self))

    ###########################################################################
    # Information about the domain
    ###########################################################################
    def pld(self):
        '''Return the 'pay-level domain' of the url
            (http://moz.com/blog/what-the-heck-should-we-call-domaincom)'''
        if self._host:
            return psl.get_public_suffix(self._host)
        return ''

    def tld(self):
        '''Return the top-level domain of a url'''
        if self._host:
            return '.'.join(self.pld().split('.')[1:])
        return ''

    ###########################################################################
    # Information about the type of url it is
    ###########################################################################
    def absolute(self):
        '''Return True if this is a fully-qualified URL with a hostname and
        everything'''
        return bool(self._host)

    ###########################################################################
    # Get a string representation. These methods can't be chained, as they
    # return strings
    ###########################################################################
    def unicode(self):
        '''Return a unicode version of this url'''
        return self.encode('utf-8').decode('utf-8')

    def utf8(self):
        '''Return a utf-8 version of this url'''
        return self.encode('utf-8')
<|endoftext|>


<commit_before>"""
wal - Generate and change colorschemes on the fly.
Created by Dylan Araps
"""
import argparse
import re
import subprocess
import random

import os
from os.path import expanduser

import pathlib
from pathlib import Path

# Internal variables.
CACHE_DIR = expanduser("~") + "/.cache/wal"
COLOR_COUNT = 16
OS = os.uname

def get_args():
    """Get the script arguments."""
    description = "wal - Generate colorschemes on the fly"
    arg = argparse.ArgumentParser(description=description)

    # Add the args.
    arg.add_argument('-a', metavar='0-100', type=int,
                     help='Set terminal background transparency. \
                           *Only works in URxvt*')

    arg.add_argument('-c', action='store_true',
                     help='Delete all cached colorschemes.')

    arg.add_argument('-f', metavar='"/path/to/colors"',
                     help='Load colors directly from a colorscheme file.')

    arg.add_argument('-i', metavar='"/path/to/img.jpg"', required=True,
                     help='Which image or directory to use.')

    arg.add_argument('-n', action='store_true',
                     help='Skip setting the wallpaper.')

    arg.add_argument('-o', metavar='script_name',
                     help='External script to run after "wal".')

    arg.add_argument('-q', action='store_true',
                     help='Quiet mode, don\'t print anything.')

    arg.add_argument('-r', action='store_true',
                     help='Reload current colorscheme.')

    arg.add_argument('-t', action='store_true',
                     help='Fix artifacts in VTE Terminals. \
                           (Termite, xfce4-terminal)')

    arg.add_argument('-x', action='store_true',
                     help='Use extended 16-color palette.')

    return arg.parse_args()

def get_image(img):
    """Validate image input."""
    image = Path(img)

    if image.is_file():
        return image

    elif image.is_dir():
        rand = random.choice(os.listdir(image))
        rand_img = Path(str(image) + "/" + rand)

        if rand_img.is_file():
            return rand_img

def get_colors(img):
    """Generate a colorscheme using imagemagick."""
    colors = []

    # Create colorscheme dir.
    pathlib.Path(CACHE_DIR + "/schemes").mkdir(parents=True, exist_ok=True)

    # Cache file.
    cache_file = CACHE_DIR + "/schemes/" + img.replace('/', '_')

    # Cache the wallpaper name.
    wal = open(CACHE_DIR + "/wal", 'w')
    wal.write(img + "\n")
    wal.close()

    # Long-ass imagemagick command.
    magic = subprocess.Popen(["convert", img, "+dither", "-colors",
                              str(COLOR_COUNT), "-unique-colors", "txt:-"],
                             stdout=subprocess.PIPE,
                             stderr=subprocess.PIPE)

    # Create a list of hex colors.
    for color in magic.stdout:
        hex_color = re.search('#.{6}', str(color))

        if hex_color:
            colors.append(hex_color.group(0))

    # Remove the first element, which isn't a color.
    del colors[0]

    # Cache the colorscheme.
    scheme = open(cache_file, 'w')
    for color in colors:
        scheme.write(color + "\n")
    scheme.close()

def main():
    """Main script function."""
    args = get_args()
    image = str(get_image(args.i))
    get_colors(image)
    return 0

main()
<commit_msg>General: Check if scheme exists<commit_after>"""
wal - Generate and change colorschemes on the fly.
Created by Dylan Araps
"""
import argparse
import re
import subprocess
import random

import os
from os.path import expanduser

import pathlib
from pathlib import Path

# Internal variables.
CACHE_DIR = expanduser("~") + "/.cache/wal"
COLOR_COUNT = 16
OS = os.uname

def get_args():
    """Get the script arguments."""
    description = "wal - Generate colorschemes on the fly"
    arg = argparse.ArgumentParser(description=description)

    # Add the args.
    arg.add_argument('-a', metavar='0-100', type=int,
                     help='Set terminal background transparency. \
                           *Only works in URxvt*')

    arg.add_argument('-c', action='store_true',
                     help='Delete all cached colorschemes.')

    arg.add_argument('-f', metavar='"/path/to/colors"',
                     help='Load colors directly from a colorscheme file.')

    arg.add_argument('-i', metavar='"/path/to/img.jpg"', required=True,
                     help='Which image or directory to use.')

    arg.add_argument('-n', action='store_true',
                     help='Skip setting the wallpaper.')

    arg.add_argument('-o', metavar='script_name',
                     help='External script to run after "wal".')

    arg.add_argument('-q', action='store_true',
                     help='Quiet mode, don\'t print anything.')

    arg.add_argument('-r', action='store_true',
                     help='Reload current colorscheme.')

    arg.add_argument('-t', action='store_true',
                     help='Fix artifacts in VTE Terminals. \
                           (Termite, xfce4-terminal)')

    arg.add_argument('-x', action='store_true',
                     help='Use extended 16-color palette.')

    return arg.parse_args()

def get_image(img):
    """Validate image input."""
    image = Path(img)

    if image.is_file():
        return image

    elif image.is_dir():
        rand = random.choice(os.listdir(image))
        rand_img = Path(str(image) + "/" + rand)

        if rand_img.is_file():
            return rand_img

def gen_colors(img):
    """Generate a color palette using imagemagick."""
    colors = []

    # Long-ass imagemagick command.
    magic = subprocess.Popen(["convert", img, "+dither", "-colors",
                              str(COLOR_COUNT), "-unique-colors", "txt:-"],
                             stdout=subprocess.PIPE,
                             stderr=subprocess.PIPE)

    # Create a list of hex colors.
    for color in magic.stdout:
        hex_color = re.search('#.{6}', str(color))

        if hex_color:
            colors.append(hex_color.group(0))

    # Remove the first element, which isn't a color.
    del colors[0]

    return colors

def get_colors(img):
    """Generate a colorscheme using imagemagick."""
    # Cache file.
    cache_file = Path(CACHE_DIR + "/schemes/" + img.replace('/', '_'))

    if not cache_file.is_file():
        # Cache the wallpaper name.
        wal = open(CACHE_DIR + "/wal", 'w')
        wal.write(img + "\n")
        wal.close()

        # Generate the colors.
        colors = gen_colors(img)

        # Cache the colorscheme.
        scheme = open(cache_file, 'w')
        for color in colors:
            scheme.write(color + "\n")
        scheme.close()

def main():
    """Main script function."""
    args = get_args()
    image = str(get_image(args.i))

    # Create colorscheme dir.
    pathlib.Path(CACHE_DIR + "/schemes").mkdir(parents=True, exist_ok=True)

    get_colors(image)
    return 0

main()
<|endoftext|>


<commit_before>import hashlib
import hmac
import os
import urllib

import postmark
import requests
from postmark_inbound import PostmarkInbound
from raven.contrib.flask import Sentry

from flask import Flask, request, render_template, redirect

#
# app configuration
#

SERVICE_EMAIL = os.environ.get('SERVICE_EMAIL')

POSTMARK_KEY = os.environ.get('POSTMARK_KEY')
POSTMARK_SENDER = os.environ.get('POSTMARK_SENDER')

SUNLIGHT_KEY = os.environ.get('SUNLIGHT_KEY')
SUNLIGHT_SECRET = os.environ.get('SUNLIGHT_SECRET')
SUNLIGHT_URL = os.environ.get('SUNLIGHT_URL')

SENTRY_DSN = os.environ.get('SENTRY_DSN')

REGISTRATION_ENABLED = os.environ.get('REGISTRATION_ENABLED', '') != ''

#
# API registration
#

def get_signature(params):
    data = sorted([(k, unicode(v).encode('utf-8')) for k, v in params.items() if k != 'signature'])
    qs = urllib.urlencode(data)
    return hmac.new(SUNLIGHT_SECRET, qs, hashlib.sha1).hexdigest()

def key_notification(key, addr):
    context = {
        'key': key,
        'email': addr,
    }
    message = render_template('email/success.txt', **context)
    mail = postmark.PMMail(
        api_key=POSTMARK_KEY,
        sender=POSTMARK_SENDER,
        to=addr,
        subject='Here is your brand new Sunlight API key!',
        text_body=message,
    )
    mail.send()

def disabled_notification(addr):
    message = render_template('email/disabled.txt')
    mail = postmark.PMMail(
        api_key=POSTMARK_KEY,
        sender=POSTMARK_SENDER,
        to=addr,
        subject='Ack! A small problem with your Sunlight Foundation API key',
        text_body=message,
    )
    mail.send()

def register_key(addr, name):
    params = {
        'apikey': SUNLIGHT_KEY,
        'email': addr,
        'name': name or 'Sunlight Event Attendee',
    }
    params['signature'] = get_signature(params)
    resp = requests.post(SUNLIGHT_URL, params)
    data = resp.json()
    return data['key']

#
# init web app
#

app = Flask(__name__)

if SENTRY_DSN:
    app.config['SENTRY_DSN'] = SENTRY_DSN
    sentry = Sentry(app)

#
# routes
#

@app.route('/email', methods=['POST'])
def email_handler():

    email = PostmarkInbound(json=request.data)

    app.logger.debug('recipient addr = %s' % email.to())
    app.logger.debug('sender addr = %s' % email.sender())

    valid_recipients = [e for e in email.to() if e.get('Email') == SERVICE_EMAIL]

    if valid_recipients:

        sender = email.sender()

        addr = sender.get('Email')
        name = sender.get('Name')

        if REGISTRATION_ENABLED:
            key = register_key(addr, name)
            key_notification(key, addr)
            app.logger.debug('key = %s' % key)

        else:
            disabled_notification(addr)

    return ''

@app.route('/email', methods=['GET'])
def mailto_redirect():

    subject = "Hello API"
    body = "Just hit Send and you'll receive an email containing your new API key.\n\nYou'll also be agreeing to our terms of service, which you can read at http://sunlightfoundation.com/api/usage/terms."

    return redirect('mailto:%s?subject=%s&body=%s' % (SERVICE_EMAIL, subject, body))

if __name__ == '__main__':
    app.run(debug=True, port=8000)
<commit_msg>Ugh. Fine. No newlines in the redirect URL.<commit_after>import hashlib
import hmac
import os
import urllib

import postmark
import requests
from postmark_inbound import PostmarkInbound
from raven.contrib.flask import Sentry

from flask import Flask, request, render_template, redirect

#
# app configuration
#

SERVICE_EMAIL = os.environ.get('SERVICE_EMAIL')

POSTMARK_KEY = os.environ.get('POSTMARK_KEY')
POSTMARK_SENDER = os.environ.get('POSTMARK_SENDER')

SUNLIGHT_KEY = os.environ.get('SUNLIGHT_KEY')
SUNLIGHT_SECRET = os.environ.get('SUNLIGHT_SECRET')
SUNLIGHT_URL = os.environ.get('SUNLIGHT_URL')

SENTRY_DSN = os.environ.get('SENTRY_DSN')

REGISTRATION_ENABLED = os.environ.get('REGISTRATION_ENABLED', '') != ''

#
# API registration
#

def get_signature(params):
    data = sorted([(k, unicode(v).encode('utf-8')) for k, v in params.items() if k != 'signature'])
    qs = urllib.urlencode(data)
    return hmac.new(SUNLIGHT_SECRET, qs, hashlib.sha1).hexdigest()

def key_notification(key, addr):
    context = {
        'key': key,
        'email': addr,
    }
    message = render_template('email/success.txt', **context)
    mail = postmark.PMMail(
        api_key=POSTMARK_KEY,
        sender=POSTMARK_SENDER,
        to=addr,
        subject='Here is your brand new Sunlight API key!',
        text_body=message,
    )
    mail.send()

def disabled_notification(addr):
    message = render_template('email/disabled.txt')
    mail = postmark.PMMail(
        api_key=POSTMARK_KEY,
        sender=POSTMARK_SENDER,
        to=addr,
        subject='Ack! A small problem with your Sunlight Foundation API key',
        text_body=message,
    )
    mail.send()

def register_key(addr, name):
    params = {
        'apikey': SUNLIGHT_KEY,
        'email': addr,
        'name': name or 'Sunlight Event Attendee',
    }
    params['signature'] = get_signature(params)
    resp = requests.post(SUNLIGHT_URL, params)
    data = resp.json()
    return data['key']

#
# init web app
#

app = Flask(__name__)

if SENTRY_DSN:
    app.config['SENTRY_DSN'] = SENTRY_DSN
    sentry = Sentry(app)

#
# routes
#

@app.route('/email', methods=['POST'])
def email_handler():

    email = PostmarkInbound(json=request.data)

    app.logger.debug('recipient addr = %s' % email.to())
    app.logger.debug('sender addr = %s' % email.sender())

    valid_recipients = [e for e in email.to() if e.get('Email') == SERVICE_EMAIL]

    if valid_recipients:

        sender = email.sender()

        addr = sender.get('Email')
        name = sender.get('Name')

        if REGISTRATION_ENABLED:
            key = register_key(addr, name)
            key_notification(key, addr)
            app.logger.debug('key = %s' % key)

        else:
            disabled_notification(addr)

    return ''

@app.route('/email', methods=['GET'])
def mailto_redirect():

    subject = "Hello API"
    body = "Just hit Send and you'll receive an email containing your new API key. You'll also be agreeing to our terms of service, which you can read at http://sunlightfoundation.com/api/usage/terms."

    return redirect('mailto:%s?subject=%s&body=%s' % (SERVICE_EMAIL, subject, body))

if __name__ == '__main__':
    app.run(debug=True, port=8000)
<|endoftext|>


<commit_before>#-*- coding: utf-8 -*-

from lxml import etree<commit_msg>añadiendo código para abrir los archvos<commit_after>#-*- coding: utf-8 -*-

from lxml import etree

#def alcoholemia(valor):

#Abrimos los ficheros con los datos

with open("./DATA/controles-alcoholemia.xml", "r")as alcohol:
    alcoholr = etree.parse(alcohol)

<|endoftext|>


<commit_before>#!bin/python
import json
import lib_zpr
#import logging
#from logging.handlers import RotatingFileHandler

from flask import Flask, jsonify, make_response

app = Flask(__name__)

# app.logger.setLevel(logging.INFO)
# app.logger.disabled = False
# handler = logging.handlers.RotatingFileHandler(
#     '/var/log/zpr_flask.log',
#     'a',
#     maxBytes=1024 * 1024 * 100,
#     backupCount=20
#     )
# log = logging.getLogger('werkzeug')
# log.setLevel(logging.DEBUG)
# app.logger.addHandler(handler)

api_version = 'v1.0'
api_base = str('/zpr/{v}'.format(v=api_version))
extra_files = [ '/var/lib/zpr/api/lib_zpr.py', '/var/lib/zpr/api/zpr.py' ]

@app.errorhandler(404)
def not_found(error):
    return make_response(jsonify({'error': 'Not found'}), 404)

# @app.route('/zpr/job')
# def ls_test():
#     return json.dumps(call('ls'))

# @app.route('{a}/job/rsync/<backup_host>'.format(a=api_base), methods=['GET'])
# def check_job(backup_host):
#     job = str(lib_zpr.check_zpr_rsync_job(backup_host))
#     return json.dumps(job)

@app.route('{a}/job/rsync/<backup_host>'.format(a=api_base), methods=['GET'])
def check_rsync_job(backup_host):
    lib_zpr.check_tsp_job(
        executable='rsync',
        jobname=backup_host
        )
    return json.dumps(str(lib_zpr.check_tsp_job_out[0]))

@app.route('{a}/job/duplicity/<backup_host>'.format(a=api_base), methods=['GET'])
def check_offsite_job(backup_host):
    lib_zpr.check_tsp_job(
        executable='duplicity',
        jobname=backup_host
        )
    return json.dumps(str(lib_zpr.check_tsp_job_out[0]))

if __name__ == '__main__':
#   formatter = logging.Formatter(\
#       "%(asctime)s - %(levelname)s - %(name)s: \t%(messages)s")
#   handler.setFormatter(formatter)
    app.run(host='127.0.0.1', extra_files=':'.join(extra_files))
<commit_msg>Reenable debug<commit_after>#!bin/python
import json
import lib_zpr
#import logging
#from logging.handlers import RotatingFileHandler

from flask import Flask, jsonify, make_response

app = Flask(__name__)

# app.logger.setLevel(logging.INFO)
# app.logger.disabled = False
# handler = logging.handlers.RotatingFileHandler(
#     '/var/log/zpr_flask.log',
#     'a',
#     maxBytes=1024 * 1024 * 100,
#     backupCount=20
#     )
# log = logging.getLogger('werkzeug')
# log.setLevel(logging.DEBUG)
# app.logger.addHandler(handler)

api_version = 'v1.0'
api_base = str('/zpr/{v}'.format(v=api_version))

@app.errorhandler(404)
def not_found(error):
    return make_response(jsonify({'error': 'Not found'}), 404)

# @app.route('/zpr/job')
# def ls_test():
#     return json.dumps(call('ls'))

# @app.route('{a}/job/rsync/<backup_host>'.format(a=api_base), methods=['GET'])
# def check_job(backup_host):
#     job = str(lib_zpr.check_zpr_rsync_job(backup_host))
#     return json.dumps(job)

@app.route('{a}/job/rsync/<backup_host>'.format(a=api_base), methods=['GET'])
def check_rsync_job(backup_host):
    lib_zpr.check_tsp_job(
        executable='rsync',
        jobname=backup_host
        )
    return json.dumps(str(lib_zpr.check_tsp_job_out[0]))

@app.route('{a}/job/duplicity/<backup_host>'.format(a=api_base), methods=['GET'])
def check_offsite_job(backup_host):
    lib_zpr.check_tsp_job(
        executable='duplicity',
        jobname=backup_host
        )
    return json.dumps(str(lib_zpr.check_tsp_job_out[0]))

if __name__ == '__main__':
#   formatter = logging.Formatter(\
#       "%(asctime)s - %(levelname)s - %(name)s: \t%(messages)s")
#   handler.setFormatter(formatter)
    app.run(debug=True, host='127.0.0.1', extra_files='/var/lib/zpr/api/lib_zpr.py')
<|endoftext|>


<commit_before>"""Provides the repository macro to import LLVM."""

load("//third_party:repo.bzl", "tf_http_archive")

def repo(name):
    """Imports LLVM."""
    LLVM_COMMIT = "955b91c19c00ed4c917559a5d66d14c669dde2e3"
    LLVM_SHA256 = "64d5d7be95c3f8819ef3c82b813ad345f1ae8d827afc451653da380c60325245"

    tf_http_archive(
        name = name,
        sha256 = LLVM_SHA256,
        strip_prefix = "llvm-project-{commit}".format(commit = LLVM_COMMIT),
        urls = [
            "https://storage.googleapis.com/mirror.tensorflow.org/github.com/llvm/llvm-project/archive/{commit}.tar.gz".format(commit = LLVM_COMMIT),
            "https://github.com/llvm/llvm-project/archive/{commit}.tar.gz".format(commit = LLVM_COMMIT),
        ],
        build_file = "//third_party/llvm:BUILD.bazel",
    )
<commit_msg>Integrate LLVM at llvm/llvm-project@9cdd4ea06f09<commit_after>"""Provides the repository macro to import LLVM."""

load("//third_party:repo.bzl", "tf_http_archive")

def repo(name):
    """Imports LLVM."""
    LLVM_COMMIT = "9cdd4ea06f094efaedb46e848e004baaad7cb183"
    LLVM_SHA256 = "5036640cf56af43fe802e43610b5bfdcffffdf2068619d6ae6fc47395d9f4d9b"

    tf_http_archive(
        name = name,
        sha256 = LLVM_SHA256,
        strip_prefix = "llvm-project-{commit}".format(commit = LLVM_COMMIT),
        urls = [
            "https://storage.googleapis.com/mirror.tensorflow.org/github.com/llvm/llvm-project/archive/{commit}.tar.gz".format(commit = LLVM_COMMIT),
            "https://github.com/llvm/llvm-project/archive/{commit}.tar.gz".format(commit = LLVM_COMMIT),
        ],
        build_file = "//third_party/llvm:BUILD.bazel",
    )
<|endoftext|>