<commit_before>from pypokerengine.engine.pay_info import PayInfo
from pypokerengine.engine.card import Card
from pypokerengine.engine.poker_constants import PokerConstants as Const

class Player:

  ACTION_FOLD_STR = "FOLD"
  ACTION_CALL_STR = "CALL"
  ACTION_RAISE_STR = "RAISE"
  ACTION_SMALL_BLIND = "SMALLBLIND"
  ACTION_BIG_BLIND = "BIGBLIND"

  def __init__(self, uuid, initial_stack, name="No Name"):
    self.name = name
    self.uuid = uuid
    self.hole_card = []
    self.stack = initial_stack
    self.round_action_histories = self.__init_round_action_histories()
    self.action_histories = []
    self.pay_info = PayInfo()

  def add_holecard(self, cards):
    if len(self.hole_card) != 0:
      raise ValueError(self.__dup_hole_msg)
    if len(cards) != 2:
      raise ValueError(self.__wrong_num_hole_msg % (len(cards)))
    if not all([isinstance(card, Card) for card in cards]):
      raise ValueError(self.__wrong_type_hole_msg)
    self.hole_card = cards

  def clear_holecard(self):
    self.hole_card = []

  def append_chip(self, amount):
    self.stack += amount

  def collect_bet(self, amount):
    if self.stack < amount:
      raise ValueError(self.__collect_err_msg % (amount, self.stack))
    self.stack -= amount

  def is_active(self):
    return self.pay_info.status != PayInfo.FOLDED

  def is_waiting_ask(self):
    return self.pay_info.status == PayInfo.PAY_TILL_END

  def add_action_history(self, kind, chip_amount=None, add_amount=None, sb_amount=None):
    history = None
    if kind == Const.Action.FOLD:
      history = self.__fold_history()
    elif kind == Const.Action.CALL:
      history = self.__call_history(chip_amount)
    elif kind == Const.Action.RAISE:
      history = self.__raise_history(chip_amount, add_amount)
    elif kind == Const.Action.SMALL_BLIND:
      history = self.__blind_history(True, sb_amount)
    elif kind == Const.Action.BIG_BLIND:
      history = self.__blind_history(False, sb_amount)
    elif kind == Const.Action.ANTE:
      history = self.__ante_history(chip_amount)
    else:
      raise "UnKnown action history is added (kind = %s)" % kind
    history = self.__add_uuid_on_history(history)
    self.action_histories.append(history)

  def save_street_action_histories(self, street_flg):
    self.round_action_histories[street_flg] = self.action_histories
    self.action_histories = []

  def clear_action_histories(self):
    self.round_action_histories = self.__init_round_action_histories()
    self.action_histories = []

  def clear_pay_info(self):
    self.pay_info = PayInfo()

  def paid_sum(self):
    pay_history = [h for h in self.action_histories if h["action"] != "FOLD"]
    last_pay_history = pay_history[-1] if len(pay_history)!=0 else None
    return last_pay_history["amount"] if last_pay_history else 0

  def serialize(self):
    hole = [card.to_id() for card in self.hole_card]
    return [
        self.name, self.uuid, self.stack, hole,\
            self.action_histories[::], self.pay_info.serialize(), self.round_action_histories[::]
    ]

  @classmethod
  def deserialize(self, serial):
    hole = [Card.from_id(cid) for cid in serial[3]]
    player = self(serial[1], serial[2], serial[0])
    if len(hole)!=0: player.add_holecard(hole)
    player.action_histories = serial[4]
    player.pay_info = PayInfo.deserialize(serial[5])
    player.round_action_histories = serial[6]
    return player

  """ private """

  __dup_hole_msg = "Hole card is already set"
  __wrong_num_hole_msg = "You passed  %d hole cards"
  __wrong_type_hole_msg = "You passed not Card object as hole card"
  __collect_err_msg = "Failed to collect %d chips. Because he has only %d chips"

  def __init_round_action_histories(self):
    return [None for _ in range(4)]  # 4 == len(["preflop", "flop", "turn", "river"])

  def __fold_history(self):
    return { "action" : self.ACTION_FOLD_STR }

  def __call_history(self, bet_amount):
    return {
        "action" : self.ACTION_CALL_STR,
        "amount" : bet_amount,
        "paid" : bet_amount - self.paid_sum()
    }

  def __raise_history(self, bet_amount, add_amount):
    return {
        "action" : self.ACTION_RAISE_STR,
        "amount" : bet_amount,
        "paid" : bet_amount - self.paid_sum(),
        "add_amount" : add_amount
        }

  def __blind_history(self, small_blind, sb_amount):
    assert(sb_amount is not None)
    action = self.ACTION_SMALL_BLIND if small_blind else self.ACTION_BIG_BLIND
    amount = sb_amount if small_blind else sb_amount*2
    add_amount = sb_amount
    return {
        "action" : action,
        "amount" : amount,
        "add_amount" : add_amount
        }

  def __ante_history(self, pay_amount):
    assert(pay_amount > 0)
    return {
        "action" : "ANTE",
        "amount" : pay_amount
        }

  def __add_uuid_on_history(self, history):
    history["uuid"] = self.uuid
    return history

<commit_msg>Make Ante action as const<commit_after>from pypokerengine.engine.pay_info import PayInfo
from pypokerengine.engine.card import Card
from pypokerengine.engine.poker_constants import PokerConstants as Const

class Player:

  ACTION_FOLD_STR = "FOLD"
  ACTION_CALL_STR = "CALL"
  ACTION_RAISE_STR = "RAISE"
  ACTION_SMALL_BLIND = "SMALLBLIND"
  ACTION_BIG_BLIND = "BIGBLIND"
  ACTION_ANTE = "ANTE"

  def __init__(self, uuid, initial_stack, name="No Name"):
    self.name = name
    self.uuid = uuid
    self.hole_card = []
    self.stack = initial_stack
    self.round_action_histories = self.__init_round_action_histories()
    self.action_histories = []
    self.pay_info = PayInfo()

  def add_holecard(self, cards):
    if len(self.hole_card) != 0:
      raise ValueError(self.__dup_hole_msg)
    if len(cards) != 2:
      raise ValueError(self.__wrong_num_hole_msg % (len(cards)))
    if not all([isinstance(card, Card) for card in cards]):
      raise ValueError(self.__wrong_type_hole_msg)
    self.hole_card = cards

  def clear_holecard(self):
    self.hole_card = []

  def append_chip(self, amount):
    self.stack += amount

  def collect_bet(self, amount):
    if self.stack < amount:
      raise ValueError(self.__collect_err_msg % (amount, self.stack))
    self.stack -= amount

  def is_active(self):
    return self.pay_info.status != PayInfo.FOLDED

  def is_waiting_ask(self):
    return self.pay_info.status == PayInfo.PAY_TILL_END

  def add_action_history(self, kind, chip_amount=None, add_amount=None, sb_amount=None):
    history = None
    if kind == Const.Action.FOLD:
      history = self.__fold_history()
    elif kind == Const.Action.CALL:
      history = self.__call_history(chip_amount)
    elif kind == Const.Action.RAISE:
      history = self.__raise_history(chip_amount, add_amount)
    elif kind == Const.Action.SMALL_BLIND:
      history = self.__blind_history(True, sb_amount)
    elif kind == Const.Action.BIG_BLIND:
      history = self.__blind_history(False, sb_amount)
    elif kind == Const.Action.ANTE:
      history = self.__ante_history(chip_amount)
    else:
      raise "UnKnown action history is added (kind = %s)" % kind
    history = self.__add_uuid_on_history(history)
    self.action_histories.append(history)

  def save_street_action_histories(self, street_flg):
    self.round_action_histories[street_flg] = self.action_histories
    self.action_histories = []

  def clear_action_histories(self):
    self.round_action_histories = self.__init_round_action_histories()
    self.action_histories = []

  def clear_pay_info(self):
    self.pay_info = PayInfo()

  def paid_sum(self):
    pay_history = [h for h in self.action_histories if h["action"] != "FOLD"]
    last_pay_history = pay_history[-1] if len(pay_history)!=0 else None
    return last_pay_history["amount"] if last_pay_history else 0

  def serialize(self):
    hole = [card.to_id() for card in self.hole_card]
    return [
        self.name, self.uuid, self.stack, hole,\
            self.action_histories[::], self.pay_info.serialize(), self.round_action_histories[::]
    ]

  @classmethod
  def deserialize(self, serial):
    hole = [Card.from_id(cid) for cid in serial[3]]
    player = self(serial[1], serial[2], serial[0])
    if len(hole)!=0: player.add_holecard(hole)
    player.action_histories = serial[4]
    player.pay_info = PayInfo.deserialize(serial[5])
    player.round_action_histories = serial[6]
    return player

  """ private """

  __dup_hole_msg = "Hole card is already set"
  __wrong_num_hole_msg = "You passed  %d hole cards"
  __wrong_type_hole_msg = "You passed not Card object as hole card"
  __collect_err_msg = "Failed to collect %d chips. Because he has only %d chips"

  def __init_round_action_histories(self):
    return [None for _ in range(4)]  # 4 == len(["preflop", "flop", "turn", "river"])

  def __fold_history(self):
    return { "action" : self.ACTION_FOLD_STR }

  def __call_history(self, bet_amount):
    return {
        "action" : self.ACTION_CALL_STR,
        "amount" : bet_amount,
        "paid" : bet_amount - self.paid_sum()
    }

  def __raise_history(self, bet_amount, add_amount):
    return {
        "action" : self.ACTION_RAISE_STR,
        "amount" : bet_amount,
        "paid" : bet_amount - self.paid_sum(),
        "add_amount" : add_amount
        }

  def __blind_history(self, small_blind, sb_amount):
    assert(sb_amount is not None)
    action = self.ACTION_SMALL_BLIND if small_blind else self.ACTION_BIG_BLIND
    amount = sb_amount if small_blind else sb_amount*2
    add_amount = sb_amount
    return {
        "action" : action,
        "amount" : amount,
        "add_amount" : add_amount
        }

  def __ante_history(self, pay_amount):
    assert(pay_amount > 0)
    return {
        "action" : self.ACTION_ANTE,
        "amount" : pay_amount
        }

  def __add_uuid_on_history(self, history):
    history["uuid"] = self.uuid
    return history

<|endoftext|>


<commit_before>"""Module for nodes of factor graphs.

This module contains classes for nodes of factor graphs,
which are used to build factor graphs.

Classes:
    Node: Abstract class for nodes.
    VNode: Class for variable nodes.
    IOVNode: Class for custom input-output variable nodes.
    FNode: Class for factor nodes.
    IOFNode: Class for custom input-output factor nodes.

"""

from abc import ABC, abstractmethod, abstractproperty
from enum import Enum
from types import MethodType

import networkx as nx
import numpy as np

class NodeType(Enum):

    """Enumeration for node types."""

    variable_node = 1
    factor_node = 2

class Node(ABC):

    """Abstract base class for all nodes."""

    def __init__(self, label):
        """Create a node with an associated label."""
        self.__label = str(label)
        self.__graph = None

    def __str__(self):
        """Return string representation."""
        return self.__label

    @abstractproperty
    def type(self):
        pass

    @property
    def graph(self):
        return self.__graph

    @graph.setter
    def graph(self, graph):
        self.__graph = graph

    def neighbors(self, exclusion=None):
        """Get all neighbors with a given exclusion.

        Return iterator over all neighboring nodes
        without the given exclusion node.

        Positional arguments:
        exclusion -- the exclusion node

        """

        if exclusion is None:
            return nx.all_neighbors(self.graph, self)
        else:
            # Build iterator set
            iterator = (exclusion,) \
                if not isinstance(exclusion, list) else exclusion

            # Return neighbors excluding iterator set
            return (n for n in nx.all_neighbors(self.graph, self)
                    if n not in iterator)

    @abstractmethod
    def spa(self, tnode):
        pass

    @abstractmethod
    def mpa(self, tnode):
        pass

    @abstractmethod
    def msa(self, tnode):
        pass

    @abstractmethod
    def mf(self, tnode):
        pass

class VNode(Node):

    """Variable node.

    Variable node inherited from node base class.
    Extends the base class with message passing methods.

    """

    def __init__(self, label, rv_type, observed=False):
        """Create a variable node."""
        super().__init__(label)
        self.init = rv_type.unity(self)
        self.observed = observed

    @property
    def type(self):
        return NodeType.variable_node

    @property
    def init(self):
        return self.__init

    @init.setter
    def init(self, init):
        self.__init = init

    def belief(self, normalize=True):
        """Return belief of the variable node.

        Args:
            normalize: Boolean flag if belief should be normalized.

        """
        iterator = self.graph.neighbors(self)

        # Pick first node
        n = next(iterator)

        # Product over all incoming messages
        belief = self.graph[n][self]['object'].get_message(n, self)
        if not self.graph[n][self]['object'].logarithmic:
            for n in iterator:
                belief *= self.graph[n][self]['object'].get_message(n, self)
        else:
            for n in iterator:
                belief += self.graph[n][self]['object'].get_message(n, self)

        if normalize:
            belief = belief.normalize()

        return belief

    def maximum(self, normalize=True):
        """Return the maximum probability of the variable node.

        Args:
            normalize: Boolean flag if belief should be normalized.

        """
        b = self.belief(normalize)
        return np.amax(b.pmf)

    def argmax(self):
        """Return the argument for maximum probability of the variable node."""
        # In case of multiple occurrences of the maximum values,
        # the indices corresponding to the first occurrence are returned.
        b = self.belief()
        return b.argmax(self)

    def spa(self, tnode):
        """Return message of the sum-product algorithm."""
        if self.observed:
            return self.init
        else:
            # Initial message
            msg = self.init

            # Product over incoming messages
            for n in self.neighbors(tnode):
                msg *= self.graph[n][self]['object'].get_message(n, self)

            return msg

    def mpa(self, tnode):
        """Return message of the max-product algorithm."""
        return self.spa(tnode)

    def msa(self, tnode):
        """Return message of the max-sum algorithm."""
        if self.observed:
            return self.init.log()
        else:
            # Initial (logarithmized) message
            msg = self.init.log()

            # Sum over incoming messages
            for n in self.neighbors(tnode):
                msg += self.graph[n][self]['object'].get_message(n, self)

            return msg

    def mf(self, tnode):
        """Return message of the mean-field algorithm."""
        if self.observed:
            return self.init
        else:
            return self.belief(self.graph)

class IOVNode(VNode):

    """Input-output variable node.

    Input-output variable node inherited from variable node class.
    Overwrites all message passing methods of the base class
    with a given callback function.

    """

    def __init__(self, label, init=None, observed=False, callback=None):
        """Create an input-output variable node."""
        super().__init__(label, init, observed)
        if callback is not None:
            self.set_callback(callback)

    def set_callback(self, callback):
        """Set callback function.

        Add bounded methods to the class instance in order to overwrite
        the existing message passing methods.

        """
        self.spa = MethodType(callback, self)
        self.mpa = MethodType(callback, self)
        self.msa = MethodType(callback, self)
        self.mf = MethodType(callback, self)

class FNode(Node):

    """Factor node.

    Factor node inherited from node base class.
    Extends the base class with message passing methods.

    """

    def __init__(self, label, factor=None):
        """Create a factor node."""
        super().__init__(label)
        self.factor = factor
        self.record = {}

    @property
    def type(self):
        return NodeType.factor_node

    @property
    def factor(self):
        return self.__factor

    @factor.setter
    def factor(self, factor):
        self.__factor = factor

    def spa(self, tnode):
        """Return message of the sum-product algorithm."""
        # Initialize with local factor
        msg = self.factor

        # Product over incoming messages
        for n in self.neighbors(tnode):
            msg *= self.graph[n][self]['object'].get_message(n, self)

        # Integration/Summation over incoming variables
        for n in self.neighbors(tnode):
            msg = msg.marginalize(n, normalize=False)

        return msg

    def mpa(self, tnode):
        """Return message of the max-product algorithm."""
        self.record[tnode] = {}

        # Initialize with local factor
        msg = self.factor

        # Product over incoming messages
        for n in self.neighbors(tnode):
            msg *= self.graph[n][self]['object'].get_message(n, self)

        # Maximization over incoming variables
        for n in self.neighbors(tnode):
            self.record[tnode][n] = msg.argmax(n)  # Record for back-tracking
            msg = msg.maximize(n, normalize=False)

        return msg

    def msa(self, tnode):
        """Return message of the max-sum algorithm."""
        self.record[tnode] = {}

        # Initialize with (logarithmized) local factor
        msg = self.factor.log()

        # Sum over incoming messages
        for n in self.neighbors(tnode):
            msg += self.graph[n][self]['object'].get_message(n, self)

        # Maximization over incoming variables
        for n in self.neighbors(tnode):
            self.record[tnode][n] = msg.argmax(n)  # Record for back-tracking
            msg = msg.maximize(n, normalize=False)

        return msg

    def mf(self, tnode):
        """Return message of the mean-field algorithm."""
        # Initialize with local factor
        msg = self.factor

#         # Product over incoming messages
#         for n in self.neighbors(graph, self, tnode):
#             msg *= graph[n][self]['object'].get_message(n, self)
#
#         # Integration/Summation over incoming variables
#         for n in self.neighbors(graph, self, tnode):
#             msg = msg.int(n)

        return msg

class IOFNode(FNode):

    """Input-output factor node.

    Input-output factor node inherited from factor node class.
    Overwrites all message passing methods of the base class
    with a given callback function.

    """

    def __init__(self, label, factor, callback=None):
        """Create an input-output factor node."""
        super().__init__(self, label, factor)
        if callback is not None:
            self.set_callback(callback)

    def set_callback(self, callback):
        """Set callback function.

        Add bounded methods to the class instance in order to overwrite
        the existing message passing methods.

        """
        self.spa = MethodType(callback, self)
        self.mpa = MethodType(callback, self)
        self.msa = MethodType(callback, self)
        self.mf = MethodType(callback, self)
<commit_msg>use docstring instead of pass in abstract class<commit_after>"""Module for nodes of factor graphs.

This module contains classes for nodes of factor graphs,
which are used to build factor graphs.

Classes:
    Node: Abstract class for nodes.
    VNode: Class for variable nodes.
    IOVNode: Class for custom input-output variable nodes.
    FNode: Class for factor nodes.
    IOFNode: Class for custom input-output factor nodes.

"""

from abc import ABC, abstractmethod, abstractproperty
from enum import Enum
from types import MethodType

import networkx as nx
import numpy as np

class NodeType(Enum):

    """Enumeration for node types."""

    variable_node = 1
    factor_node = 2

class Node(ABC):

    """Abstract base class for all nodes."""

    def __init__(self, label):
        """Create a node with an associated label."""
        self.__label = str(label)
        self.__graph = None

    def __str__(self):
        """Return string representation."""
        return self.__label

    @abstractproperty
    def type(self):
        """Specify the NodeType."""

    @property
    def graph(self):
        return self.__graph

    @graph.setter
    def graph(self, graph):
        self.__graph = graph

    def neighbors(self, exclusion=None):
        """Get all neighbors with a given exclusion.

        Return iterator over all neighboring nodes
        without the given exclusion node.

        Positional arguments:
        exclusion -- the exclusion node

        """

        if exclusion is None:
            return nx.all_neighbors(self.graph, self)
        else:
            # Build iterator set
            iterator = (exclusion,) \
                if not isinstance(exclusion, list) else exclusion

            # Return neighbors excluding iterator set
            return (n for n in nx.all_neighbors(self.graph, self)
                    if n not in iterator)

    @abstractmethod
    def spa(self, tnode):
        """Return message of the sum-product algorithm."""

    @abstractmethod
    def mpa(self, tnode):
        """Return message of the max-product algorithm."""

    @abstractmethod
    def msa(self, tnode):
        """Return message of the max-sum algorithm."""

    @abstractmethod
    def mf(self, tnode):
        """Return message of the mean-field algorithm."""

class VNode(Node):

    """Variable node.

    Variable node inherited from node base class.
    Extends the base class with message passing methods.

    """

    def __init__(self, label, rv_type, observed=False):
        """Create a variable node."""
        super().__init__(label)
        self.init = rv_type.unity(self)
        self.observed = observed

    @property
    def type(self):
        return NodeType.variable_node

    @property
    def init(self):
        return self.__init

    @init.setter
    def init(self, init):
        self.__init = init

    def belief(self, normalize=True):
        """Return belief of the variable node.

        Args:
            normalize: Boolean flag if belief should be normalized.

        """
        iterator = self.graph.neighbors(self)

        # Pick first node
        n = next(iterator)

        # Product over all incoming messages
        belief = self.graph[n][self]['object'].get_message(n, self)
        if not self.graph[n][self]['object'].logarithmic:
            for n in iterator:
                belief *= self.graph[n][self]['object'].get_message(n, self)
        else:
            for n in iterator:
                belief += self.graph[n][self]['object'].get_message(n, self)

        if normalize:
            belief = belief.normalize()

        return belief

    def maximum(self, normalize=True):
        """Return the maximum probability of the variable node.

        Args:
            normalize: Boolean flag if belief should be normalized.

        """
        b = self.belief(normalize)
        return np.amax(b.pmf)

    def argmax(self):
        """Return the argument for maximum probability of the variable node."""
        # In case of multiple occurrences of the maximum values,
        # the indices corresponding to the first occurrence are returned.
        b = self.belief()
        return b.argmax(self)

    def spa(self, tnode):
        """Return message of the sum-product algorithm."""
        if self.observed:
            return self.init
        else:
            # Initial message
            msg = self.init

            # Product over incoming messages
            for n in self.neighbors(tnode):
                msg *= self.graph[n][self]['object'].get_message(n, self)

            return msg

    def mpa(self, tnode):
        """Return message of the max-product algorithm."""
        return self.spa(tnode)

    def msa(self, tnode):
        """Return message of the max-sum algorithm."""
        if self.observed:
            return self.init.log()
        else:
            # Initial (logarithmized) message
            msg = self.init.log()

            # Sum over incoming messages
            for n in self.neighbors(tnode):
                msg += self.graph[n][self]['object'].get_message(n, self)

            return msg

    def mf(self, tnode):
        """Return message of the mean-field algorithm."""
        if self.observed:
            return self.init
        else:
            return self.belief(self.graph)

class IOVNode(VNode):

    """Input-output variable node.

    Input-output variable node inherited from variable node class.
    Overwrites all message passing methods of the base class
    with a given callback function.

    """

    def __init__(self, label, init=None, observed=False, callback=None):
        """Create an input-output variable node."""
        super().__init__(label, init, observed)
        if callback is not None:
            self.set_callback(callback)

    def set_callback(self, callback):
        """Set callback function.

        Add bounded methods to the class instance in order to overwrite
        the existing message passing methods.

        """
        self.spa = MethodType(callback, self)
        self.mpa = MethodType(callback, self)
        self.msa = MethodType(callback, self)
        self.mf = MethodType(callback, self)

class FNode(Node):

    """Factor node.

    Factor node inherited from node base class.
    Extends the base class with message passing methods.

    """

    def __init__(self, label, factor=None):
        """Create a factor node."""
        super().__init__(label)
        self.factor = factor
        self.record = {}

    @property
    def type(self):
        return NodeType.factor_node

    @property
    def factor(self):
        return self.__factor

    @factor.setter
    def factor(self, factor):
        self.__factor = factor

    def spa(self, tnode):
        """Return message of the sum-product algorithm."""
        # Initialize with local factor
        msg = self.factor

        # Product over incoming messages
        for n in self.neighbors(tnode):
            msg *= self.graph[n][self]['object'].get_message(n, self)

        # Integration/Summation over incoming variables
        for n in self.neighbors(tnode):
            msg = msg.marginalize(n, normalize=False)

        return msg

    def mpa(self, tnode):
        """Return message of the max-product algorithm."""
        self.record[tnode] = {}

        # Initialize with local factor
        msg = self.factor

        # Product over incoming messages
        for n in self.neighbors(tnode):
            msg *= self.graph[n][self]['object'].get_message(n, self)

        # Maximization over incoming variables
        for n in self.neighbors(tnode):
            self.record[tnode][n] = msg.argmax(n)  # Record for back-tracking
            msg = msg.maximize(n, normalize=False)

        return msg

    def msa(self, tnode):
        """Return message of the max-sum algorithm."""
        self.record[tnode] = {}

        # Initialize with (logarithmized) local factor
        msg = self.factor.log()

        # Sum over incoming messages
        for n in self.neighbors(tnode):
            msg += self.graph[n][self]['object'].get_message(n, self)

        # Maximization over incoming variables
        for n in self.neighbors(tnode):
            self.record[tnode][n] = msg.argmax(n)  # Record for back-tracking
            msg = msg.maximize(n, normalize=False)

        return msg

    def mf(self, tnode):
        """Return message of the mean-field algorithm."""
        # Initialize with local factor
        msg = self.factor

#         # Product over incoming messages
#         for n in self.neighbors(graph, self, tnode):
#             msg *= graph[n][self]['object'].get_message(n, self)
#
#         # Integration/Summation over incoming variables
#         for n in self.neighbors(graph, self, tnode):
#             msg = msg.int(n)

        return msg

class IOFNode(FNode):

    """Input-output factor node.

    Input-output factor node inherited from factor node class.
    Overwrites all message passing methods of the base class
    with a given callback function.

    """

    def __init__(self, label, factor, callback=None):
        """Create an input-output factor node."""
        super().__init__(self, label, factor)
        if callback is not None:
            self.set_callback(callback)

    def set_callback(self, callback):
        """Set callback function.

        Add bounded methods to the class instance in order to overwrite
        the existing message passing methods.

        """
        self.spa = MethodType(callback, self)
        self.mpa = MethodType(callback, self)
        self.msa = MethodType(callback, self)
        self.mf = MethodType(callback, self)
<|endoftext|>


<commit_before>import collections

import numpy as np
from scipy import sparse, ndimage as ndi
import networkx as nx

from viridis import tree

from . import evaluate as ev
from . import sparselol

def edge_matrix(labels, connectivity=1):
    """Generate a COO matrix containing the coordinates of edge pixels.

    Parameters
    ----------
    labels : array of int
        An array of labeled pixels (or voxels).
    connectivity : int in {1, ..., labels.ndim}
        The square connectivity for considering neighborhood.

    Returns
    -------
    edges : sparse.coo_matrix
        A COO matrix where (i, j) indicate neighboring labels and the
        corresponding data element is the linear index of the edge pixel
        in the labels array.
    """
    conn = ndi.generate_binary_structure(labels.ndim, connectivity)
    eroded = ndi.grey_erosion(labels, footprint=conn).ravel()
    dilated = ndi.grey_dilation(labels, footprint=conn).ravel()
    labels = labels.ravel()
    boundaries0 = np.flatnonzero(eroded != labels)
    boundaries1 = np.flatnonzero(dilated != labels)
    labels_small = np.concatenate((eroded[boundaries0], labels[boundaries1]))
    labels_large = np.concatenate((labels[boundaries0], dilated[boundaries1]))
    n = np.max(labels_large) + 1
    data = np.concatenate((boundaries0, boundaries1))
    sparse_graph = sparse.coo_matrix((data, (labels_small, labels_large)),
                                     dtype=np.int_, shape=(n, n))
    return sparse_graph

def sparse_boundaries(coo_boundaries):
    """Use a sparselol to map edges to boundary extents.

    Parameters
    ----------
    coo_boundaries : sparse.coo_matrix
        The boundary locations encoded in ``(i, j, loc)`` form in a sparse COO
        matrix (scipy), where ``loc`` is the raveled index of a pixel that is
        part of the boundary between segments ``i`` and ``j``.

    Returns
    -------
    edge_to_idx : CSR matrix
    """
    edge_to_idx = coo_boundaries.tocsr()
    # edge_to_idx: CSR matrix that maps each edge to a unique integer
    edge_to_idx.data = np.arange(len(edge_to_idx.data), dtype=np.int_)
    edge_labels = np.ravel(edge_to_idx[coo_boundaries.row, coo_boundaries.col])
    bounds = sparselol.extents(edge_labels, input_indices=coo_boundaries.data)
    return edge_to_idx, bounds

def fast_rag(labels, connectivity=1, out=None):
    """Build a data-free region adjacency graph quickly.

    Parameters
    ----------
    labels : array of int
        Image pre-segmentation or segmentation
    connectivity : int in {1, ..., labels.ndim}, optional
        Use square connectivity equal to `connectivity`. See
        `scipy.ndimage.generate_binary_structure` for more.
    out : networkx.Graph, optional
        Add edges into this graph object.

    Returns
    -------
    g : networkx Graph
        A graph where nodes represent regions in `labels` and edges
        indicate adjacency.

    Examples
    --------
    >>> labels = np.array([[1, 1, 1, 2, 2],
    ...                    [1, 1, 1, 2, 2],
    ...                    [3, 3, 4, 4, 4],
    ...                    [3, 3, 4, 4, 4]], dtype=np.int_)
    >>> sorted(fast_rag(labels).edges())
    [(1, 2), (1, 3), (1, 4), (2, 4), (3, 4)]

    Use the ``out`` parameter to build into an existing networkx graph.
    Warning: the existing graph contents will be cleared!

    >>> import networkx as nx
    >>> g = nx.Graph()
    >>> h = fast_rag(labels, out=g)
    >>> g is h
    True
    >>> sorted(h.edges())
    [(1, 2), (1, 3), (1, 4), (2, 4), (3, 4)]

    The edges contain the number of pixels counted in the boundary:

    >>> h[1][4]
    {'count': 2}
    >>> h[1][3]
    {'count': 4}

    ``fast_rag`` works on data of any dimension. For a 1D array:

    >>> labels = np.array([1, 1, 5, 5], dtype=np.int_)
    >>> fast_rag(labels).edges()
    [(1, 5)]
    """
    coo_graph = edge_matrix(labels, connectivity)
    # use a broadcast array of ones as data; these will get aggregated
    # into counts when the COO is converted to CSR
    coo_graph.data = np.broadcast_to(np.ones((1,), dtype=np.int_),
                                     coo_graph.row.shape)
    sparse_graph = coo_graph.tocsr()
    rag = nx.Graph() if out is None else out
    rag = nx.from_scipy_sparse_matrix(sparse_graph, create_using=rag,
                                      edge_attribute='count')
    return rag

class Rag(object):
    """A minimal region adjacency graph class.

    Parameters
    ----------
    labels : array of int
        An n-dimensional array of integer-labeled regions.
    connectivity : int in {1, ..., `labels.ndim`}, optional
        The square connectivity, determining which nearby pixels are
        considered neighbors.

    Attributes
    ----------
    labels : array of int
        Reference to the input. (ie if the input array is modified, so will
        the value in this attribute!)
    graph : networkx.Graph
        The region adjacency graph constructed from `labels`.
    tree : viridis.tree.Ultrametric
        The merge tree, for which the nodes in `graph` are leaves.
    """
    def __init__(self, labels : np.ndarray, connectivity: int = 1):
        self.labels = labels
        self.graph = fast_rag(labels, connectivity)
        self.tree = tree.Ultrametric(init_nodes=self.graph.nodes())

    def merge_subgraph(self, subgraph: collections.Iterable = {},
                       source: int = None):
        """Merge nodes given by `subgraph`.

        Parameters
        ----------
        subgraph : iterable of int, optional
            A subset of nodes in `self.graph`.
        source : int, optional
            Merge subgraph starting at this node.
        """
        # first, turn node collection into graph (ie with corresponding edges)
        subgraph = self.graph.subgraph(subgraph)
        if len(subgraph) == 0:
            # do nothing given empty subgraph
            return
        for connected_subgraph in nx.connected_component_subgraphs(subgraph):
            ordered_nodes = nx.dfs_preorder_nodes(connected_subgraph, source)
            current_node = next(ordered_nodes)
            for next_node in ordered_nodes:
                current_node = self.tree.merge(current_node, next_node)

    def current_segmentation(self,
                             cut_threshold: float = np.inf) -> np.ndarray:
        """Return the segmentation implied by the graph and current merge tree.

        Parameters
        ----------
        cut_threshold : float, optional
            If provided, cut the merge tree at this threshold (virtually;
            the tree is not modified) before calculating the segmentation.

        Returns
        -------
        seg : array of int
            The segmentation.

        """
        label_map = self.tree.get_map(cut_threshold)
        return label_map[self.labels]

def best_segmentation(fragments: np.ndarray, ground_truth: np.ndarray,
                      random_seed: int = None) -> np.ndarray:
    """Return the best segmentation possible when only merging in `fragments`.

    Parameters
    ----------
    fragments : array of int
        An initial oversegmentation.
    ground_truth : array of int
        The true segmentation.
    random_seed : int, optional
        Seed `numpy.random` with this value.

    Returns
    -------
    segments : array of int
        The closest segmentation to `ground_truth` that can be obtained
        by only merging in `fragments`.

    Examples
    --------
    >>> fragments = np.array([[1, 1, 1, 2],
    ...                       [1, 1, 2, 2],
    ...                       [3, 4, 4, 4]], dtype=np.int_)
    >>> ground_truth = np.array([[1, 1, 2, 2]] * 3, dtype=np.int_)
    >>> best_segmentation(fragments, ground_truth)
    array([[5, 5, 5, 6],
           [5, 5, 6, 6],
           [5, 6, 6, 6]])
    """
    if random_seed is not None:
        np.random.seed(random_seed)
    assignments = ev.assignment_table(fragments, ground_truth).tocsc()
    indptr = assignments.indptr
    rag = Rag(fragments)
    for i in range(len(indptr) - 1):
        rag.merge_subgraph(assignments.indices[indptr[i]:indptr[i+1]])
    return rag.current_segmentation()
<commit_msg>Use ID 1..n instead of 0..n-1 in sparse boundaries<commit_after>import collections

import numpy as np
from scipy import sparse, ndimage as ndi
import networkx as nx

from viridis import tree

from . import evaluate as ev
from . import sparselol

def edge_matrix(labels, connectivity=1):
    """Generate a COO matrix containing the coordinates of edge pixels.

    Parameters
    ----------
    labels : array of int
        An array of labeled pixels (or voxels).
    connectivity : int in {1, ..., labels.ndim}
        The square connectivity for considering neighborhood.

    Returns
    -------
    edges : sparse.coo_matrix
        A COO matrix where (i, j) indicate neighboring labels and the
        corresponding data element is the linear index of the edge pixel
        in the labels array.
    """
    conn = ndi.generate_binary_structure(labels.ndim, connectivity)
    eroded = ndi.grey_erosion(labels, footprint=conn).ravel()
    dilated = ndi.grey_dilation(labels, footprint=conn).ravel()
    labels = labels.ravel()
    boundaries0 = np.flatnonzero(eroded != labels)
    boundaries1 = np.flatnonzero(dilated != labels)
    labels_small = np.concatenate((eroded[boundaries0], labels[boundaries1]))
    labels_large = np.concatenate((labels[boundaries0], dilated[boundaries1]))
    n = np.max(labels_large) + 1
    data = np.concatenate((boundaries0, boundaries1))
    sparse_graph = sparse.coo_matrix((data, (labels_small, labels_large)),
                                     dtype=np.int_, shape=(n, n))
    return sparse_graph

def sparse_boundaries(coo_boundaries):
    """Use a sparselol to map edges to boundary extents.

    Parameters
    ----------
    coo_boundaries : sparse.coo_matrix
        The boundary locations encoded in ``(i, j, loc)`` form in a sparse COO
        matrix (scipy), where ``loc`` is the raveled index of a pixel that is
        part of the boundary between segments ``i`` and ``j``.

    Returns
    -------
    edge_to_idx : CSR matrix
    """
    edge_to_idx = coo_boundaries.tocsr()
    # edge_to_idx: CSR matrix that maps each edge to a unique integer
    # we don't use the ID 0 so that empty spots can be used to mean "no ID".
    edge_to_idx.data = np.arange(1, len(edge_to_idx.data) + 1, dtype=np.int_)
    edge_labels = np.ravel(edge_to_idx[coo_boundaries.row, coo_boundaries.col])
    bounds = sparselol.extents(edge_labels, input_indices=coo_boundaries.data)
    return edge_to_idx, bounds

def fast_rag(labels, connectivity=1, out=None):
    """Build a data-free region adjacency graph quickly.

    Parameters
    ----------
    labels : array of int
        Image pre-segmentation or segmentation
    connectivity : int in {1, ..., labels.ndim}, optional
        Use square connectivity equal to `connectivity`. See
        `scipy.ndimage.generate_binary_structure` for more.
    out : networkx.Graph, optional
        Add edges into this graph object.

    Returns
    -------
    g : networkx Graph
        A graph where nodes represent regions in `labels` and edges
        indicate adjacency.

    Examples
    --------
    >>> labels = np.array([[1, 1, 1, 2, 2],
    ...                    [1, 1, 1, 2, 2],
    ...                    [3, 3, 4, 4, 4],
    ...                    [3, 3, 4, 4, 4]], dtype=np.int_)
    >>> sorted(fast_rag(labels).edges())
    [(1, 2), (1, 3), (1, 4), (2, 4), (3, 4)]

    Use the ``out`` parameter to build into an existing networkx graph.
    Warning: the existing graph contents will be cleared!

    >>> import networkx as nx
    >>> g = nx.Graph()
    >>> h = fast_rag(labels, out=g)
    >>> g is h
    True
    >>> sorted(h.edges())
    [(1, 2), (1, 3), (1, 4), (2, 4), (3, 4)]

    The edges contain the number of pixels counted in the boundary:

    >>> h[1][4]
    {'count': 2}
    >>> h[1][3]
    {'count': 4}

    ``fast_rag`` works on data of any dimension. For a 1D array:

    >>> labels = np.array([1, 1, 5, 5], dtype=np.int_)
    >>> fast_rag(labels).edges()
    [(1, 5)]
    """
    coo_graph = edge_matrix(labels, connectivity)
    # use a broadcast array of ones as data; these will get aggregated
    # into counts when the COO is converted to CSR
    coo_graph.data = np.broadcast_to(np.ones((1,), dtype=np.int_),
                                     coo_graph.row.shape)
    sparse_graph = coo_graph.tocsr()
    rag = nx.Graph() if out is None else out
    rag = nx.from_scipy_sparse_matrix(sparse_graph, create_using=rag,
                                      edge_attribute='count')
    return rag

class Rag(object):
    """A minimal region adjacency graph class.

    Parameters
    ----------
    labels : array of int
        An n-dimensional array of integer-labeled regions.
    connectivity : int in {1, ..., `labels.ndim`}, optional
        The square connectivity, determining which nearby pixels are
        considered neighbors.

    Attributes
    ----------
    labels : array of int
        Reference to the input. (ie if the input array is modified, so will
        the value in this attribute!)
    graph : networkx.Graph
        The region adjacency graph constructed from `labels`.
    tree : viridis.tree.Ultrametric
        The merge tree, for which the nodes in `graph` are leaves.
    """
    def __init__(self, labels : np.ndarray, connectivity: int = 1):
        self.labels = labels
        self.graph = fast_rag(labels, connectivity)
        self.tree = tree.Ultrametric(init_nodes=self.graph.nodes())

    def merge_subgraph(self, subgraph: collections.Iterable = {},
                       source: int = None):
        """Merge nodes given by `subgraph`.

        Parameters
        ----------
        subgraph : iterable of int, optional
            A subset of nodes in `self.graph`.
        source : int, optional
            Merge subgraph starting at this node.
        """
        # first, turn node collection into graph (ie with corresponding edges)
        subgraph = self.graph.subgraph(subgraph)
        if len(subgraph) == 0:
            # do nothing given empty subgraph
            return
        for connected_subgraph in nx.connected_component_subgraphs(subgraph):
            ordered_nodes = nx.dfs_preorder_nodes(connected_subgraph, source)
            current_node = next(ordered_nodes)
            for next_node in ordered_nodes:
                current_node = self.tree.merge(current_node, next_node)

    def current_segmentation(self,
                             cut_threshold: float = np.inf) -> np.ndarray:
        """Return the segmentation implied by the graph and current merge tree.

        Parameters
        ----------
        cut_threshold : float, optional
            If provided, cut the merge tree at this threshold (virtually;
            the tree is not modified) before calculating the segmentation.

        Returns
        -------
        seg : array of int
            The segmentation.

        """
        label_map = self.tree.get_map(cut_threshold)
        return label_map[self.labels]

def best_segmentation(fragments: np.ndarray, ground_truth: np.ndarray,
                      random_seed: int = None) -> np.ndarray:
    """Return the best segmentation possible when only merging in `fragments`.

    Parameters
    ----------
    fragments : array of int
        An initial oversegmentation.
    ground_truth : array of int
        The true segmentation.
    random_seed : int, optional
        Seed `numpy.random` with this value.

    Returns
    -------
    segments : array of int
        The closest segmentation to `ground_truth` that can be obtained
        by only merging in `fragments`.

    Examples
    --------
    >>> fragments = np.array([[1, 1, 1, 2],
    ...                       [1, 1, 2, 2],
    ...                       [3, 4, 4, 4]], dtype=np.int_)
    >>> ground_truth = np.array([[1, 1, 2, 2]] * 3, dtype=np.int_)
    >>> best_segmentation(fragments, ground_truth)
    array([[5, 5, 5, 6],
           [5, 5, 6, 6],
           [5, 6, 6, 6]])
    """
    if random_seed is not None:
        np.random.seed(random_seed)
    assignments = ev.assignment_table(fragments, ground_truth).tocsc()
    indptr = assignments.indptr
    rag = Rag(fragments)
    for i in range(len(indptr) - 1):
        rag.merge_subgraph(assignments.indices[indptr[i]:indptr[i+1]])
    return rag.current_segmentation()
<|endoftext|>


<commit_before>#     Copyright 2022. ThingsBoard
#
#     Licensed under the Apache License, Version 2.0 (the "License");
#     you may not use this file except in compliance with the License.
#     You may obtain a copy of the License at
#
#         http://www.apache.org/licenses/LICENSE-2.0
#
#     Unless required by applicable law or agreed to in writing, software
#     distributed under the License is distributed on an "AS IS" BASIS,
#     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#     See the License for the specific language governing permissions and
#     limitations under the License.

"""Import libraries"""

import time
from random import choice
from string import ascii_lowercase
from threading import Thread

import serial

from thingsboard_gateway.connectors.connector import Connector, log  # Import base class for connector and logger
from thingsboard_gateway.tb_utility.tb_loader import TBModuleLoader

class CustomSerialConnector(Thread, Connector):  # Define a connector class, it should inherit from "Connector" class.
    def __init__(self, gateway, config, connector_type):
        super().__init__()  # Initialize parents classes
        self.statistics = {'MessagesReceived': 0,
                           'MessagesSent': 0}  # Dictionary, will save information about count received and sent messages.
        self.__config = config  # Save configuration from the configuration file.
        self.__gateway = gateway  # Save gateway object, we will use some gateway methods for adding devices and saving data from them.
        self.setName(self.__config.get("name",
                                       "Custom %s connector " % self.get_name() + ''.join(
                                           choice(ascii_lowercase) for _ in range(5))))  # get from the configuration or create name for logs.
        log.info("Starting Custom %s connector", self.get_name())  # Send message to logger
        self.daemon = True  # Set self thread as daemon
        self.stopped = True  # Service variable for check state
        self.__connected = False  # Service variable for check connection to device
        self.__devices = {}  # Dictionary with devices, will contain devices configurations, converters for devices and serial port objects
        self.__load_converters(connector_type)  # Call function to load converters and save it into devices dictionary
        self.__connect_to_devices()  # Call function for connect to devices
        log.info('Custom connector %s initialization success.', self.get_name())  # Message to logger
        log.info("Devices in configuration file found: %s ", '\n'.join(device for device in self.__devices))  # Message to logger

    def __connect_to_devices(self):  # Function for opening connection and connecting to devices
        for device in self.__devices:
            try:  # Start error handler
                connection_start = time.time()
                if self.__devices[device].get("serial") is None \
                        or self.__devices[device]["serial"] is None \
                        or not self.__devices[device]["serial"].isOpen():  # Connect only if serial not available earlier or it is closed.
                    self.__devices[device]["serial"] = None
                    while self.__devices[device]["serial"] is None or not self.__devices[device]["serial"].isOpen():  # Try connect
                        # connection to serial port with parameters from configuration file or default
                        device_config = self.__devices[device]["device_config"]
                        self.__devices[device]["serial"] = serial.Serial(port=device_config.get('port', '/dev/ttyUSB0'),
                                                                         baudrate=device_config.get('baudrate', 9600),
                                                                         bytesize=device_config.get('bytesize', serial.EIGHTBITS),
                                                                         parity=device_config.get('parity', serial.PARITY_NONE),
                                                                         stopbits=device_config.get('stopbits', serial.STOPBITS_ONE),
                                                                         timeout=device_config.get('timeout', 1),
                                                                         xonxoff=device_config.get('xonxoff', False),
                                                                         rtscts=device_config.get('rtscts', False),
                                                                         write_timeout=device_config.get('write_timeout', None),
                                                                         dsrdtr=device_config.get('dsrdtr', False),
                                                                         inter_byte_timeout=device_config.get('inter_byte_timeout', None),
                                                                         exclusive=device_config.get('exclusive', None))
                        time.sleep(.1)
                        if time.time() - connection_start > 10:  # Break connection try if it setting up for 10 seconds
                            log.error("Connection refused per timeout for device %s", device_config.get("name"))
                            break
            except serial.serialutil.SerialException:
                log.error("Port %s for device %s - not found", self.__devices[device]["device_config"].get('port', '/dev/ttyUSB0'), device)
            except Exception as e:
                log.exception(e)
            else:  # if no exception handled - add device and change connection state
                self.__gateway.add_device(self.__devices[device]["device_config"]["name"], {"connector": self}, self.__devices[device]["device_config"]["type"])
                self.__connected = True

    def open(self):  # Function called by gateway on start
        self.stopped = False
        self.start()

    def get_name(self):  # Function used for logging, sending data and statistic
        return self.name

    def is_connected(self):  # Function for checking connection state
        return self.__connected

    def __load_converters(self, connector_type):  # Function for search a converter and save it.
        devices_config = self.__config.get('devices')
        try:
            if devices_config is not None:
                for device_config in devices_config:
                    if device_config.get('converter') is not None:
                        converter = TBModuleLoader.import_module(connector_type, device_config['converter'])
                        self.__devices[device_config['name']] = {'converter': converter(device_config),
                                                                 'device_config': device_config}
                    else:
                        log.error('Converter configuration for the custom connector %s -- not found, please check your configuration file.', self.get_name())
            else:
                log.error('Section "devices" in the configuration not found. A custom connector %s has being stopped.', self.get_name())
                self.close()
        except Exception as e:
            log.exception(e)

    def run(self):  # Main loop of thread
        try:
            while True:
                for device in self.__devices:
                    device_serial_port = self.__devices[device]["serial"]
                    received_character = b''
                    data_from_device = b''
                    while received_character != b'\n':  # We will read until receive LF symbol
                        try:
                            received_character = device_serial_port.read(1)  # Read one symbol per time
                        except AttributeError as e:
                            if device_serial_port is None:
                                self.__connect_to_devices()  # if port not found - try to connect to it
                                raise e
                        except Exception as e:
                            log.exception(e)
                            break
                        else:
                            data_from_device = data_from_device + received_character
                    try:
                        converted_data = self.__devices[device]['converter'].convert(self.__devices[device]['device_config'], data_from_device)
                        self.__gateway.send_to_storage(self.get_name(), converted_data)
                        time.sleep(.1)
                    except Exception as e:
                        log.exception(e)
                        self.close()
                        raise e
                if not self.__connected:
                    break
        except Exception as e:
            log.exception(e)

    def close(self):  # Close connect function, usually used if exception handled in gateway main loop or in connector main loop
        self.stopped = True
        for device in self.__devices:
            self.__gateway.del_device(self.__devices[device])
            if self.__devices[device]['serial'].isOpen():
                self.__devices[device]['serial'].close()

    def on_attributes_update(self, content):  # Function used for processing attribute update requests from ThingsBoard
        log.debug(content)
        if self.__devices.get(content["device"]) is not None:
            device_config = self.__devices[content["device"]].get("device_config")
            if device_config is not None and device_config.get("attributeUpdates") is not None:
                requests = device_config["attributeUpdates"]
                for request in requests:
                    attribute = request.get("attributeOnThingsBoard")
                    log.debug(attribute)
                    if attribute is not None and attribute in content["data"]:
                        try:
                            value = content["data"][attribute]
                            str_to_send = str(request["stringToDevice"].replace("${" + attribute + "}", str(value))).encode("UTF-8")
                            self.__devices[content["device"]]["serial"].write(str_to_send)
                            log.debug("Attribute update request to device %s : %s", content["device"], str_to_send)
                            time.sleep(.01)
                        except Exception as e:
                            log.exception(e)

    def server_side_rpc_handler(self, content):
        pass
<commit_msg>Serial Connecter: Delete device from connector<commit_after>#     Copyright 2022. ThingsBoard
#
#     Licensed under the Apache License, Version 2.0 (the "License");
#     you may not use this file except in compliance with the License.
#     You may obtain a copy of the License at
#
#         http://www.apache.org/licenses/LICENSE-2.0
#
#     Unless required by applicable law or agreed to in writing, software
#     distributed under the License is distributed on an "AS IS" BASIS,
#     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#     See the License for the specific language governing permissions and
#     limitations under the License.

"""Import libraries"""

import time
from random import choice
from string import ascii_lowercase
from threading import Thread

import serial

from thingsboard_gateway.connectors.connector import Connector, log  # Import base class for connector and logger
from thingsboard_gateway.tb_utility.tb_loader import TBModuleLoader

class CustomSerialConnector(Thread, Connector):  # Define a connector class, it should inherit from "Connector" class.
    def __init__(self, gateway, config, connector_type):
        super().__init__()  # Initialize parents classes
        self.statistics = {'MessagesReceived': 0,
                           'MessagesSent': 0}  # Dictionary, will save information about count received and sent messages.
        self.__config = config  # Save configuration from the configuration file.
        self.__gateway = gateway  # Save gateway object, we will use some gateway methods for adding devices and saving data from them.
        self.setName(self.__config.get("name",
                                       "Custom %s connector " % self.get_name() + ''.join(
                                           choice(ascii_lowercase) for _ in range(5))))  # get from the configuration or create name for logs.
        log.info("Starting Custom %s connector", self.get_name())  # Send message to logger
        self.daemon = True  # Set self thread as daemon
        self.stopped = True  # Service variable for check state
        self.__connected = False  # Service variable for check connection to device
        self.__devices = {}  # Dictionary with devices, will contain devices configurations, converters for devices and serial port objects
        self.__load_converters(connector_type)  # Call function to load converters and save it into devices dictionary
        self.__connect_to_devices()  # Call function for connect to devices
        log.info('Custom connector %s initialization success.', self.get_name())  # Message to logger
        log.info("Devices in configuration file found: %s ", '\n'.join(device for device in self.__devices))  # Message to logger

    def __connect_to_devices(self):  # Function for opening connection and connecting to devices
        for device in self.__devices:
            try:  # Start error handler
                connection_start = time.time()
                if self.__devices[device].get("serial") is None \
                        or self.__devices[device]["serial"] is None \
                        or not self.__devices[device]["serial"].isOpen():  # Connect only if serial not available earlier or it is closed.
                    self.__devices[device]["serial"] = None
                    while self.__devices[device]["serial"] is None or not self.__devices[device]["serial"].isOpen():  # Try connect
                        # connection to serial port with parameters from configuration file or default
                        device_config = self.__devices[device]["device_config"]
                        self.__devices[device]["serial"] = serial.Serial(port=device_config.get('port', '/dev/ttyUSB0'),
                                                                         baudrate=device_config.get('baudrate', 9600),
                                                                         bytesize=device_config.get('bytesize', serial.EIGHTBITS),
                                                                         parity=device_config.get('parity', serial.PARITY_NONE),
                                                                         stopbits=device_config.get('stopbits', serial.STOPBITS_ONE),
                                                                         timeout=device_config.get('timeout', 1),
                                                                         xonxoff=device_config.get('xonxoff', False),
                                                                         rtscts=device_config.get('rtscts', False),
                                                                         write_timeout=device_config.get('write_timeout', None),
                                                                         dsrdtr=device_config.get('dsrdtr', False),
                                                                         inter_byte_timeout=device_config.get('inter_byte_timeout', None),
                                                                         exclusive=device_config.get('exclusive', None))
                        time.sleep(.1)
                        if time.time() - connection_start > 10:  # Break connection try if it setting up for 10 seconds
                            log.error("Connection refused per timeout for device %s", device_config.get("name"))
                            break
            except serial.serialutil.SerialException:
                log.error("Port %s for device %s - not found", self.__devices[device]["device_config"].get('port', '/dev/ttyUSB0'), device)
            except Exception as e:
                log.exception(e)
            else:  # if no exception handled - add device and change connection state
                self.__gateway.add_device(self.__devices[device]["device_config"]["name"], {"connector": self}, self.__devices[device]["device_config"]["type"])
                self.__connected = True

    def open(self):  # Function called by gateway on start
        self.stopped = False
        self.start()

    def get_name(self):  # Function used for logging, sending data and statistic
        return self.name

    def is_connected(self):  # Function for checking connection state
        return self.__connected

    def __load_converters(self, connector_type):  # Function for search a converter and save it.
        devices_config = self.__config.get('devices')
        try:
            if devices_config is not None:
                for device_config in devices_config:
                    if device_config.get('converter') is not None:
                        converter = TBModuleLoader.import_module(connector_type, device_config['converter'])
                        self.__devices[device_config['name']] = {'converter': converter(device_config),
                                                                 'device_config': device_config}
                    else:
                        log.error('Converter configuration for the custom connector %s -- not found, please check your configuration file.', self.get_name())
            else:
                log.error('Section "devices" in the configuration not found. A custom connector %s has being stopped.', self.get_name())
                self.close()
        except Exception as e:
            log.exception(e)

    def run(self):  # Main loop of thread
        try:
            while not self.stopped:
                for device in self.__devices:
                    device_serial_port = self.__devices[device]["serial"]
                    received_character = b''
                    data_from_device = b''
                    while not self.stopped and received_character != b'\n':  # We will read until receive LF symbol
                        try:
                            received_character = device_serial_port.read(1)  # Read one symbol per time
                        except AttributeError as e:
                            if device_serial_port is None:
                                self.__connect_to_devices()  # if port not found - try to connect to it
                                raise e
                        except Exception as e:
                            log.exception(e)
                            break
                        else:
                            data_from_device = data_from_device + received_character
                    try:
                        if len(data_from_device) > 0:
                            converted_data = self.__devices[device]['converter'].convert(self.__devices[device]['device_config'], data_from_device)
                            self.__gateway.send_to_storage(self.get_name(), converted_data)
                        time.sleep(.1)
                    except Exception as e:
                        log.exception(e)
                        self.close()
                        raise e
                if not self.__connected:
                    break
        except Exception as e:
            log.exception(e)

    def close(self):  # Close connect function, usually used if exception handled in gateway main loop or in connector main loop
        self.stopped = True
        for device in self.__devices:
            self.__gateway.del_device(self.__devices[device]["device_config"]["name"])
            if self.__devices[device]['serial'].isOpen():
                self.__devices[device]['serial'].close()

    def on_attributes_update(self, content):  # Function used for processing attribute update requests from ThingsBoard
        log.debug(content)
        if self.__devices.get(content["device"]) is not None:
            device_config = self.__devices[content["device"]].get("device_config")
            if device_config is not None and device_config.get("attributeUpdates") is not None:
                requests = device_config["attributeUpdates"]
                for request in requests:
                    attribute = request.get("attributeOnThingsBoard")
                    log.debug(attribute)
                    if attribute is not None and attribute in content["data"]:
                        try:
                            value = content["data"][attribute]
                            str_to_send = str(request["stringToDevice"].replace("${" + attribute + "}", str(value))).encode("UTF-8")
                            self.__devices[content["device"]]["serial"].write(str_to_send)
                            log.debug("Attribute update request to device %s : %s", content["device"], str_to_send)
                            time.sleep(.01)
                        except Exception as e:
                            log.exception(e)

    def server_side_rpc_handler(self, content):
        pass
<|endoftext|>


<commit_before>import numpy as np
import pylab as pl

def lineplot_orb(points,orbs,bfs,doshow=False):
    zvals = [z for (x,y,z) in points]
    for orb in orbs:
        pl.plot(zvals,orb_on_points(points,orb,bfs))
    #pl.savefig('pyq_orb.png')
    if doshow:
        pl.show()
    return

def bf_on_points(points,bf): return np.array([bf(*point) for point in points],'d')
def orb_on_points(points,orb,bfs):
    f = np.zeros(len(points),'d')
    for c,bf in zip(orb,bfs):
        f = f + c*bf_on_points(points,bf)
    return f

def lineplot_bfs(points,bfs,doshow=False):
    zvals = [z for (x,y,z) in points]
    for bf in bfs:
        pl.plot(zvals,bf_on_points(points,bf))
    if doshow:
        pl.show()
    return

def test_plot_bfs():
    from pyquante2 import basisset,h2
    bfs = basisset(h2,'sto3g')
    zvals = np.linspace(-5,5)
    points = [(0,0,z) for z in zvals]
    lineplot_bfs(points,bfs,True)
    return

def test_plot_orbs():
    from pyquante2 import basisset,h2
    bfs = basisset(h2,'sto3g')
    orbs = np.array([[1.0,1.0],
                     [1.0,-1.0]],'d')

    zvals = np.linspace(-5,5)
    points = [(0,0,z) for z in zvals]
    lineplot_orb(points,orbs,bfs,True)
    return

if __name__ == '__main__':
    test_plot_orbs()

<commit_msg>Fixed looping over orbitals, added plot titles<commit_after>import numpy as np
import pylab as pl

def lineplot_orbs(points,orbs,bfs,doshow=False,
               title="Line plot of pyquante orbital"):
    zvals = [z for (x,y,z) in points]
    for orb in orbs.T: # Transpose makes interations work
        pl.plot(zvals,orb_on_points(points,orb,bfs))
    #pl.savefig('pyq_orb.png')
    pl.title(title)
    if doshow:
        pl.show()
    return

def bf_on_points(points,bf): return np.array([bf(*point) for point in points],'d')
def orb_on_points(points,orb,bfs):
    f = np.zeros(len(points),'d')
    for c,bf in zip(orb,bfs):
        f = f + c*bf_on_points(points,bf)
    return f

def lineplot_bfs(points,bfs,doshow=False,
               title="Line plot of pyquante bfs"):
    zvals = [z for (x,y,z) in points]
    for bf in bfs:
        pl.plot(zvals,bf_on_points(points,bf))
    pl.title(title)
    if doshow:
        pl.show()
    return

def test_plot_bfs():
    from pyquante2 import basisset,h2
    bfs = basisset(h2,'sto3g')
    zvals = np.linspace(-5,5)
    points = [(0,0,z) for z in zvals]
    lineplot_bfs(points,bfs,True)
    return

def test_plot_orbs():
    from pyquante2 import basisset,h2
    bfs = basisset(h2,'sto3g')
    orbs = np.array([[1.0,1.0],
                     [1.0,-1.0]],'d')

    zvals = np.linspace(-5,5)
    points = [(0,0,z) for z in zvals]
    lineplot_orbs(points,orbs,bfs,True)
    return

if __name__ == '__main__':
    test_plot_orbs()

<|endoftext|>


<commit_before>#!/usr/bin/python
# -*- encoding: utf-8 -*-
import os
import psutil
import pyexcel as pe
from nose.tools import raises, eq_

def test_date_util_parse():
    from pyexcel_ods3.converter import date_value
    value = "2015-08-17T19:20:00"
    d = date_value(value)
    assert d.strftime("%Y-%m-%dT%H:%M:%S") == "2015-08-17T19:20:00"
    value = "2015-08-17"
    d = date_value(value)
    assert d.strftime("%Y-%m-%d") == "2015-08-17"
    value = "2015-08-17T19:20:59.999999"
    d = date_value(value)
    assert d.strftime("%Y-%m-%dT%H:%M:%S") == "2015-08-17T19:20:59"
    value = "2015-08-17T19:20:59.99999"
    d = date_value(value)
    assert d.strftime("%Y-%m-%dT%H:%M:%S") == "2015-08-17T19:20:59"
    value = "2015-08-17T19:20:59.999999999999999"
    d = date_value(value)
    assert d.strftime("%Y-%m-%dT%H:%M:%S") == "2015-08-17T19:20:59"

@raises(Exception)
def test_invalid_date():
    from pyexcel_ods3.ods import date_value
    value = "2015-08-"
    date_value(value)

@raises(Exception)
def test_fake_date_time_10():
    from pyexcel_ods3.ods import date_value
    date_value("1234567890")

@raises(Exception)
def test_fake_date_time_19():
    from pyexcel_ods3.ods import date_value
    date_value("1234567890123456789")

@raises(Exception)
def test_fake_date_time_20():
    from pyexcel_ods3.ods import date_value
    date_value("12345678901234567890")

def test_issue_10():
    test_file_name = "test_issue_10.ods"
    from pyexcel_ods3 import save_data
    content = {"test": [[1, 2]]}
    save_data(test_file_name, content)
    save_data(test_file_name, content)
    assert os.path.exists(test_file_name)
    assert os.path.exists(test_file_name + ".bak") is False
    os.unlink(test_file_name)

row_max = 2
col_max = 2

def data_gen():
    for row in range(row_max // 2):
        tmp = []
        for col in range(col_max):
            tmp.append("Row: %d Col: %d" % (row, col))
        for col in range(col_max):
            tmp.append((row + col))
        yield tmp

def test_issue_11():
    test_file = "test_file.ods"
    from pyexcel_ods3 import save_data
    save_data(test_file, {"generator": data_gen()})
    os.unlink(test_file)

def test_issue_8():
    from pyexcel_ods3 import get_data
    test_file = "12_day_as_time.ods"
    data = get_data(get_fixtures(test_file),
                    skip_empty_rows=True)
    eq_(data['Sheet1'][0][0].days, 12)

def test_issue_8_1():
    from pyexcel_ods3.converter import time_value
    result = time_value('PT1111')
    eq_(result, None)

def test_issue_83_ods_file_handle():
    # this proves that odfpy
    # does not leave a file handle open at all
    proc = psutil.Process()
    test_file = get_fixtures("12_day_as_time.ods")
    open_files_l1 = proc.open_files()

    # start with a csv file
    data = pe.iget_array(file_name=test_file, library='pyexcel-ods3')
    open_files_l2 = proc.open_files()
    delta = len(open_files_l2) - len(open_files_l1)
    # cannot catch open file handle
    assert delta == 0

    # now the file handle get opened when we run through
    # the generator
    list(data)
    open_files_l3 = proc.open_files()
    delta = len(open_files_l3) - len(open_files_l1)
    # cannot catch open file handle
    assert delta == 0

    # free the fish
    pe.free_resources()
    open_files_l4 = proc.open_files()
    # this confirms that no more open file handle
    eq_(open_files_l1, open_files_l4)

def get_fixtures(filename):
    return os.path.join("tests", "fixtures", filename)
<commit_msg>:green_heart: fix broken tests<commit_after>#!/usr/bin/python
# -*- encoding: utf-8 -*-
import os
import psutil
import pyexcel as pe
from nose.tools import raises, eq_

@raises(Exception)
def test_invalid_date():
    from pyexcel_ods3.ods import date_value
    value = "2015-08-"
    date_value(value)

@raises(Exception)
def test_fake_date_time_10():
    from pyexcel_ods3.ods import date_value
    date_value("1234567890")

@raises(Exception)
def test_fake_date_time_19():
    from pyexcel_ods3.ods import date_value
    date_value("1234567890123456789")

@raises(Exception)
def test_fake_date_time_20():
    from pyexcel_ods3.ods import date_value
    date_value("12345678901234567890")

def test_issue_10():
    test_file_name = "test_issue_10.ods"
    from pyexcel_ods3 import save_data
    content = {"test": [[1, 2]]}
    save_data(test_file_name, content)
    save_data(test_file_name, content)
    assert os.path.exists(test_file_name)
    assert os.path.exists(test_file_name + ".bak") is False
    os.unlink(test_file_name)

row_max = 2
col_max = 2

def data_gen():
    for row in range(row_max // 2):
        tmp = []
        for col in range(col_max):
            tmp.append("Row: %d Col: %d" % (row, col))
        for col in range(col_max):
            tmp.append((row + col))
        yield tmp

def test_issue_11():
    test_file = "test_file.ods"
    from pyexcel_ods3 import save_data
    save_data(test_file, {"generator": data_gen()})
    os.unlink(test_file)

def test_issue_8():
    from pyexcel_ods3 import get_data
    test_file = "12_day_as_time.ods"
    data = get_data(get_fixtures(test_file),
                    skip_empty_rows=True)
    eq_(data['Sheet1'][0][0].days, 12)

def test_issue_83_ods_file_handle():
    # this proves that odfpy
    # does not leave a file handle open at all
    proc = psutil.Process()
    test_file = get_fixtures("12_day_as_time.ods")
    open_files_l1 = proc.open_files()

    # start with a csv file
    data = pe.iget_array(file_name=test_file, library='pyexcel-ods3')
    open_files_l2 = proc.open_files()
    delta = len(open_files_l2) - len(open_files_l1)
    # cannot catch open file handle
    assert delta == 0

    # now the file handle get opened when we run through
    # the generator
    list(data)
    open_files_l3 = proc.open_files()
    delta = len(open_files_l3) - len(open_files_l1)
    # cannot catch open file handle
    assert delta == 0

    # free the fish
    pe.free_resources()
    open_files_l4 = proc.open_files()
    # this confirms that no more open file handle
    eq_(open_files_l1, open_files_l4)

def get_fixtures(filename):
    return os.path.join("tests", "fixtures", filename)
<|endoftext|>


<commit_before>import discord
import os
from discord.ext import commands

from .utils.dataIO import dataIO
from .utils import checks
from random import randint

# 0 - Robin, 1 - Single, 2 - Double, 3 - Triple, 4 - Guarentee, 5 - Compass
T_TYPES = ["Round Robin", "Single Elimination",
           "Double Elimination", "Triple Elimination",
           "3 Game Guarentee", "Compass Draw"]

class Fight:
    """Cog for organizing tournaments"""

    def __init__(self, bot):
        self.bot = bot
        self.path = "data/Fox-Cogs/fight/"
        self.file_path = "data/Fox-Cogs/fight/fight.json"
        self.the_data = dataIO.load_json(self.file_path)

    def save_data(self):
        """Saves the json"""
        dataIO.save_json(self.file_path, self.the_data)

# ************************Fight command group start************************
    @commands.group(pass_context=True, no_pm=True)
    async def fight(self, ctx):
        """Participate in active tournaments!"""
        if ctx.invoked_subcommand is None:
            await self.bot.send_cmd_help(ctx)
            # await self.bot.say("I can do stuff!")

        server = ctx.message.server

        if self._isrunningFight(server):
            await self.bot.say("No tournament currently running!")
        else:
            await self.bot.say("Current tournament ID: " + self.the_data[server.id]["TOURNEYS"][self.the_data[server.id]["CURRENT"]])

    @fight.command(name="join", pass_context=True)
    async def fight_join(self, ctx, user: discord.Member):
        """Join the active brawl"""
        # Your code will go here
        if not user:
            user = ctx.message.author

        server = ctx.message.server

        if self._isrunningFight(server):
            await self.bot.say("No tournament currently running!")
        else:
            currFight = self.the_data[server.id]["TOURNEYS"][self.the_data[server.id]["CURRENT"]]

    @fight.command(name="score", pass_context=True)
    async def fight_score(self, ctx, gameID):
        if gameID is None:
            if ctx.message.author not in currFight["PLAYERS"]:
                await self.bot.say("You are not in a current tournament")
        """Enters score for current match, or for passed game ID"""
        await self.bot.say("Todo Score")

    @fight.command(name="leave", pass_context=True)
    async def fight_leave(self, ctx):
        """Forfeit your match and all future matches"""
        await self.bot.say("Todo Leave")

    @fight.command(name="leaderboard", pass_context=True)
    async def fight_leaderboard(self, ctx, ctag, ckind="Unranked", irank=0):
        """Adds clan to grab-list"""
        await self.bot.say("Todo Leaderboard")

    @fight.group(name="bracket", pass_context=True)
    async def fight_bracket(self, ctx, ctag):
        """Shows your current match your next opponent,
            run [p]fight bracket full to see all matches"""
        await self.bot.say("Todo Bracket")

        # Your code will go here
        if ctx.invoked_subcommand is None:
            await self.bot.send_cmd_help(ctx)
        # await self.bot.say("I can do stuff!")

    @fight_bracket.command(name="full")
    async def fight_bracket_full(self, ctag):
        """Shows the full bracket"""
        await self.bot.say("Todo Bracket Full")

# **********************Fightset command group start*********************
    def fightsetdec(func):
        async def decorated(self, ctx, *args, **kwargs):
            server = ctx.message.server
            await func(self, ctx, server, *args, **kwargs)
        return decorated

    @commands.group(pass_context=True, no_pm=True, aliases=['setfight'])
    @checks.mod_or_permissions(administrator=True)
    async def fightset(self, ctx):
        """Admin command for starting or managing tournaments"""
        server = ctx.message.server
        self.the_data[server.id] = {
            "CURRENT": None,
            "TOURNEYS": {}
        }
        if server.id not in self.the_data:
            self.the_data[server.id] = {
                "CURRENT": None,
                "TOURNEYS": {}
            }
            self.save_data()

        if ctx.invoked_subcommand is None:
            await self.bot.send_cmd_help(ctx)
        # await self.bot.say("I can do stuff!")

    @fightset.command(name="bestof")
    async def fightset_bestof(self, incount):
        """Adjust # of games played per match. Must be an odd number"""
        await self.bot.say("Todo Fightset Bestof")

    @fightset.command(name="bestoffinal")
    async def fightset_bestoffinal(self):
        """Adjust # of games played in finals. Must be an odd number
        (Does not apply to tournament types without finals, such as Round Robin)"""
        await self.bot.say("Todo Fightset Score")

    @fightset.command(name="toggleopen")
    async def fightset_toggleopen(self, ctx):
        """Toggles the open status of current tournament"""

        await self.bot.say("Tournament Open status: " + str())

    @fightset.command(name="setup", pass_context=True)
    async def fightset_setup(self, ctx):
        """Setup a new tournament!
        Default settings are as follows
        Name: Tourny # (counts from 0)
        Best of: 1
        Best of (final): 1
        Self Report: True
        Type: 0 (Round Robin)"""

        currServ = self.the_data[server.id]
        tourID = str(len(currServ["TOURNEYS"]))  # Can just be len without +1, tourny 0 makes len 1, tourny 1 makes len 2, etc
        currServ["CURRENT"] = tourID
        currServ["TOURNEYS"][tourID] = {"PLAYERS": [],
                                        "NAME": "Tourney "+str(tourID),
                                        "RULES": {"BESTOF": 1, "BESTOFFINAL": 1, "SELFREPORT": True, "TYPE": 0},
                                        "TYPEDATA": {},
                                        "OPEN": False}

        self.save_data()

        await self.bot.say("Tournament has been created!\n\n" + str(currServ["TOURNEYS"][tourID]))

        await self.bot.say("Adjust settings as necessary, then open the tournament with [p]fightset toggleopen")

    @fightset.command(name="stop")
    async def fightset_stop(self):
        """Stops current tournament"""

        currServ = self.the_data[server.id]
        currServ["CURRENT"] = None

        self.save_data()

        await self.bot.say("Todo Fightset Stop")

# **********************Private command group start*********************
    async def _activefight(self):
        """Checks if there is an active tournament already"""
        await self.bot.say("_activefight Todo")

    async def _infight(self, user: discord.Member):
        """Checks if passed member is already in the tournament"""
        await self.bot.say("_infight Todo")

    async def _openregistration(self):
        """Checks if tournament is accepting joins"""
        await self.bot.say("_openregistration Todo")

    async def _comparescores(self):
        """Checks user submitted scores for inconsistancies"""
        await self.bot.say("_comparescores Todo")

    async def _parsemember(self):
        await self.bot.say("Parsemember Todo")

    def _get_server_from_id(self, serverid):
        return discord.utils.get(self.bot.servers, id=serverid)

    def _isrunningFight(self, server):
        return self.the_data[server.id]["CURRENT"] is None

# **********************Single Elimination***************************
    async def _elim_setup(self, tID):
        await self.bot.say("Elim setup todo")

    async def _elim_start(self, tID):
        await self.bot.say("Elim start todo")

    async def _elim_update(self, matchID, ):
        await self.bot.say("Elim update todo")

# **********************Round-Robin**********************************
    def _rr_setup(self, tID):

        theT = self.the_data["TOURNEYS"][tID]
        theD = theT["TYPEDATA"]

        theD = {"SCHEDULE": _rr_schedule(theT["PLAYERS"]), "RESULTS": {}}

    async def _rr_printround(self, tID, rID):

        theT = self.the_data["TOURNEYS"][tID]
        theD = theT["TYPEDATA"]

        await self.bot.say("Round "+str(rID))

        for match in theD["SCHEDULE"][rID]:
            await self.bot.say(match[0] + " vs " + match[1] + " || Match ID: " + match[2])

    async def _rr_start(self, tID):

        self._rr_setup(tID)

        await self.bot.say("**Tournament is Starting**")

        await self._rr_printround(tID)

    async def _rr_update(self, matchID):

        await self.bot.say("Entering scores for match ID: " + matchID + "\n\n")

        theT = self.the_data["TOURNEYS"][tID]
        theD = theT["TYPEDATA"]

        await self.bot.say("How many points did " + theD["SCHEDULE"])

    def _rr_schedule(inlist):
        """ Create a schedule for the teams in the list and return it"""
        s = []

        firstID = ["A", "B", "C", "D", "E", "F",
                   "G", "H", "I", "J", "K", "L",
                   "M", "N", "O", "P", "Q", "R",
                   "S", "T", "U", "V", "W", "X",
                   "Y", "Z"]

        if len(inlist) % 2 == 1:
            inlist = inlist + ["BYE"]

        for i in range(len(inlist)-1):

            mid = int(len(inlist) / 2)
            l1 = inlist[:mid]
            l2 = inlist[mid:]
            l2.reverse()

            matchLetter = ""

            j = i

            while j+1 > 26:

                matchLetter += firstID[int(j + 1) % 26 - 1]

                j = (j + 1) / 26 - 1

            matchLetter += firstID[int(j+1) % 26-1]

            matchLetter = matchLetter[::-1]

            matchID = []

            for ix in range(len(l1)-1):

                matchID += [matchLetter+str(ix)]

            s += [list(zip(l1, l2, matchID))]

            inlist.insert(1, inlist.pop())

        t = {}
        for iix in s:
            t[iix[2]] = iix[:2]

        return t

def check_folders():
    if not os.path.exists("data/Fox-Cogs"):
        print("Creating data/Fox-Cogs folder...")
        os.makedirs("data/Fox-Cogs")

    if not os.path.exists("data/Fox-Cogs/fight"):
        print("Creating data/Fox-Cogs/fight folder...")
        os.makedirs("data/Fox-Cogs/fight")

def check_files():
    if not dataIO.is_valid_json("data/Fox-Cogs/fight/fight.json"):
        dataIO.save_json("data/Fox-Cogs/fight/fight.json", {})

def setup(bot):
    check_folders()
    check_files()
    bot.add_cog(Fight(bot))
<commit_msg>context<commit_after>import discord
import os
from discord.ext import commands

from .utils.dataIO import dataIO
from .utils import checks
from random import randint

# 0 - Robin, 1 - Single, 2 - Double, 3 - Triple, 4 - Guarentee, 5 - Compass
T_TYPES = ["Round Robin", "Single Elimination",
           "Double Elimination", "Triple Elimination",
           "3 Game Guarentee", "Compass Draw"]

class Fight:
    """Cog for organizing tournaments"""

    def __init__(self, bot):
        self.bot = bot
        self.path = "data/Fox-Cogs/fight/"
        self.file_path = "data/Fox-Cogs/fight/fight.json"
        self.the_data = dataIO.load_json(self.file_path)

    def save_data(self):
        """Saves the json"""
        dataIO.save_json(self.file_path, self.the_data)

# ************************Fight command group start************************
    @commands.group(pass_context=True, no_pm=True)
    async def fight(self, ctx):
        """Participate in active tournaments!"""
        if ctx.invoked_subcommand is None:
            await self.bot.send_cmd_help(ctx)
            # await self.bot.say("I can do stuff!")

        server = ctx.message.server

        if self._isrunningFight(server):
            await self.bot.say("No tournament currently running!")
        else:
            await self.bot.say("Current tournament ID: " + self.the_data[server.id]["TOURNEYS"][self.the_data[server.id]["CURRENT"]])

    @fight.command(name="join", pass_context=True)
    async def fight_join(self, ctx, user: discord.Member):
        """Join the active brawl"""
        # Your code will go here
        if not user:
            user = ctx.message.author

        server = ctx.message.server

        if self._isrunningFight(server):
            await self.bot.say("No tournament currently running!")
        else:
            currFight = self.the_data[server.id]["TOURNEYS"][self.the_data[server.id]["CURRENT"]]

    @fight.command(name="score", pass_context=True)
    async def fight_score(self, ctx, gameID):
        if gameID is None:
            if ctx.message.author not in currFight["PLAYERS"]:
                await self.bot.say("You are not in a current tournament")
        """Enters score for current match, or for passed game ID"""
        await self.bot.say("Todo Score")

    @fight.command(name="leave", pass_context=True)
    async def fight_leave(self, ctx):
        """Forfeit your match and all future matches"""
        await self.bot.say("Todo Leave")

    @fight.command(name="leaderboard", pass_context=True)
    async def fight_leaderboard(self, ctx, ctag, ckind="Unranked", irank=0):
        """Adds clan to grab-list"""
        await self.bot.say("Todo Leaderboard")

    @fight.group(name="bracket", pass_context=True)
    async def fight_bracket(self, ctx, ctag):
        """Shows your current match your next opponent,
            run [p]fight bracket full to see all matches"""
        await self.bot.say("Todo Bracket")

        # Your code will go here
        if ctx.invoked_subcommand is None:
            await self.bot.send_cmd_help(ctx)
        # await self.bot.say("I can do stuff!")

    @fight_bracket.command(name="full")
    async def fight_bracket_full(self, ctag):
        """Shows the full bracket"""
        await self.bot.say("Todo Bracket Full")

# **********************Fightset command group start*********************
    def fightsetdec(func):
        async def decorated(self, ctx, *args, **kwargs):
            server = ctx.message.server
            await func(self, ctx, server, *args, **kwargs)
        return decorated

    @commands.group(pass_context=True, no_pm=True, aliases=['setfight'])
    @checks.mod_or_permissions(administrator=True)
    async def fightset(self, ctx):
        """Admin command for starting or managing tournaments"""
        server = ctx.message.server
        self.the_data[server.id] = {
            "CURRENT": None,
            "TOURNEYS": {}
        }
        if server.id not in self.the_data:
            self.the_data[server.id] = {
                "CURRENT": None,
                "TOURNEYS": {}
            }
            self.save_data()

        if ctx.invoked_subcommand is None:
            await self.bot.send_cmd_help(ctx)
        # await self.bot.say("I can do stuff!")

    @fightset.command(name="bestof")
    async def fightset_bestof(self, incount):
        """Adjust # of games played per match. Must be an odd number"""
        await self.bot.say("Todo Fightset Bestof")

    @fightset.command(name="bestoffinal")
    async def fightset_bestoffinal(self):
        """Adjust # of games played in finals. Must be an odd number
        (Does not apply to tournament types without finals, such as Round Robin)"""
        await self.bot.say("Todo Fightset Score")

    @fightset.command(name="toggleopen")
    async def fightset_toggleopen(self, ctx):
        """Toggles the open status of current tournament"""

        await self.bot.say("Tournament Open status: " + str())

    @fightset.command(name="setup", pass_context=True)
    async def fightset_setup(self, ctx):
        """Setup a new tournament!
        Default settings are as follows
        Name: Tourny # (counts from 0)
        Best of: 1
        Best of (final): 1
        Self Report: True
        Type: 0 (Round Robin)"""

        server = ctx.message.server
        currServ = self.the_data[server.id]
        tourID = str(len(currServ["TOURNEYS"]))  # Can just be len without +1, tourny 0 makes len 1, tourny 1 makes len 2, etc
        currServ["CURRENT"] = tourID
        currServ["TOURNEYS"][tourID] = {"PLAYERS": [],
                                        "NAME": "Tourney "+str(tourID),
                                        "RULES": {"BESTOF": 1, "BESTOFFINAL": 1, "SELFREPORT": True, "TYPE": 0},
                                        "TYPEDATA": {},
                                        "OPEN": False}

        self.save_data()

        await self.bot.say("Tournament has been created!\n\n" + str(currServ["TOURNEYS"][tourID]))

        await self.bot.say("Adjust settings as necessary, then open the tournament with [p]fightset toggleopen")

    @fightset.command(name="stop", pass_context=True)
    async def fightset_stop(self,ctx):
        """Stops current tournament"""

        server = ctx.message.server
        currServ = self.the_data[server.id]
        currServ["CURRENT"] = None

        self.save_data()

        await self.bot.say("Todo Fightset Stop")

# **********************Private command group start*********************
    async def _activefight(self):
        """Checks if there is an active tournament already"""
        await self.bot.say("_activefight Todo")

    async def _infight(self, user: discord.Member):
        """Checks if passed member is already in the tournament"""
        await self.bot.say("_infight Todo")

    async def _openregistration(self):
        """Checks if tournament is accepting joins"""
        await self.bot.say("_openregistration Todo")

    async def _comparescores(self):
        """Checks user submitted scores for inconsistancies"""
        await self.bot.say("_comparescores Todo")

    async def _parsemember(self):
        await self.bot.say("Parsemember Todo")

    def _get_server_from_id(self, serverid):
        return discord.utils.get(self.bot.servers, id=serverid)

    def _isrunningFight(self, server):
        return self.the_data[server.id]["CURRENT"] is None

# **********************Single Elimination***************************
    async def _elim_setup(self, tID):
        await self.bot.say("Elim setup todo")

    async def _elim_start(self, tID):
        await self.bot.say("Elim start todo")

    async def _elim_update(self, matchID, ):
        await self.bot.say("Elim update todo")

# **********************Round-Robin**********************************
    def _rr_setup(self, tID):

        theT = self.the_data["TOURNEYS"][tID]
        theD = theT["TYPEDATA"]

        theD = {"SCHEDULE": _rr_schedule(theT["PLAYERS"]), "RESULTS": {}}

    async def _rr_printround(self, tID, rID):

        theT = self.the_data["TOURNEYS"][tID]
        theD = theT["TYPEDATA"]

        await self.bot.say("Round "+str(rID))

        for match in theD["SCHEDULE"][rID]:
            await self.bot.say(match[0] + " vs " + match[1] + " || Match ID: " + match[2])

    async def _rr_start(self, tID):

        self._rr_setup(tID)

        await self.bot.say("**Tournament is Starting**")

        await self._rr_printround(tID)

    async def _rr_update(self, matchID):

        await self.bot.say("Entering scores for match ID: " + matchID + "\n\n")

        theT = self.the_data["TOURNEYS"][tID]
        theD = theT["TYPEDATA"]

        await self.bot.say("How many points did " + theD["SCHEDULE"])

    def _rr_schedule(inlist):
        """ Create a schedule for the teams in the list and return it"""
        s = []

        firstID = ["A", "B", "C", "D", "E", "F",
                   "G", "H", "I", "J", "K", "L",
                   "M", "N", "O", "P", "Q", "R",
                   "S", "T", "U", "V", "W", "X",
                   "Y", "Z"]

        if len(inlist) % 2 == 1:
            inlist = inlist + ["BYE"]

        for i in range(len(inlist)-1):

            mid = int(len(inlist) / 2)
            l1 = inlist[:mid]
            l2 = inlist[mid:]
            l2.reverse()

            matchLetter = ""

            j = i

            while j+1 > 26:

                matchLetter += firstID[int(j + 1) % 26 - 1]

                j = (j + 1) / 26 - 1

            matchLetter += firstID[int(j+1) % 26-1]

            matchLetter = matchLetter[::-1]

            matchID = []

            for ix in range(len(l1)-1):

                matchID += [matchLetter+str(ix)]

            s += [list(zip(l1, l2, matchID))]

            inlist.insert(1, inlist.pop())

        t = {}
        for iix in s:
            t[iix[2]] = iix[:2]

        return t

def check_folders():
    if not os.path.exists("data/Fox-Cogs"):
        print("Creating data/Fox-Cogs folder...")
        os.makedirs("data/Fox-Cogs")

    if not os.path.exists("data/Fox-Cogs/fight"):
        print("Creating data/Fox-Cogs/fight folder...")
        os.makedirs("data/Fox-Cogs/fight")

def check_files():
    if not dataIO.is_valid_json("data/Fox-Cogs/fight/fight.json"):
        dataIO.save_json("data/Fox-Cogs/fight/fight.json", {})

def setup(bot):
    check_folders()
    check_files()
    bot.add_cog(Fight(bot))
<|endoftext|>