<commit_before>import pytest
from ostruct import OpenStruct

def test_empty_struct():
    o = OpenStruct()

    assert o == {}
    assert isinstance(o, OpenStruct)
    assert isinstance(o.__dict__, dict)

    if o:
        assert False
    else:
        assert True

    if not o:
        assert True
    else:
        assert False

def test_shallow_struct():
    o = OpenStruct()
    o.a = 10

    assert o.a == 10

    if o:
        assert True
    else:
        assert False

    if not o:
        assert False
    else:
        assert True

def test_nested_struct():
    o = OpenStruct()
    o.a.b.c.d = 10

    assert o.a.b.c.d == 10
    assert o.a.b.c == {'d': 10}
    assert o.a.b == {'c': {'d': 10}}
    assert o.a == {'b': {'c': {'d': 10}}}
    assert o == {'a': {'b': {'c': {'d': 10}}}}

def test_constructor_args():
    o = OpenStruct(a=1, b=2, c=4)
    assert o == {'a': 1, 'b': 2, 'c': 4}

    a = OpenStruct(o)
    assert o == a

    b = OpenStruct(o.__dict__)
    assert o == b

    c = OpenStruct(**o.__dict__)
    assert o == c

    with pytest.raises(TypeError):
        OpenStruct(1)

    with pytest.raises(TypeError):
        OpenStruct(1.2)

    with pytest.raises(TypeError):
        OpenStruct(1, 2, 3)

    with pytest.raises(TypeError):
        OpenStruct([a, b])

    with pytest.raises(TypeError):
        OpenStruct('Hello!')

    with pytest.raises(TypeError):
        OpenStruct(lambda x: x**2)

def test_comparisons():
    o1 = OpenStruct()
    o1.a.b.c = 10

    assert (o1 == 10) is False
    assert (o1 is True) is False

    o2 = OpenStruct()
    o2.a.b.c = 10

    assert (o1 == o2) is True
    assert (o1 != o2) is False
    assert (o1 is o2) is False
    assert (o2 is o1) is False

    with pytest.raises(TypeError):
        o1 > o2

    with pytest.raises(TypeError):
        o1 < o2

    with pytest.raises(TypeError):
        o1 >= o2

    with pytest.raises(TypeError):
        o1 <= o2

def test_iteritems():
    o = OpenStruct()

    o.a = 1
    o.b = 2
    o.c = 4
    o.d = 8

    s = 0

    for key, value in o.iteritems():
        s += value

    assert s == 15
<commit_msg>Added test for items()<commit_after>import pytest
from ostruct import OpenStruct

def test_empty_struct():
    o = OpenStruct()

    assert o == {}
    assert isinstance(o, OpenStruct)
    assert isinstance(o.__dict__, dict)

    if o:
        assert False
    else:
        assert True

    if not o:
        assert True
    else:
        assert False

def test_shallow_struct():
    o = OpenStruct()
    o.a = 10

    assert o.a == 10

    if o:
        assert True
    else:
        assert False

    if not o:
        assert False
    else:
        assert True

def test_nested_struct():
    o = OpenStruct()
    o.a.b.c.d = 10

    assert o.a.b.c.d == 10
    assert o.a.b.c == {'d': 10}
    assert o.a.b == {'c': {'d': 10}}
    assert o.a == {'b': {'c': {'d': 10}}}
    assert o == {'a': {'b': {'c': {'d': 10}}}}

def test_constructor_args():
    o = OpenStruct(a=1, b=2, c=4)
    assert o == {'a': 1, 'b': 2, 'c': 4}

    a = OpenStruct(o)
    assert o == a

    b = OpenStruct(o.__dict__)
    assert o == b

    c = OpenStruct(**o.__dict__)
    assert o == c

    with pytest.raises(TypeError):
        OpenStruct(1)

    with pytest.raises(TypeError):
        OpenStruct(1.2)

    with pytest.raises(TypeError):
        OpenStruct(1, 2, 3)

    with pytest.raises(TypeError):
        OpenStruct([a, b])

    with pytest.raises(TypeError):
        OpenStruct('Hello!')

    with pytest.raises(TypeError):
        OpenStruct(lambda x: x**2)

def test_comparisons():
    o1 = OpenStruct()
    o1.a.b.c = 10

    assert (o1 == 10) is False
    assert (o1 is True) is False

    o2 = OpenStruct()
    o2.a.b.c = 10

    assert (o1 == o2) is True
    assert (o1 != o2) is False
    assert (o1 is o2) is False
    assert (o2 is o1) is False

    with pytest.raises(TypeError):
        o1 > o2

    with pytest.raises(TypeError):
        o1 < o2

    with pytest.raises(TypeError):
        o1 >= o2

    with pytest.raises(TypeError):
        o1 <= o2

def test_iteritems():
    o = OpenStruct()

    o.a = 1
    o.b = 2
    o.c = 4
    o.d = 8

    s = 0

    for key, value in o.iteritems():
        s += value

    assert s == 15

def test_items():
    o = OpenStruct()

    o.a = 1
    o.b = 2
    o.c = 4
    o.d = 8

    s = 0

    for key, value in o.items():
        s += value

    assert s == 15
<|endoftext|>


<commit_before>from django.db.models import Sum
from .models import CartItem
import uuid

class ShoppingCart(object):

    def __init__(self, request):
        self.cart_id = request.session.get('cart', str(uuid.uuid4()))
        request.session['cart'] = self.cart_id

    def add(self,  first_name, last_name, email, product):
        basket_item, created = CartItem.objects.get_or_create(cart=self.cart_id,
                                                              first_name=first_name,
                                                              last_name=last_name,
                                                              email=email,
                                                              product=product)
        return created

    def remove(self, cart_item):
        basket_item = CartItem.objects.get(id=cart_item)
        basket_item.delete()

    def clear(self):
        CartItem.objects.filter(cart=self.cart_id).delete()

    def __len__(self):
        return CartItem.objects.filter(cart=self.cart_id).count()

    def total(self):
        total = dict()
        total['product__price__sum'] = 0
        if CartItem.objects.filter(cart=self.cart_id).exists:
            total = CartItem.objects.filter(cart=self.cart_id).aggregate(Sum('product__price'))
        return total['product__price__sum']

    def get_basket(self):
        return CartItem.objects.filter(cart=self.cart_id)
<commit_msg>* Fix variable initialization problem for cart.<commit_after>from django.db.models import Sum
from .models import CartItem
import uuid

class ShoppingCart(object):

    def __init__(self, request):
        self.cart_id = request.session.get('cart', str(uuid.uuid4()))
        request.session['cart'] = self.cart_id

    def add(self,  first_name, last_name, email, product):
        basket_item, created = CartItem.objects.get_or_create(cart=self.cart_id,
                                                              first_name=first_name,
                                                              last_name=last_name,
                                                              email=email,
                                                              product=product)
        return created

    def remove(self, cart_item):
        basket_item = CartItem.objects.get(id=cart_item)
        basket_item.delete()

    def clear(self):
        CartItem.objects.filter(cart=self.cart_id).delete()

    def __len__(self):
        return CartItem.objects.filter(cart=self.cart_id).count()

    def total(self):
        total = dict()
        total['product__price__sum'] = 0.0
        if CartItem.objects.filter(cart=self.cart_id).exists():
            total = CartItem.objects.filter(cart=self.cart_id).aggregate(Sum('product__price'))
        return total['product__price__sum']

    def get_basket(self):
        return CartItem.objects.filter(cart=self.cart_id)
<|endoftext|>


<commit_before>'''
Search Anaconda Cloud for packages
'''
import logging

from binstar_client.utils import get_server_api
from binstar_client.utils.pprint import pprint_packages

log = logging.getLogger('binstar.search')

def search(args):

    aserver_api = get_server_api(args.token, args.site, args.log_level)

    packages = aserver_api.search(args.name, package_type=args.package_type, platform=args.platform)
    pprint_packages(packages, access=False)
    log.info("Found %i packages" % len(packages))
    log.info("\nRun 'anaconda show <USER/PACKAGE>' to get installation details")

def add_parser(subparsers):
    parser = subparsers.add_parser(
        'search',
        help='Search Anaconda Cloud',
        description='Search Anaconda Cloud',
        epilog=__doc__
    )
    parser.add_argument('name', nargs=1, help='Search string')
    parser.add_argument(
        '-t', '--package-type', choices=['conda', 'pypi'],
        help='only search for packages of this type'
    )
    parser.add_argument(
        '-p', '--platform',
        choices=['osx-32', 'osx-64', 'win-32', 'win-64', 'linux-32', 'linux-64',
                 'linux-armv6l', 'linux-armv7l', 'linux-ppc64le', 'noarch'],
        help='only search for packages of this type'
    )
    parser.set_defaults(main=search)
<commit_msg>fixed help message<commit_after>'''
Search Anaconda Cloud for packages
'''
import logging

from binstar_client.utils import get_server_api
from binstar_client.utils.pprint import pprint_packages

log = logging.getLogger('binstar.search')

def search(args):

    aserver_api = get_server_api(args.token, args.site, args.log_level)

    packages = aserver_api.search(args.name, package_type=args.package_type, platform=args.platform)
    pprint_packages(packages, access=False)
    log.info("Found %i packages" % len(packages))
    log.info("\nRun 'anaconda show <USER/PACKAGE>' to get installation details")

def add_parser(subparsers):
    parser = subparsers.add_parser(
        'search',
        help='Search Anaconda Cloud',
        description='Search Anaconda Cloud',
        epilog=__doc__
    )
    parser.add_argument('name', nargs=1, help='Search string')
    parser.add_argument(
        '-t', '--package-type', choices=['conda', 'pypi'],
        help='only search for packages of this type'
    )
    parser.add_argument(
        '-p', '--platform',
        choices=['osx-32', 'osx-64', 'win-32', 'win-64', 'linux-32', 'linux-64',
                 'linux-armv6l', 'linux-armv7l', 'linux-ppc64le', 'noarch'],
        help='only search for packages of the chosen platform'
    )
    parser.set_defaults(main=search)
<|endoftext|>


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

# experiment with a low pass filter to supress noise from crummy laptop audio
# input circuitry

# filter design & coefficients courtesy of the online digital filter tutorial
# tool at http://www-users.cs.york.ac.uk/~fisher/cgi-bin/mkfilter/trad.html

from Axon.Component import component

class LPF(component):
    """Low pass butterworth filter for 8Hz data. One pole, -3dB at 2KHz"""

    def filtering(self, data):
        output = []
        prevsample = self.prevsample
        prevout = self.prevout

#        # pole at 2KHz
#        GAIN = 2
#        PREVSCALER = 0.0

        # pole at 1KHz
        GAIN = 3.4142136
        PREVSCALER = 0.4142136

#        # pole at 500Hz
#        GAIN = 6.0273395
#        PREVSCALER = 0.6681786

        for sample in data:
            sample = sample / GAIN
            out = (sample+prevsample) + PREVSCALER*prevout
            output.append( out )
            prevsample = sample
            prevout = out

        self.prevsample = prevsample
        self.prevout = prevout
        return output

    def main(self):
        self.prevsample = 0
        self.prevout = 0
        while 1:
            while self.dataReady("inbox"):
                rawdata = self.recv("inbox")
                filtered = convertback(self.filtering( convert(rawdata) ))
                self.send(filtered,"outbox")
            self.pause()
            yield 1

def convert(data):
    converted = []
    for i in xrange(0,len(data),2):
        value = ord(data[i]) + (ord(data[i+1]) << 8)
        if value & 0x8000:
            value -= 65536
        converted.append(value)
    return converted

def convertback(data):
    output = []
    for sample in data:
        sample = int(sample)
        output.append( chr(sample & 255)+chr((sample>>8) & 255) )
    return "".join(output)

__kamaelia_components__ = ( LPF, )

if __name__ == "__main__":
    import sys
    from Kamaelia.Chassis.Pipeline import Pipeline
    from Kamaelia.Audio.PyMedia.Input import Input
    from Kamaelia.Audio.PyMedia.Output import Output
    from Kamaelia.Codec.Speex import SpeexEncode,SpeexDecode
    from Kamaelia.Audio.RawAudioMixer import RawAudioMixer

    sys.path.append("../../Tools/Whiteboard/Whiteboard")
    from Entuple import Entuple

    Pipeline( Input(sample_rate=8000, channels=1, format="S16_LE"),
              LPF(),
              SpeexEncode(3),
              SpeexDecode(3),
              Entuple(prefix=["A"],postfix=[]), # added to provide some bufering
              RawAudioMixer(),                  #
              Output(sample_rate=8000, channels=1, format="S16_LE"),
            ).run()
<commit_msg>Change license to Apache 2<commit_after>#!/usr/bin/env python
# -*- coding: utf-8 -*-

# Copyright 2010 British Broadcasting Corporation and Kamaelia Contributors(1)
#
# (1) Kamaelia Contributors are listed in the AUTHORS file and at
#     http://www.kamaelia.org/AUTHORS - please extend this file,
#     not this notice.
#
# 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.

# experiment with a low pass filter to supress noise from crummy laptop audio
# input circuitry

# filter design & coefficients courtesy of the online digital filter tutorial
# tool at http://www-users.cs.york.ac.uk/~fisher/cgi-bin/mkfilter/trad.html

from Axon.Component import component

class LPF(component):
    """Low pass butterworth filter for 8Hz data. One pole, -3dB at 2KHz"""

    def filtering(self, data):
        output = []
        prevsample = self.prevsample
        prevout = self.prevout

#        # pole at 2KHz
#        GAIN = 2
#        PREVSCALER = 0.0

        # pole at 1KHz
        GAIN = 3.4142136
        PREVSCALER = 0.4142136

#        # pole at 500Hz
#        GAIN = 6.0273395
#        PREVSCALER = 0.6681786

        for sample in data:
            sample = sample / GAIN
            out = (sample+prevsample) + PREVSCALER*prevout
            output.append( out )
            prevsample = sample
            prevout = out

        self.prevsample = prevsample
        self.prevout = prevout
        return output

    def main(self):
        self.prevsample = 0
        self.prevout = 0
        while 1:
            while self.dataReady("inbox"):
                rawdata = self.recv("inbox")
                filtered = convertback(self.filtering( convert(rawdata) ))
                self.send(filtered,"outbox")
            self.pause()
            yield 1

def convert(data):
    converted = []
    for i in xrange(0,len(data),2):
        value = ord(data[i]) + (ord(data[i+1]) << 8)
        if value & 0x8000:
            value -= 65536
        converted.append(value)
    return converted

def convertback(data):
    output = []
    for sample in data:
        sample = int(sample)
        output.append( chr(sample & 255)+chr((sample>>8) & 255) )
    return "".join(output)

__kamaelia_components__ = ( LPF, )

if __name__ == "__main__":
    import sys
    from Kamaelia.Chassis.Pipeline import Pipeline
    from Kamaelia.Audio.PyMedia.Input import Input
    from Kamaelia.Audio.PyMedia.Output import Output
    from Kamaelia.Codec.Speex import SpeexEncode,SpeexDecode
    from Kamaelia.Audio.RawAudioMixer import RawAudioMixer

    sys.path.append("../../Tools/Whiteboard/Whiteboard")
    from Entuple import Entuple

    Pipeline( Input(sample_rate=8000, channels=1, format="S16_LE"),
              LPF(),
              SpeexEncode(3),
              SpeexDecode(3),
              Entuple(prefix=["A"],postfix=[]), # added to provide some bufering
              RawAudioMixer(),                  #
              Output(sample_rate=8000, channels=1, format="S16_LE"),
            ).run()
<|endoftext|>


<commit_before>"""clashogram - Clash of Clans war moniting for telegram channels."""
import os
import time
import click
import json
import shelve
import requests
import jdatetime
import locale
import pytz
from dateutil.parser import parse as dateutil_parse

locale.setlocale(locale.LC_ALL, "fa_IR")

POLL_INTERVAL = 1

@click.command()
@click.option('--coc-token', help='CoC API token. Reads COC_API_TOKEN env var.', envvar='COC_API_TOKEN')
@click.option('--clan-tag', help='Tag of clan without hash. Reads COC_CLAN_TAG env var.',envvar='COC_CLAN_TAG')
@click.option('--bot-token', help='Telegram bot token. The bot must be admin on the channel. Reads TELEGRAM_BOT_TOKEN env var.',
              envvar='TELEGRAM_BOT_TOKEN')
@click.option('--channel-name', help='Name of telegram channel for updates. Reads TELEGRAM_CHANNEL env var.',
              envvar='TELEGRAM_CHANNEL')
def main(coc_token, clan_tag, bot_token, channel_name):
    """Publish war updates to a telegram channel."""
    monitor_currentwar(coc_token, clan_tag, bot_token, channel_name)

def monitor_currentwar(coc_token, clan_tag, bot_token, channel_name):
    """Send war news to telegram channel."""
    with shelve.open('warlog.db', writeback=True) as db:
        telegram_updater = TelegramUpdater(db, bot_token, channel_name)
        while True:
            wardata = get_currentwar(coc_token, clan_tag)
            print(wardata['state'])
            telegram_updater.update(wardata)
            save_wardata(wardata)
            time.sleep(POLL_INTERVAL)

def get_currentwar(coc_token, clan_tag):
    endpoint = get_currentwar_endpoint(clan_tag)
    res = requests.get(endpoint, headers={'Authorization': 'Bearer %s' % coc_token})
    if res.status_code == requests.codes.ok:
        return json.loads(res.content)
    else:
        raise Exception('Error calling CoC API: %s' % res)

def get_currentwar_endpoint(clan_tag):
    return 'https://api.clashofclans.com/v1/clans/{clan_tag}/currentwar'.format(
            clan_tag=requests.utils.quote('#%s' % clan_tag))

def save_wardata(wardata):
    if wardata['state'] != 'notInWar':
        war_id = "{0}{1}".format(wardata['clan']['tag'][1:],
                                 wardata['preparationStartTime'])
        if not os.path.exists('warlog'):
            os.mkdir('warlog')
        path = os.path.join('warlog', war_id)
        json.dump(wardata, open(path, 'w'), ensure_ascii=False)

class TelegramUpdater(object):
    def __init__(self, db, bot_token, channel_name):
        self.db = db
        self.bot_token = bot_token
        self.channel_name = channel_name
        self.latest_wardata = None
        self.clan_members = {}
        self.opponent_members = {}
        self.players = {}

    def update(self, wardata):
        if wardata['state'] == 'notInWar':
            print('Not in war. Waiting.')
            return

        self.populate_warinfo(wardata)
        if self.is_in_preparation():
            self.send_preparation_msg()
        elif self.is_in_war():
            self.send_war_msg()
            self.send_attack_msgs()
        elif self.is_war_over():
            self.send_war_over_msg()
        else:
            print("Current war status is uknown. We stay quiet.")

    def populate_warinfo(self, wardata):
        self.latest_wardata = wardata
        if self.get_war_id() not in self.db:
            self.db[self.get_war_id()] = {}
        if self.is_new_war(wardata):
            for member in wardata['clan']['members']:
                self.clan_members[member['tag']] = member
                self.players[member['tag']] = member
            for opponent in wardata['opponent']['members']:
                self.opponent_members[opponent['tag']] = opponent
                self.players[opponent['tag']] = opponent

    def is_new_war(self, wardata):
        return self.create_war_id(wardata) in self.db

    def get_war_id(self):
        return self.create_war_id(self.latest_wardata)

    def create_war_id(self, wardata):
        return "{0}{1}".format(wardata['clan']['tag'],
                               wardata['preparationStartTime'])

    def is_in_preparation(self):
        return self.latest_wardata['state'] == 'preparation'

    def send_preparation_msg(self):
        if not self.is_preparation_msg_sent():
            msg = self.create_preparation_msg()
            self.send(msg)
            self.db[self.get_war_id()]['preparation_msg_sent'] = True

    def is_preparation_msg_sent(self):
        return self.db[self.get_war_id()].get('preparation_msg_sent', False)

    def create_preparation_msg(self):
        msg_template = """{top_imoji} {title}
کلن {ourclan} در برابر کلن {opponentclan}
تگ {ourtag} در برابر {opponenttag}
جنگ قبیله {start} شروع خواهد شد.
شاد باشید! {final_emoji}
"""
        msg = msg_template.format(top_imoji='\U0001F3C1',
                                  title='جنگ  در راه است!',
                                  ourclan=self.latest_wardata['clan']['name'],
                                  opponentclan=self.latest_wardata['opponent']['name'],
                                  ourtag=self.latest_wardata['clan']['tag'],
                                  opponenttag=self.latest_wardata['opponent']['tag'],
                                  start=self.format_time(self.latest_wardata['endTime']),
                                  final_emoji='\U0001F6E1')
        return msg

    def format_time(self, timestamp):
        utc_time = dateutil_parse(timestamp, fuzzy=True)
        tehran_time = utc_time.replace(tzinfo=pytz.timezone("Asia/Tehran"))
        fmt = jdatetime.datetime.fromgregorian(datetime=tehran_time).strftime("%a, %d %b %Y %H:%M:%S")
        return convert_to_persian_numbers(fmt)

    def is_in_war(self):
        return self.latest_wardata['state'] == 'inWar'

    def send_war_msg(self):
        if not self.is_war_msg_sent():
            msg = self.create_war_msg()
            self.send(msg)
            self.db[self.get_war_id()]['war_msg_sent'] = True

    def is_war_msg_sent(self):
        return self.db[self.get_war_id()].get('war_msg_sent', False)

    def create_war_msg(self):
        return 'war start message'

    def send_attack_msgs(self):
        for member in self.clan_members.values():
            if 'attacks' in member:
                self.send_clan_attack_msg(member)
        for opponent in self.opponent_members.values():
            if 'attacks' in opponent:
                self.send_opponent_attack_msg(opponent)

    def send_clan_attack_msg(self, attacker):
        for attack in attacker['attacks']:
            if not self.is_attack_msg_sent(attack):
                msg = self.create_clan_attack_msg(attacker, attack)
                self.send(msg)
                self.db[self.get_war_id()][self.get_attack_id(attack)] = True

    def is_attack_msg_sent(self, attack):
        attack_id = self.get_attack_id(attack)
        return self.db[self.get_war_id()].get(attack_id, False)

    def create_clan_attack_msg(self, member, attack):
        msg_template = """{top_imoji} {title}
کلن {ourclan}\tدر برابر\tکلن {opponentclan}
تگ {ourtag}\tدر برابر\t{opponenttag}
مهاجم:\t{attacker_name}\tتاون {attacker_thlevel} رده {attacker_map_position}
در مصاف
مدافع:\t{defender_name}\tتاون ${defender_thlevel} رده {defender_map_position}
ستاره‌های قبلی:\t{previous_stars}\tستاره‌های جدید:\t{new_stars}
درصد تخریب: {destruction_percentage}%

شاد باشید!\t {final_emoji}
"""
        defender = self.get_player_info(attack['defenderTag'])
        msg = msg_template.format(top_imoji='\U0001F535',
                                  title='گزارش حمله! \U0001F692',
                                  ourclan=self.latest_wardata['clan']['name'],
                                  opponentclan=self.latest_wardata['opponent']['name'],
                                  ourtag=self.latest_wardata['clan']['tag'],
                                  opponenttag=self.latest_wardata['opponent']['tag'],
                                  attacker_name=member['name'],
                                  attacker_thlevel=member['townhallLevel'],
                                  attacker_map_position=member['mapPosition'],
                                  defender_name=defender['name'],
                                  defender_thlevel=defender['townhallLevel'],
                                  defender_map_position=defender['mapPosition'],
                                  previous_stars='?',
                                  new_stars=attack['stars'],
                                  destruction_percentage=attack['destructionPercentage'],
                                  final_emoji='\U0001F6E1')
        return msg

    def get_player_info(self, tag):
        if tag not in self.players:
            raise Exception('Player %s not found.' % tag)
        return self.players[tag]

    def get_attack_id(self, attack):
        return "attack{}{}".format(attack['attackerTag'][1:],

                                   attack['defenderTag'][1:])

    def send_opponent_attack_msg(self, attacker):
        for attack in attacker['attacks']:
            if not self.is_attack_msg_sent(attack):
                msg = self.create_opponent_attack_msg(attacker, attack)
                self.send(msg)
                self.db[self.get_war_id()][self.get_attack_id(attack)] = True

    def create_opponent_attack_msg(self, member, attack):
        msg_template = """{top_imoji} {title}
کلن {ourclan}\tدر برابر\tکلن {opponentclan}
تگ {ourtag}\tدر برابر\t{opponenttag}
مهاجم:\t{attacker_name}\tتاون {attacker_thlevel} رده {attacker_map_position}
در مصاف
مدافع:\t{defender_name}\tتاون ${defender_thlevel} رده {defender_map_position}
ستاره‌های قبلی:\t{previous_stars}\tستاره‌های جدید:\t{new_stars}
درصد تخریب: {destruction_percentage}%

شاد باشید!\t {final_emoji}
"""
        defender = self.get_player_info(attack['defenderTag'])
        msg = msg_template.format(top_imoji='\U0001F534',
                                  title='کلن زیر آتش! \U0001F691',
                                  ourclan=self.latest_wardata['clan']['name'],
                                  opponentclan=self.latest_wardata['opponent']['name'],
                                  ourtag=self.latest_wardata['clan']['tag'],
                                  opponenttag=self.latest_wardata['opponent']['tag'],
                                  attacker_name=member['name'],
                                  attacker_thlevel=member['townhallLevel'],
                                  attacker_map_position=member['mapPosition'],
                                  defender_name=defender['name'],
                                  defender_thlevel=defender['townhallLevel'],
                                  defender_map_position=defender['mapPosition'],
                                  previous_stars='?',
                                  new_stars=attack['stars'],
                                  destruction_percentage=attack['destructionPercentage'],
                                  final_emoji='\U0001F6E1')
        return msg

    def is_war_over(self):
        return self.latest_wardata['state'] == 'warEnded'

    def send_war_over_msg(self):
        if not self.is_war_over_msg_sent():
            msg = self.create_war_over_msg()
            self.send(msg)
            self.db[self.get_war_id()]['war_over_msg_sent'] = True

    def is_war_over_msg_sent(self):
        return self.db[self.get_war_id()].get('war_over_msg_sent', False)

    def create_war_over_msg(self):
        return 'war over message'

    def send(self, msg):
        print(msg)
        endpoint = "https://api.telegram.org/bot{bot_token}/sendMessage?parse_mode={mode}&chat_id=@{channel_name}&text={text}".format(bot_token=self.bot_token, mode='Markdown', channel_name=self.channel_name, text=requests.utils.quote(msg))
        print(endpoint)
        requests.post(endpoint)

def convert_to_persian_numbers(text):
    # Supper intelligent and super efficient :)
    return text.replace('0', '۰').replace('1', '۱').replace('2', '۲').replace('3', '۳').replace('4', '۴').replace('5', '۵').replace('6', '۶').replace('7', '۷').replace('8', '۸').replace('9', '۹')

if __name__ == '__main__':
    try:
        main()
    except Exception as error:
        print(error)
        raise(error)

<commit_msg>Update header and imports.<commit_after>#!/usr/bin/env python
"""clashogram - Clash of Clans war moniting for telegram channels."""
import os
import time
import json
import shelve
import locale

import jdatetime
import requests
import click
import pytz
from dateutil.parser import parse as dateutil_parse

locale.setlocale(locale.LC_ALL, "fa_IR")

POLL_INTERVAL = 1

@click.command()
@click.option('--coc-token', help='CoC API token. Reads COC_API_TOKEN env var.', envvar='COC_API_TOKEN', prompt=True)
@click.option('--clan-tag', help='Tag of clan without hash. Reads COC_CLAN_TAG env var.',envvar='COC_CLAN_TAG', prompt=True)
@click.option('--bot-token', help='Telegram bot token. The bot must be admin on the channel. Reads TELEGRAM_BOT_TOKEN env var.',
              envvar='TELEGRAM_BOT_TOKEN', prompt=True)
@click.option('--channel-name', help='Name of telegram channel for updates. Reads TELEGRAM_CHANNEL env var.',
              envvar='TELEGRAM_CHANNEL', prompt=True)
def main(coc_token, clan_tag, bot_token, channel_name):
    """Publish war updates to a telegram channel."""
    monitor_currentwar(coc_token, clan_tag, bot_token, channel_name)

def monitor_currentwar(coc_token, clan_tag, bot_token, channel_name):
    """Send war news to telegram channel."""
    with shelve.open('warlog.db', writeback=True) as db:
        telegram_updater = TelegramUpdater(db, bot_token, channel_name)
        while True:
            wardata = get_currentwar(coc_token, clan_tag)
            print(wardata['state'])
            telegram_updater.update(wardata)
            save_wardata(wardata)
            time.sleep(POLL_INTERVAL)

def get_currentwar(coc_token, clan_tag):
    endpoint = get_currentwar_endpoint(clan_tag)
    res = requests.get(endpoint, headers={'Authorization': 'Bearer %s' % coc_token})
    if res.status_code == requests.codes.ok:
        return json.loads(res.content)
    else:
        raise Exception('Error calling CoC API: %s' % res)

def get_currentwar_endpoint(clan_tag):
    return 'https://api.clashofclans.com/v1/clans/{clan_tag}/currentwar'.format(
            clan_tag=requests.utils.quote('#%s' % clan_tag))

def save_wardata(wardata):
    if wardata['state'] != 'notInWar':
        war_id = "{0}{1}".format(wardata['clan']['tag'][1:],
                                 wardata['preparationStartTime'])
        if not os.path.exists('warlog'):
            os.mkdir('warlog')
        path = os.path.join('warlog', war_id)
        json.dump(wardata, open(path, 'w'), ensure_ascii=False)

class TelegramUpdater(object):
    def __init__(self, db, bot_token, channel_name):
        self.db = db
        self.bot_token = bot_token
        self.channel_name = channel_name
        self.latest_wardata = None
        self.clan_members = {}
        self.opponent_members = {}
        self.players = {}

    def update(self, wardata):
        if wardata['state'] == 'notInWar':
            print('Not in war. Waiting.')
            return

        self.populate_warinfo(wardata)
        if self.is_in_preparation():
            self.send_preparation_msg()
        elif self.is_in_war():
            self.send_war_msg()
            self.send_attack_msgs()
        elif self.is_war_over():
            self.send_war_over_msg()
        else:
            print("Current war status is uknown. We stay quiet.")

    def populate_warinfo(self, wardata):
        self.latest_wardata = wardata
        if self.get_war_id() not in self.db:
            self.db[self.get_war_id()] = {}
        if self.is_new_war(wardata):
            for member in wardata['clan']['members']:
                self.clan_members[member['tag']] = member
                self.players[member['tag']] = member
            for opponent in wardata['opponent']['members']:
                self.opponent_members[opponent['tag']] = opponent
                self.players[opponent['tag']] = opponent

    def is_new_war(self, wardata):
        return self.create_war_id(wardata) in self.db

    def get_war_id(self):
        return self.create_war_id(self.latest_wardata)

    def create_war_id(self, wardata):
        return "{0}{1}".format(wardata['clan']['tag'],
                               wardata['preparationStartTime'])

    def is_in_preparation(self):
        return self.latest_wardata['state'] == 'preparation'

    def send_preparation_msg(self):
        if not self.is_preparation_msg_sent():
            msg = self.create_preparation_msg()
            self.send(msg)
            self.db[self.get_war_id()]['preparation_msg_sent'] = True

    def is_preparation_msg_sent(self):
        return self.db[self.get_war_id()].get('preparation_msg_sent', False)

    def create_preparation_msg(self):
        msg_template = """{top_imoji} {title}
کلن {ourclan} در برابر کلن {opponentclan}
تگ {ourtag} در برابر {opponenttag}
جنگ قبیله {start} شروع خواهد شد.
شاد باشید! {final_emoji}
"""
        msg = msg_template.format(top_imoji='\U0001F3C1',
                                  title='جنگ  در راه است!',
                                  ourclan=self.latest_wardata['clan']['name'],
                                  opponentclan=self.latest_wardata['opponent']['name'],
                                  ourtag=self.latest_wardata['clan']['tag'],
                                  opponenttag=self.latest_wardata['opponent']['tag'],
                                  start=self.format_time(self.latest_wardata['endTime']),
                                  final_emoji='\U0001F6E1')
        return msg

    def format_time(self, timestamp):
        utc_time = dateutil_parse(timestamp, fuzzy=True)
        tehran_time = utc_time.replace(tzinfo=pytz.timezone("Asia/Tehran"))
        fmt = jdatetime.datetime.fromgregorian(datetime=tehran_time).strftime("%a, %d %b %Y %H:%M:%S")
        return convert_to_persian_numbers(fmt)

    def is_in_war(self):
        return self.latest_wardata['state'] == 'inWar'

    def send_war_msg(self):
        if not self.is_war_msg_sent():
            msg = self.create_war_msg()
            self.send(msg)
            self.db[self.get_war_id()]['war_msg_sent'] = True

    def is_war_msg_sent(self):
        return self.db[self.get_war_id()].get('war_msg_sent', False)

    def create_war_msg(self):
        return 'war start message'

    def send_attack_msgs(self):
        for member in self.clan_members.values():
            if 'attacks' in member:
                self.send_clan_attack_msg(member)
        for opponent in self.opponent_members.values():
            if 'attacks' in opponent:
                self.send_opponent_attack_msg(opponent)

    def send_clan_attack_msg(self, attacker):
        for attack in attacker['attacks']:
            if not self.is_attack_msg_sent(attack):
                msg = self.create_clan_attack_msg(attacker, attack)
                self.send(msg)
                self.db[self.get_war_id()][self.get_attack_id(attack)] = True

    def is_attack_msg_sent(self, attack):
        attack_id = self.get_attack_id(attack)
        return self.db[self.get_war_id()].get(attack_id, False)

    def create_clan_attack_msg(self, member, attack):
        msg_template = """{top_imoji} {title}
کلن {ourclan} در برابر کلن {opponentclan}
تگ {ourtag} در برابر {opponenttag}
مهاجم:{attacker_name}تاون {attacker_thlevel} رده {attacker_map_position}
در مصاف
مدافع:{defender_name}تاون {defender_thlevel} رده {defender_map_position}
ستاره‌های قبلی:{previous_stars}ستاره‌های جدید:{new_stars}
درصد تخریب: {destruction_percentage}%

شاد باشید! {final_emoji}
"""
        defender = self.get_player_info(attack['defenderTag'])
        msg = msg_template.format(top_imoji='\U0001F535',
                                  title='گزارش حمله! \U0001F692',
                                  ourclan=self.latest_wardata['clan']['name'],
                                  opponentclan=self.latest_wardata['opponent']['name'],
                                  ourtag=self.latest_wardata['clan']['tag'],
                                  opponenttag=self.latest_wardata['opponent']['tag'],
                                  attacker_name=member['name'],
                                  attacker_thlevel=member['townhallLevel'],
                                  attacker_map_position=member['mapPosition'],
                                  defender_name=defender['name'],
                                  defender_thlevel=defender['townhallLevel'],
                                  defender_map_position=defender['mapPosition'],
                                  previous_stars='?',
                                  new_stars=attack['stars'],
                                  destruction_percentage=attack['destructionPercentage'],
                                  final_emoji='\U0001F6E1')
        return msg

    def get_player_info(self, tag):
        if tag not in self.players:
            raise Exception('Player %s not found.' % tag)
        return self.players[tag]

    def get_attack_id(self, attack):
        return "attack{}{}".format(attack['attackerTag'][1:],

                                   attack['defenderTag'][1:])

    def send_opponent_attack_msg(self, attacker):
        for attack in attacker['attacks']:
            if not self.is_attack_msg_sent(attack):
                msg = self.create_opponent_attack_msg(attacker, attack)
                self.send(msg)
                self.db[self.get_war_id()][self.get_attack_id(attack)] = True

    def create_opponent_attack_msg(self, member, attack):
        msg_template = """{top_imoji} {title}
کلن {ourclan} در برابر کلن {opponentclan}
تگ {ourtag} در برابر {opponenttag}
مهاجم:{attacker_name}تاون {attacker_thlevel} رده {attacker_map_position}
در مصاف
مدافع:{defender_name}تاون {defender_thlevel} رده {defender_map_position}
ستاره‌های قبلی:{previous_stars}ستاره‌های جدید:{new_stars}
درصد تخریب: {destruction_percentage}%

شاد باشید! {final_emoji}
"""
        defender = self.get_player_info(attack['defenderTag'])
        msg = msg_template.format(top_imoji='\U0001F534',
                                  title='کلن زیر آتش! \U0001F691',
                                  ourclan=self.latest_wardata['clan']['name'],
                                  opponentclan=self.latest_wardata['opponent']['name'],
                                  ourtag=self.latest_wardata['clan']['tag'],
                                  opponenttag=self.latest_wardata['opponent']['tag'],
                                  attacker_name=member['name'],
                                  attacker_thlevel=member['townhallLevel'],
                                  attacker_map_position=member['mapPosition'],
                                  defender_name=defender['name'],
                                  defender_thlevel=defender['townhallLevel'],
                                  defender_map_position=defender['mapPosition'],
                                  previous_stars='?',
                                  new_stars=attack['stars'],
                                  destruction_percentage=attack['destructionPercentage'],
                                  final_emoji='\U0001F6E1')
        return msg

    def is_war_over(self):
        return self.latest_wardata['state'] == 'warEnded'

    def send_war_over_msg(self):
        if not self.is_war_over_msg_sent():
            msg = self.create_war_over_msg()
            self.send(msg)
            self.db[self.get_war_id()]['war_over_msg_sent'] = True

    def is_war_over_msg_sent(self):
        return self.db[self.get_war_id()].get('war_over_msg_sent', False)

    def create_war_over_msg(self):
        return 'war over message'

    def send(self, msg):
        print(msg)
        endpoint = "https://api.telegram.org/bot{bot_token}/sendMessage?parse_mode={mode}&chat_id=@{channel_name}&text={text}".format(bot_token=self.bot_token, mode='Markdown', channel_name=self.channel_name, text=requests.utils.quote(msg))
        requests.post(endpoint)

def convert_to_persian_numbers(text):
    # Supper intelligent and super efficient :)
    return text.replace('0', '۰').replace('1', '۱').replace('2', '۲').replace('3', '۳').replace('4', '۴').replace('5', '۵').replace('6', '۶').replace('7', '۷').replace('8', '۸').replace('9', '۹')

if __name__ == '__main__':
    main()

<|endoftext|>


<commit_before>"""add campaign country code

Revision ID: 76b8da7e112d
Revises: 3c34cfd19bf8
Create Date: 2016-09-20 15:04:05.740203

"""

# revision identifiers, used by Alembic.
revision = '76b8da7e112d'
down_revision = '3c34cfd19bf8'
branch_labels = None
depends_on = None

from alembic import op
import sqlalchemy as sa

def upgrade():
    ### commands auto generated by Alembic - please adjust! ###
    with op.batch_alter_table('campaign_campaign', schema=None) as batch_op:
        batch_op.add_column(sa.Column('country_code', sa.String(length=100), nullable=True, server_default='us'))
        batch_op.create_index(batch_op.f('ix_campaign_campaign_country_code'), ['country_code'])

    with op.batch_alter_table('campaign_recording', schema=None) as batch_op:
        batch_op.drop_constraint(u'fk_campaign_recording_campaign_id_campaign_campaign', type_='foreignkey')
        batch_op.drop_column('selected')
        batch_op.drop_column('campaign_id')

    ### end Alembic commands ###

def downgrade():
    ### commands auto generated by Alembic - please adjust! ###
    with op.batch_alter_table('campaign_recording', schema=None) as batch_op:
        batch_op.add_column(sa.Column('campaign_id', sa.INTEGER(), nullable=True))
        batch_op.add_column(sa.Column('selected', sa.BOOLEAN(), nullable=True))
        batch_op.create_foreign_key(u'fk_campaign_recording_campaign_id_campaign_campaign', 'campaign_campaign', ['campaign_id'], ['id'])

    with op.batch_alter_table('campaign_campaign', schema=None) as batch_op:
        batch_op.drop_index(batch_op.f('ix_campaign_campaign_country_code'))
        batch_op.drop_column('country_code')

    ### end Alembic commands ###
<commit_msg>Straighten alembic upgrade revisions<commit_after>"""add campaign country code

Revision ID: 76b8da7e112d
Revises: 38f01b0893b8
Create Date: 2016-09-20 15:04:05.740203

"""

# revision identifiers, used by Alembic.
revision = '76b8da7e112d'
down_revision = '38f01b0893b8'
branch_labels = None
depends_on = None

from alembic import op
import sqlalchemy as sa

def upgrade():
    ### commands auto generated by Alembic - please adjust! ###
    with op.batch_alter_table('campaign_campaign', schema=None) as batch_op:
        batch_op.add_column(sa.Column('country_code', sa.String(length=100), nullable=True, server_default='us'))
        batch_op.create_index(batch_op.f('ix_campaign_campaign_country_code'), ['country_code'])

    with op.batch_alter_table('campaign_recording', schema=None) as batch_op:
        batch_op.drop_constraint(u'fk_campaign_recording_campaign_id_campaign_campaign', type_='foreignkey')
        batch_op.drop_column('selected')
        batch_op.drop_column('campaign_id')

    ### end Alembic commands ###

def downgrade():
    ### commands auto generated by Alembic - please adjust! ###
    with op.batch_alter_table('campaign_recording', schema=None) as batch_op:
        batch_op.add_column(sa.Column('campaign_id', sa.INTEGER(), nullable=True))
        batch_op.add_column(sa.Column('selected', sa.BOOLEAN(), nullable=True))
        batch_op.create_foreign_key(u'fk_campaign_recording_campaign_id_campaign_campaign', 'campaign_campaign', ['campaign_id'], ['id'])

    with op.batch_alter_table('campaign_campaign', schema=None) as batch_op:
        batch_op.drop_index(batch_op.f('ix_campaign_campaign_country_code'))
        batch_op.drop_column('country_code')

    ### end Alembic commands ###
<|endoftext|>


<commit_before>import sys
import logging

from raven.utils.testutils import TestCase

from raven.base import Client
from raven.breadcrumbs import record_breadcrumb

try:
    from cStringIO import StringIO as BytesIO
except ImportError:
    from io import BytesIO

class BreadcrumbTestCase(TestCase):

    def test_crumb_buffer(self):
        for enable in 1, 0:
            client = Client('http://foo:bar@example.com/0',
                            enable_breadcrumbs=enable)
            with client.context:
                record_breadcrumb('foo', data={'bar': 'baz'},
                                  message='aha', category='huhu')
                crumbs = client.context.breadcrumbs.get_buffer()
                assert len(crumbs) == enable

    def test_log_crumb_reporting(self):
        client = Client('http://foo:bar@example.com/0')
        with client.context:
            log = logging.getLogger('whatever.foo')
            log.info('This is a message with %s!', 'foo', blah='baz')
            crumbs = client.context.breadcrumbs.get_buffer()

        assert len(crumbs) == 1
        assert crumbs[0]['type'] == 'default'
        assert crumbs[0]['category'] == 'whatever.foo'
        assert crumbs[0]['data'] == {'blah': 'baz'}
        assert crumbs[0]['message'] == 'This is a message with foo!'

    def test_log_location(self):
        out = BytesIO()
        logger = logging.getLogger(__name__)
        logger.setLevel(logging.DEBUG)
        handler = logging.StreamHandler(out)
        handler.setFormatter(logging.Formatter(
            '%(name)s|%(filename)s|%(funcName)s|%(lineno)d|'
            '%(levelname)s|%(message)s'))
        logger.addHandler(handler)

        client = Client('http://foo:bar@example.com/0')
        with client.context:
            logger.info('Hello World!')
            lineno = sys._getframe().f_lineno - 1

        items = out.getvalue().strip().decode('utf-8').split('|')
        assert items[0] == b'tests.breadcrumbs.tests'
        assert items[1].rstrip(b'co') == b'tests.py'
        assert items[2] == b'test_log_location'
        assert int(items[3]) == lineno
        assert items[4] == b'INFO'
        assert items[5] == b'Hello World!'
<commit_msg>Fixed tests for python 3<commit_after>import sys
import logging

from raven.utils.testutils import TestCase

from raven.base import Client
from raven.breadcrumbs import record_breadcrumb

from io import StringIO

class BreadcrumbTestCase(TestCase):

    def test_crumb_buffer(self):
        for enable in 1, 0:
            client = Client('http://foo:bar@example.com/0',
                            enable_breadcrumbs=enable)
            with client.context:
                record_breadcrumb('foo', data={'bar': 'baz'},
                                  message='aha', category='huhu')
                crumbs = client.context.breadcrumbs.get_buffer()
                assert len(crumbs) == enable

    def test_log_crumb_reporting(self):
        client = Client('http://foo:bar@example.com/0')
        with client.context:
            log = logging.getLogger('whatever.foo')
            log.info('This is a message with %s!', 'foo', blah='baz')
            crumbs = client.context.breadcrumbs.get_buffer()

        assert len(crumbs) == 1
        assert crumbs[0]['type'] == 'default'
        assert crumbs[0]['category'] == 'whatever.foo'
        assert crumbs[0]['data'] == {'blah': 'baz'}
        assert crumbs[0]['message'] == 'This is a message with foo!'

    def test_log_location(self):
        out = StringIO()
        logger = logging.getLogger(__name__)
        logger.setLevel(logging.DEBUG)
        handler = logging.StreamHandler(out)
        handler.setFormatter(logging.Formatter(
            u'%(name)s|%(filename)s|%(funcName)s|%(lineno)d|'
            u'%(levelname)s|%(message)s'))
        logger.addHandler(handler)

        client = Client('http://foo:bar@example.com/0')
        with client.context:
            logger.info('Hello World!')
            lineno = sys._getframe().f_lineno - 1

        items = out.getvalue().strip().split('|')
        assert items[0] == 'tests.breadcrumbs.tests'
        assert items[1].rstrip('co') == 'tests.py'
        assert items[2] == 'test_log_location'
        assert int(items[3]) == lineno
        assert items[4] == 'INFO'
        assert items[5] == 'Hello World!'
<|endoftext|>


<commit_before># These are methods to do with MIME and crypto, implementing PGP/MIME.

import re
import StringIO
import email.parser

from email.mime.multipart import MIMEMultipart
from email.mime.base import MIMEBase

from mailpile.crypto.state import EncryptionInfo, SignatureInfo
from mailpile.i18n import gettext as _
from mailpile.i18n import ngettext as _n
from mailpile.mail_generator import Generator

##[ Common utilities ]#########################################################

def Normalize(payload):
    # http://tools.ietf.org/html/rfc3156 says we must:
    #
    #   - use CRLF everywhere
    #   - strip trailing whitespace
    #   - end with a CRLF
    #
    # In particlar, the stripping of trailing whitespace seems (based on
    # experiments with mutt), to in practice mean "strip trailing whitespace
    # off the last line"...
    #
    text = re.sub(r'\r?\n', '\r\n', payload).rstrip(' \t')
    if not text.endswith('\r\n'):
        text += '\r\n'
    return text

def MessageAsString(part, unixfrom=False):
    buf = StringIO.StringIO()
    Generator(buf).flatten(part, unixfrom=unixfrom)
    return Normalize(buf.getvalue()).replace('--\r\n--', '--\r\n\r\n--')

class EncryptionFailureError(ValueError):
    pass

class SignatureFailureError(ValueError):
    pass

DEFAULT_CHARSETS = ['utf-8', 'iso-8859-1']

def _decode_text_part(part, payload, charsets=None):
    for cs in (c for c in ([part.get_content_charset() or None] +
                           (charsets or DEFAULT_CHARSETS)) if c):
        try:
            return cs, payload.decode(cs)
        except (UnicodeDecodeError, TypeError, LookupError):
            pass
    return '8bit', payload

def _update_text_payload(part, payload, charsets=None):
    if 'content-transfer-encoding' in part:
        # We want this recalculated by the charset setting below
        del part['content-transfer-encoding']
    charset, payload = _decode_text_part(part, payload, charsets=charsets)
    part.set_payload(payload, charset)

##[ Methods for unwrapping encrypted parts ]###################################

def UnwrapMimeCrypto(part, protocols=None, psi=None, pei=None, charsets=None):
    """
    This method will replace encrypted and signed parts with their
    contents and set part attributes describing the security properties
    instead.
    """
    part.signature_info = SignatureInfo(parent=psi)
    part.encryption_info = EncryptionInfo(parent=pei)
    mimetype = part.get_content_type()
    if part.is_multipart():

        # FIXME: Check the protocol. PGP? Something else?
        # FIXME: This is where we add hooks for other MIME encryption
        #        schemes, so route to callbacks by protocol.
        crypto_cls = protocols['openpgp']

        # Containers are by default not bubbly
        part.signature_info.bubbly = False
        part.encryption_info.bubbly = False

        if mimetype == 'multipart/signed':
            try:
                boundary = part.get_boundary()
                payload, signature = part.get_payload()

                # The Python get_payload() method likes to rewrite headers,
                # which breaks signature verification. So we manually parse
                # out the raw payload here.
                head, raw_payload, junk = part.as_string(
                    ).replace('\r\n', '\n').split('\n--%s\n' % boundary, 2)

                part.signature_info = crypto_cls().verify(
                    Normalize(raw_payload), signature.get_payload())
                part.signature_info.bubble_up(psi)

                # Reparent the contents up, removing the signature wrapper
                part.set_payload(payload.get_payload())
                for h in payload.keys():
                    del part[h]
                for h, v in payload.items():
                    part.add_header(h, v)

                # Try again, in case we just unwrapped another layer
                # of multipart/something.
                UnwrapMimeCrypto(part,
                                 protocols=protocols,
                                 psi=part.signature_info,
                                 pei=part.encryption_info,
                                 charsets=charsets)

            except (IOError, OSError, ValueError, IndexError, KeyError):
                part.signature_info = SignatureInfo()
                part.signature_info["status"] = "error"
                part.signature_info.bubble_up(psi)

        elif mimetype == 'multipart/encrypted':
            try:
                preamble, payload = part.get_payload()

                (part.signature_info, part.encryption_info, decrypted
                 ) = crypto_cls().decrypt(payload.as_string())
            except (IOError, OSError, ValueError, IndexError, KeyError):
                part.encryption_info = EncryptionInfo()
                part.encryption_info["status"] = "error"

            part.signature_info.bubble_up(psi)
            part.encryption_info.bubble_up(pei)

            if part.encryption_info['status'] == 'decrypted':
                newpart = email.parser.Parser().parse(
                    StringIO.StringIO(decrypted))

                # Reparent the contents up, removing the encryption wrapper
                part.set_payload(newpart.get_payload())
                for h in newpart.keys():
                    del part[h]
                for h, v in newpart.items():
                    part.add_header(h, v)

                # Try again, in case we just unwrapped another layer
                # of multipart/something.
                UnwrapMimeCrypto(part,
                                 protocols=protocols,
                                 psi=part.signature_info,
                                 pei=part.encryption_info,
                                 charsets=charsets)

        # If we are still multipart after the above shenanigans (perhaps due
        # to an error state), recurse into our subparts and unwrap them too.
        elif part.is_multipart():
            for sp in part.get_payload():
                UnwrapMimeCrypto(sp,
                                 protocols=protocols,
                                 psi=part.signature_info,
                                 pei=part.encryption_info,
                                 charsets=charsets)

    elif mimetype == 'text/plain':
        return UnwrapPlainTextCrypto(part,
                                     protocols=protocols,
                                     psi=psi,
                                     pei=pei,
                                     charsets=charsets)

    else:
        # FIXME: This is where we would handle cryptoschemes that don't
        #        appear as multipart/...
        pass

    # Mix in our bubbles
    part.signature_info.mix_bubbles()
    part.encryption_info.mix_bubbles()

    # Bubble up!
    part.signature_info.bubble_up(psi)
    part.encryption_info.bubble_up(pei)

def UnwrapPlainTextCrypto(part, protocols=None, psi=None, pei=None,
                                charsets=None):
    """
    This method will replace encrypted and signed parts with their
    contents and set part attributes describing the security properties
    instead.
    """
    payload = part.get_payload(None, True).strip()
    si = SignatureInfo(parent=psi)
    ei = EncryptionInfo(parent=pei)
    for crypto_cls in protocols.values():
        crypto = crypto_cls()

        if (payload.startswith(crypto.ARMOR_BEGIN_ENCRYPTED) and
                payload.endswith(crypto.ARMOR_END_ENCRYPTED)):
            try:
                si, ei, text = crypto.decrypt(payload)
                _update_text_payload(part, text, charsets=charsets)
            except (IOError, OSError, ValueError, IndexError, KeyError):
                ei = EncryptionInfo()
                ei["status"] = "error"
            break

        elif (payload.startswith(crypto.ARMOR_BEGIN_SIGNED) and
                payload.endswith(crypto.ARMOR_END_SIGNED)):
            try:
                si = crypto.verify(payload)
            except (IOError, OSError, ValueError, IndexError, KeyError):
                si = SignatureInfo()
                si["status"] = "error"
            _update_text_payload(part, crypto.remove_armor(payload),
                                 charsets=charsets)
            break

    part.signature_info = si
    part.signature_info.bubble_up(psi)
    part.encryption_info = ei
    part.encryption_info.bubble_up(pei)

##[ Methods for encrypting and signing ]#######################################

class MimeWrapper:
    CONTAINER_TYPE = 'multipart/mixed'
    CONTAINER_PARAMS = ()

    def __init__(self, config, cleaner=None, sender=None, recipients=None):
        self.config = config
        self.sender = sender
        self.cleaner = cleaner
        self.recipients = recipients or []
        self.container = c = MIMEMultipart()
        c.set_type(self.CONTAINER_TYPE)
        c.signature_info = SignatureInfo(bubbly=False)
        c.encryption_info = EncryptionInfo(bubbly=False)
        if self.cleaner:
            self.cleaner(self.container)
        for pn, pv in self.CONTAINER_PARAMS:
            self.container.set_param(pn, pv)

    def crypto(self):
        return NotImplementedError("Please override me")

    def attach(self, part):
        c = self.container
        c.attach(part)

        if not hasattr(part, 'signature_info'):
            part.signature_info = SignatureInfo(parent=c.signature_info)
            part.encryption_info = EncryptionInfo(parent=c.encryption_info)
        else:
            part.signature_info.parent = c.signature_info
            part.signature_info.bubbly = True
            part.encryption_info.parent = c.encryption_info
            part.encryption_info.bubbly = True

        if self.cleaner:
            self.cleaner(part)
        del part['MIME-Version']
        return self

    def get_keys(self, people):
        return people

    def flatten(self, msg, unixfrom=False):
        return MessageAsString(msg, unixfrom=unixfrom)

    def get_only_text_part(self, msg):
        count = 0
        only_text_part = None
        for part in msg.walk():
            if part.is_multipart():
                continue
            count += 1
            if part.get_content_type() != 'text/plain' or count != 1:
                return False
            else:
                only_text_part = part
        return only_text_part

    def wrap(self, msg):
        for h in msg.keys():
            hl = h.lower()
            if not hl.startswith('content-') and not hl.startswith('mime-'):
                self.container[h] = msg[h]
                del msg[h]
        if hasattr(msg, 'signature_info'):
            self.container.signature_info = msg.signature_info
            self.container.encryption_info = msg.encryption_info
        return self.container

class MimeSigningWrapper(MimeWrapper):
    CONTAINER_TYPE = 'multipart/signed'
    CONTAINER_PARAMS = ()
    SIGNATURE_TYPE = 'application/x-signature'
    SIGNATURE_DESC = 'Abstract Digital Signature'

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

        self.sigblock = MIMEBase(*self.SIGNATURE_TYPE.split('/'))
        self.sigblock.set_param("name", "signature.asc")
        for h, v in (("Content-Description", self.SIGNATURE_DESC),
                     ("Content-Disposition",
                      "attachment; filename=\"signature.asc\"")):
            self.sigblock.add_header(h, v)

    def _update_crypto_status(self, part):
        part.signature_info.part_status = 'verified'

    def wrap(self, msg, prefer_inline=False):
        from_key = self.get_keys([self.sender])[0]

        if prefer_inline:
            prefer_inline = self.get_only_text_part(msg)

        if prefer_inline is not False:
            message_text = Normalize(prefer_inline.get_payload(None, True)
                                     .strip() + '\r\n\r\n')
            status, sig = self.crypto().sign(message_text,
                                             fromkey=from_key,
                                             clearsign=True,
                                             armor=True)
            if status == 0:
                _update_text_payload(prefer_inline, sig)
                self._update_crypto_status(prefer_inline)
                return msg

        else:
            MimeWrapper.wrap(self, msg)
            self.attach(msg)
            self.attach(self.sigblock)
            message_text = self.flatten(msg)
            status, sig = self.crypto().sign(message_text,
                                             fromkey=from_key, armor=True)
            if status == 0:
                self.sigblock.set_payload(sig)
                self._update_crypto_status(self.container)
                return self.container

        raise SignatureFailureError(_('Failed to sign message!'))

class MimeEncryptingWrapper(MimeWrapper):
    CONTAINER_TYPE = 'multipart/encrypted'
    CONTAINER_PARAMS = ()
    ENCRYPTION_TYPE = 'application/x-encrypted'
    ENCRYPTION_VERSION = 0

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

        self.version = MIMEBase(*self.ENCRYPTION_TYPE.split('/'))
        self.version.set_payload('Version: %s\n' % self.ENCRYPTION_VERSION)
        for h, v in (("Content-Disposition", "attachment"), ):
            self.version.add_header(h, v)

        self.enc_data = MIMEBase('application', 'octet-stream')
        for h, v in (("Content-Disposition",
                      "attachment; filename=\"msg.asc\""), ):
            self.enc_data.add_header(h, v)

        self.attach(self.version)
        self.attach(self.enc_data)

    def _encrypt(self, message_text, tokeys=None, armor=False):
        return self.crypto().encrypt(message_text,
                                     tokeys=tokeys, armor=True)

    def _update_crypto_status(self, part):
        part.encryption_info.part_status = 'decrypted'

    def wrap(self, msg, prefer_inline=False):
        to_keys = set(self.get_keys(self.recipients + [self.sender]))

        if prefer_inline:
            prefer_inline = self.get_only_text_part(msg)

        if prefer_inline is not False:
            message_text = Normalize(prefer_inline.get_payload(None, True))
            status, enc = self._encrypt(message_text,
                                        tokeys=to_keys,
                                        armor=True)
            if status == 0:
                _update_text_payload(prefer_inline, enc)
                self._update_crypto_status(prefer_inline)
                return msg

        else:
            MimeWrapper.wrap(self, msg)
            del msg['MIME-Version']
            if self.cleaner:
                self.cleaner(msg)
            message_text = self.flatten(msg)
            status, enc = self._encrypt(message_text,
                                        tokeys=to_keys,
                                        armor=True)
            if status == 0:
                self.enc_data.set_payload(enc)
                self._update_crypto_status(self.enc_data)
                return self.container

        raise EncryptionFailureError(_('Failed to encrypt message!'))
<commit_msg>Remove more MIME-Version garbage<commit_after># These are methods to do with MIME and crypto, implementing PGP/MIME.

import re
import StringIO
import email.parser

from email.mime.multipart import MIMEMultipart
from email.mime.base import MIMEBase

from mailpile.crypto.state import EncryptionInfo, SignatureInfo
from mailpile.i18n import gettext as _
from mailpile.i18n import ngettext as _n
from mailpile.mail_generator import Generator

##[ Common utilities ]#########################################################

def Normalize(payload):
    # http://tools.ietf.org/html/rfc3156 says we must:
    #
    #   - use CRLF everywhere
    #   - strip trailing whitespace
    #   - end with a CRLF
    #
    # In particlar, the stripping of trailing whitespace seems (based on
    # experiments with mutt), to in practice mean "strip trailing whitespace
    # off the last line"...
    #
    text = re.sub(r'\r?\n', '\r\n', payload).rstrip(' \t')
    if not text.endswith('\r\n'):
        text += '\r\n'
    return text

def MessageAsString(part, unixfrom=False):
    buf = StringIO.StringIO()
    Generator(buf).flatten(part, unixfrom=unixfrom)
    return Normalize(buf.getvalue()).replace('--\r\n--', '--\r\n\r\n--')

class EncryptionFailureError(ValueError):
    pass

class SignatureFailureError(ValueError):
    pass

DEFAULT_CHARSETS = ['utf-8', 'iso-8859-1']

def _decode_text_part(part, payload, charsets=None):
    for cs in (c for c in ([part.get_content_charset() or None] +
                           (charsets or DEFAULT_CHARSETS)) if c):
        try:
            return cs, payload.decode(cs)
        except (UnicodeDecodeError, TypeError, LookupError):
            pass
    return '8bit', payload

def _update_text_payload(part, payload, charsets=None):
    if 'content-transfer-encoding' in part:
        # We want this recalculated by the charset setting below
        del part['content-transfer-encoding']
    charset, payload = _decode_text_part(part, payload, charsets=charsets)
    part.set_payload(payload, charset)

##[ Methods for unwrapping encrypted parts ]###################################

def UnwrapMimeCrypto(part, protocols=None, psi=None, pei=None, charsets=None):
    """
    This method will replace encrypted and signed parts with their
    contents and set part attributes describing the security properties
    instead.
    """
    part.signature_info = SignatureInfo(parent=psi)
    part.encryption_info = EncryptionInfo(parent=pei)
    mimetype = part.get_content_type()
    if part.is_multipart():

        # FIXME: Check the protocol. PGP? Something else?
        # FIXME: This is where we add hooks for other MIME encryption
        #        schemes, so route to callbacks by protocol.
        crypto_cls = protocols['openpgp']

        # Containers are by default not bubbly
        part.signature_info.bubbly = False
        part.encryption_info.bubbly = False

        if mimetype == 'multipart/signed':
            try:
                boundary = part.get_boundary()
                payload, signature = part.get_payload()

                # The Python get_payload() method likes to rewrite headers,
                # which breaks signature verification. So we manually parse
                # out the raw payload here.
                head, raw_payload, junk = part.as_string(
                    ).replace('\r\n', '\n').split('\n--%s\n' % boundary, 2)

                part.signature_info = crypto_cls().verify(
                    Normalize(raw_payload), signature.get_payload())
                part.signature_info.bubble_up(psi)

                # Reparent the contents up, removing the signature wrapper
                part.set_payload(payload.get_payload())
                for h in payload.keys():
                    del part[h]
                for h, v in payload.items():
                    part.add_header(h, v)

                # Try again, in case we just unwrapped another layer
                # of multipart/something.
                UnwrapMimeCrypto(part,
                                 protocols=protocols,
                                 psi=part.signature_info,
                                 pei=part.encryption_info,
                                 charsets=charsets)

            except (IOError, OSError, ValueError, IndexError, KeyError):
                part.signature_info = SignatureInfo()
                part.signature_info["status"] = "error"
                part.signature_info.bubble_up(psi)

        elif mimetype == 'multipart/encrypted':
            try:
                preamble, payload = part.get_payload()

                (part.signature_info, part.encryption_info, decrypted
                 ) = crypto_cls().decrypt(payload.as_string())
            except (IOError, OSError, ValueError, IndexError, KeyError):
                part.encryption_info = EncryptionInfo()
                part.encryption_info["status"] = "error"

            part.signature_info.bubble_up(psi)
            part.encryption_info.bubble_up(pei)

            if part.encryption_info['status'] == 'decrypted':
                newpart = email.parser.Parser().parse(
                    StringIO.StringIO(decrypted))

                # Reparent the contents up, removing the encryption wrapper
                part.set_payload(newpart.get_payload())
                for h in newpart.keys():
                    del part[h]
                for h, v in newpart.items():
                    part.add_header(h, v)

                # Try again, in case we just unwrapped another layer
                # of multipart/something.
                UnwrapMimeCrypto(part,
                                 protocols=protocols,
                                 psi=part.signature_info,
                                 pei=part.encryption_info,
                                 charsets=charsets)

        # If we are still multipart after the above shenanigans (perhaps due
        # to an error state), recurse into our subparts and unwrap them too.
        elif part.is_multipart():
            for sp in part.get_payload():
                UnwrapMimeCrypto(sp,
                                 protocols=protocols,
                                 psi=part.signature_info,
                                 pei=part.encryption_info,
                                 charsets=charsets)

    elif mimetype == 'text/plain':
        return UnwrapPlainTextCrypto(part,
                                     protocols=protocols,
                                     psi=psi,
                                     pei=pei,
                                     charsets=charsets)

    else:
        # FIXME: This is where we would handle cryptoschemes that don't
        #        appear as multipart/...
        pass

    # Mix in our bubbles
    part.signature_info.mix_bubbles()
    part.encryption_info.mix_bubbles()

    # Bubble up!
    part.signature_info.bubble_up(psi)
    part.encryption_info.bubble_up(pei)

def UnwrapPlainTextCrypto(part, protocols=None, psi=None, pei=None,
                                charsets=None):
    """
    This method will replace encrypted and signed parts with their
    contents and set part attributes describing the security properties
    instead.
    """
    payload = part.get_payload(None, True).strip()
    si = SignatureInfo(parent=psi)
    ei = EncryptionInfo(parent=pei)
    for crypto_cls in protocols.values():
        crypto = crypto_cls()

        if (payload.startswith(crypto.ARMOR_BEGIN_ENCRYPTED) and
                payload.endswith(crypto.ARMOR_END_ENCRYPTED)):
            try:
                si, ei, text = crypto.decrypt(payload)
                _update_text_payload(part, text, charsets=charsets)
            except (IOError, OSError, ValueError, IndexError, KeyError):
                ei = EncryptionInfo()
                ei["status"] = "error"
            break

        elif (payload.startswith(crypto.ARMOR_BEGIN_SIGNED) and
                payload.endswith(crypto.ARMOR_END_SIGNED)):
            try:
                si = crypto.verify(payload)
            except (IOError, OSError, ValueError, IndexError, KeyError):
                si = SignatureInfo()
                si["status"] = "error"
            _update_text_payload(part, crypto.remove_armor(payload),
                                 charsets=charsets)
            break

    part.signature_info = si
    part.signature_info.bubble_up(psi)
    part.encryption_info = ei
    part.encryption_info.bubble_up(pei)

##[ Methods for encrypting and signing ]#######################################

class MimeWrapper:
    CONTAINER_TYPE = 'multipart/mixed'
    CONTAINER_PARAMS = ()

    def __init__(self, config, cleaner=None, sender=None, recipients=None):
        self.config = config
        self.sender = sender
        self.cleaner = cleaner
        self.recipients = recipients or []
        self.container = c = MIMEMultipart()
        c.set_type(self.CONTAINER_TYPE)
        c.signature_info = SignatureInfo(bubbly=False)
        c.encryption_info = EncryptionInfo(bubbly=False)
        if self.cleaner:
            self.cleaner(self.container)
        for pn, pv in self.CONTAINER_PARAMS:
            self.container.set_param(pn, pv)

    def crypto(self):
        return NotImplementedError("Please override me")

    def attach(self, part):
        c = self.container
        c.attach(part)

        if not hasattr(part, 'signature_info'):
            part.signature_info = SignatureInfo(parent=c.signature_info)
            part.encryption_info = EncryptionInfo(parent=c.encryption_info)
        else:
            part.signature_info.parent = c.signature_info
            part.signature_info.bubbly = True
            part.encryption_info.parent = c.encryption_info
            part.encryption_info.bubbly = True

        if self.cleaner:
            self.cleaner(part)
        del part['MIME-Version']
        return self

    def get_keys(self, people):
        return people

    def flatten(self, msg, unixfrom=False):
        return MessageAsString(msg, unixfrom=unixfrom)

    def get_only_text_part(self, msg):
        count = 0
        only_text_part = None
        for part in msg.walk():
            if part.is_multipart():
                continue
            count += 1
            if part.get_content_type() != 'text/plain' or count != 1:
                return False
            else:
                only_text_part = part
        return only_text_part

    def wrap(self, msg):
        for h in msg.keys():
            hl = h.lower()
            if not hl.startswith('content-') and not hl.startswith('mime-'):
                self.container[h] = msg[h]
                del msg[h]
            elif hl == 'mime-version':
                del msg[h]
        if hasattr(msg, 'signature_info'):
            self.container.signature_info = msg.signature_info
            self.container.encryption_info = msg.encryption_info
        return self.container

class MimeSigningWrapper(MimeWrapper):
    CONTAINER_TYPE = 'multipart/signed'
    CONTAINER_PARAMS = ()
    SIGNATURE_TYPE = 'application/x-signature'
    SIGNATURE_DESC = 'Abstract Digital Signature'

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

        self.sigblock = MIMEBase(*self.SIGNATURE_TYPE.split('/'))
        self.sigblock.set_param("name", "signature.asc")
        for h, v in (("Content-Description", self.SIGNATURE_DESC),
                     ("Content-Disposition",
                      "attachment; filename=\"signature.asc\"")):
            self.sigblock.add_header(h, v)

    def _update_crypto_status(self, part):
        part.signature_info.part_status = 'verified'

    def wrap(self, msg, prefer_inline=False):
        from_key = self.get_keys([self.sender])[0]

        if prefer_inline:
            prefer_inline = self.get_only_text_part(msg)

        if prefer_inline is not False:
            message_text = Normalize(prefer_inline.get_payload(None, True)
                                     .strip() + '\r\n\r\n')
            status, sig = self.crypto().sign(message_text,
                                             fromkey=from_key,
                                             clearsign=True,
                                             armor=True)
            if status == 0:
                _update_text_payload(prefer_inline, sig)
                self._update_crypto_status(prefer_inline)
                return msg

        else:
            MimeWrapper.wrap(self, msg)
            self.attach(msg)
            self.attach(self.sigblock)
            message_text = self.flatten(msg)
            status, sig = self.crypto().sign(message_text,
                                             fromkey=from_key, armor=True)
            if status == 0:
                self.sigblock.set_payload(sig)
                self._update_crypto_status(self.container)
                return self.container

        raise SignatureFailureError(_('Failed to sign message!'))

class MimeEncryptingWrapper(MimeWrapper):
    CONTAINER_TYPE = 'multipart/encrypted'
    CONTAINER_PARAMS = ()
    ENCRYPTION_TYPE = 'application/x-encrypted'
    ENCRYPTION_VERSION = 0

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

        self.version = MIMEBase(*self.ENCRYPTION_TYPE.split('/'))
        self.version.set_payload('Version: %s\n' % self.ENCRYPTION_VERSION)
        for h, v in (("Content-Disposition", "attachment"), ):
            self.version.add_header(h, v)

        self.enc_data = MIMEBase('application', 'octet-stream')
        for h, v in (("Content-Disposition",
                      "attachment; filename=\"msg.asc\""), ):
            self.enc_data.add_header(h, v)

        self.attach(self.version)
        self.attach(self.enc_data)

    def _encrypt(self, message_text, tokeys=None, armor=False):
        return self.crypto().encrypt(message_text,
                                     tokeys=tokeys, armor=True)

    def _update_crypto_status(self, part):
        part.encryption_info.part_status = 'decrypted'

    def wrap(self, msg, prefer_inline=False):
        to_keys = set(self.get_keys(self.recipients + [self.sender]))

        if prefer_inline:
            prefer_inline = self.get_only_text_part(msg)

        if prefer_inline is not False:
            message_text = Normalize(prefer_inline.get_payload(None, True))
            status, enc = self._encrypt(message_text,
                                        tokeys=to_keys,
                                        armor=True)
            if status == 0:
                _update_text_payload(prefer_inline, enc)
                self._update_crypto_status(prefer_inline)
                return msg

        else:
            MimeWrapper.wrap(self, msg)
            del msg['MIME-Version']
            if self.cleaner:
                self.cleaner(msg)
            message_text = self.flatten(msg)
            status, enc = self._encrypt(message_text,
                                        tokeys=to_keys,
                                        armor=True)
            if status == 0:
                self.enc_data.set_payload(enc)
                self._update_crypto_status(self.enc_data)
                return self.container

        raise EncryptionFailureError(_('Failed to encrypt message!'))
<|endoftext|>


<commit_before>'''
@author: jnaous
'''

try:
    from cStringIO import StringIO
except ImportError:
    from StringIO import StringIO
import xmlrpclib
import urlparse
import base64
import logging
logger = logging.getLogger("TestClientTransport")

class AuthorizationRequired(Exception):
    pass

class TestClientTransport(xmlrpclib.Transport):
    """Handles connections to XML-RPC server through Django test client"""

    def __init__(self, defaults={}, *args, **kwargs):
        from django.test.client import Client
        xmlrpclib.Transport.__init__(self, *args, **kwargs)
        self.client = Client(**defaults)

    def add_auth(self, host, headers):
        """
        Add Basic authentication information to the headers if it is given
        in host.
        """
        url = "http://%s" % host
        parsed = urlparse.urlparse(url)
        if parsed.username and parsed.password:
            auth = "%s:%s" % (parsed.username, parsed.password)
            headers["HTTP_AUTHORIZATION"] = "Basic %s" % base64.b64encode(auth)

    def request(self, host, handler, request_body, verbose=0):
        headers = dict(content_type="text/xml")
        self.add_auth(host, headers)
        self.verbose = verbose
        response = self.client.post(handler, request_body, **headers)
        logger.debug("Received response:\n%s" % response)
        if "WWW-Authenticate" in response:
            raise AuthorizationRequired(
                "Authorization required. Got response\n%s" % response)
        res = StringIO(response.content)
        res.seek(0)
        return self.parse_response(res)
<commit_msg>formatting<commit_after>'''
@author: jnaous
'''

try:
    from cStringIO import StringIO
except ImportError:
    from StringIO import StringIO
import xmlrpclib
import urlparse
import base64
import logging

logger = logging.getLogger("TestClientTransport")

class AuthorizationRequired(Exception):
    pass

class TestClientTransport(xmlrpclib.Transport):
    """Handles connections to XML-RPC server through Django test client"""

    def __init__(self, defaults={}, *args, **kwargs):
        from django.test.client import Client
        xmlrpclib.Transport.__init__(self, *args, **kwargs)
        self.client = Client(**defaults)

    def add_auth(self, host, headers):
        """
        Add Basic authentication information to the headers if it is given
        in host.
        """
        url = "http://%s" % host
        parsed = urlparse.urlparse(url)
        if parsed.username and parsed.password:
            auth = "%s:%s" % (parsed.username, parsed.password)
            headers["HTTP_AUTHORIZATION"] = "Basic %s" % base64.b64encode(auth)

    def request(self, host, handler, request_body, verbose=0):
        headers = dict(content_type="text/xml")
        self.add_auth(host, headers)
        self.verbose = verbose
        response = self.client.post(handler, request_body, **headers)
        logger.debug("Received response:\n%s" % response)
        if "WWW-Authenticate" in response:
            raise AuthorizationRequired(
                "Authorization required. Got response\n%s" % response)
        res = StringIO(response.content)
        res.seek(0)
        return self.parse_response(res)
<|endoftext|>


<commit_before>from astropy.io import fits
import matplotlib.pyplot as plt
from astropy.wcs import WCS
from astropy.visualization import *
from astropy.visualization.mpl_normalize import ImageNormalize

def wcs_header(image,ota):
  """
  A function to update the keywords in a QR'd image that start
  with PV to TPV. This is done in order to be used with the
  astropy wcs and reproject packages.

  image: fits image to be used
  ota: ota you would like to update. The qr'd images come down
  as a multi extension fits file. extenstions 1-9 are the 9
  different ota's.

  This fucntion will return a dictionary 'header'. This will
  not overwrite the header for any given ota, but can be passed
  to the various atropy packages

  """
  hdu = fits.open(image)
  header = hdu[ota].header
  oldkeys = []
  newkeys = []

  for key,i in header.iteritems():
    if 'PV' in key[0:2]:
      oldkeys.append(key)
      newkeys.append('T'+key)

  for i in range(len(oldkeys)):
    header[newkeys[i]] = header.pop(oldkeys[i])

  return hdu,header

# Example use, imshow will have ra dec in degrees rather than x and y.
hdu,header = wcs_header('20140406T225633.1_GCPair-F1_odi_r.5898.fits.fz',1)
norm = ImageNormalize(stretch=LinearStretch())
ax1 = plt.subplot(1,1,1, projection=WCS(header))
ax1.imshow(hdu[1].data,cmap='Greys_r',vmin=850,vmax=1065,origin='lower',norm=norm)
plt.show()

<commit_msg>Delete headerfix.py<commit_after><|endoftext|>


<commit_before>##############################################################
#
# This module should be invoked by a shell-script that says:
#
#    python -c "import direct.ffi.jGenPyCode" <arguments>
#
# Before invoking python, the shell-script may need to set
# these environment variables, to make sure that everything
# can be located appropriately.
#
#    PYTHONPATH
#    PATH
#    LD_LIBRARY_PATH
#
##############################################################

import sys,os

##############################################################
#
# Locate the 'direct' tree and the 'pandac' tree.
#
##############################################################

DIRECT=None
PANDAC=None
for dir in sys.path:
    if (DIRECT is None):
        if os.path.exists(os.path.join(dir,"direct")):
            DIRECT=os.path.join(dir,"direct")
    if (PANDAC is None):
        if (os.path.exists(os.path.join(dir,"pandac"))):
            PANDAC=os.path.join(dir,"pandac")

if (DIRECT is None):
    sys.exit("Could not locate the 'direct' python modules")
if (PANDAC is None):
    sys.exit("Could not locate the 'pandac' python modules")

##############################################################
#
# Locate direct/src/extensions.
#
# It could be inside the direct tree.  It may be underneath
# a 'src' subdirectory.  Or, the direct tree may actually be
# a stub that points to the source tree.
#
##############################################################

EXTENSIONS=None

if (EXTENSIONS is None):
  if os.path.isdir(os.path.join(DIRECT,"src","extensions")):
    EXTENSIONS=os.path.join(DIRECT,"src","extensions")

if (EXTENSIONS is None):
  if os.path.isdir(os.path.join(DIRECT,"extensions")):
    EXTENSIONS=os.path.join(DIRECT,"extensions")

if (EXTENSIONS is None):
  if os.path.isdir(os.path.join(DIRECT,"..","..","direct","src","extensions")):
    EXTENSIONS=os.path.join(DIRECT,"..","..","direct","src","extensions")

if (EXTENSIONS is None):
  sys.exit("Could not locate direct/src/extensions")

##############################################################
#
# Call genpycode with default paths.
#
##############################################################

from direct.ffi import DoGenPyCode
from direct.ffi import FFIConstants
DoGenPyCode.outputDir = PANDAC
DoGenPyCode.directDir = DIRECT
DoGenPyCode.extensionsDir = EXTENSIONS
DoGenPyCode.interrogateLib = r'libdtoolconfig'
DoGenPyCode.codeLibs = ['libpandaexpress','libpanda','libpandaphysics','libpandafx','libdirect','libpandaegg']
DoGenPyCode.etcPath = [os.path.join(PANDAC,"input")]

#print "outputDir = ",DoGenPyCode.outputDir
#print "directDir = ",DoGenPyCode.directDir
#print "extensionsDir = ",DoGenPyCode.extensionsDir
#print "interrogateLib = ",DoGenPyCode.interrogateLib
#print "codeLibs = ",DoGenPyCode.codeLibs
#print "etcPath = ",DoGenPyCode.etcPath

DoGenPyCode.run()

<commit_msg>Converted over to native<commit_after>##############################################################
#
# This module should be invoked by a shell-script that says:
#
#    python -c "import direct.ffi.jGenPyCode" <arguments>
#
# Before invoking python, the shell-script may need to set
# these environment variables, to make sure that everything
# can be located appropriately.
#
#    PYTHONPATH
#    PATH
#    LD_LIBRARY_PATH
#
##############################################################

import sys,os

##############################################################
#
# Locate the 'direct' tree and the 'pandac' tree.
#
##############################################################

DIRECT=None
PANDAC=None
for dir in sys.path:
    if (DIRECT is None):
        if os.path.exists(os.path.join(dir,"direct")):
            DIRECT=os.path.join(dir,"direct")
    if (PANDAC is None):
        if (os.path.exists(os.path.join(dir,"pandac"))):
            PANDAC=os.path.join(dir,"pandac")

if (DIRECT is None):
    sys.exit("Could not locate the 'direct' python modules")
if (PANDAC is None):
    sys.exit("Could not locate the 'pandac' python modules")

##############################################################
#
# Locate direct/src/extensions.
#
# It could be inside the direct tree.  It may be underneath
# a 'src' subdirectory.  Or, the direct tree may actually be
# a stub that points to the source tree.
#
##############################################################

EXTENSIONS=None

if (EXTENSIONS is None):
  if os.path.isdir(os.path.join(DIRECT,"src","extensions_native")):
    EXTENSIONS=os.path.join(DIRECT,"src","extensions_native")

if (EXTENSIONS is None):
  if os.path.isdir(os.path.join(DIRECT,"extensions_native")):
    EXTENSIONS=os.path.join(DIRECT,"extensions_native")

if (EXTENSIONS is None):
  if os.path.isdir(os.path.join(DIRECT,"..","..","direct","src","extensions_native")):
    EXTENSIONS=os.path.join(DIRECT,"..","..","direct","src","extensions_native")

if (EXTENSIONS is None):
  sys.exit("Could not locate direct/src/extensions_native")

##############################################################
#
# Call genpycode with default paths.
#
##############################################################

from direct.ffi import DoGenPyCode
from direct.ffi import FFIConstants
DoGenPyCode.outputDir = PANDAC
DoGenPyCode.directDir = DIRECT
DoGenPyCode.extensionsDir = EXTENSIONS
DoGenPyCode.interrogateLib = r'libdtoolconfig'
DoGenPyCode.codeLibs = ['libpandaexpress','libpanda','libpandaphysics','libpandafx','libdirect','libpandaegg']
DoGenPyCode.etcPath = [os.path.join(PANDAC,"input")]
DoGenPyCode.native = 1

#print "outputDir = ",DoGenPyCode.outputDir
#print "directDir = ",DoGenPyCode.directDir
#print "extensionsDir = ",DoGenPyCode.extensionsDir
#print "interrogateLib = ",DoGenPyCode.interrogateLib
#print "codeLibs = ",DoGenPyCode.codeLibs
#print "etcPath = ",DoGenPyCode.etcPath
#print "native = ",DoGenPyCode.native

DoGenPyCode.run()

<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
'''
Used to manage the thorium register. The thorium register is where compound
values are stored and computed, such as averages etc.

.. versionadded:: Carbon

:depends: statistics PyPi module
'''

# import python libs
from __future__ import absolute_import

try:
    import statistics
    HAS_STATS = True
except ImportError:
    HAS_STATS = False

def __virtual__():
    '''
    The statistics module must be pip installed
    '''
    return HAS_STATS

def calc(name, num, oper, ref=None):
    '''
    Perform a calculation on the ``num`` most recent values. Requires a list.
    Valid values for ``oper`` are:

      - add: Add last ``num`` values together
      - mul: Multiple last ``num`` values together
      - mean: Calculate mean of last ``num`` values
      - median: Calculate median of last ``num`` values
      - median_low: Calculate low median of last ``num`` values
      - median_high: Calculate high median of last ``num`` values
      - median_grouped: Calculate grouped median of last ``num`` values
      - mode: Calculate mode of last ``num`` values

    USAGE::

    code-block:: yaml

        foo:
          reg.calc:
            - name: myregentry
            - num: 5
            - oper: mean
    '''
    ret = {'name': name,
           'changes': {},
           'comment': '',
           'result': True}
    if name not in __reg__:
        ret['comment'] = '{0} not found in register'.format(name)
        ret['result'] = False

    def opadd(vals):
        sum = 0
        for val in vals:
            sum = sum + val
        return sum

    def opmul(vals):
        prod = 0
        for val in vals:
            prod = prod * val
        return prod

    ops = {
        'add': opadd,
        'mul': opmul,
        'mean': statistics.mean,
        'median': statistics.median,
        'median_low': statistics.median_low,
        'median_high': statistics.median_high,
        'median_grouped': statistics.median_grouped,
        'mode': statistics.mode,
    }

    count = 0
    vals = []
    __reg__[name]['val'].reverse()
    for regitem in __reg__[name]['val']:
        count += 1
        if count > num:
            break
        if ref is None:
            vals.append(regitem)
        else:
            vals.append(regitem[ref])

    answer = ops[oper](vals)

    ret['changes'] = {
        'Number of values': len(vals),
        'Operator': oper,
        'Answer': answer,
    }
    return ret

def add(name, num, ref=None):
    '''
    Adds together the ``num`` most recent values. Requires a list.

    USAGE::

    code-block:: yaml

        foo:
          reg.add:
            - name: myregentry
            - num: 5
    '''
    return calc(name, num, 'add', ref)

def mul(name, num, ref=None):
    '''
    Multiplies together the ``num`` most recent values. Requires a list.

    USAGE::

    code-block:: yaml

        foo:
          reg.mul:
            - name: myregentry
            - num: 5
    '''
    return calc(name, num, 'mul', ref)

def mean(name, num, ref=None):
    '''
    Calculates the mean of the ``num`` most recent values. Requires a list.

    USAGE::

    code-block:: yaml

        foo:
          reg.mean:
            - name: myregentry
            - num: 5
    '''
    return calc(name, num, 'mean', ref)

def median(name, num, ref=None):
    '''
    Calculates the mean of the ``num`` most recent values. Requires a list.

    USAGE::

    code-block:: yaml

        foo:
          reg.median:
            - name: myregentry
            - num: 5
    '''
    return calc(name, num, 'median', ref)

def median_low(name, num, ref=None):
    '''
    Calculates the low mean of the ``num`` most recent values. Requires a list.

    USAGE::

    code-block:: yaml

        foo:
          reg.median_low:
            - name: myregentry
            - num: 5
    '''
    return calc(name, num, 'median_low', ref)

def median_high(name, num, ref=None):
    '''
    Calculates the high mean of the ``num`` most recent values. Requires a list.

    USAGE::

    code-block:: yaml

        foo:
          reg.median_high:
            - name: myregentry
            - num: 5
    '''
    return calc(name, num, 'median_high', ref)

def median_grouped(name, num, ref=None):
    '''
    Calculates the grouped mean of the ``num`` most recent values. Requires a
    list.

    USAGE::

    code-block:: yaml

        foo:
          reg.median_grouped:
            - name: myregentry
            - num: 5
    '''
    return calc(name, num, 'median_grouped', ref)

def mode(name, num, ref=None):
    '''
    Calculates the mode of the ``num`` most recent values. Requires a list.

    USAGE::

    code-block:: yaml

        foo:
          reg.mode:
            - name: myregentry
            - num: 5
    '''
    return calc(name, num, 'mode', ref)
<commit_msg>Add threshholds to calc module<commit_after># -*- coding: utf-8 -*-
'''
Used to manage the thorium register. The thorium register is where compound
values are stored and computed, such as averages etc.

.. versionadded:: Carbon

:depends: statistics PyPi module
'''

# import python libs
from __future__ import absolute_import

try:
    import statistics
    HAS_STATS = True
except ImportError:
    HAS_STATS = False

def __virtual__():
    '''
    The statistics module must be pip installed
    '''
    return HAS_STATS

def calc(name, num, oper, minimum=0, maximum=0, ref=None):
    '''
    Perform a calculation on the ``num`` most recent values. Requires a list.
    Valid values for ``oper`` are:

      - add: Add last ``num`` values together
      - mul: Multiple last ``num`` values together
      - mean: Calculate mean of last ``num`` values
      - median: Calculate median of last ``num`` values
      - median_low: Calculate low median of last ``num`` values
      - median_high: Calculate high median of last ``num`` values
      - median_grouped: Calculate grouped median of last ``num`` values
      - mode: Calculate mode of last ``num`` values

    USAGE::

    code-block:: yaml

        foo:
          reg.calc:
            - name: myregentry
            - num: 5
            - oper: mean
    '''
    ret = {'name': name,
           'changes': {},
           'comment': '',
           'result': True}
    if name not in __reg__:
        ret['comment'] = '{0} not found in register'.format(name)
        ret['result'] = False

    def opadd(vals):
        sum = 0
        for val in vals:
            sum = sum + val
        return sum

    def opmul(vals):
        prod = 0
        for val in vals:
            prod = prod * val
        return prod

    ops = {
        'add': opadd,
        'mul': opmul,
        'mean': statistics.mean,
        'median': statistics.median,
        'median_low': statistics.median_low,
        'median_high': statistics.median_high,
        'median_grouped': statistics.median_grouped,
        'mode': statistics.mode,
    }

    count = 0
    vals = []
    __reg__[name]['val'].reverse()
    for regitem in __reg__[name]['val']:
        count += 1
        if count > num:
            break
        if ref is None:
            vals.append(regitem)
        else:
            vals.append(regitem[ref])

    answer = ops[oper](vals)

    if minimum > 0 and answer < minimum:
        ret['result'] = False

    if maximum > 0 and answer > maximum:
        ret['result'] = False

    ret['changes'] = {
        'Number of values': len(vals),
        'Operator': oper,
        'Answer': answer,
    }
    return ret

def add(name, num, ref=None):
    '''
    Adds together the ``num`` most recent values. Requires a list.

    USAGE::

    code-block:: yaml

        foo:
          reg.add:
            - name: myregentry
            - num: 5
    '''
    return calc(name, num, 'add', ref)

def mul(name, num, ref=None):
    '''
    Multiplies together the ``num`` most recent values. Requires a list.

    USAGE::

    code-block:: yaml

        foo:
          reg.mul:
            - name: myregentry
            - num: 5
    '''
    return calc(name, num, 'mul', ref)

def mean(name, num, ref=None):
    '''
    Calculates the mean of the ``num`` most recent values. Requires a list.

    USAGE::

    code-block:: yaml

        foo:
          reg.mean:
            - name: myregentry
            - num: 5
    '''
    return calc(name, num, 'mean', ref)

def median(name, num, ref=None):
    '''
    Calculates the mean of the ``num`` most recent values. Requires a list.

    USAGE::

    code-block:: yaml

        foo:
          reg.median:
            - name: myregentry
            - num: 5
    '''
    return calc(name, num, 'median', ref)

def median_low(name, num, ref=None):
    '''
    Calculates the low mean of the ``num`` most recent values. Requires a list.

    USAGE::

    code-block:: yaml

        foo:
          reg.median_low:
            - name: myregentry
            - num: 5
    '''
    return calc(name, num, 'median_low', ref)

def median_high(name, num, ref=None):
    '''
    Calculates the high mean of the ``num`` most recent values. Requires a list.

    USAGE::

    code-block:: yaml

        foo:
          reg.median_high:
            - name: myregentry
            - num: 5
    '''
    return calc(name, num, 'median_high', ref)

def median_grouped(name, num, ref=None):
    '''
    Calculates the grouped mean of the ``num`` most recent values. Requires a
    list.

    USAGE::

    code-block:: yaml

        foo:
          reg.median_grouped:
            - name: myregentry
            - num: 5
    '''
    return calc(name, num, 'median_grouped', ref)

def mode(name, num, ref=None):
    '''
    Calculates the mode of the ``num`` most recent values. Requires a list.

    USAGE::

    code-block:: yaml

        foo:
          reg.mode:
            - name: myregentry
            - num: 5
    '''
    return calc(name, num, 'mode', ref)
<|endoftext|>