<commit_before># Copyright (c) 2001-2014, Canal TP and/or its affiliates. All rights reserved.
#
# This file is part of Navitia,
#     the software to build cool stuff with public transport.
#
# Hope you'll enjoy and contribute to this project,
#     powered by Canal TP (www.canaltp.fr).
# Help us simplify mobility and open public transport:
#     a non ending quest to the responsive locomotion way of traveling!
#
# LICENCE: This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# Stay tuned using
# twitter @navitia
# IRC #navitia on freenode
# https://groups.google.com/d/forum/navitia
# www.navitia.io

from flask.ext.restful import Resource
from converters_collection_type import collections_to_resource_type
from converters_collection_type import resource_type_to_collection
from jormungandr import utils
from jormungandr.interfaces.v1.StatedResource import StatedResource
from jormungandr.stat_manager import manage_stat_caller
from make_links import add_id_links, clean_links, add_pagination_links
from functools import wraps
from collections import OrderedDict, deque
from flask import url_for
from flask.ext.restful.utils import unpack
from jormungandr.authentication import authentication_required
import navitiacommon.type_pb2 as type_pb2

class ResourceUri(StatedResource):

    def __init__(self, authentication=True, *args, **kwargs):
        StatedResource.__init__(self, *args, **kwargs)
        self.region = None
        self.method_decorators.append(add_id_links())
        self.method_decorators.append(add_address_poi_id(self))
        self.method_decorators.append(add_computed_resources(self))
        self.method_decorators.append(add_pagination_links())
        self.method_decorators.append(clean_links())
        if authentication:
            #some rare API (eg journey) must handle the authenfication by themself, thus deactivate it
            #by default ALWAYS use authentication=True
            self.method_decorators.append(authentication_required)

    def get_filter(self, items):
        filter_list = []
        if len(items) % 2 != 0:
            items = items[:-1]
        type_ = None

        for item in items:
            if not type_:
                if item != "coord":
                    if(item == "calendars"):
                        type_ = 'calendar'
                    else:
                        type_ = collections_to_resource_type[item]
                else:
                    type_ = "coord"
            else:
                if type_ == "coord" or type_ == "address":
                    splitted_coord = item.split(";")
                    if len(splitted_coord) == 2:
                        lon, lat = splitted_coord
                        object_type = "stop_point"
                        if(self.collection == "pois"):
                            object_type = "poi"
                        filter_ = object_type + ".coord DWITHIN(" + lon + ","
                        filter_ += lat + ",200)"
                        filter_list.append(filter_)
                    else:
                        filter_list.append(type_ + ".uri=" + item)
                elif type_ == 'poi':
                    filter_list.append(type_ + '.uri=' + item.split(":")[-1])
                else:
                    filter_list.append(type_ + ".uri=" + item)
                type_ = None
        return " and ".join(filter_list)

class add_address_poi_id(object):

    def __init__(self, resource):
        self.resource = resource

    def __call__(self, f):
        @wraps(f)
        def wrapper(*args, **kwargs):
            objects = f(*args, **kwargs)

            def add_id(objects, region, type_=None):
                if isinstance(objects, (list, tuple)):
                    for item in objects:
                        add_id(item, region, type_)
                elif hasattr(objects, 'keys'):
                    for v in objects.keys():
                        add_id(objects[v], region, v)
                    if 'address' == type_:
                        lon = objects['coord']['lon']
                        lat = objects['coord']['lat']
                        objects['id'] = lon + ';' + lat
                    if 'embedded_type' in objects.keys() and\
                        (objects['embedded_type'] == 'address' or
                         objects['embedded_type'] == 'poi' or
                         objects['embedded_type'] == 'administrative_region') and\
                         objects['embedded_type'] in objects:
                        objects["id"] = objects[objects['embedded_type']]["id"]
            if self.resource.region:
                add_id(objects, self.resource.region)
            return objects
        return wrapper

class add_computed_resources(object):

    def __init__(self, resource):
        self.resource = resource

    def __call__(self, f):
        @wraps(f)
        def wrapper(*args, **kwargs):
            response = f(*args, **kwargs)
            if isinstance(response, tuple):
                data, code, header = unpack(response)
            else:
                data = response
            collection = None
            kwargs["_external"] = True
            templated = True
            for key in data.keys():
                if key in collections_to_resource_type.keys():
                    collection = key
                if key in resource_type_to_collection.keys():
                    collection = resource_type_to_collection[key]
            if collection is None:
                return response
            kwargs["uri"] = collection + '/'
            if "id" in kwargs.keys():
                kwargs["uri"] += kwargs["id"]
                del kwargs["id"]
                templated = False
            else:
                kwargs["uri"] += '{' + collection + ".id}"
            if collection in ['stop_areas', 'stop_points', 'lines', 'routes',
                              'addresses'] and "region" in kwargs:
                for api in ['route_schedules', 'stop_schedules',
                            'arrivals', 'departures', "places_nearby"]:
                    data['links'].append({
                        "href": url_for("v1." + api, **kwargs),
                        "rel": api,
                        "templated": templated
                    })
            if collection in ['stop_areas', 'stop_points', 'addresses']:
                data['links'].append({
                    "href": url_for("v1.journeys", **kwargs),
                    "rel": "journeys",
                    "templated": templated
                })
            #for lines we add the link to the calendars
            if 'region' in kwargs:
                if collection == 'lines':
                    data['links'].append({
                        "href": url_for("v1.calendars", **kwargs),
                        "rel": "calendars",
                        "templated": templated
                    })
                if collection in ['stop_areas', 'lines', 'networks']:
                    data['links'].append({
                        "href": url_for("v1.disruptions", **kwargs),
                        "rel": "disruptions",
                        "templated": templated
                    })
            if isinstance(response, tuple):
                return data, code, header
            else:
                return data
        return wrapper

class complete_links(object):
    def __init__(self, resource):
        self.resource = resource
    def complete(self, data, collect):
        queue = deque()
        result = []
        for v in data.itervalues():
            queue.append(v)
        collect_type = collect["type"]
        while queue:
            elem = queue.pop()
            if isinstance(elem, (list, tuple)):
                queue.extend(elem)
            elif hasattr(elem, 'iterkeys'):
                if 'type' in elem and elem['type'] == collect_type:
                    if collect_type == "notes":
                        result.append({"id": elem['id'], "value": elem['value'], "type": collect_type})
                    elif collect_type == "exceptions":
                        type_= "Remove"
                        if elem['except_type'] == 0:
                            type_ = "Add"
                        result.append({"id": elem['id'], "date": elem['date'], "type" : type_})
                    for del_ in collect["del"]:
                        del elem[del_]
                else:
                    queue.extend(elem.itervalues())
        return result

    def __call__(self, f):
        @wraps(f)
        def wrapper(*args, **kwargs):
            objects = f(*args, **kwargs)
            if isinstance(objects, tuple):
                data, code, header = unpack(objects)
            else:
                data = objects

            if self.resource.region:
                collection = {
                    "notes" : {"type" : "notes",
                              "del":["value"]},
                    "exceptions" : {"type" : "exceptions",
                              "del":["date","except_type"]}
                }
                # Add notes exceptions
                for col in collection:
                    if not col in data or not isinstance(data[col], list):
                        data[col] = []
                        res = []
                        note = self.complete(data, collection[col])
                        [res.append(item) for item in note if not item in res]
                        data[col].extend(res)

            if isinstance(objects, tuple):
                return data, code, header
            else:
                return data

        return wrapper

class update_journeys_status(object):

    def __init__(self, resource):
        self.resource = resource

    def update_status(self, journey, disruptions):

        class find_most_dangerous_disruption:
            def __init__(self):
                self.max_priority_label = None
                self.max_priority = []

            def __call__(self, key, obj):
                try:
                    if 'links' not in obj:
                        return
                except TypeError:
                    return
                real_disruptions = [disruptions[d['id']] for d in obj['links'] if d['type'] == 'disruption']
                for d in real_disruptions:
                    prio = d['severity']['priority']
                    self.max_priority = prio if not self.max_priority else max(self.max_priority, prio)
                    if self.max_priority == prio:
                        self.max_priority_label = d['severity']['effect']

        v = find_most_dangerous_disruption()
        utils.walk_dict(journey, v)

        if v.max_priority_label:
            journey['status'] = v.max_priority_label

    def __call__(self, f):
        @wraps(f)
        def wrapper(*args, **kwargs):
            objects = f(*args, **kwargs)
            if isinstance(objects, tuple):
                data, code, header = unpack(objects)
            else:
                data = objects

            if self.resource.region and "journeys" in data:

                all_disruptions = {d['id']: d for d in data['disruptions']}

                for journey in data["journeys"]:
                    self.update_status(journey, all_disruptions)

            if isinstance(objects, tuple):
                return data, code, header
            else:
                return data

        return wrapper
<commit_msg>Add check : avoid keyError exception<commit_after># Copyright (c) 2001-2014, Canal TP and/or its affiliates. All rights reserved.
#
# This file is part of Navitia,
#     the software to build cool stuff with public transport.
#
# Hope you'll enjoy and contribute to this project,
#     powered by Canal TP (www.canaltp.fr).
# Help us simplify mobility and open public transport:
#     a non ending quest to the responsive locomotion way of traveling!
#
# LICENCE: This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# Stay tuned using
# twitter @navitia
# IRC #navitia on freenode
# https://groups.google.com/d/forum/navitia
# www.navitia.io

from flask.ext.restful import Resource
from converters_collection_type import collections_to_resource_type
from converters_collection_type import resource_type_to_collection
from jormungandr import utils
from jormungandr.interfaces.v1.StatedResource import StatedResource
from jormungandr.stat_manager import manage_stat_caller
from make_links import add_id_links, clean_links, add_pagination_links
from functools import wraps
from collections import OrderedDict, deque
from flask import url_for
from flask.ext.restful.utils import unpack
from jormungandr.authentication import authentication_required
import navitiacommon.type_pb2 as type_pb2

class ResourceUri(StatedResource):

    def __init__(self, authentication=True, *args, **kwargs):
        StatedResource.__init__(self, *args, **kwargs)
        self.region = None
        self.method_decorators.append(add_id_links())
        self.method_decorators.append(add_address_poi_id(self))
        self.method_decorators.append(add_computed_resources(self))
        self.method_decorators.append(add_pagination_links())
        self.method_decorators.append(clean_links())
        if authentication:
            #some rare API (eg journey) must handle the authenfication by themself, thus deactivate it
            #by default ALWAYS use authentication=True
            self.method_decorators.append(authentication_required)

    def get_filter(self, items):
        filter_list = []
        if len(items) % 2 != 0:
            items = items[:-1]
        type_ = None

        for item in items:
            if not type_:
                if item != "coord":
                    if(item == "calendars"):
                        type_ = 'calendar'
                    else:
                        type_ = collections_to_resource_type[item]
                else:
                    type_ = "coord"
            else:
                if type_ == "coord" or type_ == "address":
                    splitted_coord = item.split(";")
                    if len(splitted_coord) == 2:
                        lon, lat = splitted_coord
                        object_type = "stop_point"
                        if(self.collection == "pois"):
                            object_type = "poi"
                        filter_ = object_type + ".coord DWITHIN(" + lon + ","
                        filter_ += lat + ",200)"
                        filter_list.append(filter_)
                    else:
                        filter_list.append(type_ + ".uri=" + item)
                elif type_ == 'poi':
                    filter_list.append(type_ + '.uri=' + item.split(":")[-1])
                else:
                    filter_list.append(type_ + ".uri=" + item)
                type_ = None
        return " and ".join(filter_list)

class add_address_poi_id(object):

    def __init__(self, resource):
        self.resource = resource

    def __call__(self, f):
        @wraps(f)
        def wrapper(*args, **kwargs):
            objects = f(*args, **kwargs)

            def add_id(objects, region, type_=None):
                if isinstance(objects, (list, tuple)):
                    for item in objects:
                        add_id(item, region, type_)
                elif hasattr(objects, 'keys'):
                    for v in objects.keys():
                        add_id(objects[v], region, v)
                    if 'address' == type_ and 'coord' in objects:
                        lon = objects['coord']['lon']
                        lat = objects['coord']['lat']
                        objects['id'] = lon + ';' + lat
                    if 'embedded_type' in objects.keys() and\
                        (objects['embedded_type'] == 'address' or
                         objects['embedded_type'] == 'poi' or
                         objects['embedded_type'] == 'administrative_region') and\
                         objects['embedded_type'] in objects:
                        objects["id"] = objects[objects['embedded_type']]["id"]
            if self.resource.region:
                add_id(objects, self.resource.region)
            return objects
        return wrapper

class add_computed_resources(object):

    def __init__(self, resource):
        self.resource = resource

    def __call__(self, f):
        @wraps(f)
        def wrapper(*args, **kwargs):
            response = f(*args, **kwargs)
            if isinstance(response, tuple):
                data, code, header = unpack(response)
            else:
                data = response
            collection = None
            kwargs["_external"] = True
            templated = True
            for key in data.keys():
                if key in collections_to_resource_type.keys():
                    collection = key
                if key in resource_type_to_collection.keys():
                    collection = resource_type_to_collection[key]
            if collection is None:
                return response
            kwargs["uri"] = collection + '/'
            if "id" in kwargs.keys():
                kwargs["uri"] += kwargs["id"]
                del kwargs["id"]
                templated = False
            else:
                kwargs["uri"] += '{' + collection + ".id}"
            if collection in ['stop_areas', 'stop_points', 'lines', 'routes',
                              'addresses'] and "region" in kwargs:
                for api in ['route_schedules', 'stop_schedules',
                            'arrivals', 'departures', "places_nearby"]:
                    data['links'].append({
                        "href": url_for("v1." + api, **kwargs),
                        "rel": api,
                        "templated": templated
                    })
            if collection in ['stop_areas', 'stop_points', 'addresses']:
                data['links'].append({
                    "href": url_for("v1.journeys", **kwargs),
                    "rel": "journeys",
                    "templated": templated
                })
            #for lines we add the link to the calendars
            if 'region' in kwargs:
                if collection == 'lines':
                    data['links'].append({
                        "href": url_for("v1.calendars", **kwargs),
                        "rel": "calendars",
                        "templated": templated
                    })
                if collection in ['stop_areas', 'lines', 'networks']:
                    data['links'].append({
                        "href": url_for("v1.disruptions", **kwargs),
                        "rel": "disruptions",
                        "templated": templated
                    })
            if isinstance(response, tuple):
                return data, code, header
            else:
                return data
        return wrapper

class complete_links(object):
    def __init__(self, resource):
        self.resource = resource
    def complete(self, data, collect):
        queue = deque()
        result = []
        for v in data.itervalues():
            queue.append(v)
        collect_type = collect["type"]
        while queue:
            elem = queue.pop()
            if isinstance(elem, (list, tuple)):
                queue.extend(elem)
            elif hasattr(elem, 'iterkeys'):
                if 'type' in elem and elem['type'] == collect_type:
                    if collect_type == "notes":
                        result.append({"id": elem['id'], "value": elem['value'], "type": collect_type})
                    elif collect_type == "exceptions":
                        type_= "Remove"
                        if elem['except_type'] == 0:
                            type_ = "Add"
                        result.append({"id": elem['id'], "date": elem['date'], "type" : type_})
                    for del_ in collect["del"]:
                        del elem[del_]
                else:
                    queue.extend(elem.itervalues())
        return result

    def __call__(self, f):
        @wraps(f)
        def wrapper(*args, **kwargs):
            objects = f(*args, **kwargs)
            if isinstance(objects, tuple):
                data, code, header = unpack(objects)
            else:
                data = objects

            if self.resource.region:
                collection = {
                    "notes" : {"type" : "notes",
                              "del":["value"]},
                    "exceptions" : {"type" : "exceptions",
                              "del":["date","except_type"]}
                }
                # Add notes exceptions
                for col in collection:
                    if not col in data or not isinstance(data[col], list):
                        data[col] = []
                        res = []
                        note = self.complete(data, collection[col])
                        [res.append(item) for item in note if not item in res]
                        data[col].extend(res)

            if isinstance(objects, tuple):
                return data, code, header
            else:
                return data

        return wrapper

class update_journeys_status(object):

    def __init__(self, resource):
        self.resource = resource

    def update_status(self, journey, disruptions):

        class find_most_dangerous_disruption:
            def __init__(self):
                self.max_priority_label = None
                self.max_priority = []

            def __call__(self, key, obj):
                try:
                    if 'links' not in obj:
                        return
                except TypeError:
                    return
                real_disruptions = [disruptions[d['id']] for d in obj['links'] if d['type'] == 'disruption']
                for d in real_disruptions:
                    prio = d['severity']['priority']
                    self.max_priority = prio if not self.max_priority else max(self.max_priority, prio)
                    if self.max_priority == prio:
                        self.max_priority_label = d['severity']['effect']

        v = find_most_dangerous_disruption()
        utils.walk_dict(journey, v)

        if v.max_priority_label:
            journey['status'] = v.max_priority_label

    def __call__(self, f):
        @wraps(f)
        def wrapper(*args, **kwargs):
            objects = f(*args, **kwargs)
            if isinstance(objects, tuple):
                data, code, header = unpack(objects)
            else:
                data = objects

            if self.resource.region and "journeys" in data:

                all_disruptions = {d['id']: d for d in data['disruptions']}

                for journey in data["journeys"]:
                    self.update_status(journey, all_disruptions)

            if isinstance(objects, tuple):
                return data, code, header
            else:
                return data

        return wrapper
<|endoftext|>


<commit_before>from PyQt4.Qt import QMessageBox, QDialog, QVBoxLayout, QLabel, QThread, SIGNAL, QGridLayout, QInputDialog, QPushButton
import PyQt4.QtCore as QtCore
from binascii import unhexlify
from struct import pack
from sys import stderr
from time import sleep
from base64 import b64encode, b64decode

from electrum_gui.qt.password_dialog import make_password_dialog, run_password_dialog
from electrum_gui.qt.util import ok_cancel_buttons, EnterButton
from electrum.account import BIP32_Account
from electrum.bitcoin import EncodeBase58Check, public_key_to_bc_address, bc_address_to_hash_160
from electrum.i18n import _
from electrum.plugins import BasePlugin
from electrum.transaction import deserialize
from electrum.wallet import NewWallet

try:
    from trezorlib.client import types
    from trezorlib.client import proto, BaseClient, ProtocolMixin
    from trezorlib.qt.pinmatrix import PinMatrixWidget
    from trezorlib.transport import ConnectionError
    from trezorlib.transport_hid import HidTransport
    TREZOR = True
except ImportError:
    TREZOR = False

def log(msg):
    stderr.write("%s\n" % msg)
    stderr.flush()

def give_error(message):
    QMessageBox.warning(QDialog(), _('Warning'), _(message), _('OK'))
    raise Exception(message)

class Plugin(BasePlugin):

    def fullname(self): return 'Trezor Wallet'

    def description(self): return 'Provides support for Trezor hardware wallet\n\nRequires github.com/trezor/python-trezor'

    def __init__(self, gui, name):
        BasePlugin.__init__(self, gui, name)
        self._is_available = self._init()
        self._requires_settings = True
        self.wallet = None

    def _init(self):
        return TREZOR

    def is_available(self):
        if self.wallet is None:
            return self._is_available
        if self.wallet.storage.get('wallet_type') == 'trezor':
            return True
        return False

    def requires_settings(self):
        return self._requires_settings

    def set_enabled(self, enabled):
        self.wallet.storage.put('use_' + self.name, enabled)

    def is_enabled(self):
        if not self.is_available():
            return False

        if not self.wallet or self.wallet.storage.get('wallet_type') == 'trezor':
            return True

        return self.wallet.storage.get('use_' + self.name) is True

    def enable(self):
        return BasePlugin.enable(self)

    def load_wallet(self, wallet):
        self.wallet = wallet

    def add_wallet_types(self, wallet_types):
        wallet_types.append(('trezor', _("Trezor wallet"), TrezorWallet))

    def installwizard_restore(self, wizard, storage):
        if storage.get('wallet_type') != 'trezor':
            return
        wallet = TrezorWallet(storage)
        try:
            wallet.create_main_account(None)
        except BaseException as e:
            QMessageBox.information(None, _('Error'), str(e), _('OK'))
            return
        return wallet

    def send_tx(self, tx):
        try:
            self.wallet.sign_transaction(tx, None, None)
        except Exception as e:
            tx.error = str(e)

    def settings_widget(self, window):
        return EnterButton(_('Settings'), self.settings_dialog)

    def settings_dialog(self):
        get_label = lambda: self.wallet.get_client().features.label
        update_label = lambda: current_label_label.setText("Label: %s" % get_label())

        d = QDialog()
        layout = QGridLayout(d)
        layout.addWidget(QLabel("Trezor Options"),0,0)
        layout.addWidget(QLabel("ID:"),1,0)
        layout.addWidget(QLabel(" %s" % self.wallet.get_client().get_device_id()),1,1)

        def modify_label():
            response = QInputDialog().getText(None, "Set New Trezor Label", "New Trezor Label:  (upon submission confirm on Trezor)")
            if not response[1]:
                return
            new_label = str(response[0])
            twd.start("Please confirm label change on Trezor")
            status = self.wallet.get_client().apply_settings(label=new_label)
            twd.stop()
            update_label()

        current_label_label = QLabel()
        update_label()
        change_label_button = QPushButton("Modify")
        change_label_button.clicked.connect(modify_label)
        layout.addWidget(current_label_label,3,0)
        layout.addWidget(change_label_button,3,1)

        if d.exec_():
          return True
        else:
          return False

class TrezorWallet(NewWallet):
    wallet_type = 'trezor'

    def __init__(self, storage):
        NewWallet.__init__(self, storage)
        self.transport = None
        self.client = None
        self.mpk = None
        self.device_checked = False

    def get_action(self):
        if not self.accounts:
            return 'create_accounts'

    def can_create_accounts(self):
        return True

    def can_change_password(self):
        return False

    def has_seed(self):
        return False

    def is_watching_only(self):
        return False

    def get_client(self):
        if not TREZOR:
            give_error('please install github.com/trezor/python-trezor')

        if not self.client or self.client.bad:
            try:
                d = HidTransport.enumerate()[0]
                self.transport = HidTransport(d)
            except:
                give_error('Could not connect to your Trezor. Please verify the cable is connected and that no other app is using it.')
            self.client = QtGuiTrezorClient(self.transport)
            self.client.set_tx_api(self)
            #self.client.clear_session()# TODO Doesn't work with firmware 1.1, returns proto.Failure
            self.client.bad = False
            self.device_checked = False
            self.proper_device = False
        return self.client

    def address_id(self, address):
        account_id, (change, address_index) = self.get_address_index(address)
        return "44'/0'/%s'/%d/%d" % (account_id, change, address_index)

    def create_main_account(self, password):
        self.create_account('Main account', None) #name, empty password

    def derive_xkeys(self, root, derivation, password):
        derivation = derivation.replace(self.root_name,"44'/0'/")
        xpub = self.get_public_key(derivation)
        return xpub, None

    def get_public_key(self, bip32_path):
        address_n = self.get_client().expand_path(bip32_path)
        node = self.get_client().get_public_node(address_n).node
        xpub = "0488B21E".decode('hex') + chr(node.depth) + self.i4b(node.fingerprint) + self.i4b(node.child_num) + node.chain_code + node.public_key
        return EncodeBase58Check(xpub)

    def get_master_public_key(self):
        if not self.mpk:
            self.mpk = self.get_public_key("44'/0'")
        return self.mpk

    def i4b(self, x):
        return pack('>I', x)

    def add_keypairs(self, tx, keypairs, password):
        #do nothing - no priv keys available
        pass

    def decrypt_message(self, pubkey, message, password):
        address = public_key_to_bc_address(pubkey.decode('hex'))
        address_path = self.address_id(address)
        address_n = self.get_client().expand_path(address_path)
        try:
            decrypted_msg = self.get_client().decrypt_message(address_n, b64decode(message))
        except Exception, e:
            give_error(e)
        finally:
            twd.emit(SIGNAL('trezor_done'))
        return str(decrypted_msg)

    def sign_message(self, address, message, password):
        if not self.check_proper_device():
            give_error('Wrong device or password')
        try:
            address_path = self.address_id(address)
            address_n = self.get_client().expand_path(address_path)
        except Exception, e:
            give_error(e)
        try:
            msg_sig = self.get_client().sign_message('Bitcoin', address_n, message)
        except Exception, e:
            give_error(e)
        finally:
            twd.emit(SIGNAL('trezor_done'))
        b64_msg_sig = b64encode(msg_sig.signature)
        return str(b64_msg_sig)

    def sign_transaction(self, tx, keypairs, password):
        if tx.error or tx.is_complete():
            return

        if not self.check_proper_device():
            give_error('Wrong device or password')

        inputs = self.tx_inputs(tx)
        outputs = self.tx_outputs(tx)
        try:
            signed_tx = self.get_client().sign_tx('Bitcoin', inputs, outputs)[1]
        except Exception, e:
            give_error(e)
        finally:
            twd.emit(SIGNAL('trezor_done'))
        values = [i['value'] for i in tx.inputs]
        raw = signed_tx.encode('hex')
        tx.update(raw)
        for i, txinput in enumerate(tx.inputs):
            txinput['value'] = values[i]

    def tx_inputs(self, tx):
        inputs = []

        for txinput in tx.inputs:
            txinputtype = types.TxInputType()
            address = txinput['address']
            try:
                address_path = self.address_id(address)
                address_n = self.get_client().expand_path(address_path)
                txinputtype.address_n.extend(address_n)
            except: pass

            if ('is_coinbase' in txinput and txinput['is_coinbase']):
                prev_hash = "\0"*32
                prev_index = 0xffffffff # signed int -1
            else:
                prev_hash = unhexlify(txinput['prevout_hash'])
                prev_index = txinput['prevout_n']

            txinputtype.prev_hash = prev_hash
            txinputtype.prev_index = prev_index

            if 'scriptSig' in txinput:
                script_sig = txinput['scriptSig']
                txinputtype.script_sig = script_sig

            if 'sequence' in txinput:
                sequence = txinput['sequence']
                txinputtype.sequence = sequence

            inputs.append(txinputtype)
            #TODO P2SH
        return inputs

    def tx_outputs(self, tx):
        outputs = []

        for type, address, amount in tx.outputs:
            assert type == 'address'
            txoutputtype = types.TxOutputType()
            if self.is_change(address):
                address_path = self.address_id(address)
                address_n = self.get_client().expand_path(address_path)
                txoutputtype.address_n.extend(address_n)
            else:
                txoutputtype.address = address
            txoutputtype.amount = amount
            addrtype, hash_160 = bc_address_to_hash_160(address)
            if addrtype == 0:
                txoutputtype.script_type = types.PAYTOADDRESS
            elif addrtype == 5:
                txoutputtype.script_type = types.PAYTOSCRIPTHASH
            else:
                raise BaseException('addrtype')
            outputs.append(txoutputtype)

        return outputs

    def electrum_tx_to_txtype(self, tx):
        t = types.TransactionType()
        d = deserialize(tx.raw)
        t.version = d['version']
        t.lock_time = d['lockTime']

        inputs = self.tx_inputs(tx)
        t.inputs.extend(inputs)

        for vout in d['outputs']:
            o = t.bin_outputs.add()
            o.amount = vout['value']
            o.script_pubkey = vout['scriptPubKey'].decode('hex')

        return t

    def get_tx(self, tx_hash):
        tx = self.transactions[tx_hash]
        return self.electrum_tx_to_txtype(tx)

    def check_proper_device(self):
        self.get_client().ping('t')
        if not self.device_checked:
            address = self.addresses(False, False)[0]
            address_id = self.address_id(address)
            n = self.get_client().expand_path(address_id)
            device_address = self.get_client().get_address('Bitcoin', n)
            self.device_checked = True

            if device_address != address:
                self.proper_device = False
            else:
                self.proper_device = True

        return self.proper_device

class TrezorQtGuiMixin(object):

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

    def callback_ButtonRequest(self, msg):
        if msg.code == 3:
            message = "Confirm transaction outputs on Trezor device to continue"
        elif msg.code == 8:
            message = "Confirm transaction fee on Trezor device to continue"
        elif msg.code == 7:
            message = "Confirm message to sign on Trezor device to continue"
        else:
            message = "Check Trezor device to continue"
        twd.start(message)
        return proto.ButtonAck()

    def callback_PinMatrixRequest(self, msg):
        if msg.type == 1:
            desc = 'current PIN'
        elif msg.type == 2:
            desc = 'new PIN'
        elif msg.type == 3:
            desc = 'new PIN again'
        else:
            desc = 'PIN'

        pin = self.pin_dialog(msg="Please enter Trezor %s" % desc)
        if not pin:
            return proto.Cancel()
        return proto.PinMatrixAck(pin=pin)

    def callback_PassphraseRequest(self, msg):
        confirmed, p, passphrase = self.password_dialog()
        if not confirmed:
            QMessageBox.critical(None, _('Error'), _("Password request canceled"), _('OK'))
            return proto.Cancel()
        if passphrase is None:
            passphrase='' # Even blank string is valid Trezor passphrase
        return proto.PassphraseAck(passphrase=passphrase)

    def callback_WordRequest(self, msg):
        #TODO
        log("Enter one word of mnemonic: ")
        word = raw_input()
        return proto.WordAck(word=word)

    def password_dialog(self, msg=None):
        if not msg:
            msg = _("Please enter your Trezor password")

        d = QDialog()
        d.setModal(1)
        d.setLayout( make_password_dialog(d, None, msg, False) )
        return run_password_dialog(d, None, None)

    def pin_dialog(self, msg):
        d = QDialog(None)
        d.setModal(1)
        d.setWindowTitle(_("Enter PIN"))
        matrix = PinMatrixWidget()

        vbox = QVBoxLayout()
        vbox.addWidget(QLabel(msg))
        vbox.addWidget(matrix)
        vbox.addLayout(ok_cancel_buttons(d))
        d.setLayout(vbox)

        if not d.exec_(): return
        return str(matrix.get_value())

class TrezorWaitingDialog(QThread):
    def __init__(self):
        QThread.__init__(self)
        self.waiting = False

    def start(self, message):
        self.d = QDialog()
        self.d.setModal(1)
        self.d.setWindowTitle('Please Check Trezor Device')
        self.d.setWindowFlags(self.d.windowFlags() | QtCore.Qt.WindowStaysOnTopHint)
        l = QLabel(message)
        vbox = QVBoxLayout(self.d)
        vbox.addWidget(l)
        self.d.show()
        if not self.waiting:
            self.waiting = True
            self.d.connect(twd, SIGNAL('trezor_done'), self.stop)

    def stop(self):
        self.d.hide()
        self.waiting = False

if TREZOR:
    class QtGuiTrezorClient(ProtocolMixin, TrezorQtGuiMixin, BaseClient):
        def call_raw(self, msg):
            try:
                resp = BaseClient.call_raw(self, msg)
            except ConnectionError:
                self.bad = True
                raise

            return resp

    twd = TrezorWaitingDialog()

<commit_msg>Removed hard coded purpose and coin_type (provided by Wallet.get_address_index) Only look up address when not a coinbase transaction<commit_after>from PyQt4.Qt import QMessageBox, QDialog, QVBoxLayout, QLabel, QThread, SIGNAL, QGridLayout, QInputDialog, QPushButton
import PyQt4.QtCore as QtCore
from binascii import unhexlify
from struct import pack
from sys import stderr
from time import sleep
from base64 import b64encode, b64decode

from electrum_gui.qt.password_dialog import make_password_dialog, run_password_dialog
from electrum_gui.qt.util import ok_cancel_buttons, EnterButton
from electrum.account import BIP32_Account
from electrum.bitcoin import EncodeBase58Check, public_key_to_bc_address, bc_address_to_hash_160
from electrum.i18n import _
from electrum.plugins import BasePlugin
from electrum.transaction import deserialize
from electrum.wallet import NewWallet

try:
    from trezorlib.client import types
    from trezorlib.client import proto, BaseClient, ProtocolMixin
    from trezorlib.qt.pinmatrix import PinMatrixWidget
    from trezorlib.transport import ConnectionError
    from trezorlib.transport_hid import HidTransport
    TREZOR = True
except ImportError:
    TREZOR = False

def log(msg):
    stderr.write("%s\n" % msg)
    stderr.flush()

def give_error(message):
    QMessageBox.warning(QDialog(), _('Warning'), _(message), _('OK'))
    raise Exception(message)

class Plugin(BasePlugin):

    def fullname(self): return 'Trezor Wallet'

    def description(self): return 'Provides support for Trezor hardware wallet\n\nRequires github.com/trezor/python-trezor'

    def __init__(self, gui, name):
        BasePlugin.__init__(self, gui, name)
        self._is_available = self._init()
        self._requires_settings = True
        self.wallet = None

    def _init(self):
        return TREZOR

    def is_available(self):
        if self.wallet is None:
            return self._is_available
        if self.wallet.storage.get('wallet_type') == 'trezor':
            return True
        return False

    def requires_settings(self):
        return self._requires_settings

    def set_enabled(self, enabled):
        self.wallet.storage.put('use_' + self.name, enabled)

    def is_enabled(self):
        if not self.is_available():
            return False

        if not self.wallet or self.wallet.storage.get('wallet_type') == 'trezor':
            return True

        return self.wallet.storage.get('use_' + self.name) is True

    def enable(self):
        return BasePlugin.enable(self)

    def load_wallet(self, wallet):
        self.wallet = wallet

    def add_wallet_types(self, wallet_types):
        wallet_types.append(('trezor', _("Trezor wallet"), TrezorWallet))

    def installwizard_restore(self, wizard, storage):
        if storage.get('wallet_type') != 'trezor':
            return
        wallet = TrezorWallet(storage)
        try:
            wallet.create_main_account(None)
        except BaseException as e:
            QMessageBox.information(None, _('Error'), str(e), _('OK'))
            return
        return wallet

    def send_tx(self, tx):
        try:
            self.wallet.sign_transaction(tx, None, None)
        except Exception as e:
            tx.error = str(e)

    def settings_widget(self, window):
        return EnterButton(_('Settings'), self.settings_dialog)

    def settings_dialog(self):
        get_label = lambda: self.wallet.get_client().features.label
        update_label = lambda: current_label_label.setText("Label: %s" % get_label())

        d = QDialog()
        layout = QGridLayout(d)
        layout.addWidget(QLabel("Trezor Options"),0,0)
        layout.addWidget(QLabel("ID:"),1,0)
        layout.addWidget(QLabel(" %s" % self.wallet.get_client().get_device_id()),1,1)

        def modify_label():
            response = QInputDialog().getText(None, "Set New Trezor Label", "New Trezor Label:  (upon submission confirm on Trezor)")
            if not response[1]:
                return
            new_label = str(response[0])
            twd.start("Please confirm label change on Trezor")
            status = self.wallet.get_client().apply_settings(label=new_label)
            twd.stop()
            update_label()

        current_label_label = QLabel()
        update_label()
        change_label_button = QPushButton("Modify")
        change_label_button.clicked.connect(modify_label)
        layout.addWidget(current_label_label,3,0)
        layout.addWidget(change_label_button,3,1)

        if d.exec_():
          return True
        else:
          return False

class TrezorWallet(NewWallet):
    wallet_type = 'trezor'

    def __init__(self, storage):
        NewWallet.__init__(self, storage)
        self.transport = None
        self.client = None
        self.mpk = None
        self.device_checked = False

    def get_action(self):
        if not self.accounts:
            return 'create_accounts'

    def can_create_accounts(self):
        return True

    def can_change_password(self):
        return False

    def has_seed(self):
        return False

    def is_watching_only(self):
        return False

    def get_client(self):
        if not TREZOR:
            give_error('please install github.com/trezor/python-trezor')

        if not self.client or self.client.bad:
            try:
                d = HidTransport.enumerate()[0]
                self.transport = HidTransport(d)
            except:
                give_error('Could not connect to your Trezor. Please verify the cable is connected and that no other app is using it.')
            self.client = QtGuiTrezorClient(self.transport)
            self.client.set_tx_api(self)
            #self.client.clear_session()# TODO Doesn't work with firmware 1.1, returns proto.Failure
            self.client.bad = False
            self.device_checked = False
            self.proper_device = False
        return self.client

    def address_id(self, address):
        account_id, (change, address_index) = self.get_address_index(address)
        return "%s/%d/%d" % (account_id, change, address_index)

    def create_main_account(self, password):
        self.create_account('Main account', None) #name, empty password

    def derive_xkeys(self, root, derivation, password):
        derivation = derivation.replace(self.root_name,"44'/0'/")
        xpub = self.get_public_key(derivation)
        return xpub, None

    def get_public_key(self, bip32_path):
        address_n = self.get_client().expand_path(bip32_path)
        node = self.get_client().get_public_node(address_n).node
        xpub = "0488B21E".decode('hex') + chr(node.depth) + self.i4b(node.fingerprint) + self.i4b(node.child_num) + node.chain_code + node.public_key
        return EncodeBase58Check(xpub)

    def get_master_public_key(self):
        if not self.mpk:
            self.mpk = self.get_public_key("44'/0'")
        return self.mpk

    def i4b(self, x):
        return pack('>I', x)

    def add_keypairs(self, tx, keypairs, password):
        #do nothing - no priv keys available
        pass

    def decrypt_message(self, pubkey, message, password):
        address = public_key_to_bc_address(pubkey.decode('hex'))
        address_path = self.address_id(address)
        address_n = self.get_client().expand_path(address_path)
        try:
            decrypted_msg = self.get_client().decrypt_message(address_n, b64decode(message))
        except Exception, e:
            give_error(e)
        finally:
            twd.emit(SIGNAL('trezor_done'))
        return str(decrypted_msg)

    def sign_message(self, address, message, password):
        if not self.check_proper_device():
            give_error('Wrong device or password')
        try:
            address_path = self.address_id(address)
            address_n = self.get_client().expand_path(address_path)
        except Exception, e:
            give_error(e)
        try:
            msg_sig = self.get_client().sign_message('Bitcoin', address_n, message)
        except Exception, e:
            give_error(e)
        finally:
            twd.emit(SIGNAL('trezor_done'))
        b64_msg_sig = b64encode(msg_sig.signature)
        return str(b64_msg_sig)

    def sign_transaction(self, tx, keypairs, password):
        if tx.error or tx.is_complete():
            return

        if not self.check_proper_device():
            give_error('Wrong device or password')

        inputs = self.tx_inputs(tx)
        outputs = self.tx_outputs(tx)
        try:
            signed_tx = self.get_client().sign_tx('Bitcoin', inputs, outputs)[1]
        except Exception, e:
            give_error(e)
        finally:
            twd.emit(SIGNAL('trezor_done'))
        values = [i['value'] for i in tx.inputs]
        raw = signed_tx.encode('hex')
        tx.update(raw)
        for i, txinput in enumerate(tx.inputs):
            txinput['value'] = values[i]

    def tx_inputs(self, tx):
        inputs = []

        for txinput in tx.inputs:
            txinputtype = types.TxInputType()
            if ('is_coinbase' in txinput and txinput['is_coinbase']):
                prev_hash = "\0"*32
                prev_index = 0xffffffff # signed int -1
            else:
                address = txinput['address']
                try:
                    address_path = self.address_id(address)
                    address_n = self.get_client().expand_path(address_path)
                    txinputtype.address_n.extend(address_n)
                except: pass

                prev_hash = unhexlify(txinput['prevout_hash'])
                prev_index = txinput['prevout_n']

            txinputtype.prev_hash = prev_hash
            txinputtype.prev_index = prev_index

            if 'scriptSig' in txinput:
                script_sig = txinput['scriptSig']
                txinputtype.script_sig = script_sig

            if 'sequence' in txinput:
                sequence = txinput['sequence']
                txinputtype.sequence = sequence

            inputs.append(txinputtype)
            #TODO P2SH
        return inputs

    def tx_outputs(self, tx):
        outputs = []

        for type, address, amount in tx.outputs:
            assert type == 'address'
            txoutputtype = types.TxOutputType()
            if self.is_change(address):
                address_path = self.address_id(address)
                address_n = self.get_client().expand_path(address_path)
                txoutputtype.address_n.extend(address_n)
            else:
                txoutputtype.address = address
            txoutputtype.amount = amount
            addrtype, hash_160 = bc_address_to_hash_160(address)
            if addrtype == 0:
                txoutputtype.script_type = types.PAYTOADDRESS
            elif addrtype == 5:
                txoutputtype.script_type = types.PAYTOSCRIPTHASH
            else:
                raise BaseException('addrtype')
            outputs.append(txoutputtype)

        return outputs

    def electrum_tx_to_txtype(self, tx):
        t = types.TransactionType()
        d = deserialize(tx.raw)
        t.version = d['version']
        t.lock_time = d['lockTime']

        inputs = self.tx_inputs(tx)
        t.inputs.extend(inputs)

        for vout in d['outputs']:
            o = t.bin_outputs.add()
            o.amount = vout['value']
            o.script_pubkey = vout['scriptPubKey'].decode('hex')

        return t

    def get_tx(self, tx_hash):
        tx = self.transactions[tx_hash]
        return self.electrum_tx_to_txtype(tx)

    def check_proper_device(self):
        self.get_client().ping('t')
        if not self.device_checked:
            address = self.addresses(False, False)[0]
            address_id = self.address_id(address)
            n = self.get_client().expand_path(address_id)
            device_address = self.get_client().get_address('Bitcoin', n)
            self.device_checked = True

            if device_address != address:
                self.proper_device = False
            else:
                self.proper_device = True

        return self.proper_device

class TrezorQtGuiMixin(object):

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

    def callback_ButtonRequest(self, msg):
        if msg.code == 3:
            message = "Confirm transaction outputs on Trezor device to continue"
        elif msg.code == 8:
            message = "Confirm transaction fee on Trezor device to continue"
        elif msg.code == 7:
            message = "Confirm message to sign on Trezor device to continue"
        else:
            message = "Check Trezor device to continue"
        twd.start(message)
        return proto.ButtonAck()

    def callback_PinMatrixRequest(self, msg):
        if msg.type == 1:
            desc = 'current PIN'
        elif msg.type == 2:
            desc = 'new PIN'
        elif msg.type == 3:
            desc = 'new PIN again'
        else:
            desc = 'PIN'

        pin = self.pin_dialog(msg="Please enter Trezor %s" % desc)
        if not pin:
            return proto.Cancel()
        return proto.PinMatrixAck(pin=pin)

    def callback_PassphraseRequest(self, msg):
        confirmed, p, passphrase = self.password_dialog()
        if not confirmed:
            QMessageBox.critical(None, _('Error'), _("Password request canceled"), _('OK'))
            return proto.Cancel()
        if passphrase is None:
            passphrase='' # Even blank string is valid Trezor passphrase
        return proto.PassphraseAck(passphrase=passphrase)

    def callback_WordRequest(self, msg):
        #TODO
        log("Enter one word of mnemonic: ")
        word = raw_input()
        return proto.WordAck(word=word)

    def password_dialog(self, msg=None):
        if not msg:
            msg = _("Please enter your Trezor password")

        d = QDialog()
        d.setModal(1)
        d.setLayout( make_password_dialog(d, None, msg, False) )
        return run_password_dialog(d, None, None)

    def pin_dialog(self, msg):
        d = QDialog(None)
        d.setModal(1)
        d.setWindowTitle(_("Enter PIN"))
        matrix = PinMatrixWidget()

        vbox = QVBoxLayout()
        vbox.addWidget(QLabel(msg))
        vbox.addWidget(matrix)
        vbox.addLayout(ok_cancel_buttons(d))
        d.setLayout(vbox)

        if not d.exec_(): return
        return str(matrix.get_value())

class TrezorWaitingDialog(QThread):
    def __init__(self):
        QThread.__init__(self)
        self.waiting = False

    def start(self, message):
        self.d = QDialog()
        self.d.setModal(1)
        self.d.setWindowTitle('Please Check Trezor Device')
        self.d.setWindowFlags(self.d.windowFlags() | QtCore.Qt.WindowStaysOnTopHint)
        l = QLabel(message)
        vbox = QVBoxLayout(self.d)
        vbox.addWidget(l)
        self.d.show()
        if not self.waiting:
            self.waiting = True
            self.d.connect(twd, SIGNAL('trezor_done'), self.stop)

    def stop(self):
        self.d.hide()
        self.waiting = False

if TREZOR:
    class QtGuiTrezorClient(ProtocolMixin, TrezorQtGuiMixin, BaseClient):
        def call_raw(self, msg):
            try:
                resp = BaseClient.call_raw(self, msg)
            except ConnectionError:
                self.bad = True
                raise

            return resp

    twd = TrezorWaitingDialog()

<|endoftext|>


<commit_before>#!/usr/bin/env python
from setuptools import find_packages
from reviewboard.extensions.packaging import setup

from reviewbotext import get_package_version

PACKAGE = "reviewbotext"

setup(
    name="Review Bot Extension",
    version=get_package_version(),
    license="MIT",
    description="A Review Board extension for communicating with Review Bot",
    author="Steven MacLeod",
    maintainer="Steven MacLeod",
    include_package_data=True,
    packages=find_packages(),
    entry_points={
        'reviewboard.extensions':
            'reviewbot = reviewbotext.extension:ReviewBotExtension',
    },
    install_requires=[
        'celery>=3.0',
    ],
    classifiers=[
        "Development Status :: 4 - Beta",
        "Environment :: Web Environment",
        "Intended Audience :: Developers",
        "License :: OSI Approved :: MIT License",
        "Operating System :: OS Independent",
        "Programming Language :: Python",
        "Topic :: Software Development",
    ],
)
<commit_msg>Require celery<4.0<commit_after>#!/usr/bin/env python
from setuptools import find_packages
from reviewboard.extensions.packaging import setup

from reviewbotext import get_package_version

PACKAGE = "reviewbotext"

setup(
    name="Review Bot Extension",
    version=get_package_version(),
    license="MIT",
    description="A Review Board extension for communicating with Review Bot",
    author="Steven MacLeod",
    maintainer="Steven MacLeod",
    include_package_data=True,
    packages=find_packages(),
    entry_points={
        'reviewboard.extensions':
            'reviewbot = reviewbotext.extension:ReviewBotExtension',
    },
    install_requires=[
        'celery>=3.0,<4.0',
    ],
    classifiers=[
        "Development Status :: 4 - Beta",
        "Environment :: Web Environment",
        "Intended Audience :: Developers",
        "License :: OSI Approved :: MIT License",
        "Operating System :: OS Independent",
        "Programming Language :: Python",
        "Topic :: Software Development",
    ],
)
<|endoftext|>


<commit_before>import os
import socket
from pathlib import Path
from sys import stderr, stdout

import click
import yaml

if __name__ == '__main__':
    from ipdata import IPData
else:
    from .ipdata import IPData

class WrongAPIKey(Exception):
    pass

@click.group(help='CLI for IPData API')
def cli():
    pass

def get_api_key_path():
    home = str(Path.home())
    return os.path.join(home, '.ipdata')

def get_api_key():
    key_path = get_api_key_path()
    if os.path.exists(key_path):
        with open(key_path, 'r') as f:
            for line in f:
                if line:
                    return line
    else:
        return None

def get_my_ip():
    hostname = socket.gethostname()
    return socket.gethostbyname(hostname)

def get_and_check_api_key(api_key: str = None) -> str:
    if api_key is None:
        api_key = get_api_key()
    if api_key is None:
        print(f'Please specify IPData API Key', file=stderr)
        raise WrongAPIKey
    return api_key

@click.command()
@click.argument('api_key', type=str)
def init(api_key):
    key_path = get_api_key_path()

    ipdata = IPData(api_key)
    res = ipdata.lookup('8.8.8.8')
    if res['status'] == 200:
        try:
            existing_api_key = get_and_check_api_key()
            print(f'Warning: You already have an IPData API Key "{existing_api_key}" listed in {key_path}. '
                  f'It will be overwritten with {api_key}',
                  file=stderr)
        except WrongAPIKey:
            pass

        with open(key_path, 'w') as f:
            f.write(api_key)
        print(f'New API Key is saved to {key_path}')
    else:
        print(f'Failed to check the API Key (Error: {res["status"]}): {res["message"]}',
              file=stderr)

def json_filter(json, fields):
    res = dict()
    for name in fields:
        if name in json:
            res[name] = json[name]
        elif name.find('.') != -1:
            parts = name.split('.')
            part = parts[0] if len(parts) > 1 else None
            if part and part in json:
                sub_value = json_filter(json[part], ('.'.join(parts[1:]), ))
                if isinstance(sub_value, dict):
                    if part not in res:
                        res[part] = sub_value
                    else:
                        res[part] = {**res[part], **sub_value}
                else:
                    res[part] = sub_value
        else:
            pass
    return res

@click.command()
@click.option('--api_key', required=False, default=None, help='IPData API Key')
def myip(api_key):
    try:
        res = IPData(get_and_check_api_key(api_key)).lookup(get_my_ip())
        yaml.dump(res, stdout)
    except ValueError as e:
        print(f'Error: IP address {e}', file=stderr)

def lookup_field(data, field):
    if field in data:
        return field, data[field]
    elif '.' in field:
        parent, children = field.split('.')
        parent_field, parent_data = lookup_field(data, parent)
        if parent_field:
            children_field, children_data = lookup_field(parent_data, children)
            return parent_field, {parent_field: children_data}
    return None, None

@click.command()
@click.argument('ip', type=str)
@click.argument('fields', type=str, nargs=-1)
@click.option('--api_key', required=False, default=None, help='IPData API Key')
def ip(ip, fields, api_key):
    try:
        res = IPData(get_and_check_api_key(api_key)).lookup(ip)
        if len(fields) > 0:
            yaml.dump(json_filter(res, fields), stdout)
        else:
            yaml.dump(res, stdout)
    except ValueError as e:
        print(f'Error: IP address {e}', file=stderr)

cli.add_command(init)
cli.add_command(myip)
cli.add_command(ip)

if __name__ == '__main__':
    cli()
<commit_msg>Implemented: 'info' command<commit_after>import os
import socket
from pathlib import Path
from sys import stderr, stdout

import click
import yaml

if __name__ == '__main__':
    from ipdata import IPData
else:
    from .ipdata import IPData

class WrongAPIKey(Exception):
    pass

@click.group(help='CLI for IPData API')
def cli():
    pass

def get_api_key_path():
    home = str(Path.home())
    return os.path.join(home, '.ipdata')

def get_api_key():
    key_path = get_api_key_path()
    if os.path.exists(key_path):
        with open(key_path, 'r') as f:
            for line in f:
                if line:
                    return line
    else:
        return None

def get_my_ip():
    hostname = socket.gethostname()
    return socket.gethostbyname(hostname)

def get_and_check_api_key(api_key: str = None) -> str:
    if api_key is None:
        api_key = get_api_key()
    if api_key is None:
        print(f'Please specify IPData API Key', file=stderr)
        raise WrongAPIKey
    return api_key

@click.command()
@click.argument('api_key', type=str)
def init(api_key):
    key_path = get_api_key_path()

    ipdata = IPData(api_key)
    res = ipdata.lookup('8.8.8.8')
    if res['status'] == 200:
        try:
            existing_api_key = get_and_check_api_key()
            print(f'Warning: You already have an IPData API Key "{existing_api_key}" listed in {key_path}. '
                  f'It will be overwritten with {api_key}',
                  file=stderr)
        except WrongAPIKey:
            pass

        with open(key_path, 'w') as f:
            f.write(api_key)
        print(f'New API Key is saved to {key_path}')
    else:
        print(f'Failed to check the API Key (Error: {res["status"]}): {res["message"]}',
              file=stderr)

def json_filter(json, fields):
    res = dict()
    for name in fields:
        if name in json:
            res[name] = json[name]
        elif name.find('.') != -1:
            parts = name.split('.')
            part = parts[0] if len(parts) > 1 else None
            if part and part in json:
                sub_value = json_filter(json[part], ('.'.join(parts[1:]), ))
                if isinstance(sub_value, dict):
                    if part not in res:
                        res[part] = sub_value
                    else:
                        res[part] = {**res[part], **sub_value}
                else:
                    res[part] = sub_value
        else:
            pass
    return res

@click.command()
@click.option('--api_key', required=False, default=None, help='IPData API Key')
def myip(api_key):
    try:
        res = IPData(get_and_check_api_key(api_key)).lookup(get_my_ip())
        yaml.dump(res, stdout)
    except ValueError as e:
        print(f'Error: IP address {e}', file=stderr)

def lookup_field(data, field):
    if field in data:
        return field, data[field]
    elif '.' in field:
        parent, children = field.split('.')
        parent_field, parent_data = lookup_field(data, parent)
        if parent_field:
            children_field, children_data = lookup_field(parent_data, children)
            return parent_field, {parent_field: children_data}
    return None, None

@click.command()
@click.argument('ip', type=str)
@click.argument('fields', type=str, nargs=-1)
@click.option('--api_key', required=False, default=None, help='IPData API Key')
def ip(ip, fields, api_key):
    try:
        res = IPData(get_and_check_api_key(api_key)).lookup(ip)
        if len(fields) > 0:
            yaml.dump(json_filter(res, fields), stdout)
        else:
            yaml.dump(res, stdout)
    except ValueError as e:
        print(f'Error: IP address {e}', file=stderr)

@click.command()
@click.option('--api_key', required=False, default=None, help='IPData API Key')
def info(api_key):
    res = IPData(get_and_check_api_key(api_key)).lookup('8.8.8.8')
    print(f'Number of requests made: {res["count"]}')

cli.add_command(init)
cli.add_command(myip)
cli.add_command(ip)
cli.add_command(info)

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


<commit_before># -*- coding: utf-8 -*-
from loading import load_plugins, register_plugin

__author__ = 'Matti Gruener'
__email__ = 'matti@mistermatti.com'
__version__ = '0.1.0'

__ALL__ = [load_plugins, register_plugin]
<commit_msg>add plugin types to the __init__<commit_after># -*- coding: utf-8 -*-
from loading import load_plugins, register_plugin
from plugz import PluginTypeBase
from plugintypes import StandardPluginType

__author__ = 'Matti Gruener'
__email__ = 'matti@mistermatti.com'
__version__ = '0.1.0'

__ALL__ = [load_plugins, register_plugin, StandardPluginType, PluginTypeBase]
<|endoftext|>


<commit_before># Given an array of ints, return True if the array contains a 2 next to a 2
# somewhere.

def has22(nums):
    for i in range (1, len(nums)):
        if nums[i-1] == 2 and nums[i] == 2:
            return True
    # this will only happen if the if statement above is never True
    return False
<commit_msg>centered average problem from the bat<commit_after># Return the "centered" average of an array of ints, which we'll say is the mean
# average of the values, except ignoring the largest and smallest values in the
# array. If there are multiple copies of the smallest value, ignore just one
# copy, and likewise for the largest value. Use int division to produce the final
# average. You may assume that the array is length 3 or more.

def centered_average(nums):
    nums.sort()
    list_without_ends = nums[1:-1]
    sum = 0
    for num in list_without_ends:
        sum += num
    return sum / len(list_without_ends)
<|endoftext|>


<commit_before>import sys
import dbus

import core.module
import core.widget
import core.input
import core.decorators
"""Displays the current song being played

Requires the following library:
    * python-dbus

Parameters:
    * spotify-buttons.format:   Format string (defaults to '{artist} - {title}')
      Available values are: {album}, {title}, {artist}, {trackNumber}, {playbackStatus}
    * spotify-buttons.layout:
"""

class Module(core.module.Module):
    def __init__(self, config, theme):
        super().__init__(config, theme, core.widget.Widget(self.spotify))

        self.__layout = self.parameter("layout", "spotify-buttons.prev spotify-buttons.pause spotify-buttons.next")

        self.__song = ""
        self.__format = self.parameter("format", "{artist} - {title}")
        prev_button = self.parameter("previous", "LEFT_CLICK")
        next_button = self.parameter("next", "RIGHT_CLICK")
        pause_button = self.parameter("pause", "MIDDLE_CLICK")

        cmd = "dbus-send --session --type=method_call --dest=org.mpris.MediaPlayer2.spotify \
                /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player."
        #core.input.register(self, button=buttons[prev_button], cmd=cmd + "Previous")
        #core.input.register(self, button=buttons[next_button], cmd=cmd + "Next")
        #core.input.register(self, button=buttons[pause_button], cmd=cmd + "PlayPause")

        widget_map = {}
        for widget in self.__layout.split():
            widget = self.add_widget(name = widget_name)
            if widget_name = "spotify-buttons.prev":
                widget_map[widget] = {
                    "button": core.input.LEFT_MOUSE,
                    "cmd": cmd + "Previous",
                }
            elif widget_name = "spotify-buttons.pause":
                widget_map[widget] = {
                    "button": core.input.LEFT_MOUSE,
                    "cmd": cmd + "PlayPause",
                }
            elif widget_name = "spotify-buttons.next":
                widget_map[widget] = {
                    "button": core.input.LEFT_MOUSE,
                    "cmd": cmd + "Next",
                }

    @core.decorators.scrollable
    def spotify(self, widget):
        return self.string_song

    def hidden(self):
        return self.string_song == ""

    def update(self):
        try:
            bus = dbus.SessionBus()
            spotify = bus.get_object(
                "org.mpris.MediaPlayer2.spotify", "/org/mpris/MediaPlayer2"
            )
            spotify_iface = dbus.Interface(spotify, "org.freedesktop.DBus.Properties")
            props = spotify_iface.Get("org.mpris.MediaPlayer2.Player", "Metadata")
            playback_status = str(
                spotify_iface.Get("org.mpris.MediaPlayer2.Player", "PlaybackStatus")
            )
            self.__song = self.__format.format(
                album=str(props.get("xesam:album")),
                title=str(props.get("xesam:title")),
                artist=",".join(props.get("xesam:artist")),
                trackNumber=str(props.get("xesam:trackNumber")),
                playbackStatus="\u25B6"
                if playback_status == "Playing"
                else "\u258D\u258D"
                if playback_status == "Paused"
                else "",
            )

        except Exception:
            self.__song = ""

    @property
    def string_song(self):
        if sys.version_info.major < 3:
            return unicode(self.__song)
        return str(self.__song)
<commit_msg>create + map widgets for buttons<commit_after>import sys
import dbus

import core.module
import core.widget
import core.input
import core.decorators
"""Displays the current song being played

Requires the following library:
    * python-dbus

Parameters:
    * spotify-buttons.format:   Format string (defaults to '{artist} - {title}')
      Available values are: {album}, {title}, {artist}, {trackNumber}, {playbackStatus}
    * spotify-buttons.layout:
"""

class Module(core.module.Module):
    def __init__(self, config, theme):
        super().__init__(config, theme, core.widget.Widget(self.spotify))

        self.__layout = self.parameter("layout", "spotify-buttons.prev spotify-buttons.pause spotify-buttons.next")

        self.__song = ""
        self.__format = self.parameter("format", "{artist} - {title}")
        prev_button = self.parameter("previous", "LEFT_CLICK")
        next_button = self.parameter("next", "RIGHT_CLICK")
        pause_button = self.parameter("pause", "MIDDLE_CLICK")

        cmd = "dbus-send --session --type=method_call --dest=org.mpris.MediaPlayer2.spotify \
                /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player."

        widget_map = {}
        for widget_name in self.__layout.split():
            widget = self.add_widget(name = widget_name)
            if widget_name == "spotify-buttons.prev":
                widget_map[widget] = {
                    "button": core.input.LEFT_MOUSE,
                    "cmd": cmd + "Previous",
                }
            elif widget_name == "spotify-buttons.pause":
                widget_map[widget] = {
                    "button": core.input.LEFT_MOUSE,
                    "cmd": cmd + "PlayPause",
                }
            elif widget_name == "spotify-buttons.next":
                widget_map[widget] = {
                    "button": core.input.LEFT_MOUSE,
                    "cmd": cmd + "Next",
                }
        for widget, callback_options in widget_map.items():
            core.input.register(widget, **callback_options)

    @core.decorators.scrollable
    def spotify(self, widget):
        return self.string_song

    def hidden(self):
        return self.string_song == ""

    def update(self):
        try:
            bus = dbus.SessionBus()
            spotify = bus.get_object(
                "org.mpris.MediaPlayer2.spotify", "/org/mpris/MediaPlayer2"
            )
            spotify_iface = dbus.Interface(spotify, "org.freedesktop.DBus.Properties")
            props = spotify_iface.Get("org.mpris.MediaPlayer2.Player", "Metadata")
            playback_status = str(
                spotify_iface.Get("org.mpris.MediaPlayer2.Player", "PlaybackStatus")
            )
            self.__song = self.__format.format(
                album=str(props.get("xesam:album")),
                title=str(props.get("xesam:title")),
                artist=",".join(props.get("xesam:artist")),
                trackNumber=str(props.get("xesam:trackNumber")),
                playbackStatus="\u25B6"
                if playback_status == "Playing"
                else "\u258D\u258D"
                if playback_status == "Paused"
                else "",
            )

        except Exception:
            self.__song = ""

    @property
    def string_song(self):
        if sys.version_info.major < 3:
            return unicode(self.__song)
        return str(self.__song)
<|endoftext|>


<commit_before>"""
Module contains current pmagpy version number.
Version number is displayed by GUIs
and used by setuptools to assign number to pmagpy/pmagpy-cli.
"""

"pmagpy-3.18.0"
version = 'pmagpy-3.18.0'
<commit_msg>increment version #<commit_after>"""
Module contains current pmagpy version number.
Version number is displayed by GUIs
and used by setuptools to assign number to pmagpy/pmagpy-cli.
"""

"pmagpy-3.19.0"
version = 'pmagpy-3.19.0'
<|endoftext|>