<commit_before>#!/usr/bin/env python
#   -*- encoding: UTF-8 -*-

# This file is part of Addison Arches.
#
# Addison Arches 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.
#
# Addison Arches 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 Addison Arches.  If not, see <http://www.gnu.org/licenses/>.

import argparse
import ast
import asyncio
from collections import OrderedDict
from collections import namedtuple
import datetime
import itertools
import logging
import operator
import os
import os.path
import pickle
from pprint import pprint
import sys
import tempfile

from turberfield.utils.expert import Expert

DFLT_LOCN = os.path.expanduser(os.path.join("~", ".addisonarches"))

__doc__ = """
Encapsulates the game world in Addison Arches.
"""

class UnNamedPipe:

    def __init__(self, pipe:tuple, **kwargs):
        self.pipe = pipe
        self._in = os.fdopen(self.pipe[1], 'w', buffering=1, encoding="utf-8")
        self._out = os.fdopen(self.pipe[0], 'r', buffering=1, encoding="utf-8")

    def put_nowait(self, msg):
        """
        Put an item into the queue without blocking.
        """
        try:
            pprint(msg, stream=self._in, compact=True, width=sys.maxsize)
        except TypeError:  # 'compact' is new in Python 3.4
            pprint(msg, stream=self._in, width=sys.maxsize)
        finally:
            self._in.flush()

    def get(self):
        """
        Remove and return an item from the queue. If queue is empty,
        block until an item is available.
        """
        payload = self._out.readline().rstrip("\n")
        return ast.literal_eval(payload)

    def close(self):
        """
        Completes the use of the queue.
        """
        try:
            self._in.close()
            self._out.close()
        except:
            self.pipe = None
        finally:
            return self.pipe

class Persistent(Expert):

    Path = namedtuple("Path", ["root", "home", "slot", "file"])
    Pickled = namedtuple("Pickled", ["name", "path"])

    @staticmethod
    def make_path(path:Path, prefix="tmp", suffix=""):
        if path.slot is None:
            dctry = os.path.join(path.root, path.home)
            try:
                os.mkdir(dctry)
            except FileExistsError:
                pass
            if path.file is not None:
                slot = tempfile.mkdtemp(suffix=suffix, prefix=prefix, dir=dctry)
                return path._replace(slot=os.path.basename(slot))
            else:
                return path
        else:
            return None

    @staticmethod
    def recent_slot(path:Path):
        slots = [i for i in os.listdir(os.path.join(path.root, path.home))
                 if os.path.isdir(os.path.join(path.root, path.home, i))]
        stats = [(os.path.getmtime(os.path.join(path.root, path.home, fP)), fP)
                 for fP in slots]
        stats.sort(key=operator.itemgetter(0), reverse=True)
        return Persistent.Path(
            path.root, path.home, next((i[1] for i in stats), None), None)

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

    def declare(self, data, loop=None):
        super().declare(data, loop)
        pickles = (i for i in self._services.values()
                   if isinstance(i, Persistent.Pickled))
        for p in pickles:
            if data.get(p.name, False):
                print(p.path)

class Game(Persistent):

    Player = namedtuple("Player", ["user", "name"])

    @staticmethod
    def options(
        player,
        slot=None,
        parent=os.path.expanduser(os.path.join("~", ".addisonarches"))
    ):
        return OrderedDict([
            ("businesses.pkl", Persistent.Pickled(
                "businesses",
                Persistent.Path(parent, player.user, slot, "businesses.pkl")
            )),
        ])

    def __init__(self, player, businesses, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.businesses = businesses
        self.interval = 30
        self.stop = False
        self.clock = (
            t for t in (
                datetime.datetime(year=2015, month=5, day=11) +
                datetime.timedelta(seconds=i)
                for i in itertools.islice(
                    itertools.count(0, 30 * 60),
                    7 * 24 * 60 // 30)
                )
            if 8 <= t.hour <= 19)
        self.location = None
        self.drama = None
        self.ts = None

    def load(self):
        pickler = next(
            (i for i in self._services.values()
            if isinstance(i, Persistent.Pickled)
            and i.name == "businesses"),
            None
        )
        if pickler is not None:
            path = Persistent.recent_slot(pickler.path)._replace(file=pickler.file)
            print(path)
            # Find recent slot
            # Make slot path to businesses.pkl
            # If no file, create character and insert into businesses
        self.location = self.home

    @property
    def home(self):
        return list(self.businesses[0].inventories.keys())[0]

    @property
    def destinations(self):
        return [
            nearby for nearby in self.here.inventories
            if nearby != self.location
        ] or [self.home] if self.location != self.home else [
            list(b.inventories.keys())[0] for b in self.businesses[1:]
        ]

    @property
    def here(self):
        return next(
            (b for b in self.businesses
            if self.location in b.inventories),
            None
        )

    @property
    def routines(self):
        return [self.clock_loop]

    @asyncio.coroutine
    def clock_loop(self, commands, executor, loop=None):
        while not self.stop:
            yield from asyncio.sleep(self.interval)
            yield from commands.put("wait")
            sys.stdout.write("\n")
            sys.stdout.flush()

def parser(descr=__doc__):
    rv = argparse.ArgumentParser(description=descr)
    rv.add_argument(
        "--version", action="store_true", default=False,
        help="Print the current version number")
    rv.add_argument(
        "-v", "--verbose", required=False,
        action="store_const", dest="log_level",
        const=logging.DEBUG, default=logging.INFO,
        help="Increase the verbosity of output")
    rv.add_argument(
        "--log", default=None, dest="log_path",
        help="Set a file path for log output")
    rv.add_argument(
        "--output", default=DFLT_LOCN,
        help="path to output directory [{}]".format(DFLT_LOCN))
    return rv

def run(game, args, pipe=None):
    addisonarches.scenario.businesses.insert(
        0, CashBusiness(proprietor, None, locations, tally=Decimal(1000)))
    game = Game(businesses=addisonarches.scenario.businesses)
    console = Console(game)
    loop = asyncio.get_event_loop()
    commands = asyncio.Queue(loop=loop)
    routines = console.routines + game.routines
    executor = concurrent.futures.ThreadPoolExecutor(len(routines))
    tasks = [
        asyncio.Task(routine(commands, executor, loop=loop))
        for routine in routines
    ]
    loop.run_forever()

def run():
    p = parser()
    args = p.parse_args()
    if args.version:
        sys.stdout.write(__version__ + "\n")
        rv = 0
    else:
        try:
            os.mkdir(args.output)
        except OSError:
            pass
        rv = main(args)
    sys.exit(rv)

if __name__ == "__main__":
    run()
<commit_msg>More work on load.<commit_after>#!/usr/bin/env python
#   -*- encoding: UTF-8 -*-

# This file is part of Addison Arches.
#
# Addison Arches 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.
#
# Addison Arches 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 Addison Arches.  If not, see <http://www.gnu.org/licenses/>.

import argparse
import ast
import asyncio
from collections import OrderedDict
from collections import namedtuple
import datetime
import itertools
import logging
import operator
import os
import os.path
import pickle
from pprint import pprint
import sys
import tempfile

from turberfield.utils.expert import Expert

DFLT_LOCN = os.path.expanduser(os.path.join("~", ".addisonarches"))

__doc__ = """
Encapsulates the game world in Addison Arches.
"""

class UnNamedPipe:

    def __init__(self, pipe:tuple, **kwargs):
        self.pipe = pipe
        self._in = os.fdopen(self.pipe[1], 'w', buffering=1, encoding="utf-8")
        self._out = os.fdopen(self.pipe[0], 'r', buffering=1, encoding="utf-8")

    def put_nowait(self, msg):
        """
        Put an item into the queue without blocking.
        """
        try:
            pprint(msg, stream=self._in, compact=True, width=sys.maxsize)
        except TypeError:  # 'compact' is new in Python 3.4
            pprint(msg, stream=self._in, width=sys.maxsize)
        finally:
            self._in.flush()

    def get(self):
        """
        Remove and return an item from the queue. If queue is empty,
        block until an item is available.
        """
        payload = self._out.readline().rstrip("\n")
        return ast.literal_eval(payload)

    def close(self):
        """
        Completes the use of the queue.
        """
        try:
            self._in.close()
            self._out.close()
        except:
            self.pipe = None
        finally:
            return self.pipe

class Persistent(Expert):

    Path = namedtuple("Path", ["root", "home", "slot", "file"])
    Pickled = namedtuple("Pickled", ["name", "path"])

    @staticmethod
    def make_path(path:Path, prefix="tmp", suffix=""):
        if path.slot is None:
            dctry = os.path.join(path.root, path.home)
            try:
                os.mkdir(dctry)
            except FileExistsError:
                pass
            if path.file is not None:
                slot = tempfile.mkdtemp(suffix=suffix, prefix=prefix, dir=dctry)
                return path._replace(slot=os.path.basename(slot))
            else:
                return path
        else:
            return None

    @staticmethod
    def recent_slot(path:Path):
        slots = [i for i in os.listdir(os.path.join(path.root, path.home))
                 if os.path.isdir(os.path.join(path.root, path.home, i))]
        stats = [(os.path.getmtime(os.path.join(path.root, path.home, fP)), fP)
                 for fP in slots]
        stats.sort(key=operator.itemgetter(0), reverse=True)
        return Persistent.Path(
            path.root, path.home, next((i[1] for i in stats), None), None)

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

    def declare(self, data, loop=None):
        super().declare(data, loop)
        pickles = (i for i in self._services.values()
                   if isinstance(i, Persistent.Pickled))
        for p in pickles:
            if data.get(p.name, False):
                print(p.path)

class Game(Persistent):

    Player = namedtuple("Player", ["user", "name"])

    @staticmethod
    def options(
        player,
        slot=None,
        parent=os.path.expanduser(os.path.join("~", ".addisonarches"))
    ):
        return OrderedDict([
            ("businesses.pkl", Persistent.Pickled(
                "businesses",
                Persistent.Path(parent, player.user, slot, "businesses.pkl")
            )),
        ])

    def __init__(self, player, businesses, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.businesses = businesses
        self.interval = 30
        self.stop = False
        self.clock = (
            t for t in (
                datetime.datetime(year=2015, month=5, day=11) +
                datetime.timedelta(seconds=i)
                for i in itertools.islice(
                    itertools.count(0, 30 * 60),
                    7 * 24 * 60 // 30)
                )
            if 8 <= t.hour <= 19)
        self.location = None
        self.drama = None
        self.ts = None

    def load(self):
        pickler = next(
            (i for i in self._services.values()
            if isinstance(i, Persistent.Pickled)
            and i.name == "businesses"),
            None
        )
        if pickler is not None:
            path = Persistent.recent_slot(
                Persistent.make_path(pickler.path)
            )._replace(file=pickler.path.file)
            if not os.path.isfile(os.path.join(*path)):
                #proprietor = Character(uuid.uuid4().hex, name)
                #locations = [Location("Addison Arches 18a", 100)]

                #addisonarches.scenario.businesses.insert(
                #    0, CashBusiness(proprietor, None, locations, tally=Decimal(1000)))
                print(path)
            else:
                # TODO: load businesses from pickle file
                pass
        self.location = self.home

    @property
    def home(self):
        return list(self.businesses[0].inventories.keys())[0]

    @property
    def destinations(self):
        return [
            nearby for nearby in self.here.inventories
            if nearby != self.location
        ] or [self.home] if self.location != self.home else [
            list(b.inventories.keys())[0] for b in self.businesses[1:]
        ]

    @property
    def here(self):
        return next(
            (b for b in self.businesses
            if self.location in b.inventories),
            None
        )

    @property
    def routines(self):
        return [self.clock_loop]

    @asyncio.coroutine
    def clock_loop(self, commands, executor, loop=None):
        while not self.stop:
            yield from asyncio.sleep(self.interval)
            yield from commands.put("wait")
            sys.stdout.write("\n")
            sys.stdout.flush()

def parser(descr=__doc__):
    rv = argparse.ArgumentParser(description=descr)
    rv.add_argument(
        "--version", action="store_true", default=False,
        help="Print the current version number")
    rv.add_argument(
        "-v", "--verbose", required=False,
        action="store_const", dest="log_level",
        const=logging.DEBUG, default=logging.INFO,
        help="Increase the verbosity of output")
    rv.add_argument(
        "--log", default=None, dest="log_path",
        help="Set a file path for log output")
    rv.add_argument(
        "--output", default=DFLT_LOCN,
        help="path to output directory [{}]".format(DFLT_LOCN))
    return rv

def run(game, args, pipe=None):
    addisonarches.scenario.businesses.insert(
        0, CashBusiness(proprietor, None, locations, tally=Decimal(1000)))
    game = Game(businesses=addisonarches.scenario.businesses)
    console = Console(game)
    loop = asyncio.get_event_loop()
    commands = asyncio.Queue(loop=loop)
    routines = console.routines + game.routines
    executor = concurrent.futures.ThreadPoolExecutor(len(routines))
    tasks = [
        asyncio.Task(routine(commands, executor, loop=loop))
        for routine in routines
    ]
    loop.run_forever()

def run():
    p = parser()
    args = p.parse_args()
    if args.version:
        sys.stdout.write(__version__ + "\n")
        rv = 0
    else:
        try:
            os.mkdir(args.output)
        except OSError:
            pass
        rv = main(args)
    sys.exit(rv)

if __name__ == "__main__":
    run()
<|endoftext|>


<commit_before>from blockexplorer.settings import BLOCKCYPHER_API_KEY

from bitcoins.utils import is_valid_btc_address, is_valid_tx_hash, is_valid_block_representation

from dateutil import parser

import requests
import json

COIN_SYMBOL_MAPPINGS = {
        # format like such
        # 'coin_symbol': ('Display Name', 'Blockcypher Code', 'Blockcypher Network', 'Currency Name/Abbrev'),
        'btc': ('Bitcoin', 'btc', 'main', 'BTC'),
        'btc-testnet': ('Bitcoin Testnet', 'btc', 'test3', 'BTC'),
        'ltc': ('Litecoin', 'ltc', 'main', 'LTC'),
        'ltc-testnet': ('Litecoin Testnet', 'ltc', 'test', 'LTC'),
        'uro': ('Uro', 'uro', 'main', 'URO'),
        'bcy': ('BlockCypher Testnet', 'bcy', 'test', 'BCY'),
        }

# WET, but maintains order
COIN_SYMBOL_ORDER_LIST = ('btc', 'btc-testnet', 'ltc', 'ltc-testnet', 'uro', 'bcy')

# Django-Style List
COIN_CHOICES = []
for coin_symbol in COIN_SYMBOL_ORDER_LIST:
    COIN_CHOICES.append((coin_symbol, COIN_SYMBOL_MAPPINGS[coin_symbol][0]))

def get_address_details(address, coin_symbol='btc', max_txns=None):

    # This check appears to work for other blockchains
    # TODO: verify and/or improve
    assert is_valid_btc_address(address)

    url_to_hit = 'https://api.blockcypher.com/v1/%s/%s/addrs/%s' % (
            COIN_SYMBOL_MAPPINGS[coin_symbol][1],
            COIN_SYMBOL_MAPPINGS[coin_symbol][2],
            address)

    # print(url_to_hit)

    params = {}
    if max_txns:
        params['limit'] = max_txns
    if BLOCKCYPHER_API_KEY:
        params['token'] = BLOCKCYPHER_API_KEY

    r = requests.get(url_to_hit, params=params, verify=True)

    return json.loads(r.text)

def get_transactions_details(tx_hash, coin_symbol='btc'):

    assert is_valid_tx_hash(tx_hash)

    url_to_hit = 'https://api.blockcypher.com/v1/%s/%s/txs/%s' % (
            COIN_SYMBOL_MAPPINGS[coin_symbol][1],
            COIN_SYMBOL_MAPPINGS[coin_symbol][2],
            tx_hash)

    # print(url_to_hit)

    params = {}
    if BLOCKCYPHER_API_KEY:
        params['token'] = BLOCKCYPHER_API_KEY

    r = requests.get(url_to_hit, params=params, verify=True)

    response_dict = json.loads(r.text)

    # format this string as a datetime object
    if response_dict['block_height'] > 0:
        response_dict['confirmed'] = parser.parse(response_dict['confirmed'])
    else:
        # Blockcypher reports fake times if it's not in a block
        response_dict['confirmed'] = None
        response_dict['block_height'] = None

    return response_dict

def get_block_details(block_representation, coin_symbol='btc', max_txns=None):
    """
    block_representation may be the block number of block hash
    """

    # assert is_valid_block_representation(block_representation)

    url_to_hit = 'https://api.blockcypher.com/v1/%s/%s/blocks/%s' % (
            COIN_SYMBOL_MAPPINGS[coin_symbol][1],
            COIN_SYMBOL_MAPPINGS[coin_symbol][2],
            block_representation)

    # print(url_to_hit)

    params = {}
    if BLOCKCYPHER_API_KEY:
        params['token'] = BLOCKCYPHER_API_KEY
    if max_txns:
        params['limit'] = max_txns

    r = requests.get(url_to_hit, params=params, verify=True)

    response_dict = json.loads(r.text)

    if response_dict.get('received_time'):
        response_dict['received_time'] = parser.parse(response_dict['received_time'])

    return response_dict
<commit_msg>better time calcs<commit_after>from blockexplorer.settings import BLOCKCYPHER_API_KEY

from bitcoins.utils import is_valid_btc_address, is_valid_tx_hash

from dateutil import parser

import requests
import json

COIN_SYMBOL_MAPPINGS = {
        # format like such
        # 'coin_symbol': ('Display Name', 'Blockcypher Code', 'Blockcypher Network', 'Currency Name/Abbrev'),
        'btc': ('Bitcoin', 'btc', 'main', 'BTC'),
        'btc-testnet': ('Bitcoin Testnet', 'btc', 'test3', 'BTC'),
        'ltc': ('Litecoin', 'ltc', 'main', 'LTC'),
        'ltc-testnet': ('Litecoin Testnet', 'ltc', 'test', 'LTC'),
        'uro': ('Uro', 'uro', 'main', 'URO'),
        'bcy': ('BlockCypher Testnet', 'bcy', 'test', 'BCY'),
        }

# WET, but maintains order
COIN_SYMBOL_ORDER_LIST = ('btc', 'btc-testnet', 'ltc', 'ltc-testnet', 'uro', 'bcy')

# Django-Style List
COIN_CHOICES = []
for coin_symbol in COIN_SYMBOL_ORDER_LIST:
    COIN_CHOICES.append((coin_symbol, COIN_SYMBOL_MAPPINGS[coin_symbol][0]))

def get_address_details(address, coin_symbol='btc', max_txns=None):

    # This check appears to work for other blockchains
    # TODO: verify and/or improve
    assert is_valid_btc_address(address)

    url_to_hit = 'https://api.blockcypher.com/v1/%s/%s/addrs/%s' % (
            COIN_SYMBOL_MAPPINGS[coin_symbol][1],
            COIN_SYMBOL_MAPPINGS[coin_symbol][2],
            address)

    # print(url_to_hit)

    params = {}
    if max_txns:
        params['limit'] = max_txns
    if BLOCKCYPHER_API_KEY:
        params['token'] = BLOCKCYPHER_API_KEY

    r = requests.get(url_to_hit, params=params, verify=True)

    return json.loads(r.text)

def get_transactions_details(tx_hash, coin_symbol='btc'):

    assert is_valid_tx_hash(tx_hash)

    url_to_hit = 'https://api.blockcypher.com/v1/%s/%s/txs/%s' % (
            COIN_SYMBOL_MAPPINGS[coin_symbol][1],
            COIN_SYMBOL_MAPPINGS[coin_symbol][2],
            tx_hash)

    print(url_to_hit)

    params = {}
    if BLOCKCYPHER_API_KEY:
        params['token'] = BLOCKCYPHER_API_KEY

    r = requests.get(url_to_hit, params=params, verify=True)

    response_dict = json.loads(r.text)

    # format this string as a datetime object
    if response_dict['block_height'] > 0:
        response_dict['confirmed'] = parser.parse(response_dict['confirmed'])
        response_dict['received'] = parser.parse(response_dict['received'])
    else:
        # Blockcypher reports fake times if it's not in a block
        response_dict['confirmed'] = None
        response_dict['block_height'] = None

    return response_dict

def get_block_details(block_representation, coin_symbol='btc', max_txns=None):
    """
    block_representation may be the block number of block hash
    """

    # assert is_valid_block_representation(block_representation)

    url_to_hit = 'https://api.blockcypher.com/v1/%s/%s/blocks/%s' % (
            COIN_SYMBOL_MAPPINGS[coin_symbol][1],
            COIN_SYMBOL_MAPPINGS[coin_symbol][2],
            block_representation)

    # print(url_to_hit)

    params = {}
    if BLOCKCYPHER_API_KEY:
        params['token'] = BLOCKCYPHER_API_KEY
    if max_txns:
        params['limit'] = max_txns

    r = requests.get(url_to_hit, params=params, verify=True)

    response_dict = json.loads(r.text)

    if response_dict.get('confirmed'):
        response_dict['confirmed'] = parser.parse(response_dict['confirmed'])

    return response_dict
<|endoftext|>


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

import warnings
warnings.filterwarnings("ignore", category=DeprecationWarning)

from math import sqrt, cos
import numpy as np
from scipy.integrate import quad
from triplesec import triplesec_step
import astropy.constants as const
import astropy.units as u
import json

G = const.G.value
c = const.c.value
yr2s = 3.15576e7
au = const.au.value

def kl_period_oom(a1, a2, e2, m1, m3, m2=0):
  '''The usual KL period formula:

  t_KL = P_out^2 / P_in * (1 - e2^2)^(3/2)

  Parameters:
    a1: Inner semi-major axis in AU
    a2: Outer semi-major axis in AU
    e2: Outer eccentricity
    m1: Mass of the primary of the inner binary in M_Sun
    m3: Mass of the tertiary in M_Sun
    m2: Mass of the secondary of the inner binary in M_Sun

  Returns:
    P: The period of KL oscillations in years.
  '''

  P_out2 = a2**3 / (m1 + m2 + m3)
  P_in = sqrt(a1**3 / (m1 + m2))

  return P_out2 / P_in * (1 - e2**2)**(3./2)

def depsdh(eps, H, Th):
  '''The derivative of epsilon with respect to H.'''

  return (eps**2 / (30 * (1-eps**2) * (eps**2 - Th) * sqrt(1 - (3*eps**4 +
    eps**2 * (H - 9 * Th - 5) + 15*Th)**2 / (225 * (1-eps**2)**2 * (eps**2 -
    Th)**2))))

def kl_period_norm(Hhat, Th):
  zeta = 20 - Hhat + 24 * Th
  epsmax = 1/6. * sqrt(zeta - sqrt(zeta**2 - 2160 * Th))
  epsmin = sqrt(1/12. * (10 + Hhat + 6 * Th))

  return -2 * quad(depsdh, epsmin, epsmax, args=(Hhat, Th))[0]

def kl_tp_period(a1, a2, e1, e2, inc, m1, m3, g):
  '''Return the Kozai period in years.

  Parameters:
    a1:  Inner semi-major axis in AU
    a2:  Outer semi-major axis in AU
    e1:  Inner eccentricity
    e2:  Outer eccentricity
    inc: Mutual inclination in degrees
    m1:  Mass of the inner binary in M_Sun
    m3:  Mass of the tertiary in M_Sun
    g:   Argument of periapsis

  Returns:
    P: The period in yr
  '''

  L1toC2 = (16 * a2 * (1 - e2**2)**(3/2.) / m3 * (a2 / a1)**2 * sqrt(m1 * a1)
    / (2 * np.pi))

  th = cos(np.pi * inc / 180)
  Th = th**2 * (1 - e1**2)
  Hhat = (2 + 3*e1**2) * (1 - 3*th**2) - 15 * e1**2 * (1 - th**2) * cos(2 * g)

  return L1toC2 * kl_period_norm(Hhat, Th)

def numerical_kl_period(m, e, a, g, inc, nperiods=10, cputstop=300,
  tstop_factor=100, in_params=(1, (1e-11, 1e-11), (False, False, False))):
  '''Calculate the period of KL oscillations by explicitly integrating the
  secular equations of motion.

  Input:
    m: A list containing the three masses in solar masses (m0, m1, m2)
    r: A list containing the inner two radii in solar radii (r0, r1)
    e: A list containing the eccentricities (e1, e2)
    a: A list containing the semi-major axes in AU (a1, a2)
    g: A list containing the arguments of periapsis in degrees (g1, g2)
    inc: The mutual inclination in degrees
    nperiods: The number of KL periods to integrate for
    cputstop: The maximum wall time to allow for integration in sec
    tstop_factor: The maximum factor greater than the standard KL timescale
                  to allow for.
    in_params: A tuple containing:
      outfreq: How many steps between printing out the state
               (-1 for no printing)
      acc: A tuple containing the accuracy targets (relacc, absacc)
      terms: A tuple saying what terms to include (gc, oct, hex)

  Output:
    The average period of KL oscillations in yr.
  '''

  e_prev2 = 0.
  e_prev  = 0.

  periods = []
  emin_tstart = 0
  emax_tstart = 0

  # Prepare the inputs for triplesec_step (convert units, etc.)
  p_in  = a[0]**(3./2) / sqrt(m[0] + m[1])
  p_out = a[1]**(3./2) / sqrt(m[0] + m[1] + m[2])
  tstop = (tstop_factor * p_out**2 / p_in * (1 - e[1]**2)**(3/2) * yr2s, cputstop)
  m = [elem * const.M_sun.value for elem in m]
  a = [elem * const.au.value for elem in a]
  g = [elem * np.pi / 180 for elem in g]
  inc *= np.pi / 180
  r = [0, 0]

  for step in triplesec_step(m, r, e, a, g, inc, tstop, in_params):
    if len(periods) == 2 * nperiods:
      break
    e = step[0][3]
    t = step[0][0]
    if e_prev2 < e_prev > e:
      if emax_tstart > 0:
        periods.append(t - emax_tstart)
      emax_tstart = t
    elif e_prev2 > e_prev < e:
      if emin_tstart > 0:
        periods.append(t - emin_tstart)
      emin_tstart = t

    prevstep = step[0]
    e_prev2 = e_prev
    e_prev = e

  return np.mean(periods) * (u.s / u.yr).to(1)

if __name__ == '__main__':
  print kl_period_oom(1, 100, .9, 1, 1)
  print kl_tp_period(1, 100, .05, .9, 85, 1, 1, 0)
  print numerical_kl_period([1, 1e-6, 1], [.05, .9], [1, 100], [0, 0], 85)
<commit_msg>Added several functions to kl_period<commit_after>#! /usr/bin/env python

import warnings
warnings.filterwarnings("ignore", category=DeprecationWarning)

from math import sqrt, cos
import numpy as np
from scipy.integrate import quad
from triplesec import triplesec_step
import astropy.constants as const
import astropy.units as u
import json

G = const.G.value
c = const.c.value
yr2s = 3.15576e7
au = const.au.value

def kl_period_oom(a1, a2, e2, m1, m3, m2=0):
  '''The usual KL period formula:

  t_KL = P_out^2 / P_in * (1 - e2^2)^(3/2)

  Parameters:
    a1: Inner semi-major axis in AU
    a2: Outer semi-major axis in AU
    e2: Outer eccentricity
    m1: Mass of the primary of the inner binary in M_Sun
    m3: Mass of the tertiary in M_Sun
    m2: Mass of the secondary of the inner binary in M_Sun

  Returns:
    P: The period of KL oscillations in years.
  '''

  P_out2 = a2**3 / (m1 + m2 + m3)
  P_in = sqrt(a1**3 / (m1 + m2))

  return P_out2 / P_in * (1 - e2**2)**(3./2)

def is_librating(e1, inc, g1):
  '''Determine whether the triple is librating or rotating.

  Parameters:
    e1:  Inner eccentricity
    inc: Inclination in degrees
    g1:  Inner argument of periapsis in degrees

  Returns:
    True if librating, False if rotating.
  '''

  eps2 = 1 - e1**2
  Th = eps2 * cos(inc * np.pi / 180)**2
  Hhat = ((5 - 3 * eps2) * (eps2 - 3 * Th) - 15 * (1 - eps2) * (eps2 - Th) *
    cos(2*g1*np.pi/180)) / eps2

  print Hhat
  print Th

  if Hhat + 6 * Th - 2 > 0:
    return True
  else:
    return False

def depsdh(eps, H, Th):
  '''The derivative of epsilon with respect to H.'''

  print ((3*eps**4 + eps**2 * (H - 9 * Th - 5) + 15*Th)**2 / (225 *
    (1-eps**2)**2 * (eps**2 - Th)**2))

  return (eps**2 / (30 * (1-eps**2) * (eps**2 - Th) * sqrt(1 - (3*eps**4 +
    eps**2 * (H - 9 * Th - 5) + 15*Th)**2 / (225 * (1-eps**2)**2 * (eps**2 -
    Th)**2))))

def kl_period_norm(Hhat, Th):
  zeta = 20 - Hhat + 24 * Th
  epsmin = 1/6. * sqrt(zeta - sqrt(zeta**2 - 2160 * Th))

  # Check whether the triple is librating or rotating
  if Hhat + 6 * Th - 2 > 0:
    epsmax = 1/6. * sqrt(zeta - sqrt(zeta**2 - 2160 * Th))
  else:
    epsmax = sqrt((Hhat + 6 * Th + 10) / 12.)

  return quad(depsdh, epsmin, epsmax, args=(Hhat, Th))[0]

def kl_tp_period(a1, a2, e1, e2, inc, m1, m3, g):
  '''Return the Kozai period in years.

  Parameters:
    a1:  Inner semi-major axis in AU
    a2:  Outer semi-major axis in AU
    e1:  Inner eccentricity
    e2:  Outer eccentricity
    inc: Mutual inclination in degrees
    m1:  Mass of the inner binary in M_Sun
    m3:  Mass of the tertiary in M_Sun
    g:   Argument of periapsis in degrees

  Returns:
    P: The period in yr
  '''

  L1toC2 = (16 * a2 * (1 - e2**2)**(3/2.) / m3 * (a2 / a1)**2 * sqrt(m1 * a1)
    / (2 * np.pi))

  th = cos(np.pi * inc / 180)
  Th = th**2 * (1 - e1**2)
  Hhat = ((2 + 3*e1**2) * (1 - 3*th**2) - 15 * e1**2 * (1 - th**2) *
    cos(2 * g * np.pi / 180))

  print Hhat
  print Th

  return 2 * L1toC2 * kl_period_norm(Hhat, Th)

def numerical_kl_period(m, e, a, g, inc, nperiods=10, cputstop=300,
  tstop_factor=100, in_params=(1, (1e-11, 1e-11), (False, False, False))):
  '''Calculate the period of KL oscillations by explicitly integrating the
  secular equations of motion.

  Input:
    m: A list containing the three masses in solar masses (m0, m1, m2)
    e: A list containing the eccentricities (e1, e2)
    a: A list containing the semi-major axes in AU (a1, a2)
    g: A list containing the arguments of periapsis in degrees (g1, g2)
    inc: The mutual inclination in degrees
    nperiods: The number of KL periods to integrate for
    cputstop: The maximum wall time to allow for integration in sec
    tstop_factor: The maximum factor greater than the standard KL timescale
                  to allow for.
    in_params: A tuple containing:
      outfreq: How many steps between printing out the state
               (-1 for no printing)
      acc: A tuple containing the accuracy targets (relacc, absacc)
      terms: A tuple saying what terms to include (gc, oct, hex)

  Output:
    The average period of KL oscillations in yr.
  '''

  e_prev2 = 0.
  e_prev  = 0.

  periods = []
  emin_tstart = 0
  emax_tstart = 0

  # Prepare the inputs for triplesec_step (convert units, etc.)
  p_in  = a[0]**(3./2) / sqrt(m[0] + m[1])
  p_out = a[1]**(3./2) / sqrt(m[0] + m[1] + m[2])
  tstop = (tstop_factor * p_out**2 / p_in * (1 - e[1]**2)**(3/2) * yr2s, cputstop)
  m = [elem * const.M_sun.value for elem in m]
  a = [elem * const.au.value for elem in a]
  g = [elem * np.pi / 180 for elem in g]
  inc *= np.pi / 180
  r = [0, 0]

  for step in triplesec_step(m, r, e, a, g, inc, tstop, in_params):
    if len(periods) == 2 * nperiods:
      break
    e = step[0][3]
    t = step[0][0]
    if e_prev2 < e_prev > e:
      if emax_tstart > 0:
        periods.append(t - emax_tstart)
      emax_tstart = t
    elif e_prev2 > e_prev < e:
      if emin_tstart > 0:
        periods.append(t - emin_tstart)
      emin_tstart = t

    prevstep = step[0]
    e_prev2 = e_prev
    e_prev = e

  return np.mean(periods) * (u.s / u.yr).to(1)

if __name__ == '__main__':
  print kl_period_oom(1, 100, .9, 1, 1)
  print kl_tp_period(1, 100, .05, .9, 85, 1, 1, 0)
  print numerical_kl_period([1, 1e-6, 1], [.05, .9], [1, 100], [0, 0], 85)
<|endoftext|>


<commit_before>import importlib
import json
import jwt
import time
import uuid

from collections import namedtuple
from contextlib import closing
from hyper import HTTP20Connection

from .exceptions import (
    InternalException,
    ImproperlyConfigured,
    PayloadTooLarge,
    BadDeviceToken,
    PartialBulkMessage
)

from .utils import validate_private_key, wrap_private_key

ALGORITHM = 'ES256'
SANDBOX_HOST = 'api.development.push.apple.com:443'
PRODUCTION_HOST = 'api.push.apple.com:443'
MAX_NOTIFICATION_SIZE = 4096

APNS_RESPONSE_CODES = {
    'Success': 200,
    'BadRequest': 400,
    'TokenError': 403,
    'MethodNotAllowed': 405,
    'TokenInactive': 410,
    'PayloadTooLarge': 413,
    'TooManyRequests': 429,
    'InternalServerError': 500,
    'ServerUnavailable': 503,
}
APNSResponseStruct = namedtuple('APNSResponseStruct', ' '.join(APNS_RESPONSE_CODES.keys()))
APNSResponse = APNSResponseStruct(**APNS_RESPONSE_CODES)

class APNsClient(object):

    def __init__(self, team_id, auth_key_id,
            auth_key=None, auth_key_filepath=None, bundle_id=None, use_sandbox=False, force_proto=None, wrap_key=False
        ):

        if not (auth_key_filepath or auth_key):
            raise ImproperlyConfigured(
                'You must provide either an auth key or a path to a file containing the auth key'
            )

        if not auth_key:
            try:
                with open(auth_key_filepath, "r") as f:
                    auth_key = f.read()

            except Exception as e:
                raise ImproperlyConfigured("The APNS auth key file at %r is not readable: %s" % (auth_key_filepath, e))

        validate_private_key(auth_key)
        if wrap_key:
            auth_key = wrap_private_key(auth_key) # Some have had issues with keys that aren't wrappd to 64 lines

        self.team_id = team_id
        self.bundle_id = bundle_id
        self.auth_key = auth_key
        self.auth_key_id = auth_key_id
        self.force_proto = force_proto
        self.host = SANDBOX_HOST if use_sandbox else PRODUCTION_HOST

    def send_message(self, registration_id, alert, **kwargs):
        return self._send_message(registration_id, alert, **kwargs)

    def send_bulk_message(self, registration_ids, alert, **kwargs):
        good_registration_ids = []
        bad_registration_ids = []

        with closing(self._create_connection()) as connection:
            for registration_id in registration_ids:
                try:
                    res = self._send_message(registration_id, alert, connection=connection, **kwargs)
                    good_registration_ids.append(registration_id)
                except:
                    bad_registration_ids.append(registration_id)

        if not bad_registration_ids:
            return res

        if not good_registration_ids:
            raise BadDeviceToken("None of the registration ids were accepted"
                                 "Rerun individual ids with ``send_message()``"
                                 "to get more details about why")

        if bad_registration_ids and good_registration_ids:
            raise PartialBulkMessage(
                "Some of the registration ids were accepted. Rerun individual "
                "ids with ``send_message()`` to get more details about why. "
                "The ones that failed: \n:"
                "{bad_string}\n"
                "The ones that were pushed successfully: \n:"
                "{good_string}\n".format(
                    bad_string="\n".join(bad_registration_ids),
                    good_string = "\n".join(good_registration_ids)
                ),
                bad_registration_ids
            )

    def _create_connection(self):
        return HTTP20Connection(self.host, force_proto=self.force_proto)

    def _create_token(self):
        token = jwt.encode(
            {
                'iss': self.team_id,
                'iat': time.time()
            },
            self.auth_key,
            algorithm= ALGORITHM,
            headers={
                'alg': ALGORITHM,
                'kid': self.auth_key_id,
            }
        )
        return token.decode('ascii')

    def _send_message(self, registration_id, alert,
            badge=None, sound=None, category=None, content_available=False,
            mutable_content=False,
            action_loc_key=None, loc_key=None, loc_args=[], extra={},
            identifier=None, expiration=None, priority=10,
            connection=None, auth_token=None, bundle_id=None, topic=None,
            push_type='background'
        ):
        if not (topic or bundle_id or self.bundle_id):
            raise ImproperlyConfigured(
                'You must provide your bundle_id if you do not specify a topic'
            )

        if push_type not in ('alert', 'silent'):
            raise ImproperlyConfigured(
                'You must provide push_type with either a "alert" or "background" type'
            )

        data = {}
        aps_data = {}

        if action_loc_key or loc_key or loc_args:
            alert = {"body": alert} if alert else {}
            if action_loc_key:
                alert["action-loc-key"] = action_loc_key
            if loc_key:
                alert["loc-key"] = loc_key
            if loc_args:
                alert["loc-args"] = loc_args

        if alert is not None:
            aps_data["alert"] = alert

        if badge is not None:
            aps_data["badge"] = badge

        if sound is not None:
            aps_data["sound"] = sound

        if category is not None:
            aps_data["category"] = category

        if content_available:
            aps_data["content-available"] = 1

        if mutable_content:
            aps_data["mutable-content"] = 1

        data["aps"] = aps_data
        data.update(extra)

        # Convert to json, avoiding unnecessary whitespace with separators (keys sorted for tests)
        json_data = json.dumps(data, separators=(",", ":"), sort_keys=True).encode("utf-8")

        if len(json_data) > MAX_NOTIFICATION_SIZE:
            raise PayloadTooLarge("Notification body cannot exceed %i bytes" % (MAX_NOTIFICATION_SIZE))

        # If expiration isn't specified use 1 month from now
        expiration_time = expiration if expiration is not None else int(time.time()) + 2592000

        auth_token = auth_token or self._create_token()

        if not topic:
            topic = bundle_id if bundle_id else self.bundle_id

        request_headers = {
            'apns-expiration': str(expiration_time),
            'apns-priority': str(priority),
            'apns-topic': topic,
            'authorization': 'bearer {0}'.format(auth_token),
            'apns-push-type': push_type
        }

        if not identifier:
            identifier = uuid.uuid4()
        request_headers['apns-id'] = str(identifier)

        if connection:
            response = self._send_push_request(connection, registration_id, json_data, request_headers)
        else:
            with closing(self._create_connection()) as connection:
                response = self._send_push_request(connection, registration_id, json_data, request_headers)

        return response

    def _send_push_request(self, connection, registration_id, json_data, request_headers):
        connection.request(
            'POST',
            '/3/device/{0}'.format(registration_id),
            json_data,
            headers=request_headers
        )
        response = connection.get_response()

        if response.status != APNSResponse.Success:
            body = json.loads(response.read().decode('utf-8'))
            reason = body["reason"] if "reason" in body else None

            if reason:
                exceptions_module = importlib.import_module("gobiko.apns.exceptions")
                ExceptionClass = None
                try:
                    ExceptionClass = getattr(exceptions_module, reason)
                except AttributeError:
                    ExceptionClass = InternalException
                raise ExceptionClass()

        return True

<commit_msg>Check if token is bytes<commit_after>import importlib
import json
import jwt
import time
import uuid

from collections import namedtuple
from contextlib import closing
from hyper import HTTP20Connection

from .exceptions import (
    InternalException,
    ImproperlyConfigured,
    PayloadTooLarge,
    BadDeviceToken,
    PartialBulkMessage
)

from .utils import validate_private_key, wrap_private_key

ALGORITHM = 'ES256'
SANDBOX_HOST = 'api.development.push.apple.com:443'
PRODUCTION_HOST = 'api.push.apple.com:443'
MAX_NOTIFICATION_SIZE = 4096

APNS_RESPONSE_CODES = {
    'Success': 200,
    'BadRequest': 400,
    'TokenError': 403,
    'MethodNotAllowed': 405,
    'TokenInactive': 410,
    'PayloadTooLarge': 413,
    'TooManyRequests': 429,
    'InternalServerError': 500,
    'ServerUnavailable': 503,
}
APNSResponseStruct = namedtuple('APNSResponseStruct', ' '.join(APNS_RESPONSE_CODES.keys()))
APNSResponse = APNSResponseStruct(**APNS_RESPONSE_CODES)

class APNsClient(object):

    def __init__(self, team_id, auth_key_id,
            auth_key=None, auth_key_filepath=None, bundle_id=None, use_sandbox=False, force_proto=None, wrap_key=False
        ):

        if not (auth_key_filepath or auth_key):
            raise ImproperlyConfigured(
                'You must provide either an auth key or a path to a file containing the auth key'
            )

        if not auth_key:
            try:
                with open(auth_key_filepath, "r") as f:
                    auth_key = f.read()

            except Exception as e:
                raise ImproperlyConfigured("The APNS auth key file at %r is not readable: %s" % (auth_key_filepath, e))

        validate_private_key(auth_key)
        if wrap_key:
            auth_key = wrap_private_key(auth_key) # Some have had issues with keys that aren't wrappd to 64 lines

        self.team_id = team_id
        self.bundle_id = bundle_id
        self.auth_key = auth_key
        self.auth_key_id = auth_key_id
        self.force_proto = force_proto
        self.host = SANDBOX_HOST if use_sandbox else PRODUCTION_HOST

    def send_message(self, registration_id, alert, **kwargs):
        return self._send_message(registration_id, alert, **kwargs)

    def send_bulk_message(self, registration_ids, alert, **kwargs):
        good_registration_ids = []
        bad_registration_ids = []

        with closing(self._create_connection()) as connection:
            for registration_id in registration_ids:
                try:
                    res = self._send_message(registration_id, alert, connection=connection, **kwargs)
                    good_registration_ids.append(registration_id)
                except:
                    bad_registration_ids.append(registration_id)

        if not bad_registration_ids:
            return res

        if not good_registration_ids:
            raise BadDeviceToken("None of the registration ids were accepted"
                                 "Rerun individual ids with ``send_message()``"
                                 "to get more details about why")

        if bad_registration_ids and good_registration_ids:
            raise PartialBulkMessage(
                "Some of the registration ids were accepted. Rerun individual "
                "ids with ``send_message()`` to get more details about why. "
                "The ones that failed: \n:"
                "{bad_string}\n"
                "The ones that were pushed successfully: \n:"
                "{good_string}\n".format(
                    bad_string="\n".join(bad_registration_ids),
                    good_string = "\n".join(good_registration_ids)
                ),
                bad_registration_ids
            )

    def _create_connection(self):
        return HTTP20Connection(self.host, force_proto=self.force_proto)

    def _create_token(self):
        token = jwt.encode(
            {
                'iss': self.team_id,
                'iat': time.time()
            },
            self.auth_key,
            algorithm= ALGORITHM,
            headers={
                'alg': ALGORITHM,
                'kid': self.auth_key_id,
            }
        )

        if isinstance(token, bytes):
            token = token.decode('ascii')

        return token

    def _send_message(self, registration_id, alert,
            badge=None, sound=None, category=None, content_available=False,
            mutable_content=False,
            action_loc_key=None, loc_key=None, loc_args=[], extra={},
            identifier=None, expiration=None, priority=10,
            connection=None, auth_token=None, bundle_id=None, topic=None,
            push_type='background'
        ):
        if not (topic or bundle_id or self.bundle_id):
            raise ImproperlyConfigured(
                'You must provide your bundle_id if you do not specify a topic'
            )

        if push_type not in ('alert', 'silent'):
            raise ImproperlyConfigured(
                'You must provide push_type with either a "alert" or "background" type'
            )

        data = {}
        aps_data = {}

        if action_loc_key or loc_key or loc_args:
            alert = {"body": alert} if alert else {}
            if action_loc_key:
                alert["action-loc-key"] = action_loc_key
            if loc_key:
                alert["loc-key"] = loc_key
            if loc_args:
                alert["loc-args"] = loc_args

        if alert is not None:
            aps_data["alert"] = alert

        if badge is not None:
            aps_data["badge"] = badge

        if sound is not None:
            aps_data["sound"] = sound

        if category is not None:
            aps_data["category"] = category

        if content_available:
            aps_data["content-available"] = 1

        if mutable_content:
            aps_data["mutable-content"] = 1

        data["aps"] = aps_data
        data.update(extra)

        # Convert to json, avoiding unnecessary whitespace with separators (keys sorted for tests)
        json_data = json.dumps(data, separators=(",", ":"), sort_keys=True).encode("utf-8")

        if len(json_data) > MAX_NOTIFICATION_SIZE:
            raise PayloadTooLarge("Notification body cannot exceed %i bytes" % (MAX_NOTIFICATION_SIZE))

        # If expiration isn't specified use 1 month from now
        expiration_time = expiration if expiration is not None else int(time.time()) + 2592000

        auth_token = auth_token or self._create_token()

        if not topic:
            topic = bundle_id if bundle_id else self.bundle_id

        request_headers = {
            'apns-expiration': str(expiration_time),
            'apns-priority': str(priority),
            'apns-topic': topic,
            'authorization': 'bearer {0}'.format(auth_token),
            'apns-push-type': push_type
        }

        if not identifier:
            identifier = uuid.uuid4()
        request_headers['apns-id'] = str(identifier)

        if connection:
            response = self._send_push_request(connection, registration_id, json_data, request_headers)
        else:
            with closing(self._create_connection()) as connection:
                response = self._send_push_request(connection, registration_id, json_data, request_headers)

        return response

    def _send_push_request(self, connection, registration_id, json_data, request_headers):
        connection.request(
            'POST',
            '/3/device/{0}'.format(registration_id),
            json_data,
            headers=request_headers
        )
        response = connection.get_response()

        if response.status != APNSResponse.Success:
            body = json.loads(response.read().decode('utf-8'))
            reason = body["reason"] if "reason" in body else None

            if reason:
                exceptions_module = importlib.import_module("gobiko.apns.exceptions")
                ExceptionClass = None
                try:
                    ExceptionClass = getattr(exceptions_module, reason)
                except AttributeError:
                    ExceptionClass = InternalException
                raise ExceptionClass()

        return True

<|endoftext|>


<commit_before>"""
This module provides simple APIs that accept Oscar objects as parameters. It
decomposes these into dictionaries of data that are passed to the fine-grained
APIs of the gateway module.
"""
from oscar.apps.payment import exceptions as oscar_exceptions

from . import gateway, exceptions, models

def authenticate(amount, currency, bankcard, shipping_address, billing_address,
                 description='', order_number=None):
    """
    Perform an AUTHENTICATE request and return the TX ID if successful.
    """
    # Decompose Oscar objects into a dict of data to pass to gateway
    params = {
        'amount': amount,
        'currency': currency,
        'description': description,
        'bankcard_number': bankcard.number,
        'bankcard_cv2': bankcard.ccv,
        'bankcard_name': bankcard.name,
        'bankcard_expiry': bankcard.expiry_month('%m%y'),
    }
    if order_number is not None:
        params['reference'] = order_number
    if shipping_address:
        params.update({
            'delivery_surname': shipping_address.last_name,
            'delivery_first_names': shipping_address.first_name,
            'delivery_address1': shipping_address.line1,
            'delivery_address2': shipping_address.line2,
            'delivery_city': shipping_address.line4,
            'delivery_postcode': shipping_address.postcode,
            'delivery_country': shipping_address.country.code,
            'delivery_state': shipping_address.state,
            'delivery_phone': shipping_address.phone_number,
        })
    if billing_address:
        params.update({
            'billing_surname': billing_address.last_name,
            'billing_first_names': billing_address.first_name,
            'billing_address1': billing_address.line1,
            'billing_address2': billing_address.line2,
            'billing_city': billing_address.line4,
            'billing_postcode': billing_address.postcode,
            'billing_country': billing_address.country.code,
            'billing_state': billing_address.state,
        })

    try:
        response = gateway.authenticate(**params)
    except exceptions.GatewayError as e:
        # Translate Sagepay gateway exceptions into Oscar checkout ones
        raise oscar_exceptions.PaymentError(e.message)

    # Check if the transaction was successful (need to distinguish between
    # customer errors and system errors).
    if not response.is_registered:
        raise oscar_exceptions.PaymentError(
            response.status_detail)

    return response.tx_id

def authorise(tx_id, amount=None, description=None, order_number=None):
    """
    Perform an AUTHORISE request against a previous transaction
    """
    try:
        txn = models.RequestResponse.objects.get(
            tx_id=tx_id)
    except models.RequestResponse.DoesNotExist:
        raise oscar_exceptions.PaymentError(
            "No historic transaction found with ID %s" % tx_id)

    # Marshall data for passing to gateway
    previous_txn = gateway.PreviousTxn(
        vendor_tx_code=txn.vendor_tx_code,
        tx_id=txn.tx_id,
        tx_auth_num=txn.tx_auth_num,
        security_key=txn.security_key)
    if amount is None:
        amount = txn.amount
    if description is None:
        description = "Authorise TX ID %s" % tx_id
    params = {
        'previous_txn': previous_txn,
        'amount': amount,
        'currency': txn.currency,
        'description': description,
    }
    if order_number is not None:
        params['reference'] = order_number
    try:
        response = gateway.authorise(**params)
    except exceptions.GatewayError as e:
        raise oscar_exceptions.PaymentError(e.message)
    if not response.is_ok:
        raise oscar_exceptions.PaymentError(
            response.status_detail)
    return response.tx_id

def refund(tx_id, amount=None, description=None, order_number=None):
    """
    Perform a REFUND request against a previous transaction. The passed tx_id
    should be from the AUTHORISE request that you want to refund against.
    """
    try:
        authorise_txn = models.RequestResponse.objects.get(
            tx_id=tx_id, tx_type=gateway.TXTYPE_AUTHORISE, status='OK'
        )
    except models.RequestResponse.DoesNotExist:
        raise oscar_exceptions.PaymentError((
            "No successful AUTHORISE transaction found with "
            "ID %s") % tx_id)

    previous_txn = gateway.PreviousTxn(
        vendor_tx_code=authorise_txn.vendor_tx_code,
        tx_id=authorise_txn.tx_id,
        tx_auth_num=authorise_txn.tx_auth_num,
        security_key=authorise_txn.security_key)
    if amount is None:
        amount = authorise_txn.amount
    if description is None:
        description = "Refund TX ID %s" % tx_id
    params = {
        'previous_txn': previous_txn,
        'amount': amount,
        'currency': authorise_txn.currency,
        'description': description,
    }
    if order_number is not None:
        params['reference'] = order_number
    try:
        response = gateway.refund(**params)
    except exceptions.GatewayError as e:
        raise oscar_exceptions.PaymentError(e.message)
    if not response.is_ok:
        raise oscar_exceptions.PaymentError(
            response.status_detail)
    return response.tx_id

def void(tx_id, order_number=None):
    """
    Cancel an existing transaction
    """
    try:
        authorise_txn = models.RequestResponse.objects.get(
            tx_id=tx_id, tx_type=gateway.TXTYPE_AUTHORISE, status='OK'
        )
    except models.RequestResponse.DoesNotExist:
        raise oscar_exceptions.PaymentError((
            "No successful AUTHORISE transaction found with "
            "ID %s") % tx_id)

    previous_txn = gateway.PreviousTxn(
        vendor_tx_code=authorise_txn.vendor_tx_code,
        tx_id=authorise_txn.tx_id,
        tx_auth_num=authorise_txn.tx_auth_num,
        security_key=authorise_txn.security_key)
    params = {
        'previous_txn': previous_txn,
    }
    if order_number is not None:
        params['reference'] = order_number
    try:
        response = gateway.void(**params)
    except exceptions.GatewayError as e:
        raise oscar_exceptions.PaymentError(e.message)
    if not response.is_ok:
        raise oscar_exceptions.PaymentError(
            response.status_detail)
    return response.tx_id
<commit_msg>Authenticating requires a description field<commit_after>"""
This module provides simple APIs that accept Oscar objects as parameters. It
decomposes these into dictionaries of data that are passed to the fine-grained
APIs of the gateway module.
"""
from oscar.apps.payment import exceptions as oscar_exceptions

from . import gateway, exceptions, models

def authenticate(amount, currency, bankcard, shipping_address, billing_address,
                 description, order_number=None):
    """
    Perform an AUTHENTICATE request and return the TX ID if successful.
    """
    # Decompose Oscar objects into a dict of data to pass to gateway
    params = {
        'amount': amount,
        'currency': currency,
        'description': description,
        'bankcard_number': bankcard.number,
        'bankcard_cv2': bankcard.ccv,
        'bankcard_name': bankcard.name,
        'bankcard_expiry': bankcard.expiry_month('%m%y'),
    }
    if order_number is not None:
        params['reference'] = order_number
    if shipping_address:
        params.update({
            'delivery_surname': shipping_address.last_name,
            'delivery_first_names': shipping_address.first_name,
            'delivery_address1': shipping_address.line1,
            'delivery_address2': shipping_address.line2,
            'delivery_city': shipping_address.line4,
            'delivery_postcode': shipping_address.postcode,
            'delivery_country': shipping_address.country.code,
            'delivery_state': shipping_address.state,
            'delivery_phone': shipping_address.phone_number,
        })
    if billing_address:
        params.update({
            'billing_surname': billing_address.last_name,
            'billing_first_names': billing_address.first_name,
            'billing_address1': billing_address.line1,
            'billing_address2': billing_address.line2,
            'billing_city': billing_address.line4,
            'billing_postcode': billing_address.postcode,
            'billing_country': billing_address.country.code,
            'billing_state': billing_address.state,
        })

    try:
        response = gateway.authenticate(**params)
    except exceptions.GatewayError as e:
        # Translate Sagepay gateway exceptions into Oscar checkout ones
        raise oscar_exceptions.PaymentError(e.message)

    # Check if the transaction was successful (need to distinguish between
    # customer errors and system errors).
    if not response.is_registered:
        raise oscar_exceptions.PaymentError(
            response.status_detail)

    return response.tx_id

def authorise(tx_id, amount=None, description=None, order_number=None):
    """
    Perform an AUTHORISE request against a previous transaction
    """
    try:
        txn = models.RequestResponse.objects.get(
            tx_id=tx_id)
    except models.RequestResponse.DoesNotExist:
        raise oscar_exceptions.PaymentError(
            "No historic transaction found with ID %s" % tx_id)

    # Marshall data for passing to gateway
    previous_txn = gateway.PreviousTxn(
        vendor_tx_code=txn.vendor_tx_code,
        tx_id=txn.tx_id,
        tx_auth_num=txn.tx_auth_num,
        security_key=txn.security_key)
    if amount is None:
        amount = txn.amount
    if description is None:
        description = "Authorise TX ID %s" % tx_id
    params = {
        'previous_txn': previous_txn,
        'amount': amount,
        'currency': txn.currency,
        'description': description,
    }
    if order_number is not None:
        params['reference'] = order_number
    try:
        response = gateway.authorise(**params)
    except exceptions.GatewayError as e:
        raise oscar_exceptions.PaymentError(e.message)
    if not response.is_ok:
        raise oscar_exceptions.PaymentError(
            response.status_detail)
    return response.tx_id

def refund(tx_id, amount=None, description=None, order_number=None):
    """
    Perform a REFUND request against a previous transaction. The passed tx_id
    should be from the AUTHORISE request that you want to refund against.
    """
    try:
        authorise_txn = models.RequestResponse.objects.get(
            tx_id=tx_id, tx_type=gateway.TXTYPE_AUTHORISE, status='OK'
        )
    except models.RequestResponse.DoesNotExist:
        raise oscar_exceptions.PaymentError((
            "No successful AUTHORISE transaction found with "
            "ID %s") % tx_id)

    previous_txn = gateway.PreviousTxn(
        vendor_tx_code=authorise_txn.vendor_tx_code,
        tx_id=authorise_txn.tx_id,
        tx_auth_num=authorise_txn.tx_auth_num,
        security_key=authorise_txn.security_key)
    if amount is None:
        amount = authorise_txn.amount
    if description is None:
        description = "Refund TX ID %s" % tx_id
    params = {
        'previous_txn': previous_txn,
        'amount': amount,
        'currency': authorise_txn.currency,
        'description': description,
    }
    if order_number is not None:
        params['reference'] = order_number
    try:
        response = gateway.refund(**params)
    except exceptions.GatewayError as e:
        raise oscar_exceptions.PaymentError(e.message)
    if not response.is_ok:
        raise oscar_exceptions.PaymentError(
            response.status_detail)
    return response.tx_id

def void(tx_id, order_number=None):
    """
    Cancel an existing transaction
    """
    try:
        authorise_txn = models.RequestResponse.objects.get(
            tx_id=tx_id, tx_type=gateway.TXTYPE_AUTHORISE, status='OK'
        )
    except models.RequestResponse.DoesNotExist:
        raise oscar_exceptions.PaymentError((
            "No successful AUTHORISE transaction found with "
            "ID %s") % tx_id)

    previous_txn = gateway.PreviousTxn(
        vendor_tx_code=authorise_txn.vendor_tx_code,
        tx_id=authorise_txn.tx_id,
        tx_auth_num=authorise_txn.tx_auth_num,
        security_key=authorise_txn.security_key)
    params = {
        'previous_txn': previous_txn,
    }
    if order_number is not None:
        params['reference'] = order_number
    try:
        response = gateway.void(**params)
    except exceptions.GatewayError as e:
        raise oscar_exceptions.PaymentError(e.message)
    if not response.is_ok:
        raise oscar_exceptions.PaymentError(
            response.status_detail)
    return response.tx_id
<|endoftext|>


<commit_before># python 2
from __future__ import absolute_import, print_function, unicode_literals, with_statement
import _thread

# builtins
from unittest import TestCase, main
import logging
import sys
from io import StringIO, open
from time import sleep
from os import path, remove

# plugins
from blowdrycss.utilities import unittest_file_path, change_settings_for_testing
from blowdrycss import watchdogwrapper
import blowdrycss_settings as settings

change_settings_for_testing()

class TestWatchdogWrapperMain(TestCase):
    def monitor_delete_stop(self, file_path_to_delete):
        """ Monitor console output. Delete file at file_path_to_delete. Stop watchdogwrapper.main()
        Reference: http://stackoverflow.com/questions/7602120/sending-keyboard-interrupt-programmatically

        """
        substrings = [
            '~~~ blowdrycss started ~~~',
            'Auto-Generated CSS',
            'Completed',
            'blowdry.css',
            'blowdry.min.css',
        ]

        saved_stdout = sys.stdout           # Monitor console
        try:
            out = StringIO()
            sys.stdout = out

            sleep(5)                      # Wait for main() to start.
            remove(file_path_to_delete)     # Delete delete.html
            sleep(5)                     # IMPORTANT: Must wait for output otherwise test will fail.

            output = out.getvalue()

            for substring in substrings:
                self.assertTrue(substring in output, msg=substring + '\noutput:\n' + output)
        finally:
            sys.stdout = saved_stdout

        _thread.interrupt_main()            # Stop watchdogwrapper.main().

    def test_main_auto_generate_True(self):
        # Integration test
        logging.basicConfig(level=logging.DEBUG)
        html_text = ''

        directory = unittest_file_path(folder='test_html', filename='')
        self.assertTrue(path.isdir(directory), msg=directory)

        delete_dot_html = unittest_file_path(folder='test_html', filename='delete.html')

        # Create delete.html
        with open(delete_dot_html, 'w') as _file:
            _file.write(html_text)

        self.assertTrue(path.isfile(delete_dot_html))

        settings.auto_generate = True
        _thread.start_new_thread(self.monitor_delete_stop, (delete_dot_html,))
        watchdogwrapper.main()              # Caution: Nothing will run after this line.

    def test_main_auto_generate_False(self):
        # Integration test
        logging.basicConfig(level=logging.DEBUG)
        substrings = [
            '~~~ blowdrycss started ~~~',
            'Auto-Generated CSS',
            'Completed',
            'blowdry.css',
            'blowdry.min.css',
        ]
        html_text = ''

        self.assertTrue(path.isdir(folder='test_html', filename=''))
        delete_dot_html = unittest_file_path(folder='test_html', filename='delete.html')

        # Create delete.html
        with open(delete_dot_html, 'w') as _file:
            _file.write(html_text)

        self.assertTrue(path.isfile(delete_dot_html))

        saved_stdout = sys.stdout
        try:
            out = StringIO()
            sys.stdout = out

            settings.auto_generate = False
            watchdogwrapper.main()

            remove(delete_dot_html)     # Delete delete.html

            sleep(0.25)                 # IMPORTANT: Must wait for output otherwise test will fail.

            output = out.getvalue()

            for substring in substrings:
                self.assertTrue(substring in output, msg=substring + '\noutput:\n' + output)
        finally:
            sys.stdout = saved_stdout

if __name__ == '__main__':
    main()

<commit_msg>Setup test_examplesite directory creation and lengthened the sleep time from 0.1 to 0.25 for Travis compatibility with watchdog.<commit_after># python 2
from __future__ import absolute_import, print_function, unicode_literals, with_statement
import _thread

# builtins
from unittest import TestCase, main
import logging
import sys
from io import StringIO, open
from time import sleep
from os import path, remove

# plugins
from blowdrycss.utilities import unittest_file_path, change_settings_for_testing, make_directory
from blowdrycss import watchdogwrapper
import blowdrycss_settings as settings

change_settings_for_testing()

class TestWatchdogWrapperMain(TestCase):
    def monitor_delete_stop(self, file_path_to_delete):
        """ Monitor console output. Delete file at file_path_to_delete. Stop watchdogwrapper.main()
        Reference: http://stackoverflow.com/questions/7602120/sending-keyboard-interrupt-programmatically

        """
        substrings = [
            '~~~ blowdrycss started ~~~',
            'Auto-Generated CSS',
            'Completed',
            'blowdry.css',
            'blowdry.min.css',
        ]

        saved_stdout = sys.stdout           # Monitor console
        try:
            out = StringIO()
            sys.stdout = out

            sleep(0.25)                      # Wait for main() to start.  0.1
            self.assertTrue(path.isfile(file_path_to_delete))
            remove(file_path_to_delete)     # Delete delete.html
            sleep(0.25)                     # IMPORTANT: Must wait for output otherwise test will fail.  0.25

            output = out.getvalue()

            for substring in substrings:
                self.assertTrue(substring in output, msg=substring + '\noutput:\n' + output)
        finally:
            sys.stdout = saved_stdout

        _thread.interrupt_main()            # Stop watchdogwrapper.main().

    def test_main_auto_generate_True(self):
        # Integration test
        logging.basicConfig(level=logging.DEBUG)
        html_text = ''
        test_examplesite = unittest_file_path(folder='test_examplesite', filename='')
        delete_dot_html = unittest_file_path(folder='test_examplesite', filename='delete.html')

        # Directory must be created for Travis CI case
        if not path.isdir(test_examplesite):
            make_directory(test_examplesite)

        self.assertTrue(path.isdir(test_examplesite))

        # Create file delete.html
        with open(delete_dot_html, 'w') as _file:
            _file.write(html_text)

        self.assertTrue(path.isfile(delete_dot_html))

        settings.auto_generate = True
        _thread.start_new_thread(self.monitor_delete_stop, (delete_dot_html,))
        watchdogwrapper.main()              # Caution: Nothing will run after this line.

    def test_main_auto_generate_False(self):
        # Integration test
        logging.basicConfig(level=logging.DEBUG)
        substrings = [
            '~~~ blowdrycss started ~~~',
            'Auto-Generated CSS',
            'Completed',
            'blowdry.css',
            'blowdry.min.css',
        ]
        html_text = ''
        test_examplesite = unittest_file_path(folder='test_examplesite', filename='')
        delete_dot_html = unittest_file_path(folder='test_examplesite', filename='delete.html')

        # Directory must be created for Travis CI case
        if not path.isdir(test_examplesite):
            make_directory(test_examplesite)

        self.assertTrue(path.isdir(test_examplesite))

        # Create delete.html
        with open(delete_dot_html, 'w') as _file:
            _file.write(html_text)

        self.assertTrue(path.isfile(delete_dot_html))

        saved_stdout = sys.stdout
        try:
            out = StringIO()
            sys.stdout = out

            settings.auto_generate = False
            watchdogwrapper.main()

            remove(delete_dot_html)     # Delete delete.html

            sleep(0.25)                 # IMPORTANT: Must wait for output otherwise test will fail.

            output = out.getvalue()

            for substring in substrings:
                self.assertTrue(substring in output, msg=substring + '\noutput:\n' + output)
        finally:
            sys.stdout = saved_stdout

if __name__ == '__main__':
    main()

<|endoftext|>


<commit_before>import asyncio
import aiocoap
from unittest.mock import MagicMock
from cbor2 import dumps

from foglamp.device_api.coap.sensor_values import SensorValues

def AsyncMock(*args, **kwargs):
    m = MagicMock(*args, **kwargs)

    async def mock_coro(*args, **kwargs):
        return m(*args, **kwargs)

    mock_coro.mock = m
    return mock_coro

class MagicMockConnection(MagicMock):
    execute = AsyncMock()

class AcquireContextManager(MagicMock):
    async def __aenter__(self):
        connection = MagicMockConnection()
        return connection

    async def __aexit__(self, exc_type, exc_val, exc_tb):
        pass

class MagicMockEngine(MagicMock):
    acquire = AcquireContextManager()

class CreateEngineContextManager(MagicMock):
    async def __aenter__(self):
        engine = MagicMockEngine()
        return engine

    async def __aexit__(self, exc_type, exc_val, exc_tb):
        pass

def _run(coro):
    return asyncio.get_event_loop().run_until_complete(coro)

# http://docs.sqlalchemy.org/en/latest/core/dml.html
class TestSensorValues:
    def test_invalid_payload1(self, mocker):
        """Test Bad Input"""
        mocker.patch('aiopg.sa.create_engine', return_value=CreateEngineContextManager())
        sv = SensorValues()
        request = MagicMock()
        dict_payload = {}
        request.payload = dumps(dict_payload)
        return_val = _run(sv.render_post(request))
        assert return_val.code == aiocoap.numbers.codes.Code.BAD_REQUEST

    def test_invalid_payload2(self, mocker):
        """Test Bad Input"""
        mocker.patch('aiopg.sa.create_engine', return_value=CreateEngineContextManager())
        sv = SensorValues()
        request = MagicMock()
        dict_payload = 'hello world'
        request.payload = dumps(dict_payload)
        return_val = _run(sv.render_post(request))
        assert return_val.code == aiocoap.numbers.codes.Code.BAD_REQUEST

    def test_good_payload(self, mocker):
        """Test Good Input"""
        mocker.patch('aiopg.sa.create_engine', return_value=CreateEngineContextManager())
        sv = SensorValues()
        request = MagicMock()
        dict_payload = {'timestamp':'2017-01-01T00:00:00Z', 'asset':'test'}
        request.payload = dumps(dict_payload)
        return_val = _run(sv.render_post(request))
        assert return_val.code == aiocoap.numbers.codes.Code.VALID

<commit_msg>MInor refactoring<commit_after>import asyncio
import aiocoap
from unittest.mock import MagicMock
from cbor2 import dumps

from foglamp.device_api.coap.sensor_values import SensorValues

def AsyncMock(*args, **kwargs):
    m = MagicMock(*args, **kwargs)

    async def mock_coro(*args, **kwargs):
        return m(*args, **kwargs)

    mock_coro.mock = m
    return mock_coro

class MagicMockConnection(MagicMock):
    execute = AsyncMock()

class AcquireContextManager(MagicMock):
    async def __aenter__(self):
        connection = MagicMockConnection()
        return connection

    async def __aexit__(self, exc_type, exc_val, exc_tb):
        pass

class MagicMockEngine(MagicMock):
    acquire = AcquireContextManager()

class CreateEngineContextManager(MagicMock):
    async def __aenter__(self):
        engine = MagicMockEngine()
        return engine

    async def __aexit__(self, exc_type, exc_val, exc_tb):
        pass

def _run(coro):
    return asyncio.get_event_loop().run_until_complete(coro)

# http://docs.sqlalchemy.org/en/latest/core/dml.html
class TestSensorValues:
    @staticmethod
    def __setup(mocker):
        mocker.patch('aiopg.sa.create_engine', return_value=CreateEngineContextManager())

    def test_invalid_payload1(self, mocker):
        """Test Bad Input"""
        self.__setup(mocker)
        sv = SensorValues()
        request = MagicMock()
        dict_payload = {}
        request.payload = dumps(dict_payload)
        return_val = _run(sv.render_post(request))
        assert return_val.code == aiocoap.numbers.codes.Code.BAD_REQUEST

    def test_invalid_payload2(self, mocker):
        """Test Bad Input"""
        self.__setup(mocker)
        sv = SensorValues()
        request = MagicMock()
        dict_payload = 'hello world'
        request.payload = dumps(dict_payload)
        return_val = _run(sv.render_post(request))
        assert return_val.code == aiocoap.numbers.codes.Code.BAD_REQUEST

    def test_good_payload(self, mocker):
        """Test Good Input"""
        self.__setup(mocker)
        sv = SensorValues()
        request = MagicMock()
        dict_payload = {'timestamp':'2017-01-01T00:00:00Z', 'asset':'test'}
        request.payload = dumps(dict_payload)
        return_val = _run(sv.render_post(request))
        assert return_val.code == aiocoap.numbers.codes.Code.VALID

<|endoftext|>