<commit_before># This file is part of Maker Keeper Framework.
#
# Copyright (C) 2017 reverendus
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

import hashlib
import hmac
import json
import logging
from pprint import pformat
from random import random
from typing import List

import requests
import time

from pymaker import Wad

class Order:
    def __init__(self,
                 order_id: int,
                 created_at: int,
                 is_sell: bool,
                 price: Wad,
                 amount: Wad,
                 amount_symbol: str,
                 money: Wad,
                 money_symbol: str):
        assert(isinstance(order_id, int))
        assert(isinstance(created_at, int))
        assert(isinstance(is_sell, bool))
        assert(isinstance(price, Wad))
        assert(isinstance(amount, Wad))
        assert(isinstance(amount_symbol, str))
        assert(isinstance(money, Wad))
        assert(isinstance(money_symbol, str))

        self.order_id = order_id
        self.created_at = created_at
        self.is_sell = is_sell
        self.price = price
        self.amount = amount
        self.amount_symbol = amount_symbol
        self.money = money
        self.money_symbol = money_symbol

    @property
    def sell_to_buy_price(self) -> Wad:
        return self.money / self.amount

    @property
    def buy_to_sell_price(self) -> Wad:
        return self.money / self.amount

    @property
    def remaining_sell_amount(self) -> Wad:
        return self.amount if self.is_sell else self.money

    def __eq__(self, other):
        assert(isinstance(other, Order))
        return self.order_id == other.order_id and \
               self.created_at == other.created_at and \
               self.is_sell == other.is_sell and \
               self.price == other.price and \
               self.amount == other.amount and \
               self.amount_symbol == other.amount_symbol and \
               self.money == other.money and \
               self.money_symbol == other.money_symbol

    def __hash__(self):
        return hash((self.order_id,
                     self.created_at,
                     self.is_sell,
                     self.price,
                     self.amount,
                     self.amount_symbol,
                     self.money,
                     self.money_symbol))

    def __repr__(self):
        return pformat(vars(self))

class Trade:
    def __init__(self,
                 trade_id: id,
                 timestamp: int,
                 is_sell: bool,
                 price: Wad,
                 amount: Wad,
                 amount_symbol: str,
                 money: Wad,
                 money_symbol: str,
                 fee: Wad):
        assert(isinstance(trade_id, int))
        assert(isinstance(timestamp, int))
        assert(isinstance(is_sell, bool))
        assert(isinstance(price, Wad))
        assert(isinstance(amount, Wad))
        assert(isinstance(amount_symbol, str))
        assert(isinstance(money, Wad))
        assert(isinstance(money_symbol, str))
        assert(isinstance(fee, Wad))

        self.trade_id = trade_id
        self.timestamp = timestamp
        self.is_sell = is_sell
        self.price = price
        self.amount = amount
        self.amount_symbol = amount_symbol
        self.money = money
        self.money_symbol = money_symbol
        self.fee = fee

    def __eq__(self, other):
        assert(isinstance(other, Trade))
        return self.trade_id == other.trade_id and \
               self.timestamp == other.timestamp and \
               self.is_sell == other.is_sell and \
               self.price == other.price and \
               self.amount == other.amount and \
               self.amount_symbol == other.amount_symbol and \
               self.money == other.money and \
               self.money_symbol == other.money_symbol and \
               self.fee == other.fee

    def __hash__(self):
        return hash((self.trade_id,
                     self.timestamp,
                     self.is_sell,
                     self.price,
                     self.amount,
                     self.amount_symbol,
                     self.money,
                     self.money_symbol,
                     self.fee))

    def __repr__(self):
        return pformat(vars(self))

class BiboxApi:
    """Bibox API interface.

    Developed according to the following manual:
    <https://github.com/Biboxcom/api_reference/wiki/home_en>.
    """

    logger = logging.getLogger()

    MAX_RETRIES = 5
    MIN_RETRY_DELAY = 0.1
    MAX_RETRY_DELAY = 0.3

    def __init__(self, api_server: str, api_key: str, secret: str, timeout: float):
        assert(isinstance(api_server, str))
        assert(isinstance(api_key, str))
        assert(isinstance(secret, str))
        assert(isinstance(timeout, float))

        self.api_path = api_server
        self.api_key = api_key
        self.secret = secret
        self.timeout = timeout

    def _request(self, path: str, cmd: dict, retry: bool):
        assert(isinstance(path, str))
        assert(isinstance(cmd, dict))
        assert(isinstance(retry, bool))

        cmds = json.dumps([cmd])
        call = {
            "cmds": cmds,
            "apikey": self.api_key,
            "sign": self._sign(cmds)
        }

        for try_number in range(1, self.MAX_RETRIES+1):
            result = requests.post(self.api_path + path, json=call, timeout=self.timeout)
            result_json = result.json()

            if retry and try_number < self.MAX_RETRIES:
                try:
                    if str(result_json['error']['code']) == '4003':
                        self.logger.info(f"BiBox API busy ({result_json['error']['code']}: '{result_json['error']['msg']}'), retrying")
                        time.sleep(self.MIN_RETRY_DELAY + random()*(self.MAX_RETRY_DELAY-self.MIN_RETRY_DELAY))
                        continue
                except:
                    pass

            if 'error' in result_json:
                raise Exception(f"API error, code {result_json['error']['code']}, msg: '{result_json['error']['msg']}'")

            return result_json['result'][0]['result']

    def _sign(self, msg: str) -> str:
        assert(isinstance(msg, str))
        return hmac.new(key=self.secret.encode('utf-8'), msg=msg.encode('utf-8'), digestmod=hashlib.md5).hexdigest()

    def user_info(self, retry: bool = False) -> dict:
        assert(isinstance(retry, bool))
        return self._request('/v1/user', {"cmd": "user/userInfo", "body": {}}, retry)

    def coin_list(self, retry: bool = False) -> list:
        assert(isinstance(retry, bool))
        return self._request('/v1/transfer', {"cmd": "transfer/coinList", "body": {}}, retry)

    def assets(self, retry: bool = False) -> dict:
        assert(isinstance(retry, bool))
        return self._request('/v1/transfer', {"cmd": "transfer/assets", "body": {}}, retry)

    def get_orders(self, pair: str, retry: bool = False) -> List[Order]:
        result = self._request('/v1/orderpending', {"cmd": "orderpending/orderPendingList", "body": {"pair": pair,
                                                                                "account_type": 0,
                                                                                "page": 1,
                                                                                "size": 900}}, retry)

        # We are interested in limit orders only ("order_type":2)
        items = filter(lambda item: item['order_type'] == 2, result['items'])

        return list(map(lambda item: Order(order_id=item['id'],
                                           created_at=item['createdAt'],
                                           is_sell=True if item['order_side'] == 2 else False,
                                           price=Wad.from_number(item['price']),
                                           amount=Wad.from_number(item['amount']),
                                           amount_symbol=item['coin_symbol'],
                                           money=Wad.from_number(item['money']),
                                           money_symbol=item['currency_symbol']), items))

    def place_order(self, is_sell: bool, amount: Wad, amount_symbol: str, money: Wad, money_symbol: str, retry: bool = False) -> int:
        assert(isinstance(is_sell, bool))
        assert(isinstance(amount, Wad))
        assert(isinstance(amount_symbol, str))
        assert(isinstance(money, Wad))
        assert(isinstance(money_symbol, str))
        assert(isinstance(retry, bool))

        order_id = self._request('/v1/orderpending', {"cmd": "orderpending/trade",
                                                      "body": {
                                                          "pair": amount_symbol + "_" + money_symbol,
                                                          "account_type": 0,
                                                          "order_type": 2,
                                                          "order_side": 2 if is_sell else 1,
                                                          "pay_bix": 0,
                                                          "price": float(money / amount),
                                                          "amount": float(amount),
                                                          "money": float(money)
                                                      }}, retry)

        self.logger.info(f"Placed order #{order_id} ({'SELL' if is_sell else 'BUY'}, amount {amount} {amount_symbol},"
                         f" money {money} {money_symbol})")

        return order_id

    def cancel_order(self, order_id: int, retry: bool = False):
        assert(isinstance(order_id, int))
        assert(isinstance(retry, bool))

        self.logger.info(f"Cancelling order #{order_id}...")
        self._request('/v1/orderpending', {"cmd": "orderpending/cancelTrade", "body": {"orders_id": order_id}}, retry)
        self.logger.info(f"Cancelled order #{order_id}")

    def get_trade_history(self, pair: str, number_of_trades: int, retry: bool = False) -> List[Trade]:
        assert(isinstance(pair, str))
        assert(isinstance(number_of_trades, int))
        assert(isinstance(retry, bool))

        items = []
        for page in range(1, 100):
            result = self._request('/v1/orderpending', {"cmd": "orderpending/orderHistoryList",
                                                        "body": {
                                                            "pair": pair,
                                                            "account_type": 0,
                                                            "page": page,
                                                            "size": 200
                                                        }}, retry)['items']

            # We are interested in limit orders only ("order_type":2)
            items = items + list(filter(lambda item: item['order_type'] == 2, result))

            if len(result) == 0:
                break

            if len(items) >= number_of_trades:
                break

        return list(map(lambda item: Trade(trade_id=item['id'],
                                           timestamp=int(item['createdAt']/1000),
                                           is_sell=True if item['order_side'] == 2 else False,
                                           price=Wad.from_number(item['price']),
                                           amount=Wad.from_number(item['amount']),
                                           amount_symbol=item['coin_symbol'],
                                           money=Wad.from_number(item['money']),
                                           money_symbol=item['currency_symbol'],
                                           fee=Wad.from_number(item['fee'])), items[:number_of_trades]))
<commit_msg>Logging the "Placing order..." message for Bibox<commit_after># This file is part of Maker Keeper Framework.
#
# Copyright (C) 2017 reverendus
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

import hashlib
import hmac
import json
import logging
from pprint import pformat
from random import random
from typing import List

import requests
import time

from pymaker import Wad

class Order:
    def __init__(self,
                 order_id: int,
                 created_at: int,
                 is_sell: bool,
                 price: Wad,
                 amount: Wad,
                 amount_symbol: str,
                 money: Wad,
                 money_symbol: str):
        assert(isinstance(order_id, int))
        assert(isinstance(created_at, int))
        assert(isinstance(is_sell, bool))
        assert(isinstance(price, Wad))
        assert(isinstance(amount, Wad))
        assert(isinstance(amount_symbol, str))
        assert(isinstance(money, Wad))
        assert(isinstance(money_symbol, str))

        self.order_id = order_id
        self.created_at = created_at
        self.is_sell = is_sell
        self.price = price
        self.amount = amount
        self.amount_symbol = amount_symbol
        self.money = money
        self.money_symbol = money_symbol

    @property
    def sell_to_buy_price(self) -> Wad:
        return self.money / self.amount

    @property
    def buy_to_sell_price(self) -> Wad:
        return self.money / self.amount

    @property
    def remaining_sell_amount(self) -> Wad:
        return self.amount if self.is_sell else self.money

    def __eq__(self, other):
        assert(isinstance(other, Order))
        return self.order_id == other.order_id and \
               self.created_at == other.created_at and \
               self.is_sell == other.is_sell and \
               self.price == other.price and \
               self.amount == other.amount and \
               self.amount_symbol == other.amount_symbol and \
               self.money == other.money and \
               self.money_symbol == other.money_symbol

    def __hash__(self):
        return hash((self.order_id,
                     self.created_at,
                     self.is_sell,
                     self.price,
                     self.amount,
                     self.amount_symbol,
                     self.money,
                     self.money_symbol))

    def __repr__(self):
        return pformat(vars(self))

class Trade:
    def __init__(self,
                 trade_id: id,
                 timestamp: int,
                 is_sell: bool,
                 price: Wad,
                 amount: Wad,
                 amount_symbol: str,
                 money: Wad,
                 money_symbol: str,
                 fee: Wad):
        assert(isinstance(trade_id, int))
        assert(isinstance(timestamp, int))
        assert(isinstance(is_sell, bool))
        assert(isinstance(price, Wad))
        assert(isinstance(amount, Wad))
        assert(isinstance(amount_symbol, str))
        assert(isinstance(money, Wad))
        assert(isinstance(money_symbol, str))
        assert(isinstance(fee, Wad))

        self.trade_id = trade_id
        self.timestamp = timestamp
        self.is_sell = is_sell
        self.price = price
        self.amount = amount
        self.amount_symbol = amount_symbol
        self.money = money
        self.money_symbol = money_symbol
        self.fee = fee

    def __eq__(self, other):
        assert(isinstance(other, Trade))
        return self.trade_id == other.trade_id and \
               self.timestamp == other.timestamp and \
               self.is_sell == other.is_sell and \
               self.price == other.price and \
               self.amount == other.amount and \
               self.amount_symbol == other.amount_symbol and \
               self.money == other.money and \
               self.money_symbol == other.money_symbol and \
               self.fee == other.fee

    def __hash__(self):
        return hash((self.trade_id,
                     self.timestamp,
                     self.is_sell,
                     self.price,
                     self.amount,
                     self.amount_symbol,
                     self.money,
                     self.money_symbol,
                     self.fee))

    def __repr__(self):
        return pformat(vars(self))

class BiboxApi:
    """Bibox API interface.

    Developed according to the following manual:
    <https://github.com/Biboxcom/api_reference/wiki/home_en>.
    """

    logger = logging.getLogger()

    MAX_RETRIES = 5
    MIN_RETRY_DELAY = 0.1
    MAX_RETRY_DELAY = 0.3

    def __init__(self, api_server: str, api_key: str, secret: str, timeout: float):
        assert(isinstance(api_server, str))
        assert(isinstance(api_key, str))
        assert(isinstance(secret, str))
        assert(isinstance(timeout, float))

        self.api_path = api_server
        self.api_key = api_key
        self.secret = secret
        self.timeout = timeout

    def _request(self, path: str, cmd: dict, retry: bool):
        assert(isinstance(path, str))
        assert(isinstance(cmd, dict))
        assert(isinstance(retry, bool))

        cmds = json.dumps([cmd])
        call = {
            "cmds": cmds,
            "apikey": self.api_key,
            "sign": self._sign(cmds)
        }

        for try_number in range(1, self.MAX_RETRIES+1):
            result = requests.post(self.api_path + path, json=call, timeout=self.timeout)
            result_json = result.json()

            if retry and try_number < self.MAX_RETRIES:
                try:
                    if str(result_json['error']['code']) == '4003':
                        self.logger.info(f"BiBox API busy ({result_json['error']['code']}: '{result_json['error']['msg']}'), retrying")
                        time.sleep(self.MIN_RETRY_DELAY + random()*(self.MAX_RETRY_DELAY-self.MIN_RETRY_DELAY))
                        continue
                except:
                    pass

            if 'error' in result_json:
                raise Exception(f"API error, code {result_json['error']['code']}, msg: '{result_json['error']['msg']}'")

            return result_json['result'][0]['result']

    def _sign(self, msg: str) -> str:
        assert(isinstance(msg, str))
        return hmac.new(key=self.secret.encode('utf-8'), msg=msg.encode('utf-8'), digestmod=hashlib.md5).hexdigest()

    def user_info(self, retry: bool = False) -> dict:
        assert(isinstance(retry, bool))
        return self._request('/v1/user', {"cmd": "user/userInfo", "body": {}}, retry)

    def coin_list(self, retry: bool = False) -> list:
        assert(isinstance(retry, bool))
        return self._request('/v1/transfer', {"cmd": "transfer/coinList", "body": {}}, retry)

    def assets(self, retry: bool = False) -> dict:
        assert(isinstance(retry, bool))
        return self._request('/v1/transfer', {"cmd": "transfer/assets", "body": {}}, retry)

    def get_orders(self, pair: str, retry: bool = False) -> List[Order]:
        result = self._request('/v1/orderpending', {"cmd": "orderpending/orderPendingList", "body": {"pair": pair,
                                                                                "account_type": 0,
                                                                                "page": 1,
                                                                                "size": 900}}, retry)

        # We are interested in limit orders only ("order_type":2)
        items = filter(lambda item: item['order_type'] == 2, result['items'])

        return list(map(lambda item: Order(order_id=item['id'],
                                           created_at=item['createdAt'],
                                           is_sell=True if item['order_side'] == 2 else False,
                                           price=Wad.from_number(item['price']),
                                           amount=Wad.from_number(item['amount']),
                                           amount_symbol=item['coin_symbol'],
                                           money=Wad.from_number(item['money']),
                                           money_symbol=item['currency_symbol']), items))

    def place_order(self, is_sell: bool, amount: Wad, amount_symbol: str, money: Wad, money_symbol: str, retry: bool = False) -> int:
        assert(isinstance(is_sell, bool))
        assert(isinstance(amount, Wad))
        assert(isinstance(amount_symbol, str))
        assert(isinstance(money, Wad))
        assert(isinstance(money_symbol, str))
        assert(isinstance(retry, bool))

        self.logger.info(f"Placing order ({'SELL' if is_sell else 'BUY'}, amount {amount} {amount_symbol},"
                         f" money {money} {money_symbol})...")

        order_id = self._request('/v1/orderpending', {"cmd": "orderpending/trade",
                                                      "body": {
                                                          "pair": amount_symbol + "_" + money_symbol,
                                                          "account_type": 0,
                                                          "order_type": 2,
                                                          "order_side": 2 if is_sell else 1,
                                                          "pay_bix": 0,
                                                          "price": float(money / amount),
                                                          "amount": float(amount),
                                                          "money": float(money)
                                                      }}, retry)

        self.logger.info(f"Placed order ({'SELL' if is_sell else 'BUY'}, amount {amount} {amount_symbol},"
                         f" money {money} {money_symbol}) as #{order_id}")

        return order_id

    def cancel_order(self, order_id: int, retry: bool = False):
        assert(isinstance(order_id, int))
        assert(isinstance(retry, bool))

        self.logger.info(f"Cancelling order #{order_id}...")
        self._request('/v1/orderpending', {"cmd": "orderpending/cancelTrade", "body": {"orders_id": order_id}}, retry)
        self.logger.info(f"Cancelled order #{order_id}")

    def get_trade_history(self, pair: str, number_of_trades: int, retry: bool = False) -> List[Trade]:
        assert(isinstance(pair, str))
        assert(isinstance(number_of_trades, int))
        assert(isinstance(retry, bool))

        items = []
        for page in range(1, 100):
            result = self._request('/v1/orderpending', {"cmd": "orderpending/orderHistoryList",
                                                        "body": {
                                                            "pair": pair,
                                                            "account_type": 0,
                                                            "page": page,
                                                            "size": 200
                                                        }}, retry)['items']

            # We are interested in limit orders only ("order_type":2)
            items = items + list(filter(lambda item: item['order_type'] == 2, result))

            if len(result) == 0:
                break

            if len(items) >= number_of_trades:
                break

        return list(map(lambda item: Trade(trade_id=item['id'],
                                           timestamp=int(item['createdAt']/1000),
                                           is_sell=True if item['order_side'] == 2 else False,
                                           price=Wad.from_number(item['price']),
                                           amount=Wad.from_number(item['amount']),
                                           amount_symbol=item['coin_symbol'],
                                           money=Wad.from_number(item['money']),
                                           money_symbol=item['currency_symbol'],
                                           fee=Wad.from_number(item['fee'])), items[:number_of_trades]))
<|endoftext|>


<commit_before>"""
Markov Chain methods in Python.

A toolkit of stochastic methods for biometric analysis. Features
a Metropolis-Hastings MCMC sampler and both linear and unscented
(non-linear) Kalman filters.

Pre-requisite modules: numpy, matplotlib
Required external components: TclTk

"""
__modules__ = [ 'Node',
                'Container',
                'distributions',
                'PyMCObjects',
                'utils',
                'StepMethods',
                'Model',
                'graph',
                'MultiModelInference',
                'InstantiationDecorators',
                'testsuite',
                'NormalApproximation',
                'MCMC',
                'convergencediagnostics']

__optmodules__ = ['ScipyDistributions',
                  'parallel',
                  'GibbsStepMethods',]
#ClosedCapture, OpenCapture

for mod in __modules__:
    exec "from %s import *" % mod

for mod in __optmodules__:
    try:
      exec "from %s import *" % mod
    except ImportError:
        pass

##try:
##   import parallel
##except ImportError:
##   print 'For parallel-processing dtrmity install IPython1.'

del mod

<commit_msg>Trying to import sandbox<commit_after>"""
Markov Chain methods in Python.

A toolkit of stochastic methods for biometric analysis. Features
a Metropolis-Hastings MCMC sampler and both linear and unscented
(non-linear) Kalman filters.

Pre-requisite modules: numpy, matplotlib
Required external components: TclTk

"""
__modules__ = [ 'Node',
                'Container',
                'distributions',
                'PyMCObjects',
                'utils',
                'StepMethods',
                'Model',
                'graph',
                'MultiModelInference',
                'InstantiationDecorators',
                'testsuite',
                'NormalApproximation',
                'MCMC',
                'convergencediagnostics']

__optmodules__ = ['ScipyDistributions',
                  'parallel',
                  'GibbsStepMethods',
                  'sandbox']
#ClosedCapture, OpenCapture

for mod in __modules__:
    exec "from %s import *" % mod

for mod in __optmodules__:
    try:
      exec "from %s import *" % mod
    except ImportError:
        pass

##try:
##   import parallel
##except ImportError:
##   print 'For parallel-processing dtrmity install IPython1.'

del mod

<|endoftext|>


<commit_before><commit_msg>Look at correct packaged HGVM and use normal merge job<commit_after><|endoftext|>


<commit_before>"""Callback infrastructure."""

__all__ = ["Signal"]

class Signal(object):
  """Allows signals to be sent to connected slots."""

  def __init__(self):
    """Initialising the signal."""
    self._slots = []  #: The slots connected to the signal

  def connect(self, slot):
    """Connect a callback function to the signal."""
    if slot is not None:
      self._slots.append(slot)
    return self

  def disconnect(self, slot):
    """Disconnect a callback function to the signal."""
    if slot not in self._slots:
      raise RuntimeError("%s: Slot is not connected: %s" %
                         (repr(self), str(slot)))
    self._slots.remove(slot)
    return self

  def replace(self, oldslot, newslot):
    """Replace a slot with a different one (to maintain calling order)."""
    if oldslot not in self._slots:
      raise RuntimeError("%s: Slot not connected to this signal, cannot be "\
                        "replaced: %s" % (repr(self), str(oldslot)))
    self._slots[self._slots.index(oldslot)] = newslot
    return self

  reconnect = replace

  def slot_index(self, slot):
    """Return the calling order of the slot (starting from 0)."""
    return self._slots.index(slot)

  def has_slot(self, slot):
    """Indicates if this signal has the slot."""
    return slot in self._slots

  def __call__(self, *args, **kwargs):
    """Emit a signal."""
    from .event import post_event

    for slot in self._slots:
      post_event((slot, args, kwargs))
<commit_msg>  - post traceback if debug in use<commit_after>"""Callback infrastructure."""

__all__ = ["Signal"]

class Signal(object):
  """Allows signals to be sent to connected slots."""

  def __init__(self):
    """Initialising the signal."""
    self._slots = []  #: The slots connected to the signal

  def connect(self, slot):
    """Connect a callback function to the signal."""
    if slot is not None:
      self._slots.append(slot)
    return self

  def disconnect(self, slot):
    """Disconnect a callback function to the signal."""
    if slot not in self._slots:
      raise RuntimeError("%s: Slot is not connected: %s" %
                         (repr(self), str(slot)))
    self._slots.remove(slot)
    return self

  def replace(self, oldslot, newslot):
    """Replace a slot with a different one (to maintain calling order)."""
    if oldslot not in self._slots:
      raise RuntimeError("%s: Slot not connected to this signal, cannot be "\
                        "replaced: %s" % (repr(self), str(oldslot)))
    self._slots[self._slots.index(oldslot)] = newslot
    return self

  reconnect = replace

  def slot_index(self, slot):
    """Return the calling order of the slot (starting from 0)."""
    return self._slots.index(slot)

  def has_slot(self, slot):
    """Indicates if this signal has the slot."""
    return slot in self._slots

  def __call__(self, *args, **kwargs):
    """Emit a signal."""
    from .env import flags
    from .event import post_event

    if flags["debug"]:
      from traceback import extract_stack
      tb = extract_stack()
    else:
      tb = None

    for slot in self._slots:
      post_event((slot, args, kwargs, tb))
<|endoftext|>


<commit_before>"""
This module makes use of the Python PLY package
to parse the grammars
"""
###
# Implements the lexer
###
import ply.lex as lex

reserved = {
    'is': 'IS_EQUALS',
    'and': 'AND',
    'or': 'OR',
    'not': 'NOT',
    'contains': 'CONTAINS',
    'matches': 'MATCHES',
    'true': 'TRUE',
    'false': 'FALSE',
    'undefined': 'UNDEFINED',
    'null': 'NULL',
    'empty': 'EMPTY'
}

tokens = (
    'AND',
    'OR',
    'NOT',
    'GREATER_THAN',
    'GREATER_THAN_EQUALS',
    'LESS_THAN',
    'LESS_THAN_EQUALS',
    'EQUALS',
    'DBL_EQUALS',
    'NOT_EQUALS',
    'IS_EQUALS',
    'IS_NOT_EQUALS',
    'LPAREN',
    'RPAREN',
    'LBRACK',
    'RBRACK',
    'CONTAINS',
    'MATCHES',
    'NUMBER',
    'STRING',
    'TRUE',
    'FALSE',
    'UNDEFINED',
    'NULL',
    'EMPTY'
)

# Regex rules for tokens
t_GREATER_THAN = r'>'
t_GREATER_THAN_EQUALS = r'>='

t_LESS_THAN = r'<'
t_LESS_THAN_EQUALS = r'<='

t_EQUALS = r'='
t_DBL_EQUALS = r'=='
t_NOT_EQUALS = r'!='

t_LPAREN = r'\('
t_RPAREN = r'\)'

t_LBRACK = r'{'
t_RBRACK = r'}'

# Ignore any comments
t_ignore_COMMENT = r'\#.*'

def t_NUMBER(t):
    r'-?\d+(\.\d+)?'
    return t

# Matches either a sequence of non-whitespace
# or anything that is quoted
def t_STRING(t):
    r'([\w_\-.:;]+|"[^"]*"|\'[^\']*\')'
    # Check for reserved words
    t.type = reserved.get(t.value,'STRING')
    return t

# Track the newlines
def t_newline(t):
    r'\n+'
    t.lexer.lineno += len(t.value)

# The ignore characters
t_ignore = ' \t\n'

# Error handler
def t_error(t):
    if " " in t.value:
        idx = t.value.index(" ")
        error_loc = (t.value[:idx], t.lexer.lexpos, t.lexer.lineno)
        t.lexer.errors.append(error_loc)
        t.lexer.skip(idx)
    else:
        error_loc = (t.value, t.lexer.lexpos, t.lexer.lineno)
        t.lexer.errors.append(error_loc)
        t.lexer.skip(1)

# Build the lexer
def get_lexer():
    "Returns a new instance of the lexer"
    l = lex.lex()
    l.errors = []
    return l

###
# Implements the parser
###
import ply.yacc as yacc
from . import ast

precedence = (
    ('right', 'AND', 'OR'),
    ('right', 'NOT'),
)

def p_expression_binop(p):
    """expression : expression AND expression
                  | expression OR expression"""
    p[0] = ast.LogicalOperator(p[2], p[1], p[3])
    p[0].set_position(p.lineno(2), p.lexpos(2))

def p_expression_not(p):
    "expression : NOT expression"
    p[0] = ast.NegateOperator(p[2])
    p[0].set_position(p.lineno(1), p.lexpos(1))

def p_expression_term(p):
    "expression : term"
    p[0] = p[1]

def p_term_is_not(p):
    "term : factor IS_EQUALS NOT factor"
    p[0] = ast.CompareOperator("!=", p[1], p[4])
    p[0].set_position(p.lineno(2), p.lexpos(2))

def p_term_comparison(p):
    """term : factor GREATER_THAN factor
            | factor GREATER_THAN_EQUALS factor
            | factor LESS_THAN factor
            | factor LESS_THAN_EQUALS factor
            | factor EQUALS factor
            | factor NOT_EQUALS factor
            | factor IS_NOT_EQUALS factor
            | factor IS_EQUALS factor"""
    p[0] = ast.CompareOperator(p[2], p[1], p[3])
    p[0].set_position(p.lineno(2), p.lexpos(2))

def p_term_dbl_equals(p):
    "term : factor DBL_EQUALS factor"
    p[0] = ast.CompareOperator("=", p[1], p[3])
    p[0].set_position(p.lineno(2), p.lexpos(2))

def p_contains(p):
    "term : factor CONTAINS factor"
    p[0] = ast.ContainsOperator(p[1], p[3])
    p[0].set_position(p.lineno(2), p.lexpos(2))

def p_matchse(p):
    "term : factor MATCHES factor"
    p[0] = ast.MatchOperator(p[1], ast.Regex(p[3]))
    p[0].set_position(p.lineno(2), p.lexpos(2))

def p_term_factor(p):
    "term : factor"
    p[0] = p[1]

def p_factor_string(p):
    "factor : STRING"
    p[0] = ast.Literal(p[1])
    p[0].set_position(p.lineno(1), p.lexpos(1))

def p_factor_number(p):
    "factor : NUMBER"
    p[0] = ast.Number(p[1])
    p[0].set_position(p.lineno(1), p.lexpos(1))

def p_factor_constants(p):
    """factor : TRUE
              | FALSE
              | UNDEFINED
              | NULL
              | EMPTY"""
    if p[1] == "true":
        p[0] = ast.Constant(True)
        p[0].set_position(p.lineno(1), p.lexpos(1))
    elif p[1] == "false":
        p[0] = ast.Constant(False)
        p[0].set_position(p.lineno(1), p.lexpos(1))
    elif p[1] == "null":
        p[0] = ast.Constant(None)
        p[0].set_position(p.lineno(1), p.lexpos(1))
    elif p[1] == "undefined":
        p[0] = ast.Undefined()
        p[0].set_position(p.lineno(1), p.lexpos(1))
    elif p[1] == "empty":
        p[0] = ast.Empty()
        p[0].set_position(p.lineno(1), p.lexpos(1))
    else:
        raise SyntaxError

def p_factor_parens(p):
    "factor : LPAREN expression RPAREN"
    p[0] = p[2]

def p_empty(p):
    "empty : "
    pass

def p_factor_list(p):
    """factor_list : factor factor_list
                   | empty"""
    if len(p) == 2 and p[1] is None:
        p[0] = []
    else:
        p[0] = [p[1]] + p[2]

def p_factor_sets(p):
    "factor : LBRACK factor_list RBRACK"
    p[0] = ast.LiteralSet(p[2])

def p_error(p):
    "Handles errors"
    if p is None:
        raise SyntaxError("Unexpected end of predicate!")
    else:
        err = ("Syntax error at token", p.type, p.value, p.lexpos, p.lineno)
        parser = p.lexer.parser
        parser.errors.append(err)
        parser.errok()

def get_parser(lexer=None, debug=0):
    "Returns a new instance of the parser"
    p = yacc.yacc(debug=debug)
    p.errors = []
    if lexer:
        lexer.parser = p
        p.lexer = lexer
    return p

<commit_msg>Support for case independent operators<commit_after>"""
This module makes use of the Python PLY package
to parse the grammars
"""
###
# Implements the lexer
###
import ply.lex as lex

reserved = {
    'is': 'IS_EQUALS',
    'and': 'AND',
    'or': 'OR',
    'not': 'NOT',
    'contains': 'CONTAINS',
    'matches': 'MATCHES',
    'true': 'TRUE',
    'false': 'FALSE',
    'undefined': 'UNDEFINED',
    'null': 'NULL',
    'empty': 'EMPTY'
}

tokens = (
    'AND',
    'OR',
    'NOT',
    'GREATER_THAN',
    'GREATER_THAN_EQUALS',
    'LESS_THAN',
    'LESS_THAN_EQUALS',
    'EQUALS',
    'DBL_EQUALS',
    'NOT_EQUALS',
    'IS_EQUALS',
    'IS_NOT_EQUALS',
    'LPAREN',
    'RPAREN',
    'LBRACK',
    'RBRACK',
    'CONTAINS',
    'MATCHES',
    'NUMBER',
    'STRING',
    'TRUE',
    'FALSE',
    'UNDEFINED',
    'NULL',
    'EMPTY'
)

# Regex rules for tokens
t_GREATER_THAN = r'>'
t_GREATER_THAN_EQUALS = r'>='

t_LESS_THAN = r'<'
t_LESS_THAN_EQUALS = r'<='

t_EQUALS = r'='
t_DBL_EQUALS = r'=='
t_NOT_EQUALS = r'!='

t_LPAREN = r'\('
t_RPAREN = r'\)'

t_LBRACK = r'{'
t_RBRACK = r'}'

# Ignore any comments
t_ignore_COMMENT = r'\#.*'

def t_NUMBER(t):
    r'-?\d+(\.\d+)?'
    return t

# Matches either a sequence of non-whitespace
# or anything that is quoted
def t_STRING(t):
    r'([\w_\-.:;]+|"[^"]*"|\'[^\']*\')'
    l = t.value.lower()
    if l in reserved:
        t.value = l
    # Check for reserved words
    t.type = reserved.get(t.value, 'STRING')
    return t

# Track the newlines
def t_newline(t):
    r'\n+'
    t.lexer.lineno += len(t.value)

# The ignore characters
t_ignore = ' \t\n'

# Error handler
def t_error(t):
    if " " in t.value:
        idx = t.value.index(" ")
        error_loc = (t.value[:idx], t.lexer.lexpos, t.lexer.lineno)
        t.lexer.errors.append(error_loc)
        t.lexer.skip(idx)
    else:
        error_loc = (t.value, t.lexer.lexpos, t.lexer.lineno)
        t.lexer.errors.append(error_loc)
        t.lexer.skip(1)

# Build the lexer
def get_lexer():
    "Returns a new instance of the lexer"
    l = lex.lex()
    l.errors = []
    return l

###
# Implements the parser
###
import ply.yacc as yacc
from . import ast

precedence = (
    ('right', 'AND', 'OR'),
    ('right', 'NOT'),
)

def p_expression_binop(p):
    """expression : expression AND expression
                  | expression OR expression"""
    p[0] = ast.LogicalOperator(p[2], p[1], p[3])
    p[0].set_position(p.lineno(2), p.lexpos(2))

def p_expression_not(p):
    "expression : NOT expression"
    p[0] = ast.NegateOperator(p[2])
    p[0].set_position(p.lineno(1), p.lexpos(1))

def p_expression_term(p):
    "expression : term"
    p[0] = p[1]

def p_term_is_not(p):
    "term : factor IS_EQUALS NOT factor"
    p[0] = ast.CompareOperator("!=", p[1], p[4])
    p[0].set_position(p.lineno(2), p.lexpos(2))

def p_term_comparison(p):
    """term : factor GREATER_THAN factor
            | factor GREATER_THAN_EQUALS factor
            | factor LESS_THAN factor
            | factor LESS_THAN_EQUALS factor
            | factor EQUALS factor
            | factor NOT_EQUALS factor
            | factor IS_NOT_EQUALS factor
            | factor IS_EQUALS factor"""
    p[0] = ast.CompareOperator(p[2], p[1], p[3])
    p[0].set_position(p.lineno(2), p.lexpos(2))

def p_term_dbl_equals(p):
    "term : factor DBL_EQUALS factor"
    p[0] = ast.CompareOperator("=", p[1], p[3])
    p[0].set_position(p.lineno(2), p.lexpos(2))

def p_contains(p):
    "term : factor CONTAINS factor"
    p[0] = ast.ContainsOperator(p[1], p[3])
    p[0].set_position(p.lineno(2), p.lexpos(2))

def p_matchse(p):
    "term : factor MATCHES factor"
    p[0] = ast.MatchOperator(p[1], ast.Regex(p[3]))
    p[0].set_position(p.lineno(2), p.lexpos(2))

def p_term_factor(p):
    "term : factor"
    p[0] = p[1]

def p_factor_string(p):
    "factor : STRING"
    p[0] = ast.Literal(p[1])
    p[0].set_position(p.lineno(1), p.lexpos(1))

def p_factor_number(p):
    "factor : NUMBER"
    p[0] = ast.Number(p[1])
    p[0].set_position(p.lineno(1), p.lexpos(1))

def p_factor_constants(p):
    """factor : TRUE
              | FALSE
              | UNDEFINED
              | NULL
              | EMPTY"""
    if p[1] == "true":
        p[0] = ast.Constant(True)
        p[0].set_position(p.lineno(1), p.lexpos(1))
    elif p[1] == "false":
        p[0] = ast.Constant(False)
        p[0].set_position(p.lineno(1), p.lexpos(1))
    elif p[1] == "null":
        p[0] = ast.Constant(None)
        p[0].set_position(p.lineno(1), p.lexpos(1))
    elif p[1] == "undefined":
        p[0] = ast.Undefined()
        p[0].set_position(p.lineno(1), p.lexpos(1))
    elif p[1] == "empty":
        p[0] = ast.Empty()
        p[0].set_position(p.lineno(1), p.lexpos(1))
    else:
        raise SyntaxError

def p_factor_parens(p):
    "factor : LPAREN expression RPAREN"
    p[0] = p[2]

def p_empty(p):
    "empty : "
    pass

def p_factor_list(p):
    """factor_list : factor factor_list
                   | empty"""
    if len(p) == 2 and p[1] is None:
        p[0] = []
    else:
        p[0] = [p[1]] + p[2]

def p_factor_sets(p):
    "factor : LBRACK factor_list RBRACK"
    p[0] = ast.LiteralSet(p[2])

def p_error(p):
    "Handles errors"
    if p is None:
        raise SyntaxError("Unexpected end of predicate!")
    else:
        err = ("Syntax error at token", p.type, p.value, p.lexpos, p.lineno)
        parser = p.lexer.parser
        parser.errors.append(err)
        parser.errok()

def get_parser(lexer=None, debug=0):
    "Returns a new instance of the parser"
    p = yacc.yacc(debug=debug)
    p.errors = []
    if lexer:
        lexer.parser = p
        p.lexer = lexer
    return p

<|endoftext|>


<commit_before># Copyright 2014 Dan Kilman
#
# 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 sys
from StringIO import StringIO

import argh

import pysource
from pysource import daemonizer
from pysource import client
from pysource import config

class DaemonCommands(object):
    """Daemon related commands."""

    namespace = 'daemon'

    @staticmethod
    def start():
        """Start the daemon process."""
        started = daemonizer.start()
        if not started:
            return 'Daemon already started'

    @staticmethod
    def stop():
        """Stop the daemon process."""
        stopped = daemonizer.stop()
        if stopped:
            return 'Daemon stopped'
        else:
            return 'Daemon not running'

    @staticmethod
    def restart():
        """Restart the daemon process."""
        daemonizer.restart()

    @staticmethod
    def status():
        """Check the daemon process status."""
        status, pid = daemonizer.status()
        if status == daemonizer.STATUS_STOPPED:
            return 'Daemon is (probably) stopped'
        elif status == daemonizer.STATUS_CORRUPTED:
            if pid:
                return 'Daemon pidfile exists but process does not seem ' \
                       'to be running (pid: {0}). You should probably clean ' \
                       'the files in {1} and manually check if there' \
                       ' is a daemon running somewhere.'\
                       .format(pid, config.pysource_dir)
            else:
                return 'Daemon seems to be in an unstable state. Manually ' \
                       'remove the files in {0} and kill leftover daemon ' \
                       'processes (if there are any).'\
                       .format(config.pysource_dir)
        else:
            return 'Daemon is (probably) running (pid: {0})'.format(pid)

    @classmethod
    def commands(cls):
        return [cls.start, cls.stop, cls.restart, cls.status]

def list_registered():
    """List all functions currently registered."""
    descriptors = client.list_registered()
    if len(descriptors) == 0:
        yield 'No functions registered'
    else:
        yield 'Registered functions:'
        for descriptor in descriptors:
            name = descriptor['name']
            piped = descriptor['piped']
            suffix = ' (piped)' if piped else ''
            yield '{}{}'.format(name, suffix)

def update_env(verbose=False):
    """
    Update environment variables at the daemon with the current client
    environment.
    """
    status = client.update_env()
    if status != 'updated':
        raise pysource.error('Failed updating environment')
    if verbose:
        return 'Environment updated'

def source_registered(verbose=False):
    """Source all functions currently registered."""
    return client.source_registered(verbose=verbose)

@argh.arg('function_name', help='The name of the function to source.')
def source_named(function_name, piped=False, verbose=False):
    """Source a function named by the first positional argument."""
    return client.source_named(function_name,
                               piped=piped,
                               verbose=verbose)

@argh.arg('def_content', help='The function definition itself.')
def source_def(def_content, piped=False, verbose=False):
    """Source an inline function definition."""
    return client.source_def(def_content,
                             piped=piped,
                             verbose=verbose)

@argh.arg('content', help='The code to execute at the daemon.')
def source_inline(content, verbose=False):
    """
    Execute arbitrary code at the daemon. If code contains function
    definitions, they will be sourced at the client.
    """
    return client.source_content(content,
                                 verbose=verbose)

@argh.arg('source_path', help='The path to the file to source.')
def source(source_path, verbose=False):
    """Source a file by its path."""
    return client.source_path(source_path,
                              verbose=verbose)

@argh.arg('function_name', help='The name of the function to run.')
def run(function_name, *args):
    """Run the function named by the first positional argument."""
    result = client.run_function(function_name, args)
    if result:
        return result

@argh.arg('function_name', help='The name of the function to run.')
def run_piped(function_name, *args):
    """
    Run the function named by the first positional argument as a piped
    function.
    """
    client.run_piped_function(function_name, args)

def main():
    errors = StringIO()
    parser = argh.ArghParser()
    argh.add_commands(parser, [
        source,
        run,
        run_piped,
        list_registered,
        source_registered,
        source_named,
        source_def,
        source_inline,
        update_env
    ])
    argh.add_commands(parser,
                      functions=DaemonCommands.commands(),
                      namespace=DaemonCommands.namespace,
                      title=DaemonCommands.__doc__)
    argh.dispatch(parser, completion=False, errors_file=errors)
    if errors.len > 0:
        sys.exit(errors.getvalue().strip())

if __name__ == '__main__':
    main()
<commit_msg>remove the dots<commit_after># Copyright 2014 Dan Kilman
#
# 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 sys
from StringIO import StringIO

import argh

import pysource
from pysource import daemonizer
from pysource import client
from pysource import config

class DaemonCommands(object):
    """Daemon related commands"""

    namespace = 'daemon'

    @staticmethod
    def start():
        """Start the daemon process"""
        started = daemonizer.start()
        if not started:
            return 'Daemon already started'

    @staticmethod
    def stop():
        """Stop the daemon process"""
        stopped = daemonizer.stop()
        if stopped:
            return 'Daemon stopped'
        else:
            return 'Daemon not running'

    @staticmethod
    def restart():
        """Restart the daemon process"""
        daemonizer.restart()

    @staticmethod
    def status():
        """Check the daemon process status"""
        status, pid = daemonizer.status()
        if status == daemonizer.STATUS_STOPPED:
            return 'Daemon is (probably) stopped'
        elif status == daemonizer.STATUS_CORRUPTED:
            if pid:
                return 'Daemon pidfile exists but process does not seem ' \
                       'to be running (pid: {0}). You should probably clean ' \
                       'the files in {1} and manually check if there' \
                       ' is a daemon running somewhere.'\
                       .format(pid, config.pysource_dir)
            else:
                return 'Daemon seems to be in an unstable state. Manually ' \
                       'remove the files in {0} and kill leftover daemon ' \
                       'processes (if there are any).'\
                       .format(config.pysource_dir)
        else:
            return 'Daemon is (probably) running (pid: {0})'.format(pid)

    @classmethod
    def commands(cls):
        return [cls.start, cls.stop, cls.restart, cls.status]

def list_registered():
    """List all functions currently registered"""
    descriptors = client.list_registered()
    if len(descriptors) == 0:
        yield 'No functions registered'
    else:
        yield 'Registered functions:'
        for descriptor in descriptors:
            name = descriptor['name']
            piped = descriptor['piped']
            suffix = ' (piped)' if piped else ''
            yield '{}{}'.format(name, suffix)

def update_env(verbose=False):
    """
    Update environment variables at the daemon with the current client
    environment
    """
    status = client.update_env()
    if status != 'updated':
        raise pysource.error('Failed updating environment')
    if verbose:
        return 'Environment updated'

def source_registered(verbose=False):
    """Source all functions currently registered"""
    return client.source_registered(verbose=verbose)

@argh.arg('function_name', help='The name of the function to source.')
def source_named(function_name, piped=False, verbose=False):
    """Source a function named by the first positional argument"""
    return client.source_named(function_name,
                               piped=piped,
                               verbose=verbose)

@argh.arg('def_content', help='The function definition itself.')
def source_def(def_content, piped=False, verbose=False):
    """Source an inline function definition"""
    return client.source_def(def_content,
                             piped=piped,
                             verbose=verbose)

@argh.arg('content', help='The code to execute at the daemon.')
def source_inline(content, verbose=False):
    """
    Execute arbitrary code at the daemon. If code contains function
    definitions, they will be sourced at the client
    """
    return client.source_content(content,
                                 verbose=verbose)

@argh.arg('source_path', help='The path to the file to source.')
def source(source_path, verbose=False):
    """Source a file by its path"""
    return client.source_path(source_path,
                              verbose=verbose)

@argh.arg('function_name', help='The name of the function to run.')
def run(function_name, *args):
    """Run the function named by the first positional argument"""
    result = client.run_function(function_name, args)
    if result:
        return result

@argh.arg('function_name', help='The name of the function to run.')
def run_piped(function_name, *args):
    """
    Run the function named by the first positional argument as a piped
    function
    """
    client.run_piped_function(function_name, args)

def main():
    errors = StringIO()
    parser = argh.ArghParser()
    argh.add_commands(parser, [
        source,
        run,
        run_piped,
        list_registered,
        source_registered,
        source_named,
        source_def,
        source_inline,
        update_env
    ], )
    argh.add_commands(parser,
                      functions=DaemonCommands.commands(),
                      namespace=DaemonCommands.namespace,
                      title=DaemonCommands.__doc__)
    argh.dispatch(parser, completion=False, errors_file=errors)
    if errors.len > 0:
        sys.exit(errors.getvalue().strip())

if __name__ == '__main__':
    main()
<|endoftext|>


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

import requests, os.path, csv, re, sys
from tempfile import NamedTemporaryFile
from datetime import date, datetime, timedelta
from time import sleep
from socket import error as socket_error

if sys.version_info[0] < 3:  # Python 2
    from urlparse import urlsplit
    from ConfigParser import SafeConfigParser
    from Queue import Queue
else:  # Python 3
    from urllib.parse import urlsplit
    from configparser import SafeConfigParser
    from queue import Queue

### --- User DB Downloads --- ###
class Downloader(object):

    # INI config file parser
    __prs = SafeConfigParser()
    defaults = {}

    def __init__(self, api_key=None, personal_key=None, section=None,
                 conf_path=None, max_attempts=10):

        section = section or 'defaults'

        # If not set on constructor load api and personal keys from config
        if not (api_key and personal_key):
            r = self.read_conf(section, conf_path)
            if not r:
                print('You need to set api key & personal key!')
        else:
            self.defaults['api_key'] = api_key
            self.defaults['personal_key'] = personal_key
        self.q = Queue()

        self.max_attempts = max_attempts

    def read_conf(self, section, conf_path):
        ''' Read $HOME/.pyswrve config file '''

        conf_path = conf_path or os.path.join(os.path.expanduser('~'),
                                              '.pyswrve')
        if not os.path.exists(conf_path):
            return False
        self.__prs.read(conf_path)

        api_key = self.__prs.get(section, 'api_key')
        personal_key = self.__prs.get(section, 'personal_key')

        self.defaults['api_key'] = api_key
        self.defaults['personal_key'] = personal_key

        return True

    def get_urls(self, item, sec='data_files'):
        ''' Get urls list from swrve '''

        req = requests.get('https://dashboard.swrve.com/api/1/userdbs.json',
                           params=self.defaults).json()

        if type(req[sec][item]) == list:
            return req[sec][item]
        else:
            return [req[sec][item]]

    def download_file(self, url, path, mark_task=False, delay=None):
        ''' Download file '''

        # Get file name from url and join it to path
        fpath = os.path.join(path, os.path.split(urlsplit(url)[2])[1])

        # Request file and save it
        attempts_counter = 1
        while attempts_counter <= self.max_attempts:
            # If connection reset by pear (for exeample)
            # restart file downloading
            try:
                req = requests.get(url, params=self.defaults, stream=True)
                with open(fpath, 'w') as f:
                    for i in req.iter_content(chunk_size=1024):
                        if i:
                            f.write(i)
                            f.flush()
                print('%s download complete' % fpath)
                break
            except socket_error:
                msg = '%s downloading error. Restarting. Attempt: %s / %s'
                print(msg % (fpath, attempts_counter, self.max_attempts))
                attempts_counter += 1

        # Mark this task as done and start next queue's file download
        if mark_task:
            if delay:
                sleep(delay)
            self.q.task_done()
            self.download_start(path)

    def load_to_queue(self, lst):
        ''' Paste urls from list to download queue '''

        for item in lst:
            self.q.put(item)

    def download_start(self, path, delay=None):
        ''' Start download of next queue's file '''

        if not self.q.empty():
            self.download_file(self.q.get(block=True), path, True, delay)
        else:
            print('All downloads are complete')

### --- Functions --- ###
def aggregate_weeks(data, day_average=False):
    ''' Aggregate days data by weeks '''

    week_data = []

    start_week = data[0][0].split('-')
    for i in range(1, 4):
        start_week[i] = int(start_week[i])
    start_week = date(start_week[1], start_week[2], start_week[3])

    week_value = 0
    i = 0
    for day in data:
        if i < 6:
            week_value += day[1]
            i += 1
        else:
            week_value += day[1]
            if day_average:
                week_data.append([str(start_week), round(week_value / 7.0, 4)])
            else:
                week_data.append([str(start_week), week_value])
            start_week += timedelta(days=7)
            i = 0
            week_value = 0

    if len(data) % 7:
        date_week = str(start_week) + ' (%s / 7)' % i
        if day_average:
            week_data.append([date_week, round(week_value / float(i), 4)])
        else:
            week_data.append([date_week, week_value])

    return week_data

def str2date(str_date, to_datetime=False):
    ''' Convert string to datetime.date or datetime.datetime '''

    str_date = str_date.split('-')
    for i in range(3):
        str_date[i] = int(str_date[i])

    if to_datetime:
        dobj = datetime
    else:
        dobj = date

    return dobj(str_date[0], str_date[1], str_date[2])

def list2dict(lst, head=None):
    '''
    Transform list with lists (as rows) to dict where
    keys are cols headers and values are cols
    '''

    if not head:
        head = lst[0]
        lst = lst[1:]

    index_dct = {}
    results_dct = {}
    for i in range(len(head)):
        index_dct[i] = head[i]
        results_dct[head[i]] = []

    for line in lst:
        for i in range(len(line)):
            results_dct[index_dct[i]].append(line[i])

    return results_dct

def save_to_csv(data, head=None, fname=None):
    ''' Write data to csv file '''

    if fname:  # file path selected by user
        f = open(fname, 'w')
    else:  # temp file
        f = NamedTemporaryFile(suffix='.csv', prefix='pyswrve_', delete=False)
        fname = f.name

    # Data can be dict from api.SwrveSession.get_evt_stat
    # if method return dict with payload
    if type(data) == dict:

        # If data[key] = [ [DATE, value], [DATE2, value2] ... ]
        if type(data[data.keys()[0]][0]) == list:
            fields = ['DATE'] + data.keys()
            l = True
        else:  # data[key] = [value1, value2, ... ]
            fields = data.keys()
            l = False

        w = csv.DictWriter(f, fieldnames=fields)
        w.writeheader()

        for i in range(len(data[data.keys()[0]])):
            row = {}
            for key in data.keys():
                if l:  # data[key][i] == ['D-2015-01-31', 125.00]
                    row[key] = data[key][i][1]
                else:  # data[key][i] = 125.00
                    row[key] = data[key][i]

            if l:  # DATE
                row['DATE'] = data[data.keys()[0]][i][0]

            w.writerow(row)

    # Data can be list with KPI, events fired, etc...
    elif type(data) == list:
        w = csv.writer(f)

        if head:
            w.writerow(head)

        # data[0] == ['D-2015-01-31', 125.00]
        if type(data[0]) == list:
            w.writerows(data)
        else:  # data = [100.00, 125.00, 150.00 ... ]
            w.writerows([[i] for i in data])

    f.close()
    print('File %s saved' % fname)

def generate_pyplot_styles(count=None, with_black=False, with_white=False):
    '''
    Generate list with line styles for drawing plots with matplotlib
    Return list
    '''

    markers = ['.', ',', 'o', 'v', '^', '<', '>']
    for i in range(1, 5):
        markers.append(str(i))
    markers += ['s', 'p', '*', 'h', 'H', '+', 'x', 'D', 'd', '|', '_']

    colors = 'bgrcmy'
    if with_black:
        colors += 'k'
    if with_white:
        colors += 'w'

    styles = []
    for marker in markers:
        for linestyle in ['-', '--', '-.', ':']:
            for color in colors:
                styles.append(color+marker+linestyle)

    count = count or len(styles)

    return styles[:count]

def generate_dates_list(start, stop):
    ''' Generate list with dates as strings like '2015-01-31' '''

    dates_list = []

    # '2015-05-14' => (2015, 5, 14)
    start = start.split('-')
    stop = stop.split('-')
    for i in range(3):
        start[i] = int(start[i])
        stop[i] = int(stop[i])

    # dt since start to stop
    dt = date(stop[0], stop[1], stop[2]) - date(start[0], start[1], start[2])

    for i in range(dt.days+1):
        d = str(date(start[0], start[1], start[2]) + timedelta(days=i))
        dates_list.append(d)

    return dates_list

def postgresql_csv_fix(fname):
    ''' Fix csv file for loading to PostgreSQL '''

    with open(fname) as f:
        data = f.read()

    data = re.sub('\\\,', '.', data)  # iPhone7,2 => iPhone7.2

    data = re.sub(',\r,', ',,', data)  # fix rows splitted in the middle
    data = re.sub(',\n,', ',,', data)
    rsplit = re.findall('\w\r,', data, re.DOTALL)
    if rsplit:
        for item in rsplit:
            data = re.sub(item[0]+'\r,', item[0]+',', data)

    nsplit = re.findall('\w\n,', data, re.DOTALL)
    if nsplit:
        for item in nsplit:
            data = re.sub(item[0]+'\n,', item[0]+',', data)

    data = re.sub(',\",', ',0,', data)  # fix " on level's pos

    with open(fname, 'w') as f:
        f.write(data)

def csv_rm_broken_rows(fname, row_len, delimiter=','):
    ''' Delete rows with mismatched length '''

    with open(fname) as f:
        data = f.readlines()

    results = ''
    for row in data:
        if len(re.findall(delimiter, row)) < row_len-1:
            continue
        results += row

    with open(fname, 'w') as f:
        f.write(results)
<commit_msg>rm unnecessarн funcs<commit_after># -*- coding: utf-8 -*-

import requests, os.path, csv, re, sys
from tempfile import NamedTemporaryFile
from datetime import date, datetime, timedelta
from time import sleep
from socket import error as socket_error

if sys.version_info[0] < 3:  # Python 2
    from urlparse import urlsplit
    from ConfigParser import SafeConfigParser
    from Queue import Queue
else:  # Python 3
    from urllib.parse import urlsplit
    from configparser import SafeConfigParser
    from queue import Queue

### --- User DB Downloads --- ###
class Downloader(object):

    # INI config file parser
    __prs = SafeConfigParser()
    defaults = {}

    def __init__(self, api_key=None, personal_key=None, section=None,
                 conf_path=None, max_attempts=10):

        section = section or 'defaults'

        # If not set on constructor load api and personal keys from config
        if not (api_key and personal_key):
            r = self.read_conf(section, conf_path)
            if not r:
                print('You need to set api key & personal key!')
        else:
            self.defaults['api_key'] = api_key
            self.defaults['personal_key'] = personal_key
        self.q = Queue()

        self.max_attempts = max_attempts

    def read_conf(self, section, conf_path):
        ''' Read $HOME/.pyswrve config file '''

        conf_path = conf_path or os.path.join(os.path.expanduser('~'),
                                              '.pyswrve')
        if not os.path.exists(conf_path):
            return False
        self.__prs.read(conf_path)

        api_key = self.__prs.get(section, 'api_key')
        personal_key = self.__prs.get(section, 'personal_key')

        self.defaults['api_key'] = api_key
        self.defaults['personal_key'] = personal_key

        return True

    def get_urls(self, item, sec='data_files'):
        ''' Get urls list from swrve '''

        req = requests.get('https://dashboard.swrve.com/api/1/userdbs.json',
                           params=self.defaults).json()

        if type(req[sec][item]) == list:
            return req[sec][item]
        else:
            return [req[sec][item]]

    def download_file(self, url, path, mark_task=False, delay=None):
        ''' Download file '''

        # Get file name from url and join it to path
        fpath = os.path.join(path, os.path.split(urlsplit(url)[2])[1])

        # Request file and save it
        attempts_counter = 1
        while attempts_counter <= self.max_attempts:
            # If connection reset by pear (for exeample)
            # restart file downloading
            try:
                req = requests.get(url, params=self.defaults, stream=True)
                with open(fpath, 'w') as f:
                    for i in req.iter_content(chunk_size=1024):
                        if i:
                            f.write(i)
                            f.flush()
                print('%s download complete' % fpath)
                break
            except socket_error:
                msg = '%s downloading error. Restarting. Attempt: %s / %s'
                print(msg % (fpath, attempts_counter, self.max_attempts))
                attempts_counter += 1

        # Mark this task as done and start next queue's file download
        if mark_task:
            if delay:
                sleep(delay)
            self.q.task_done()
            self.download_start(path)

    def load_to_queue(self, lst):
        ''' Paste urls from list to download queue '''

        for item in lst:
            self.q.put(item)

    def download_start(self, path, delay=None):
        ''' Start download of next queue's file '''

        if not self.q.empty():
            self.download_file(self.q.get(block=True), path, True, delay)
        else:
            print('All downloads are complete')

### --- Functions --- ###
def aggregate_weeks(data, day_average=False):
    ''' Aggregate days data by weeks '''

    week_data = []

    start_week = data[0][0].split('-')
    for i in range(1, 4):
        start_week[i] = int(start_week[i])
    start_week = date(start_week[1], start_week[2], start_week[3])

    week_value = 0
    i = 0
    for day in data:
        if i < 6:
            week_value += day[1]
            i += 1
        else:
            week_value += day[1]
            if day_average:
                week_data.append([str(start_week), round(week_value / 7.0, 4)])
            else:
                week_data.append([str(start_week), week_value])
            start_week += timedelta(days=7)
            i = 0
            week_value = 0

    if len(data) % 7:
        date_week = str(start_week) + ' (%s / 7)' % i
        if day_average:
            week_data.append([date_week, round(week_value / float(i), 4)])
        else:
            week_data.append([date_week, week_value])

    return week_data

def str2date(str_date, to_datetime=False):
    ''' Convert string to datetime.date or datetime.datetime '''

    str_date = str_date.split('-')
    for i in range(3):
        str_date[i] = int(str_date[i])

    if to_datetime:
        dobj = datetime
    else:
        dobj = date

    return dobj(str_date[0], str_date[1], str_date[2])

def list2dict(lst, head=None):
    '''
    Transform list with lists (as rows) to dict where
    keys are cols headers and values are cols
    '''

    if not head:
        head = lst[0]
        lst = lst[1:]

    index_dct = {}
    results_dct = {}
    for i in range(len(head)):
        index_dct[i] = head[i]
        results_dct[head[i]] = []

    for line in lst:
        for i in range(len(line)):
            results_dct[index_dct[i]].append(line[i])

    return results_dct

def save_to_csv(data, head=None, fname=None):
    ''' Write data to csv file '''

    if fname:  # file path selected by user
        f = open(fname, 'w')
    else:  # temp file
        f = NamedTemporaryFile(suffix='.csv', prefix='pyswrve_', delete=False)
        fname = f.name

    # Data can be dict from api.SwrveSession.get_evt_stat
    # if method return dict with payload
    if type(data) == dict:

        # If data[key] = [ [DATE, value], [DATE2, value2] ... ]
        if type(data[data.keys()[0]][0]) == list:
            fields = ['DATE'] + data.keys()
            l = True
        else:  # data[key] = [value1, value2, ... ]
            fields = data.keys()
            l = False

        w = csv.DictWriter(f, fieldnames=fields)
        w.writeheader()

        for i in range(len(data[data.keys()[0]])):
            row = {}
            for key in data.keys():
                if l:  # data[key][i] == ['D-2015-01-31', 125.00]
                    row[key] = data[key][i][1]
                else:  # data[key][i] = 125.00
                    row[key] = data[key][i]

            if l:  # DATE
                row['DATE'] = data[data.keys()[0]][i][0]

            w.writerow(row)

    # Data can be list with KPI, events fired, etc...
    elif type(data) == list:
        w = csv.writer(f)

        if head:
            w.writerow(head)

        # data[0] == ['D-2015-01-31', 125.00]
        if type(data[0]) == list:
            w.writerows(data)
        else:  # data = [100.00, 125.00, 150.00 ... ]
            w.writerows([[i] for i in data])

    f.close()
    print('File %s saved' % fname)

def generate_pyplot_styles(count=None, with_black=False, with_white=False):
    '''
    Generate list with line styles for drawing plots with matplotlib
    Return list
    '''

    markers = ['.', ',', 'o', 'v', '^', '<', '>']
    for i in range(1, 5):
        markers.append(str(i))
    markers += ['s', 'p', '*', 'h', 'H', '+', 'x', 'D', 'd', '|', '_']

    colors = 'bgrcmy'
    if with_black:
        colors += 'k'
    if with_white:
        colors += 'w'

    styles = []
    for marker in markers:
        for linestyle in ['-', '--', '-.', ':']:
            for color in colors:
                styles.append(color+marker+linestyle)

    count = count or len(styles)

    return styles[:count]

def generate_dates_list(start, stop):
    ''' Generate list with dates as strings like '2015-01-31' '''

    dates_list = []

    # '2015-05-14' => (2015, 5, 14)
    start = start.split('-')
    stop = stop.split('-')
    for i in range(3):
        start[i] = int(start[i])
        stop[i] = int(stop[i])

    # dt since start to stop
    dt = date(stop[0], stop[1], stop[2]) - date(start[0], start[1], start[2])

    for i in range(dt.days+1):
        d = str(date(start[0], start[1], start[2]) + timedelta(days=i))
        dates_list.append(d)

    return dates_list
<|endoftext|>


<commit_before>#!/usr/bin/env python
# -*- coding: utf-8 -*-
'''
plot.py
-------

Plots a simple :py:mod:`pysyzygy` light curve, along with the
observer view of the orbit, the limb darkening profile, and a
table of the transit parameters.

.. figure:: ../img/transit_plot.png
    :width: 600px
    :align: center
    :height: 100px
    :alt: alternate text
    :figclass: align-center

'''

from __future__ import division, print_function, absolute_import, unicode_literals
from .transit import Transit, QUADRATIC, KIPPING, NONLINEAR
import numpy as np
import matplotlib.pyplot as pl
import matplotlib.cm as cm
from matplotlib.colors import LinearSegmentedColormap, colorConverter
import sys

__all__ = ['PlotTransit']

def I(r, limbdark):
  '''
  The standard quadratic limb darkening law.

  :param ndarray r: The radius vector
  :param limbdark: A :py:class:`pysyzygy.transit.LIMBDARK` instance containing
                   the limb darkening law information

  :returns: The stellar intensity as a function of `r`

  '''

  if limbdark.ldmodel == QUADRATIC:
    u1 = limbdark.u1
    u2 = limbdark.u2
    return (1-u1*(1-np.sqrt(1-r**2))-u2*(1-np.sqrt(1-r**2))**2)/(1-u1/3-u2/6)/np.pi
  elif limbdark.ldmodel == KIPPING:
    a = np.sqrt(limbdark.q1)
    b = 2*limbdark.q2
    u1 = a*b
    u2 = a*(1 - b)
    return (1-u1*(1-np.sqrt(1-r**2))-u2*(1-np.sqrt(1-r**2))**2)/(1-u1/3-u2/6)/np.pi
  elif limbdark.ldmodel == NONLINEAR:
    raise Exception('Nonlinear model not yet implemented!')                           # TODO!
  else:
    raise Exception('Invalid limb darkening model.')

def PlotTransit(compact = False, ldplot = True, plottitle = "",
                xlim = None, binned = True, **kwargs):
  '''
  Plots a light curve described by `kwargs`

  :param bool compact: Display the compact version of the plot? Default `False`
  :param bool ldplot: Displat the limb darkening inset? Default `True`
  :param str plottitle: The title of the plot. Default `""`
  :param float xlim: The half-width of the orbit plot in stellar radii. Default is to \
                     auto adjust this
  :param bool binned: Bin the light curve model to the exposure time? Default `True`
  :param kwargs: Any keyword arguments to be passed to :py:func:`pysyzygy.transit.Transit`

  :returns fig: The :py:mod:`matplotlib` figure object

  '''

  # Plotting
  fig = pl.figure(figsize = (12,8))
  fig.subplots_adjust(hspace=0.3)
  ax1, ax2 = pl.subplot(211), pl.subplot(212)
  if not compact:
    fig.subplots_adjust(right = 0.7)

  t0 = kwargs.pop('t0', 0.)
  trn = Transit(**kwargs)
  try:
    trn.Compute()
    notransit = False
  except Exception as e:
    if str(e) == "Object does not transit the star.":
      notransit = True
    else: raise Exception(e)

  time = trn.arrays.time + t0

  if not notransit:
    if binned:
      trn.Bin()
      flux = trn.arrays.bflx
    else:
      flux = trn.arrays.flux

    time = np.concatenate(([-1.e5], time, [1.e5]))                                    # Add baseline on each side
    flux = np.concatenate(([1.], flux, [1.]))
    ax1.plot(time, flux, '-', color='DarkBlue')
    rng = np.max(flux) - np.min(flux)

    if rng > 0:
      ax1.set_ylim(np.min(flux) - 0.1*rng, np.max(flux) + 0.1*rng)
      left = np.argmax(flux < (1. - 1.e-8))
      right = np.argmax(flux[left:] > (1. - 1.e-8)) + left
      rng = time[right] - time[left]
      ax1.set_xlim(time[left] - rng, time[right] + rng)

  ax1.set_xlabel('Time (Days)', fontweight='bold')
  ax1.set_ylabel('Normalized Flux', fontweight='bold')

  # Adjust these for full-orbit plotting
  maxpts = kwargs.get('maxpts', 10000); kwargs.update({'maxpts': maxpts})
  per = kwargs.get('per', 10.); kwargs.update({'per': per})
  kwargs.update({'fullorbit': True})
  kwargs.update({'exppts': 30})
  kwargs.update({'exptime': 50 * per / maxpts})
  trn = Transit(**kwargs)

  try:
    trn.Compute()
  except Exception as e:
    if str(e) == "Object does not transit the star.":
      pass
    else: raise Exception(e)

  # Sky-projected motion
  x = trn.arrays.x
  y = trn.arrays.y
  z = trn.arrays.z
  inc = (np.arccos(trn.transit.bcirc/trn.transit.aRs)*180./np.pi)                     # Orbital inclination

  # Mask the star
  for j in range(len(x)):
    if (x[j]**2 + y[j]**2) < 1. and (z[j] > 0):
      x[j] = np.nan
      y[j] = np.nan

  # The star
  r = np.linspace(0,1,100)
  Ir = I(r,trn.limbdark)/I(0,trn.limbdark)

  for ri,Iri in zip(r[::-1],Ir[::-1]):
    star = pl.Circle((0, 0), ri, color=str(0.95*Iri), alpha=1.)
    ax2.add_artist(star)

  # Inset: Limb darkening
  if ldplot:
    if compact:
      inset1 = pl.axes([0.145, 0.32, .09, .1])
    else:
      inset1 = fig.add_axes([0.725,0.3,0.2,0.15])
    inset1.plot(r,Ir,'k-')
    pl.setp(inset1, xlim=(-0.1,1.1), ylim=(-0.1,1.1), xticks=[0,1], yticks=[0,1])
    for tick in inset1.xaxis.get_major_ticks() + inset1.yaxis.get_major_ticks():
      tick.label.set_fontsize(8)
    inset1.set_ylabel(r'I/I$_0$', fontsize=8, labelpad=-8)
    inset1.set_xlabel(r'r/R$_\star$', fontsize=8, labelpad=-8)
    inset1.set_title('Limb Darkening', fontweight='bold', fontsize=9)

  # Inset: Top view of orbit
  if compact:
    inset2 = pl.axes([0.135, 0.115, .1, .1])
  else:
    inset2 = fig.add_axes([0.725,0.1,0.2,0.15])
  pl.setp(inset2, xticks=[], yticks=[])
  trn.transit.bcirc = trn.transit.aRs                                                 # This ensures we are face-on
  try:
    trn.Compute()
  except Exception as e:
    if str(e) == "Object does not transit the star.":
      pass
    else: raise Exception(e)
  xp = trn.arrays.x
  yp = trn.arrays.y
  inset2.plot(xp, yp, '-', color='DarkBlue', alpha=0.5)
  # Draw some invisible dots at the corners to set the window size
  xmin, xmax, ymin, ymax = np.nanmin(xp), np.nanmax(xp), np.nanmin(yp), np.nanmax(yp)
  xrng = xmax - xmin
  yrng = ymax - ymin
  xmin -= 0.1*xrng; xmax += 0.1*xrng;
  ymin -= 0.1*yrng; ymax += 0.1*yrng;
  inset2.scatter([xmin,xmin,xmax,xmax], [ymin,ymax,ymin,ymax], alpha = 0.)
  # Plot the star
  for ri,Iri in zip(r[::-10],Ir[::-10]):
    star = pl.Circle((0, 0), ri, color=str(0.95*Iri), alpha=1.)
    inset2.add_artist(star)
  # Plot the planet
  ycenter = yp[np.where(np.abs(xp) == np.nanmin(np.abs(xp)))][0]
  while ycenter > 0:
    xp[np.where(np.abs(xp) == np.nanmin(np.abs(xp)))] = np.nan
    ycenter = yp[np.where(np.abs(xp) == np.nanmin(np.abs(xp)))][0]
  planet = pl.Circle((0, ycenter), trn.transit.RpRs, color='DarkBlue', alpha=1.)
  inset2.add_artist(planet)
  inset2.set_title('Top View', fontweight='bold', fontsize=9)
  inset2.set_aspect('equal','datalim')

  # The orbit itself
  with np.errstate(invalid='ignore'):
    ax2.plot(x, y, '-', color='DarkBlue', lw = 1. if per < 30. else
                                               max(1. - (per - 30.) / 100., 0.3) )

  # The planet
  with np.errstate(invalid = 'ignore'):
    ycenter = y[np.where(np.abs(x) == np.nanmin(np.abs(x)))][0]
  while ycenter > 0:
    x[np.where(np.abs(x) == np.nanmin(np.abs(x)))] = np.nan
    ycenter = y[np.where(np.abs(x) == np.nanmin(np.abs(x)))][0]
  planet = pl.Circle((0, ycenter), trn.transit.RpRs, color='DarkBlue', alpha=1.)
  ax2.add_artist(planet)

  # Force aspect
  if xlim is None:
    xlim = 1.1 * max(np.nanmax(x), np.nanmax(-x))
  ax2.set_ylim(-xlim/3.2,xlim/3.2)
  ax2.set_xlim(-xlim,xlim)

  ax2.set_xlabel(r'X (R$_\star$)', fontweight='bold')
  ax2.set_ylabel(r'Y (R$_\star$)', fontweight='bold')
  ax1.set_title(plottitle, fontsize=12)

  if not compact:
    rect = 0.725,0.55,0.2,0.35
    ax3 = fig.add_axes(rect)
    ax3.xaxis.set_visible(False)
    ax3.yaxis.set_visible(False)

    # Table of parameters
    ltable = [ r'$P:$',
               r'$e:$',
               r'$i:$',
               r'$\omega:$',
               r'$\rho_\star:$',
               r'$M_p:$',
               r'$R_p:$',
               r'$q_1:$',
               r'$q_2:$']
    rtable = [ r'$%.4f\ \mathrm{days}$' % trn.transit.per,
               r'$%.5f$' % trn.transit.ecc,
               r'$%.4f^\circ$' % inc,
               r'$%.3f^\circ$' % (trn.transit.w*180./np.pi),
               r'$%.5f\ \mathrm{g/cm^3}$' % trn.transit.rhos,
               r'$%.5f\ M_\star$' % trn.transit.MpMs,
               r'$%.5f\ R_\star$' % trn.transit.RpRs,
               r'$%.5f$' % trn.limbdark.q1,
               r'$%.5f$' % trn.limbdark.q2]
    yt = 0.875
    for l,r in zip(ltable, rtable):
      ax3.annotate(l, xy=(0.25, yt), xycoords="axes fraction", ha='right', fontsize=16)
      ax3.annotate(r, xy=(0.35, yt), xycoords="axes fraction", fontsize=16)
      yt -= 0.1

  return fig<commit_msg>bugfix<commit_after>#!/usr/bin/env python
# -*- coding: utf-8 -*-
'''
plot.py
-------

Plots a simple :py:mod:`pysyzygy` light curve, along with the
observer view of the orbit, the limb darkening profile, and a
table of the transit parameters.

.. figure:: ../pysyzygy/img/transit_plot.png
    :width: 600px
    :align: center
    :height: 100px
    :alt: alternate text
    :figclass: align-center

'''

from __future__ import division, print_function, absolute_import, unicode_literals
from .transit import Transit, QUADRATIC, KIPPING, NONLINEAR
import numpy as np
import matplotlib.pyplot as pl
import matplotlib.cm as cm
from matplotlib.colors import LinearSegmentedColormap, colorConverter
import sys

__all__ = ['PlotTransit']

def I(r, limbdark):
  '''
  The standard quadratic limb darkening law.

  :param ndarray r: The radius vector
  :param limbdark: A :py:class:`pysyzygy.transit.LIMBDARK` instance containing
                   the limb darkening law information

  :returns: The stellar intensity as a function of `r`

  '''

  if limbdark.ldmodel == QUADRATIC:
    u1 = limbdark.u1
    u2 = limbdark.u2
    return (1-u1*(1-np.sqrt(1-r**2))-u2*(1-np.sqrt(1-r**2))**2)/(1-u1/3-u2/6)/np.pi
  elif limbdark.ldmodel == KIPPING:
    a = np.sqrt(limbdark.q1)
    b = 2*limbdark.q2
    u1 = a*b
    u2 = a*(1 - b)
    return (1-u1*(1-np.sqrt(1-r**2))-u2*(1-np.sqrt(1-r**2))**2)/(1-u1/3-u2/6)/np.pi
  elif limbdark.ldmodel == NONLINEAR:
    raise Exception('Nonlinear model not yet implemented!')                           # TODO!
  else:
    raise Exception('Invalid limb darkening model.')

def PlotTransit(compact = False, ldplot = True, plottitle = "",
                xlim = None, binned = True, **kwargs):
  '''
  Plots a light curve described by `kwargs`

  :param bool compact: Display the compact version of the plot? Default `False`
  :param bool ldplot: Displat the limb darkening inset? Default `True`
  :param str plottitle: The title of the plot. Default `""`
  :param float xlim: The half-width of the orbit plot in stellar radii. Default is to \
                     auto adjust this
  :param bool binned: Bin the light curve model to the exposure time? Default `True`
  :param kwargs: Any keyword arguments to be passed to :py:func:`pysyzygy.transit.Transit`

  :returns fig: The :py:mod:`matplotlib` figure object

  '''

  # Plotting
  fig = pl.figure(figsize = (12,8))
  fig.subplots_adjust(hspace=0.3)
  ax1, ax2 = pl.subplot(211), pl.subplot(212)
  if not compact:
    fig.subplots_adjust(right = 0.7)

  t0 = kwargs.pop('t0', 0.)
  trn = Transit(**kwargs)
  try:
    trn.Compute()
    notransit = False
  except Exception as e:
    if str(e) == "Object does not transit the star.":
      notransit = True
    else: raise Exception(e)

  time = trn.arrays.time + t0

  if not notransit:
    if binned:
      trn.Bin()
      flux = trn.arrays.bflx
    else:
      flux = trn.arrays.flux

    time = np.concatenate(([-1.e5], time, [1.e5]))                                    # Add baseline on each side
    flux = np.concatenate(([1.], flux, [1.]))
    ax1.plot(time, flux, '-', color='DarkBlue')
    rng = np.max(flux) - np.min(flux)

    if rng > 0:
      ax1.set_ylim(np.min(flux) - 0.1*rng, np.max(flux) + 0.1*rng)
      left = np.argmax(flux < (1. - 1.e-8))
      right = np.argmax(flux[left:] > (1. - 1.e-8)) + left
      rng = time[right] - time[left]
      ax1.set_xlim(time[left] - rng, time[right] + rng)

  ax1.set_xlabel('Time (Days)', fontweight='bold')
  ax1.set_ylabel('Normalized Flux', fontweight='bold')

  # Adjust these for full-orbit plotting
  maxpts = kwargs.get('maxpts', 10000); kwargs.update({'maxpts': maxpts})
  per = kwargs.get('per', 10.); kwargs.update({'per': per})
  kwargs.update({'fullorbit': True})
  kwargs.update({'exppts': 30})
  kwargs.update({'exptime': 50 * per / maxpts})
  trn = Transit(**kwargs)

  try:
    trn.Compute()
  except Exception as e:
    if str(e) == "Object does not transit the star.":
      pass
    else: raise Exception(e)

  # Sky-projected motion
  x = trn.arrays.x
  y = trn.arrays.y
  z = trn.arrays.z
  inc = (np.arccos(trn.transit.bcirc/trn.transit.aRs)*180./np.pi)                     # Orbital inclination

  # Mask the star
  for j in range(len(x)):
    if (x[j]**2 + y[j]**2) < 1. and (z[j] > 0):
      x[j] = np.nan
      y[j] = np.nan

  # The star
  r = np.linspace(0,1,100)
  Ir = I(r,trn.limbdark)/I(0,trn.limbdark)

  for ri,Iri in zip(r[::-1],Ir[::-1]):
    star = pl.Circle((0, 0), ri, color=str(0.95*Iri), alpha=1.)
    ax2.add_artist(star)

  # Inset: Limb darkening
  if ldplot:
    if compact:
      inset1 = pl.axes([0.145, 0.32, .09, .1])
    else:
      inset1 = fig.add_axes([0.725,0.3,0.2,0.15])
    inset1.plot(r,Ir,'k-')
    pl.setp(inset1, xlim=(-0.1,1.1), ylim=(-0.1,1.1), xticks=[0,1], yticks=[0,1])
    for tick in inset1.xaxis.get_major_ticks() + inset1.yaxis.get_major_ticks():
      tick.label.set_fontsize(8)
    inset1.set_ylabel(r'I/I$_0$', fontsize=8, labelpad=-8)
    inset1.set_xlabel(r'r/R$_\star$', fontsize=8, labelpad=-8)
    inset1.set_title('Limb Darkening', fontweight='bold', fontsize=9)

  # Inset: Top view of orbit
  if compact:
    inset2 = pl.axes([0.135, 0.115, .1, .1])
  else:
    inset2 = fig.add_axes([0.725,0.1,0.2,0.15])
  pl.setp(inset2, xticks=[], yticks=[])
  trn.transit.bcirc = trn.transit.aRs                                                 # This ensures we are face-on
  try:
    trn.Compute()
  except Exception as e:
    if str(e) == "Object does not transit the star.":
      pass
    else: raise Exception(e)
  xp = trn.arrays.x
  yp = trn.arrays.y
  inset2.plot(xp, yp, '-', color='DarkBlue', alpha=0.5)
  # Draw some invisible dots at the corners to set the window size
  xmin, xmax, ymin, ymax = np.nanmin(xp), np.nanmax(xp), np.nanmin(yp), np.nanmax(yp)
  xrng = xmax - xmin
  yrng = ymax - ymin
  xmin -= 0.1*xrng; xmax += 0.1*xrng;
  ymin -= 0.1*yrng; ymax += 0.1*yrng;
  inset2.scatter([xmin,xmin,xmax,xmax], [ymin,ymax,ymin,ymax], alpha = 0.)
  # Plot the star
  for ri,Iri in zip(r[::-10],Ir[::-10]):
    star = pl.Circle((0, 0), ri, color=str(0.95*Iri), alpha=1.)
    inset2.add_artist(star)
  # Plot the planet
  ycenter = yp[np.where(np.abs(xp) == np.nanmin(np.abs(xp)))][0]
  while ycenter > 0:
    xp[np.where(np.abs(xp) == np.nanmin(np.abs(xp)))] = np.nan
    ycenter = yp[np.where(np.abs(xp) == np.nanmin(np.abs(xp)))][0]
  planet = pl.Circle((0, ycenter), trn.transit.RpRs, color='DarkBlue', alpha=1.)
  inset2.add_artist(planet)
  inset2.set_title('Top View', fontweight='bold', fontsize=9)
  inset2.set_aspect('equal','datalim')

  # The orbit itself
  with np.errstate(invalid='ignore'):
    ax2.plot(x, y, '-', color='DarkBlue', lw = 1. if per < 30. else
                                               max(1. - (per - 30.) / 100., 0.3) )

  # The planet
  with np.errstate(invalid = 'ignore'):
    ycenter = y[np.where(np.abs(x) == np.nanmin(np.abs(x)))][0]
  while ycenter > 0:
    x[np.where(np.abs(x) == np.nanmin(np.abs(x)))] = np.nan
    ycenter = y[np.where(np.abs(x) == np.nanmin(np.abs(x)))][0]
  planet = pl.Circle((0, ycenter), trn.transit.RpRs, color='DarkBlue', alpha=1.)
  ax2.add_artist(planet)

  # Force aspect
  if xlim is None:
    xlim = 1.1 * max(np.nanmax(x), np.nanmax(-x))
  ax2.set_ylim(-xlim/3.2,xlim/3.2)
  ax2.set_xlim(-xlim,xlim)

  ax2.set_xlabel(r'X (R$_\star$)', fontweight='bold')
  ax2.set_ylabel(r'Y (R$_\star$)', fontweight='bold')
  ax1.set_title(plottitle, fontsize=12)

  if not compact:
    rect = 0.725,0.55,0.2,0.35
    ax3 = fig.add_axes(rect)
    ax3.xaxis.set_visible(False)
    ax3.yaxis.set_visible(False)

    # Table of parameters
    ltable = [ r'$P:$',
               r'$e:$',
               r'$i:$',
               r'$\omega:$',
               r'$\rho_\star:$',
               r'$M_p:$',
               r'$R_p:$',
               r'$q_1:$',
               r'$q_2:$']
    rtable = [ r'$%.4f\ \mathrm{days}$' % trn.transit.per,
               r'$%.5f$' % trn.transit.ecc,
               r'$%.4f^\circ$' % inc,
               r'$%.3f^\circ$' % (trn.transit.w*180./np.pi),
               r'$%.5f\ \mathrm{g/cm^3}$' % trn.transit.rhos,
               r'$%.5f\ M_\star$' % trn.transit.MpMs,
               r'$%.5f\ R_\star$' % trn.transit.RpRs,
               r'$%.5f$' % trn.limbdark.q1,
               r'$%.5f$' % trn.limbdark.q2]
    yt = 0.875
    for l,r in zip(ltable, rtable):
      ax3.annotate(l, xy=(0.25, yt), xycoords="axes fraction", ha='right', fontsize=16)
      ax3.annotate(r, xy=(0.35, yt), xycoords="axes fraction", fontsize=16)
      yt -= 0.1

  return fig<|endoftext|>


<commit_before>#!/usr/bin/python
#
# Script to run tests.
#
# Copyright 2012, Kristinn Gudjonsson <kiddi@kiddaland.net>.
# Copyright 2013, Joachim Metz <joachim.metz@gmail.com>.
#
# 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 glob
import os
import unittest
import sys

def FindTestFiles(path):
  """Find the test files (*_test.py) within the specified path."""
  file_list = []

  for directory, _, _ in os.walk(path):
    directory_pattern = os.path.join(directory, '*.py')

    for pattern_match in glob.iglob(directory_pattern):
      if os.path.isfile(pattern_match):
        file_list.append(pattern_match)

  return file_list

def RunTests(path):
  """Runs all the test for the test files found within the specified path."""
  test_classes = []

  for test_file in FindTestFiles(path):
    library_name = test_file.rstrip('.py').replace('/', '.').lstrip('.')
    test_classes.append(library_name)

  tests = unittest.TestLoader().loadTestsFromNames(test_classes)
  test_run = unittest.TextTestRunner(verbosity=1)
  return test_run.run(tests)

def FormatHeader(header, char='*'):
  """Format and return a header for output."""
  return ('\n{:%s^80}' % char).format(u' %s ' % header)

def PrintResults(my_results):
  """Print the results from an aggregated test run."""
  errors = 0
  failures = 0
  print 'Ran: {} tests.'.format(my_results.testsRun)
  if my_results.wasSuccessful():
    print '--++'*20
    print 'Yeee you know what, all tests came out clean.'
    print '--++'*20
  else:
    errors = len(my_results.errors)
    failures = len(my_results.failures)

    print my_results.printErrors()
    print FormatHeader('Tests failed.')
    print '  {:>10s}: {}\n  {:>10s}: {}\n  {:>10s}: {}'.format(
        'Errors', errors, 'Failures', failures, 'Total',
        errors + failures)
    print '+='*40

if __name__ == '__main__':
  # Find the path to the pytsk3 Python module.
  results = glob.glob(os.path.join('build', 'lib.*'))

  if len(results) != 1:
    sys.path.insert(0, results[0])

  test_results = RunTests(os.path.join('.', 'tests'))

  PrintResults(test_results)
  if not test_results.wasSuccessful():
    sys.exit(1)
<commit_msg>Small fix for run_tests.py<commit_after>#!/usr/bin/python
#
# Script to run tests.
#
# Copyright 2012, Kristinn Gudjonsson <kiddi@kiddaland.net>.
# Copyright 2013, Joachim Metz <joachim.metz@gmail.com>.
#
# 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 glob
import os
import unittest
import sys

def FindTestFiles(path):
  """Find the test files (*_test.py) within the specified path."""
  file_list = []

  for directory, _, _ in os.walk(path):
    directory_pattern = os.path.join(directory, '*.py')

    for pattern_match in glob.iglob(directory_pattern):
      if os.path.isfile(pattern_match):
        file_list.append(pattern_match)

  return file_list

def RunTests(path):
  """Runs all the test for the test files found within the specified path."""
  test_classes = []

  for test_file in FindTestFiles(path):
    library_name = test_file.rstrip('.py').replace('/', '.').lstrip('.')
    test_classes.append(library_name)

  tests = unittest.TestLoader().loadTestsFromNames(test_classes)
  test_run = unittest.TextTestRunner(verbosity=1)
  return test_run.run(tests)

def FormatHeader(header, char='*'):
  """Format and return a header for output."""
  return ('\n{:%s^80}' % char).format(u' %s ' % header)

def PrintResults(my_results):
  """Print the results from an aggregated test run."""
  errors = 0
  failures = 0
  print 'Ran: {} tests.'.format(my_results.testsRun)
  if my_results.wasSuccessful():
    print '--++'*20
    print 'Yeee you know what, all tests came out clean.'
    print '--++'*20
  else:
    errors = len(my_results.errors)
    failures = len(my_results.failures)

    print my_results.printErrors()
    print FormatHeader('Tests failed.')
    print '  {:>10s}: {}\n  {:>10s}: {}\n  {:>10s}: {}'.format(
        'Errors', errors, 'Failures', failures, 'Total',
        errors + failures)
    print '+='*40

if __name__ == '__main__':
  # Find the path to the pytsk3 Python module.
  results = glob.glob(os.path.join('build', 'lib.*'))

  if len(results) != 1:
    print 'Unable to find pytsk3.so in build directory.'
    sys.exit(1)

  sys.path.append(results[0])

  test_results = RunTests(os.path.join('.', 'tests'))

  PrintResults(test_results)
  if not test_results.wasSuccessful():
    sys.exit(1)
<|endoftext|>