<commit_before>from dmutils.audit import AuditTypes
from flask import jsonify, abort, request, current_app

from sqlalchemy.exc import IntegrityError
from sqlalchemy import asc
from sqlalchemy.types import String

from .. import main
from ... import db
from ...utils import drop_foreign_fields, json_has_required_keys
from ...validation import is_valid_service_id_or_400
from ...models import Service, DraftService, Supplier, AuditEvent, Framework
from ...service_utils import validate_and_return_updater_request, update_and_validate_service, index_service, \
    validate_service, commit_and_archive_service, create_service_from_draft
from ...draft_utils import validate_and_return_draft_request, get_draft_validation_errors

@main.route('/draft-services/copy-from/<string:service_id>', methods=['PUT'])
def copy_draft_service_from_existing_service(service_id):
    """
    Create a draft service from an existing service
    :param service_id:
    :return:
    """
    is_valid_service_id_or_400(service_id)
    updater_json = validate_and_return_updater_request()

    service = Service.query.filter(
        Service.service_id == service_id
    ).first_or_404()

    draft_service = DraftService.query.filter(
        DraftService.service_id == service_id
    ).first()
    if draft_service:
        abort(400, "Draft already exists for service {}".format(service_id))

    draft = DraftService.from_service(service)

    db.session.add(draft)
    db.session.flush()

    audit = AuditEvent(
        audit_type=AuditTypes.create_draft_service,
        user=updater_json['updated_by'],
        data={
            "draftId": draft.id,
            "serviceId": service_id
        },
        db_object=draft
    )
    db.session.add(audit)

    try:
        db.session.commit()
    except IntegrityError as e:
        db.session.rollback()
        abort(400, "Database Error: {0}".format(e))

    return jsonify(services=draft.serialize()), 201

@main.route('/draft-services/<int:draft_id>', methods=['POST'])
def edit_draft_service(draft_id):
    """
    Edit a draft service
    :param draft_id:
    :return:
    """

    updater_json = validate_and_return_updater_request()
    update_json = validate_and_return_draft_request()
    page_questions = update_json.pop('page_questions', [])
    draft = DraftService.query.filter(
        DraftService.id == draft_id
    ).first_or_404()

    draft.update_from_json(update_json)
    errs = get_draft_validation_errors(draft.data,
                                       draft.data['lot'],
                                       framework_id=draft.framework_id,
                                       required=page_questions)
    if errs:
        abort(400, errs)

    audit = AuditEvent(
        audit_type=AuditTypes.update_draft_service,
        user=updater_json['updated_by'],
        data={
            "draftId": draft_id,
            "serviceId": draft.service_id,
            "updateJson": update_json
        },
        db_object=draft
    )

    db.session.add(draft)
    db.session.add(audit)

    try:
        db.session.commit()
    except IntegrityError as e:
        db.session.rollback()
        abort(400, "Database Error: {0}".format(e))

    return jsonify(services=draft.serialize()), 200

@main.route('/draft-services', methods=['GET'])
def list_draft_services():
    supplier_id = request.args.get('supplier_id')
    service_id = request.args.get('service_id')
    framework_slug = request.args.get('framework')
    if supplier_id is None:
        abort(400, "Invalid page argument: supplier_id is required")
    try:
        supplier_id = int(supplier_id)
    except ValueError:
        abort(400, "Invalid supplier_id: %s" % supplier_id)

    supplier = Supplier.query.filter(Supplier.supplier_id == supplier_id).all()
    if not supplier:
        abort(404, "supplier_id '%d' not found" % supplier_id)

    services = DraftService.query.order_by(
        asc(DraftService.framework_id),
        asc(DraftService.data['lot'].cast(String).label('data_lot')),
        asc(DraftService.data['serviceName'].
            cast(String).label('data_servicename'))
    )

    if service_id:
        is_valid_service_id_or_400(service_id)
        services = services.filter(DraftService.service_id == service_id)

    if framework_slug:
        framework = Framework.query.filter(
            Framework.slug == framework_slug
        ).first()
        services = services.filter(DraftService.framework_id == framework.id)

    items = services.filter(DraftService.supplier_id == supplier_id).all()
    return jsonify(
        services=[service.serialize() for service in items],
        links=dict()
    )

@main.route('/draft-services/<int:draft_id>', methods=['GET'])
def fetch_draft_service(draft_id):
    """
    Return a draft service
    :param draft_id:
    :return:
    """

    draft = DraftService.query.filter(
        DraftService.id == draft_id
    ).first_or_404()

    return jsonify(services=draft.serialize())

@main.route('/draft-services/<int:draft_id>', methods=['DELETE'])
def delete_draft_service(draft_id):
    """
    Delete a draft service
    :param draft_id:
    :return:
    """

    updater_json = validate_and_return_updater_request()

    draft = DraftService.query.filter(
        DraftService.id == draft_id
    ).first_or_404()

    audit = AuditEvent(
        audit_type=AuditTypes.delete_draft_service,
        user=updater_json['updated_by'],
        data={
            "draftId": draft_id,
            "serviceId": draft.service_id
        },
        db_object=None
    )

    db.session.delete(draft)
    db.session.add(audit)
    try:
        db.session.commit()
    except IntegrityError as e:
        db.session.rollback()
        abort(400, "Database Error: {0}".format(e))

    return jsonify(message="done"), 200

@main.route('/draft-services/<int:draft_id>/publish', methods=['POST'])
def publish_draft_service(draft_id):
    """
    Publish a draft service
    :param draft_id:
    :return:
    """

    update_details = validate_and_return_updater_request()

    draft = DraftService.query.filter(
        DraftService.id == draft_id
    ).first_or_404()

    if draft.service_id:
        service = Service.query.filter(
            Service.service_id == draft.service_id
        ).first_or_404()

        service_from_draft = update_and_validate_service(
            service,
            draft.data)

    else:
        service_from_draft = create_service_from_draft(draft, "enabled")

    commit_and_archive_service(service_from_draft, update_details,
                               AuditTypes.publish_draft_service,
                               audit_data={'draftId': draft_id})

    try:
        db.session.delete(draft)
        db.session.commit()
    except IntegrityError as e:
        db.session.rollback()
        current_app.logger.warning(
            'Failed to delete draft {} after publishing service {}: {}'.format(
                draft_id, service_from_draft.service_id, e.message)
        )

    index_service(service_from_draft)

    return jsonify(services=service_from_draft.serialize()), 200

@main.route('/draft-services/<string:framework_slug>/create', methods=['POST'])
def create_new_draft_service(framework_slug):
    """
    Create a new draft service with lot, supplier_id, draft_id, framework_id
    :return: the new draft id and location e.g.
    HTTP/1.1 201 Created Location: /draft-services/63636
    """
    updater_json = validate_and_return_updater_request()
    draft_json = validate_and_return_draft_request()
    json_has_required_keys(draft_json, ['lot', 'supplierId'])

    framework = Framework.query.filter(
        Framework.slug == framework_slug
    ).first()

    if framework.status != 'open':
        abort(400, "'{}' is not open for submissions".format(framework_slug))

    supplier_id = draft_json['supplierId']
    lot = draft_json['lot']
    errs = get_draft_validation_errors(draft_json, lot, slug=framework_slug)
    if errs:
        return jsonify(errors=errs), 400

    draft_json = drop_foreign_fields(draft_json, ['supplierId'])
    draft = DraftService(
        framework_id=framework.id,
        supplier_id=supplier_id,
        data=draft_json,
        status="not-submitted"
    )
    try:
        db.session.add(draft)
        db.session.flush()

        audit = AuditEvent(
            audit_type=AuditTypes.create_draft_service,
            user=updater_json['updated_by'],
            data={
                "draftId": draft.id
            },
            db_object=draft
        )
        db.session.add(audit)

        db.session.commit()
    except IntegrityError as e:
        db.session.rollback()
        abort(400, "Database Error: {0}".format(e))

    return jsonify(services=draft.serialize()), 201

@main.route('/draft-services/<int:draft_id>/copy', methods=['POST'])
def copy_draft_service(draft_id):
    updater_json = validate_and_return_updater_request()

    original_draft = DraftService.query.filter(
        DraftService.id == draft_id
    ).first_or_404()

    draft_copy = original_draft.copy()

    try:
        db.session.add(draft_copy)
        db.session.flush()

        audit = AuditEvent(
            audit_type=AuditTypes.create_draft_service,
            user=updater_json['updated_by'],
            data={
                "draftId": draft_copy.id,
                "originalDraftId": original_draft.id,
            },
            db_object=draft_copy
        )
        db.session.add(audit)

        db.session.commit()
    except IntegrityError as e:
        db.session.rollback()
        abort(400, "Database Error: {0}".format(e))

    return jsonify(services=draft_copy.serialize()), 201
<commit_msg>Order drafts by id instead of serviceName<commit_after>from dmutils.audit import AuditTypes
from flask import jsonify, abort, request, current_app

from sqlalchemy.exc import IntegrityError
from sqlalchemy import asc
from sqlalchemy.types import String

from .. import main
from ... import db
from ...utils import drop_foreign_fields, json_has_required_keys
from ...validation import is_valid_service_id_or_400
from ...models import Service, DraftService, Supplier, AuditEvent, Framework
from ...service_utils import validate_and_return_updater_request, \
    update_and_validate_service, index_service, \
    commit_and_archive_service, create_service_from_draft
from ...draft_utils import validate_and_return_draft_request, get_draft_validation_errors

@main.route('/draft-services/copy-from/<string:service_id>', methods=['PUT'])
def copy_draft_service_from_existing_service(service_id):
    """
    Create a draft service from an existing service
    :param service_id:
    :return:
    """
    is_valid_service_id_or_400(service_id)
    updater_json = validate_and_return_updater_request()

    service = Service.query.filter(
        Service.service_id == service_id
    ).first_or_404()

    draft_service = DraftService.query.filter(
        DraftService.service_id == service_id
    ).first()
    if draft_service:
        abort(400, "Draft already exists for service {}".format(service_id))

    draft = DraftService.from_service(service)

    db.session.add(draft)
    db.session.flush()

    audit = AuditEvent(
        audit_type=AuditTypes.create_draft_service,
        user=updater_json['updated_by'],
        data={
            "draftId": draft.id,
            "serviceId": service_id
        },
        db_object=draft
    )
    db.session.add(audit)

    try:
        db.session.commit()
    except IntegrityError as e:
        db.session.rollback()
        abort(400, "Database Error: {0}".format(e))

    return jsonify(services=draft.serialize()), 201

@main.route('/draft-services/<int:draft_id>', methods=['POST'])
def edit_draft_service(draft_id):
    """
    Edit a draft service
    :param draft_id:
    :return:
    """

    updater_json = validate_and_return_updater_request()
    update_json = validate_and_return_draft_request()
    page_questions = update_json.pop('page_questions', [])
    draft = DraftService.query.filter(
        DraftService.id == draft_id
    ).first_or_404()

    draft.update_from_json(update_json)
    errs = get_draft_validation_errors(draft.data,
                                       draft.data['lot'],
                                       framework_id=draft.framework_id,
                                       required=page_questions)
    if errs:
        abort(400, errs)

    audit = AuditEvent(
        audit_type=AuditTypes.update_draft_service,
        user=updater_json['updated_by'],
        data={
            "draftId": draft_id,
            "serviceId": draft.service_id,
            "updateJson": update_json
        },
        db_object=draft
    )

    db.session.add(draft)
    db.session.add(audit)

    try:
        db.session.commit()
    except IntegrityError as e:
        db.session.rollback()
        abort(400, "Database Error: {0}".format(e))

    return jsonify(services=draft.serialize()), 200

@main.route('/draft-services', methods=['GET'])
def list_draft_services():
    supplier_id = request.args.get('supplier_id')
    service_id = request.args.get('service_id')
    framework_slug = request.args.get('framework')
    if supplier_id is None:
        abort(400, "Invalid page argument: supplier_id is required")
    try:
        supplier_id = int(supplier_id)
    except ValueError:
        abort(400, "Invalid supplier_id: %s" % supplier_id)

    supplier = Supplier.query.filter(Supplier.supplier_id == supplier_id).all()
    if not supplier:
        abort(404, "supplier_id '%d' not found" % supplier_id)

    services = DraftService.query.order_by(
        asc(DraftService.framework_id),
        asc(DraftService.data['lot'].cast(String).label('data_lot')),
        asc(DraftService.id)
    )

    if service_id:
        is_valid_service_id_or_400(service_id)
        services = services.filter(DraftService.service_id == service_id)

    if framework_slug:
        framework = Framework.query.filter(
            Framework.slug == framework_slug
        ).first()
        services = services.filter(DraftService.framework_id == framework.id)

    items = services.filter(DraftService.supplier_id == supplier_id).all()
    return jsonify(
        services=[service.serialize() for service in items],
        links=dict()
    )

@main.route('/draft-services/<int:draft_id>', methods=['GET'])
def fetch_draft_service(draft_id):
    """
    Return a draft service
    :param draft_id:
    :return:
    """

    draft = DraftService.query.filter(
        DraftService.id == draft_id
    ).first_or_404()

    return jsonify(services=draft.serialize())

@main.route('/draft-services/<int:draft_id>', methods=['DELETE'])
def delete_draft_service(draft_id):
    """
    Delete a draft service
    :param draft_id:
    :return:
    """

    updater_json = validate_and_return_updater_request()

    draft = DraftService.query.filter(
        DraftService.id == draft_id
    ).first_or_404()

    audit = AuditEvent(
        audit_type=AuditTypes.delete_draft_service,
        user=updater_json['updated_by'],
        data={
            "draftId": draft_id,
            "serviceId": draft.service_id
        },
        db_object=None
    )

    db.session.delete(draft)
    db.session.add(audit)
    try:
        db.session.commit()
    except IntegrityError as e:
        db.session.rollback()
        abort(400, "Database Error: {0}".format(e))

    return jsonify(message="done"), 200

@main.route('/draft-services/<int:draft_id>/publish', methods=['POST'])
def publish_draft_service(draft_id):
    """
    Publish a draft service
    :param draft_id:
    :return:
    """

    update_details = validate_and_return_updater_request()

    draft = DraftService.query.filter(
        DraftService.id == draft_id
    ).first_or_404()

    if draft.service_id:
        service = Service.query.filter(
            Service.service_id == draft.service_id
        ).first_or_404()

        service_from_draft = update_and_validate_service(
            service,
            draft.data)

    else:
        service_from_draft = create_service_from_draft(draft, "enabled")

    commit_and_archive_service(service_from_draft, update_details,
                               AuditTypes.publish_draft_service,
                               audit_data={'draftId': draft_id})

    try:
        db.session.delete(draft)
        db.session.commit()
    except IntegrityError as e:
        db.session.rollback()
        current_app.logger.warning(
            'Failed to delete draft {} after publishing service {}: {}'.format(
                draft_id, service_from_draft.service_id, e.message)
        )

    index_service(service_from_draft)

    return jsonify(services=service_from_draft.serialize()), 200

@main.route('/draft-services/<string:framework_slug>/create', methods=['POST'])
def create_new_draft_service(framework_slug):
    """
    Create a new draft service with lot, supplier_id, draft_id, framework_id
    :return: the new draft id and location e.g.
    HTTP/1.1 201 Created Location: /draft-services/63636
    """
    updater_json = validate_and_return_updater_request()
    draft_json = validate_and_return_draft_request()
    json_has_required_keys(draft_json, ['lot', 'supplierId'])

    framework = Framework.query.filter(
        Framework.slug == framework_slug
    ).first()

    if framework.status != 'open':
        abort(400, "'{}' is not open for submissions".format(framework_slug))

    supplier_id = draft_json['supplierId']
    lot = draft_json['lot']
    errs = get_draft_validation_errors(draft_json, lot, slug=framework_slug)
    if errs:
        return jsonify(errors=errs), 400

    draft_json = drop_foreign_fields(draft_json, ['supplierId'])
    draft = DraftService(
        framework_id=framework.id,
        supplier_id=supplier_id,
        data=draft_json,
        status="not-submitted"
    )
    try:
        db.session.add(draft)
        db.session.flush()

        audit = AuditEvent(
            audit_type=AuditTypes.create_draft_service,
            user=updater_json['updated_by'],
            data={
                "draftId": draft.id
            },
            db_object=draft
        )
        db.session.add(audit)

        db.session.commit()
    except IntegrityError as e:
        db.session.rollback()
        abort(400, "Database Error: {0}".format(e))

    return jsonify(services=draft.serialize()), 201

@main.route('/draft-services/<int:draft_id>/copy', methods=['POST'])
def copy_draft_service(draft_id):
    updater_json = validate_and_return_updater_request()

    original_draft = DraftService.query.filter(
        DraftService.id == draft_id
    ).first_or_404()

    draft_copy = original_draft.copy()

    try:
        db.session.add(draft_copy)
        db.session.flush()

        audit = AuditEvent(
            audit_type=AuditTypes.create_draft_service,
            user=updater_json['updated_by'],
            data={
                "draftId": draft_copy.id,
                "originalDraftId": original_draft.id,
            },
            db_object=draft_copy
        )
        db.session.add(audit)

        db.session.commit()
    except IntegrityError as e:
        db.session.rollback()
        abort(400, "Database Error: {0}".format(e))

    return jsonify(services=draft_copy.serialize()), 201
<|endoftext|>


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

from random import sample

import geojson
import shapely.geometry as sgeom
from notifications_utils.safe_string import make_string_safe_for_id

import cartopy.crs as ccrs
import cartopy.feature as cfeature
import matplotlib.pyplot as plt
from repo import BroadcastAreasRepository

def main():

    print()  # noqa: T001
    print("pick a library")  # noqa: T001
    for library in BroadcastAreasRepository().get_libraries():
        print("  ", library)  # noqa: T001

    library = input("> ")
    lid = make_string_safe_for_id(library)

    features = []
    simple_features = []

    inp = ""
    while True:
        print()  # noqa: T001
        print("pick an area, or press enter to skip")  # noqa: T001

        all_areas = BroadcastAreasRepository().get_all_areas_for_library(lid)
        some_areas = sample(all_areas, min(len(all_areas), 25))
        for area in some_areas:
            print("  ", area[0], area[1])  # noqa: T001

        inp = input("> ")
        if inp == "":
            break

        aid = inp.strip()
        area = BroadcastAreasRepository().get_areas([aid])[0]

        feature = area[-2]
        feature_shape = sgeom.shape(geojson.loads(feature)["geometry"])
        features.append(feature_shape)

        simple_feature = area[-1]
        simple_feature_shape = sgeom.shape(geojson.loads(simple_feature)["geometry"])
        simple_features.append(simple_feature_shape)

    print()  # noqa: T001
    print("Plotting")  # noqa: T001

    fig = plt.figure()
    ax = fig.add_subplot(1, 1, 1, projection=ccrs.PlateCarree())
    ax.set_extent([-20, 5, 40, 60], crs=ccrs.PlateCarree())

    ax.add_feature(cfeature.LAND)
    ax.add_feature(cfeature.OCEAN)
    ax.add_feature(cfeature.COASTLINE)
    ax.add_feature(cfeature.BORDERS, linestyle=':')

    ax.add_geometries(
        features,
        ccrs.PlateCarree(),
        facecolor='#00ff00',
        alpha=0.25,
    )

    ax.add_geometries(
        simple_features,
        ccrs.PlateCarree(),
        facecolor='#0000ff',
        alpha=0.25,
    )

    ax.scatter(
        [
            p[0]
            for f in simple_features
            for geom in (f.geoms if hasattr(f, 'geoms') else [f])
            for p in geom.exterior.coords
        ],
        [
            p[1]
            for f in simple_features
            for geom in (f.geoms if hasattr(f, 'geoms') else [f])
            for p in geom.exterior.coords
        ],
        transform=ccrs.PlateCarree(),
    )

    plt.show()

if __name__ == '__main__':
    main()
<commit_msg>Delete plot-areas.py<commit_after><|endoftext|>


<commit_before>__all__ = [
    'WaterColumnController',
    'WaterTempController',
]

KC_LEVEL = 1200.0
HREF = 1.5

WATER_CAPACITANCE = 50000000.0
KC_TEMP = 0.15 * WATER_CAPACITANCE
TREF = 50.0

class BaseController(object):

    def __init__(self, conn, queue, kc, ref):
        self.conn = conn
        self._queue = queue
        self.kc = kc
        self.ref = ref

    def get_sensor_value(self):
        return self.queue.get()

    def run(self):
        while True:
            value = self.get_sensor_value()
            value = self.kc * (self.ref * value)
            self.set_actuator(value)

    def set_actuator_value(self, value):
        raise NotImplementedError

class WaterColumnController(BaseController):

    def __init__(self, conn, queue):
        super(WaterColumnController, self).__init__(
            conn,
            queue,
            KC_LEVEL,
            HREF,
        )

    def set_actuator_value(self, value):
        self.conn.water_flux = value

class WaterTempController(BaseController):

    def __init__(self, conn, queue):
        super(WaterTempController, self).__init__(
            conn,
            queue,
            KC_TEMP,
            TREF,
        )

    def set_actuator_value(self, value):
        self.conn.heat_flux = value
<commit_msg>Fix typos<commit_after>__all__ = [
    'WaterColumnController',
    'WaterTempController',
]

KC_LEVEL = 1200.0
HREF = 1.5

WATER_CAPACITANCE = 50000000.0
KC_TEMP = 0.15 * WATER_CAPACITANCE
TREF = 50.0

class BaseController(object):

    def __init__(self, conn, queue, kc, ref):
        self.conn = conn
        self._queue = queue
        self.kc = kc
        self.ref = ref

    def get_sensor_value(self):
        return self._queue.get()

    def run(self):
        while True:
            value = self.get_sensor_value()
            value = self.kc * (self.ref * value)
            self.set_actuator_value(value)

    def set_actuator_value(self, value):
        raise NotImplementedError

class WaterColumnController(BaseController):

    def __init__(self, conn, queue):
        super(WaterColumnController, self).__init__(
            conn,
            queue,
            KC_LEVEL,
            HREF,
        )

    def set_actuator_value(self, value):
        self.conn.water_flux = value

class WaterTempController(BaseController):

    def __init__(self, conn, queue):
        super(WaterTempController, self).__init__(
            conn,
            queue,
            KC_TEMP,
            TREF,
        )

    def set_actuator_value(self, value):
        self.conn.heat_flux = value
<|endoftext|>


<commit_before>import inflection
import inspect
import os
import sys
import yaml

from cashew.exceptions import *

class Plugin(object):
    """
    Base class for plugins. Define instance methods shared by plugins here.
    """
    aliases = []
    _settings = {}

    def is_active(self):
        return True

    def name(self):
        return inflection.titleize(self.setting('aliases')[0])

    def help(self):
        return self.setting('help')

    def initialize_settings(self, **raw_kwargs):
        self._instance_settings = {}
        for parent_class in self.__class__.imro():
            if parent_class._settings:
                self.__class__.class_update_settings(self, parent_class._settings)
            if hasattr(parent_class, 'UNSET'):
                for unset in parent_class.UNSET:
                    del self._instance_settings[unset]

        if hasattr(self.__class__, 'aliases') and self.__class__.aliases:
            alias = self.__class__.aliases[0]
            settings_from_other_classes = PluginMeta._store_other_class_settings.get(alias)
            if settings_from_other_classes:
                self.__class__.class_update_settings(self, settings_from_other_classes)

        # Apply raw_kwargs settings
        hyphen_settings = dict((k, v) for k, v in raw_kwargs.items() if k in self._instance_settings)
        underscore_settings = dict((k.replace("_", "-"), v) for k, v in raw_kwargs.items() if k.replace("_", "-") in self._instance_settings)
        self.__class__.class_update_settings(self, hyphen_settings)
        self.__class__.class_update_settings(self, underscore_settings)

    def safe_setting(self, name_hyphen, default=None):
        """
        Retrieves the setting value, but returns a default value rather than
        raising an error if the setting does not exist.
        """
        try:
            return self.setting(name_hyphen)
        except UserFeedback:
            return default

    def setting(self, name_hyphen):
        """
        Retrieves the setting value whose name is indicated by name_hyphen.

        Values starting with $ are assumed to reference environment variables,
        and the value stored in environment variables is retrieved. (It's an
        error if there's no corresponding environment variable set.)
        """
        if name_hyphen in self._instance_settings:
            value = self._instance_settings[name_hyphen][1]
        else:
            name_underscore = name_hyphen.replace("-", "_")
            if name_underscore in self._instance_settings:
                value = self._instance_settings[name_underscore][1]
            else:
                if name_underscore == name_hyphen:
                    msg = "No setting named '%s'" % name_hyphen
                else:
                    msg = "no setting named '%s' or '%s'"
                    msg = msg % (name_hyphen, name_underscore)
                raise UserFeedback(msg)

        if hasattr(value, 'startswith') and value.startswith("$"):
            env_var = value.lstrip("$")
            if os.environ.has_key(env_var):
                return os.getenv(env_var)
            else:
                msg = "'%s' is not defined in your environment" % env_var
                raise UserFeedback(msg)
        elif hasattr(value, 'startswith') and value.startswith("\$"):
            return value.replace("\$", "$")
        else:
            return value

    def setting_values(self, skip=None):
        """
        Returns dict of all setting values (removes the helpstrings)
        """
        if not skip:
            skip = []
        return dict((k, v[1]) for k, v in self._instance_settings.iteritems() if not k in skip)

    def update_settings(self, new_settings):
        self.__class__.class_update_settings(self, new_settings, False)

class PluginMeta(type):
    """
    Base meta class for anything plugin-able.
    """
    _store_other_class_settings = {} # allow plugins to define settings for other classes

    def __init__(cls, name, bases, attrs):
        assert issubclass(cls, Plugin), "%s should inherit from class Plugin" % name
        if '__metaclass__' in attrs:
            cls.plugins = {}
        elif hasattr(cls, 'aliases'):
            cls.register_plugin(cls.aliases, cls, {})

    def register_plugin(cls, alias_or_aliases, class_or_class_name, settings):
        aliases = cls.standardize_alias_or_aliases(alias_or_aliases)
        klass = cls.get_reference_to_class(class_or_class_name)

        # Ensure 'aliases' and 'help' settings are set.
        settings['aliases'] = ('aliases', aliases)
        if not settings.has_key('help'):
            docstring = klass.check_docstring()
            settings['help'] = ("Helpstring for plugin.", docstring)

        # Create the tuple which will be registered for the plugin.
        class_info = (class_or_class_name, settings)

        # Register the class_info tuple for each alias.
        for alias in aliases:
            if isinstance(class_or_class_name, type):
                modname = class_or_class_name.__module__
                alias = cls.apply_prefix(modname, alias)

            cls.plugins[alias] = class_info

        # Register any settings defined for other classes.
        if hasattr(klass, '_other_class_settings') and klass._other_class_settings:
            PluginMeta._store_other_class_settings.update(klass._other_class_settings)

    def standardize_alias_or_aliases(cls, alias_or_aliases):
        """
        Make sure we don't attempt to iterate over an alias string thinking
        it's an array.
        """
        if isinstance(alias_or_aliases, basestring):
            return [alias_or_aliases]
        else:
            return alias_or_aliases

    def get_reference_to_class(cls, class_or_class_name):
        """
        Detect if we get a class or a name, convert a name to a class.
        """
        if isinstance(class_or_class_name, type):
            return class_or_class_name

        elif isinstance(class_or_class_name, basestring):
            if ":" in class_or_class_name:
                mod_name, class_name = class_or_class_name.split(":")

                if not mod_name in sys.modules:
                    __import__(mod_name)

                mod = sys.modules[mod_name]
                return mod.__dict__[class_name]

            else:
                return cls.load_class_from_locals(class_or_class_name)

        else:
            msg = "Unexpected Type '%s'" % type(class_or_class_name)
            raise InternalCashewException(msg)

    def load_class_from_locals(cls, class_name):
        raise Exception("not implemented")

    def check_docstring(cls):
        """
        Asserts that the class has a docstring, returning it if successful.
        """
        docstring = inspect.getdoc(cls)
        if not docstring:
            breadcrumbs = " -> ".join(t.__name__ for t in inspect.getmro(cls)[:-1][::-1])
            msg = "docstring required for plugin '%s' (%s, defined in %s)"
            args = (cls.__name__, breadcrumbs, cls.__module__)
            raise InternalCashewException(msg % args)
        return docstring

    def apply_prefix(cls, modname, alias):
        return alias

    def register_plugins(cls, plugin_info):
        for k, v in plugin_info.iteritems():
            cls.register_plugin(k.split("|"), v[0], v[1])

    def register_plugins_from_dict(cls, yaml_content):
        for alias, info_dict in yaml_content.iteritems():
            if ":" in alias:
                _, alias = alias.split(":")

            if not info_dict.has_key('class'):
                import json
                msg = "invalid info dict for %s: %s" % (alias, json.dumps(info_dict))
                raise InternalCashewException(msg)

            class_name = info_dict['class']
            del info_dict['class']
            cls.register_plugin(alias.split("|"), class_name, info_dict)

    def register_plugins_from_yaml_file(cls, yaml_file):
        with open(yaml_file, 'rb') as f:
            yaml_content = yaml.safe_load(f.read())
        cls.register_plugins_from_dict(yaml_content)

    # documented above here

    def __iter__(cls, *instanceargs):
        processed_aliases = set()
        for alias in sorted(cls.plugins):
            if alias in processed_aliases:
                continue

            try:
                instance = cls.create_instance(alias, *instanceargs)
                yield(instance)
                for alias in instance.aliases:
                    processed_aliases.add(alias)

            except InactivePlugin:
                pass

    def standardize_alias(cls, alias):
        obj = cls.plugins[alias]
        keys = []
        for k, v in cls.plugins.iteritems():
            if v == obj:
                keys.append(k)
        assert alias in keys
        return sorted(keys)[0]

    def imro(cls):
        """
        Returns MRO in reverse order, skipping 'object/type' class.
        """
        return reversed(inspect.getmro(cls)[0:-2])

    def class_update_settings(cls, instance, new_settings, enforce_helpstring=True):
        for raw_key, value in new_settings.iteritems():
            key = raw_key.replace("_", "-")
            key_in_settings = instance._instance_settings.has_key(key)
            value_is_list_len_2 = isinstance(value, list) and len(value) == 2
            if isinstance(value, tuple) or (not key_in_settings and value_is_list_len_2):
                instance._instance_settings[key] = value
            else:
                if not instance._instance_settings.has_key(key):
                    if enforce_helpstring:
                        raise Exception("You must specify param '%s' as a tuple of (helpstring, value)" % key)
                    else:
                        # TODO check and warn if key is similar to an existing key
                        instance._instance_settings[key] = ('', value,)
                else:
                    orig = instance._instance_settings[key]
                    instance._instance_settings[key] = (orig[0], value,)

    def create_instance(cls, alias, *instanceargs, **instancekwargs):
        if alias.startswith('-'):
            alias = '-'
        elif not alias in cls.plugins:
            msg = "no alias '%s' available for '%s'"
            msgargs = (alias, cls.__name__)
            raise NoPlugin(msg % msgargs)

        class_or_class_name, settings = cls.plugins[alias]
        klass = cls.get_reference_to_class(class_or_class_name)

        instance = klass(*instanceargs, **instancekwargs)
        instance.alias = alias

        if not hasattr(instance, '_instance_settings'):
            instance.initialize_settings()
        instance.update_settings(settings)

        if not instance.is_active():
            raise InactivePlugin(alias)

        return instance
<commit_msg>Split out adjust_alias method.<commit_after>import inflection
import inspect
import os
import sys
import yaml

from cashew.exceptions import *

class Plugin(object):
    """
    Base class for plugins. Define instance methods shared by plugins here.
    """
    aliases = []
    _settings = {}

    def is_active(self):
        return True

    def name(self):
        return inflection.titleize(self.setting('aliases')[0])

    def help(self):
        return self.setting('help')

    def initialize_settings(self, **raw_kwargs):
        self._instance_settings = {}
        for parent_class in self.__class__.imro():
            if parent_class._settings:
                self.__class__.class_update_settings(self, parent_class._settings)
            if hasattr(parent_class, 'UNSET'):
                for unset in parent_class.UNSET:
                    del self._instance_settings[unset]

        if hasattr(self.__class__, 'aliases') and self.__class__.aliases:
            alias = self.__class__.aliases[0]
            settings_from_other_classes = PluginMeta._store_other_class_settings.get(alias)
            if settings_from_other_classes:
                self.__class__.class_update_settings(self, settings_from_other_classes)

        # Apply raw_kwargs settings
        hyphen_settings = dict((k, v) for k, v in raw_kwargs.items() if k in self._instance_settings)
        underscore_settings = dict((k.replace("_", "-"), v) for k, v in raw_kwargs.items() if k.replace("_", "-") in self._instance_settings)
        self.__class__.class_update_settings(self, hyphen_settings)
        self.__class__.class_update_settings(self, underscore_settings)

    def safe_setting(self, name_hyphen, default=None):
        """
        Retrieves the setting value, but returns a default value rather than
        raising an error if the setting does not exist.
        """
        try:
            return self.setting(name_hyphen)
        except UserFeedback:
            return default

    def setting(self, name_hyphen):
        """
        Retrieves the setting value whose name is indicated by name_hyphen.

        Values starting with $ are assumed to reference environment variables,
        and the value stored in environment variables is retrieved. (It's an
        error if there's no corresponding environment variable set.)
        """
        if name_hyphen in self._instance_settings:
            value = self._instance_settings[name_hyphen][1]
        else:
            name_underscore = name_hyphen.replace("-", "_")
            if name_underscore in self._instance_settings:
                value = self._instance_settings[name_underscore][1]
            else:
                if name_underscore == name_hyphen:
                    msg = "No setting named '%s'" % name_hyphen
                else:
                    msg = "no setting named '%s' or '%s'"
                    msg = msg % (name_hyphen, name_underscore)
                raise UserFeedback(msg)

        if hasattr(value, 'startswith') and value.startswith("$"):
            env_var = value.lstrip("$")
            if os.environ.has_key(env_var):
                return os.getenv(env_var)
            else:
                msg = "'%s' is not defined in your environment" % env_var
                raise UserFeedback(msg)
        elif hasattr(value, 'startswith') and value.startswith("\$"):
            return value.replace("\$", "$")
        else:
            return value

    def setting_values(self, skip=None):
        """
        Returns dict of all setting values (removes the helpstrings)
        """
        if not skip:
            skip = []
        return dict((k, v[1]) for k, v in self._instance_settings.iteritems() if not k in skip)

    def update_settings(self, new_settings):
        self.__class__.class_update_settings(self, new_settings, False)

class PluginMeta(type):
    """
    Base meta class for anything plugin-able.
    """
    _store_other_class_settings = {} # allow plugins to define settings for other classes

    def __init__(cls, name, bases, attrs):
        assert issubclass(cls, Plugin), "%s should inherit from class Plugin" % name
        if '__metaclass__' in attrs:
            cls.plugins = {}
        elif hasattr(cls, 'aliases'):
            cls.register_plugin(cls.aliases, cls, {})

    def register_plugin(cls, alias_or_aliases, class_or_class_name, settings):
        aliases = cls.standardize_alias_or_aliases(alias_or_aliases)
        klass = cls.get_reference_to_class(class_or_class_name)

        # Ensure 'aliases' and 'help' settings are set.
        settings['aliases'] = ('aliases', aliases)
        if not settings.has_key('help'):
            docstring = klass.check_docstring()
            settings['help'] = ("Helpstring for plugin.", docstring)

        # Create the tuple which will be registered for the plugin.
        class_info = (class_or_class_name, settings)

        # Register the class_info tuple for each alias.
        for alias in aliases:
            if isinstance(class_or_class_name, type):
                modname = class_or_class_name.__module__
                alias = cls.apply_prefix(modname, alias)

            cls.plugins[alias] = class_info

        # Register any settings defined for other classes.
        if hasattr(klass, '_other_class_settings') and klass._other_class_settings:
            PluginMeta._store_other_class_settings.update(klass._other_class_settings)

    def standardize_alias_or_aliases(cls, alias_or_aliases):
        """
        Make sure we don't attempt to iterate over an alias string thinking
        it's an array.
        """
        if isinstance(alias_or_aliases, basestring):
            return [alias_or_aliases]
        else:
            return alias_or_aliases

    def get_reference_to_class(cls, class_or_class_name):
        """
        Detect if we get a class or a name, convert a name to a class.
        """
        if isinstance(class_or_class_name, type):
            return class_or_class_name

        elif isinstance(class_or_class_name, basestring):
            if ":" in class_or_class_name:
                mod_name, class_name = class_or_class_name.split(":")

                if not mod_name in sys.modules:
                    __import__(mod_name)

                mod = sys.modules[mod_name]
                return mod.__dict__[class_name]

            else:
                return cls.load_class_from_locals(class_or_class_name)

        else:
            msg = "Unexpected Type '%s'" % type(class_or_class_name)
            raise InternalCashewException(msg)

    def load_class_from_locals(cls, class_name):
        raise Exception("not implemented")

    def check_docstring(cls):
        """
        Asserts that the class has a docstring, returning it if successful.
        """
        docstring = inspect.getdoc(cls)
        if not docstring:
            breadcrumbs = " -> ".join(t.__name__ for t in inspect.getmro(cls)[:-1][::-1])
            msg = "docstring required for plugin '%s' (%s, defined in %s)"
            args = (cls.__name__, breadcrumbs, cls.__module__)
            raise InternalCashewException(msg % args)
        return docstring

    def apply_prefix(cls, modname, alias):
        return alias

    def register_plugins(cls, plugin_info):
        for k, v in plugin_info.iteritems():
            cls.register_plugin(k.split("|"), v[0], v[1])

    def register_plugins_from_dict(cls, yaml_content):
        for alias, info_dict in yaml_content.iteritems():
            if ":" in alias:
                _, alias = alias.split(":")

            if not info_dict.has_key('class'):
                import json
                msg = "invalid info dict for %s: %s" % (alias, json.dumps(info_dict))
                raise InternalCashewException(msg)

            class_name = info_dict['class']
            del info_dict['class']
            cls.register_plugin(alias.split("|"), class_name, info_dict)

    def register_plugins_from_yaml_file(cls, yaml_file):
        with open(yaml_file, 'rb') as f:
            yaml_content = yaml.safe_load(f.read())
        cls.register_plugins_from_dict(yaml_content)

    def create_instance(cls, alias, *instanceargs, **instancekwargs):
        alias = cls.adjust_alias(alias)

        if not alias in cls.plugins:
            msg = "no alias '%s' available for '%s'"
            msgargs = (alias, cls.__name__)
            raise NoPlugin(msg % msgargs)

        class_or_class_name, settings = cls.plugins[alias]
        klass = cls.get_reference_to_class(class_or_class_name)

        instance = klass(*instanceargs, **instancekwargs)
        instance.alias = alias

        if not hasattr(instance, '_instance_settings'):
            instance.initialize_settings()
        instance.update_settings(settings)

        if not instance.is_active():
            raise InactivePlugin(alias)

        return instance

    def adjust_alias(cls, alias):
        return alias

    # documented above here

    def __iter__(cls, *instanceargs):
        processed_aliases = set()
        for alias in sorted(cls.plugins):
            if alias in processed_aliases:
                continue

            try:
                instance = cls.create_instance(alias, *instanceargs)
                yield(instance)
                for alias in instance.aliases:
                    processed_aliases.add(alias)

            except InactivePlugin:
                pass

    def standardize_alias(cls, alias):
        obj = cls.plugins[alias]
        keys = []
        for k, v in cls.plugins.iteritems():
            if v == obj:
                keys.append(k)
        assert alias in keys
        return sorted(keys)[0]

    def imro(cls):
        """
        Returns MRO in reverse order, skipping 'object/type' class.
        """
        return reversed(inspect.getmro(cls)[0:-2])

    def class_update_settings(cls, instance, new_settings, enforce_helpstring=True):
        for raw_key, value in new_settings.iteritems():
            key = raw_key.replace("_", "-")
            key_in_settings = instance._instance_settings.has_key(key)
            value_is_list_len_2 = isinstance(value, list) and len(value) == 2
            if isinstance(value, tuple) or (not key_in_settings and value_is_list_len_2):
                instance._instance_settings[key] = value
            else:
                if not instance._instance_settings.has_key(key):
                    if enforce_helpstring:
                        raise Exception("You must specify param '%s' as a tuple of (helpstring, value)" % key)
                    else:
                        # TODO check and warn if key is similar to an existing key
                        instance._instance_settings[key] = ('', value,)
                else:
                    orig = instance._instance_settings[key]
                    instance._instance_settings[key] = (orig[0], value,)
<|endoftext|>


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

# Copyright © 2012-2015 Roberto Alsina and others.

# Permission is hereby granted, free of charge, to any
# person obtaining a copy of this software and associated
# documentation files (the "Software"), to deal in the
# Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the
# Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice
# shall be included in all copies or substantial portions of
# the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

from __future__ import print_function, unicode_literals

import os
import subprocess

from nikola.plugin_categories import Command
from nikola.utils import req_missing

class CommandAuto(Command):
    """Start debugging console."""
    name = "auto"
    doc_purpose = "automatically detect site changes, rebuild and optionally refresh a browser"
    cmd_options = [
        {
            'name': 'browser',
            'short': 'b',
            'type': bool,
            'help': 'Start a web browser.',
            'default': False,
        },
        {
            'name': 'port',
            'short': 'p',
            'long': 'port',
            'default': 8000,
            'type': int,
            'help': 'Port nummber (default: 8000)',
        },
    ]

    def _execute(self, options, args):
        """Start the watcher."""
        try:
            from livereload import Server
        except ImportError:
            req_missing(['livereload'], 'use the "auto" command')
            return

        arguments = ['build']
        if self.site.configuration_filename != 'conf.py':
            arguments = ['--conf=' + self.site.configuration_filename] + arguments

        command_line = 'nikola' + ' '.join(arguments)

        # Run an initial build so we are up-to-date
        subprocess.call(["nikola"] + arguments)

        port = options and options.get('port')

        server = Server()
        server.watch(self.site.configuration_filename, command_line)
        server.watch('themes/', command_line)
        server.watch('templates/', command_line)
        for item in self.site.config['post_pages']:
            server.watch(os.path.dirname(item[0]), command_line)
        for item in self.site.config['FILES_FOLDERS']:
            server.watch(item, command_line)
        for item in self.site.config['GALLERY_FOLDERS']:
            server.watch(item, command_line)
        for item in self.site.config['LISTINGS_FOLDERS']:
            server.watch(item, command_line)

        out_folder = self.site.config['OUTPUT_FOLDER']
        if options and options.get('browser'):
            browser = True
        else:
            browser = False

        server.serve(port=port, host=None, root=out_folder, debug=True, open_url=browser)
<commit_msg>fix autorebuild<commit_after># -*- coding: utf-8 -*-

# Copyright © 2012-2015 Roberto Alsina and others.

# Permission is hereby granted, free of charge, to any
# person obtaining a copy of this software and associated
# documentation files (the "Software"), to deal in the
# Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the
# Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice
# shall be included in all copies or substantial portions of
# the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

from __future__ import print_function, unicode_literals

import os
import subprocess

from nikola.plugin_categories import Command
from nikola.utils import req_missing

class CommandAuto(Command):
    """Start debugging console."""
    name = "auto"
    doc_purpose = "automatically detect site changes, rebuild and optionally refresh a browser"
    cmd_options = [
        {
            'name': 'browser',
            'short': 'b',
            'type': bool,
            'help': 'Start a web browser.',
            'default': False,
        },
        {
            'name': 'port',
            'short': 'p',
            'long': 'port',
            'default': 8000,
            'type': int,
            'help': 'Port nummber (default: 8000)',
        },
    ]

    def _execute(self, options, args):
        """Start the watcher."""
        try:
            from livereload import Server
        except ImportError:
            req_missing(['livereload'], 'use the "auto" command')
            return

        arguments = ['build']
        if self.site.configuration_filename != 'conf.py':
            arguments = ['--conf=' + self.site.configuration_filename] + arguments

        command_line = 'nikola ' + ' '.join(arguments)

        # Run an initial build so we are up-to-date
        subprocess.call(["nikola"] + arguments)

        port = options and options.get('port')

        server = Server()
        server.watch(self.site.configuration_filename, command_line)
        server.watch('themes/', command_line)
        server.watch('templates/', command_line)
        for item in self.site.config['post_pages']:
            server.watch(os.path.dirname(item[0]), command_line)
        for item in self.site.config['FILES_FOLDERS']:
            server.watch(item, command_line)
        for item in self.site.config['GALLERY_FOLDERS']:
            server.watch(item, command_line)
        for item in self.site.config['LISTINGS_FOLDERS']:
            server.watch(item, command_line)

        out_folder = self.site.config['OUTPUT_FOLDER']
        if options and options.get('browser'):
            browser = True
        else:
            browser = False

        server.serve(port=port, host=None, root=out_folder, debug=True, open_url=browser)
<|endoftext|>


<commit_before>import discord
from discord.ext import commands
from .utils import checks
from cogs.utils.dataIO import dataIO, fileIO
from __main__ import send_cmd_help

import json
import os
import asyncio
import aiohttp
import datetime

try: # check if BeautifulSoup4 is installed
	from bs4 import BeautifulSoup
	soupAvailable = True
except:
	soupAvailable = False

...

class APIError(Exception):
	pass

class APIKeyError(Exception):
	pass

class Gw2tp:
	"""This cog finds tp prices"""

	def __init__(self, bot):
		self.bot = bot
		self.session = aiohttp.ClientSession(loop=self.bot.loop)

	@commands.command(pass_context=True)
	async def tp(self, ctx, tpbuyid: str):
		"""This finds the current buy price of an item
		Doesn't require any keys/scopes"""
		user = ctx.message.author
		try:
			commerce = 'commerce/prices/'
			endpoint = commerce + tpbuyid
			results = await self.call_api(endpoint)
		except APIKeyError as e:
			await self.bot.say(e)
			return
		except APIError as e:
			await self.bot.say("{0.mention}, API has responded with the following error: "
							   "`{1}`".format(user, e))
			return
		buyprice = results["unit_price"]
		sellprice = results ["unit_price"]
		color = self.getColor(user)
		data = discord.Embed(description=None, colour=color)
		data.add_field(name="Buy price", value=buyprice)
		data.add_field(name="Sell price", value=sellprice)

		try:
			await self.bot.say(embed=data)
		except discord.HTTPException:
			await self.bot.say("Need permission to embed links")

	async def call_api(self, endpoint):
		apiserv = 'https://api.guildwars2.com/v2/'
		url = apiserv + endpoint
		async with self.session.get(url) as r:
			results = await r.json()
		if "error" in results:
			raise APIError("The API is dead!")
		if "text" in results:
			raise APIError(results["text"])
		return results

def check_folders():
	if not os.path.exists("data/guildwars2"):
		print("Creating data/guildwars2")
		os.makedirs("data/guildwars2")

def check_files():
	files = {
		"gamedata.json": {},
		"settings.json": {"ENABLED": False},
		"language.json": {},
		"keys.json": {},
		"build.json": {"id": None}  # Yay legacy support
	}

	for filename, value in files.items():
		if not os.path.isfile("data/guildwars2/{}".format(filename)):
			print("Creating empty {}".format(filename))
			dataIO.save_json("data/guildwars2/{}".format(filename), value)

def setup(bot):
	if soupAvailable:
		bot.add_cog(Gw2tp(bot))
	else:
		raise RuntimeError("You need to run `pip3 install beautifulsoup4`")
	check_folders()
	check_files()<commit_msg>fixed clashing command<commit_after>import discord
from discord.ext import commands
from .utils import checks
from cogs.utils.dataIO import dataIO, fileIO
from __main__ import send_cmd_help

import json
import os
import asyncio
import aiohttp
import datetime

try: # check if BeautifulSoup4 is installed
	from bs4 import BeautifulSoup
	soupAvailable = True
except:
	soupAvailable = False

...

class APIError(Exception):
	pass

class APIKeyError(Exception):
	pass

class Gw2tp:
	"""This cog finds tp prices"""

	def __init__(self, bot):
		self.bot = bot
		self.session = aiohttp.ClientSession(loop=self.bot.loop)

	@commands.command(pass_context=True)
	async def tpdata(self, ctx, tpbuyid: str):
		"""This finds the current buy price of an item
		Doesn't require any keys/scopes"""
		user = ctx.message.author
		try:
			commerce = 'commerce/prices/'
			endpoint = commerce + tpbuyid
			results = await self.call_api(endpoint)
		except APIKeyError as e:
			await self.bot.say(e)
			return
		except APIError as e:
			await self.bot.say("{0.mention}, API has responded with the following error: "
							   "`{1}`".format(user, e))
			return
		buyprice = results["unit_price"]
		sellprice = results ["unit_price"]
		color = self.getColor(user)
		data = discord.Embed(description=None, colour=color)
		data.add_field(name="Buy price", value=buyprice)
		data.add_field(name="Sell price", value=sellprice)

		try:
			await self.bot.say(embed=data)
		except discord.HTTPException:
			await self.bot.say("Need permission to embed links")

	async def call_api(self, endpoint):
		apiserv = 'https://api.guildwars2.com/v2/'
		url = apiserv + endpoint
		async with self.session.get(url) as r:
			results = await r.json()
		if "error" in results:
			raise APIError("The API is dead!")
		if "text" in results:
			raise APIError(results["text"])
		return results

def check_folders():
	if not os.path.exists("data/guildwars2"):
		print("Creating data/guildwars2")
		os.makedirs("data/guildwars2")

def check_files():
	files = {
		"gamedata.json": {},
		"settings.json": {"ENABLED": False},
		"language.json": {},
		"keys.json": {},
		"build.json": {"id": None}  # Yay legacy support
	}

	for filename, value in files.items():
		if not os.path.isfile("data/guildwars2/{}".format(filename)):
			print("Creating empty {}".format(filename))
			dataIO.save_json("data/guildwars2/{}".format(filename), value)

def setup(bot):
	if soupAvailable:
		bot.add_cog(Gw2tp(bot))
	else:
		raise RuntimeError("You need to run `pip3 install beautifulsoup4`")
	check_folders()
	check_files()<|endoftext|>


<commit_before>#!/usr/bin/python
# -*- coding: UTF-8 -*-
# author: qdvictory
# date: 2017-07-08
# version: 1.0

import sys, getopt, os, shutil, json
try: input = raw_input
except NameError: pass

helpStr = "\nWelcome to Happyxcasset\n\
This version has been tested in Xcode8 and supports both python2 and python3\n\
To prevent unknown bugs, please back up your data before using it\n\
Use commands easy to understand\n\
python xcodexcassets.py -i <inputdir> -o <outputdir> -e <fileextension>\n\
-i The resource's input directory can contain subfolders\n\
-o The output directory of the resource, which is the directory of the .xcasset in Xcode\n\
-e File extension. Default 'png,jpg,jpeg,pdf'\n\
-h Help\n\
This is all, enjoy.\n"

class FileModel:
   path = ''
   fileFinder = ''
   fileName = ''
   fileFinder = ''
   singleName = ''
   extension = ''

   def __init__(self, path):
      self.path = path
      self.fileFinder,self.fileName=os.path.split(path)
      self.finderName = self.fileFinder.split('/')[-1].split(".")[0]
      self.extension = self.fileName.split('.')[1]
      self.singleName = self.fileName.split('.')[0].replace('@1x','').replace("@2x",'').replace("@3x",'')

   def __str__(self):
      return "singleName:%s, finder:%s"%(self.singleName,self.fileFinder)

   def __repr__(self):
      return "singleName:%s, finder:%s"%(self.singleName,self.fileFinder)

def walkDir(rootDir,key='finderName',extension=[]):
   allFiles = {}
   list_dirs = os.walk(rootDir)
   for root, dirs, files in list_dirs:
     # for d in dirs:
     #     print os.path.join(root, d)
     for f in files:
         filePath = os.path.join(root, f)
         m = FileModel(filePath)
         if len(m.singleName) == 0 or not (m.extension.lower() in extension):
            continue
         k = getattr(m, key)
         if k in list(allFiles.keys()):
            allFiles[k].append({k:m})
         else:
            allFiles[k] = [{k:m}]
   return allFiles

#replace file
#If the old file already exists, delete the file except for Contents.json
#new Contents.json and files insert
def replaceFileModel(inputModel,outputModel):
   #clean old finder
   outputPath = None
   contentPath = None
   if type(outputModel) != str:
      for d in outputModel:
         m = d[list(d.keys())[0]]
         outputPath = ("/").join(m.fileFinder.split("/")[:-1])
         if m.fileName != "Contents.json":
            os.remove(m.path)
         else:
            contentPath = m.path
   else:
      outputPath = outputModel

   jsondic = None

   if contentPath != None:
      file_object = open(contentPath)
      try:
         file_context = file_object.read()
         jsondic = json.loads(file_context)
      finally:
         file_object.close()

   if jsondic == None:
      jsondic = {"images":[
         {"idiom" : "universal", "scale":"1x"},
         {"idiom" : "universal", "scale":"2x"},
         {"idiom" : "universal", "scale":"3x"},
      ],
      "info":{"version":1,"author":"xcode"}
      }

   for d in inputModel:
      nm = d[list(d.keys())[0]]
      alreadyinsert = False
      for key in ["@1x.","@2x.","@3x."]:
         if key in nm.fileName:
            for sdic in jsondic["images"]:
               if sdic["scale"] == key[1:3]:
                  sdic["filename"] = nm.fileName
                  alreadyinsert = True
      if not alreadyinsert:
         for sdic in jsondic["images"]:
            if sdic["scale"] == "1x":
                  sdic["filename"] = nm.fileName

      finderPath = outputPath+"/"+nm.singleName+".imageset/"
      if not os.path.exists(finderPath):
         os.mkdir(finderPath)
      shutil.copy2(nm.path, finderPath)
      if contentPath == None:
         contentPath = finderPath+"Contents.json"

   content = json.dumps(jsondic,indent=4)
   file_object = open(contentPath,"w")
   try:
      file_object.write(content)
   finally:
      file_object.close

   print(">>> "+finderPath+" output is complete")

#    {
#   "images" : [
#     {
#       "idiom" : "universal",
#       "filename" : "message_btn_download.pdf",
#       "scale" : "1x"
#     },
#     {
#       "idiom" : "universal",
#       "scale" : "2x"
#     },
#     {
#       "idiom" : "universal",
#       "scale" : "3x"
#     }
#   ],
#   "info" : {
#     "version" : 1,
#     "author" : "xcode"
#   }
# }

def main(argv):
   inputfinder = ''
   outputfinder = ''
   extensionname = ['png', 'jpg', 'pdf', 'jpeg']
   try:
      opts, args = getopt.getopt(argv,"hi:o:e:",["inputfinder=","outfinder=","extension="])
   except getopt.GetoptError:
      print (helpStr)
      sys.exit(2)
   for opt, arg in opts:
      if opt == '-h':
         print (helpStr)
         sys.exit()
      elif opt in ("-i", "--inputfinder"):
         inputfinder = arg
      elif opt in ("-o", "--outputfinder"):
         outputfinder = arg
      elif opt in ("-e", "--extension"):
         extensionname = arg.split(",")

   if len(inputfinder) == 0 or len(outputfinder) == 0:
      print (helpStr)
      sys.exit(2)

   if not "xcassets" in outputfinder:
      print ("\n\nPlease enter the directory for xcassets in xcode correctly.\nlike \"/Users/Desktop/project/projectname/Image.xcassets\"")
      sys.exit(2)

   while (True):
      confirm = input("\n>>> This script will output all the files in the directory\n\
   (%s)\n\
   to the target directory\n\
   (%s)\n\
   and adapt to the xcode. \n\
   Before this, please back up the file in advance to prevent the file from being lost. \n\
   Please confirm the operation (y / n) "%(inputfinder,outputfinder))

      if confirm.lower() == 'y':
         break;
      elif confirm.lower() == 'n':
         sys.exit(2)

   outputFiles = walkDir(outputfinder,extension=extensionname)
   inputFiles = walkDir(inputfinder,'singleName',extensionname)
   for k in list(inputFiles.keys()):
      d = inputFiles[k]
      if k in list(outputFiles.keys()):
         replaceFileModel(d,outputFiles[k])
      else:
         replaceFileModel(d, outputfinder)

if __name__ == "__main__":
   main(sys.argv[1:])<commit_msg>update tips<commit_after>#!/usr/bin/python
# -*- coding: UTF-8 -*-
# author: qdvictory
# date: 2017-07-08
# version: 1.0

import sys, getopt, os, shutil, json
try: input = raw_input
except NameError: pass

helpStr = "\nWelcome to Happyxcasset\n\
This version has been tested in Xcode8 and supports both python2 and python3\n\
To prevent unknown bugs, please back up your data before using it\n\
Use commands easy to understand\n\
python xcodexcassets.py -i <inputdir> -o <outputdir> -e <fileextension>\n\
-i The resource's input directory can contain subfolders\n\
-o The output directory of the resource, which is the directory of the .xcasset in Xcode\n\
-e File extension. Default 'png,jpg,jpeg,pdf'\n\
-h Help\n\
This is all, enjoy.\n"

class FileModel:
   path = ''
   fileFinder = ''
   fileName = ''
   fileFinder = ''
   singleName = ''
   extension = ''

   def __init__(self, path):
      self.path = path
      self.fileFinder,self.fileName=os.path.split(path)
      self.finderName = self.fileFinder.split('/')[-1].split(".")[0]
      self.extension = self.fileName.split('.')[1]
      self.singleName = self.fileName.split('.')[0].replace('@1x','').replace("@2x",'').replace("@3x",'')

   def __str__(self):
      return "singleName:%s, finder:%s"%(self.singleName,self.fileFinder)

   def __repr__(self):
      return "singleName:%s, finder:%s"%(self.singleName,self.fileFinder)

def walkDir(rootDir,key='finderName',extension=[]):
   allFiles = {}
   list_dirs = os.walk(rootDir)
   for root, dirs, files in list_dirs:
     # for d in dirs:
     #     print os.path.join(root, d)
     for f in files:
         filePath = os.path.join(root, f)
         m = FileModel(filePath)
         if len(m.singleName) == 0 or not (m.extension.lower() in extension):
            continue
         k = getattr(m, key)
         if k in list(allFiles.keys()):
            allFiles[k].append({k:m})
         else:
            allFiles[k] = [{k:m}]
   return allFiles

#replace file
#If the old file already exists, delete the file except for Contents.json
#new Contents.json and files insert
def replaceFileModel(inputModel,outputModel):
   #clean old finder
   outputPath = None
   contentPath = None
   if type(outputModel) != str:
      for d in outputModel:
         m = d[list(d.keys())[0]]
         outputPath = ("/").join(m.fileFinder.split("/")[:-1])
         if m.fileName != "Contents.json":
            os.remove(m.path)
         else:
            contentPath = m.path
   else:
      outputPath = outputModel

   jsondic = None

   if contentPath != None:
      file_object = open(contentPath)
      try:
         file_context = file_object.read()
         jsondic = json.loads(file_context)
      finally:
         file_object.close()

   if jsondic == None:
      jsondic = {"images":[
         {"idiom" : "universal", "scale":"1x"},
         {"idiom" : "universal", "scale":"2x"},
         {"idiom" : "universal", "scale":"3x"},
      ],
      "info":{"version":1,"author":"xcode"}
      }

   for d in inputModel:
      nm = d[list(d.keys())[0]]
      alreadyinsert = False
      for key in ["@1x.","@2x.","@3x."]:
         if key in nm.fileName:
            for sdic in jsondic["images"]:
               if sdic["scale"] == key[1:3]:
                  sdic["filename"] = nm.fileName
                  alreadyinsert = True
      if not alreadyinsert:
         for sdic in jsondic["images"]:
            if sdic["scale"] == "1x":
                  sdic["filename"] = nm.fileName

      finderPath = outputPath+"/"+nm.singleName+".imageset/"
      if not os.path.exists(finderPath):
         os.mkdir(finderPath)
      shutil.copy2(nm.path, finderPath)
      if contentPath == None:
         contentPath = finderPath+"Contents.json"

   content = json.dumps(jsondic,indent=4)
   file_object = open(contentPath,"w")
   try:
      file_object.write(content)
   finally:
      file_object.close

   print(">>> "+finderPath+" output is complete")

#    {
#   "images" : [
#     {
#       "idiom" : "universal",
#       "filename" : "message_btn_download.pdf",
#       "scale" : "1x"
#     },
#     {
#       "idiom" : "universal",
#       "scale" : "2x"
#     },
#     {
#       "idiom" : "universal",
#       "scale" : "3x"
#     }
#   ],
#   "info" : {
#     "version" : 1,
#     "author" : "xcode"
#   }
# }

def main(argv):
   inputfinder = ''
   outputfinder = ''
   extensionname = ['png', 'jpg', 'pdf', 'jpeg']
   try:
      opts, args = getopt.getopt(argv,"hi:o:e:",["inputfinder=","outfinder=","extension="])
   except getopt.GetoptError:
      print (helpStr)
      sys.exit(2)
   for opt, arg in opts:
      if opt == '-h':
         print (helpStr)
         sys.exit()
      elif opt in ("-i", "--inputfinder"):
         inputfinder = arg
      elif opt in ("-o", "--outputfinder"):
         outputfinder = arg
      elif opt in ("-e", "--extension"):
         extensionname = arg.split(",")

   if len(inputfinder) == 0 or len(outputfinder) == 0 or len(extensionname)==0:
      print (helpStr)
      sys.exit(2)

   if not "xcassets" in outputfinder:
      print ("\n\nPlease enter the directory for xcassets in xcode correctly.\nlike \"/Users/Desktop/project/projectname/Image.xcassets\"")
      sys.exit(2)

   while (True):
      confirm = input("\n>>> This script will output all the files %s in the directory\n\
   (%s)\n\
   to the target directory\n\
   (%s)\n\
   and adapt to the xcode. \n\
   Before this, please back up the file in advance to prevent the file from being lost. \n\
   Please confirm the operation (y / n) "%(str(extensionname),inputfinder,outputfinder))

      if confirm.lower() == 'y':
         break;
      elif confirm.lower() == 'n':
         sys.exit(2)

   outputFiles = walkDir(outputfinder,extension=extensionname)
   inputFiles = walkDir(inputfinder,'singleName',extensionname)
   for k in list(inputFiles.keys()):
      d = inputFiles[k]
      if k in list(outputFiles.keys()):
         replaceFileModel(d,outputFiles[k])
      else:
         replaceFileModel(d, outputfinder)

if __name__ == "__main__":
   main(sys.argv[1:])<|endoftext|>


<commit_before>from scipy.stats import moment

def compute_features(roi, window_width=1, step_size=3):
    w = roi.shape[1]
    msk = roi > 0
<<<<<<< HEAD
    f = []

    x1 = 0
    x2 = x1 + window_width
    while True:

        bin = msk[:, x1:x2]
        scv = roi[:, x1:x2]
        # gradient
        gra = bin[0:-2] - bin[1:-1]
        # black-white transitions
        bwt = gra == -1
        # white-black transitions
        wbt = gra == 1
        # digits not on the contour
        dk = gra == 0

        # foreground fraction
        fgf = bin.sum() / len(bin)

        fv = [fgf,
              bwt.sum(),
              wbt.sum(),
              dk.sum(),
              moment(scv, moment=1)[0],
              moment(scv, moment=2)[0],
              moment(scv, moment=3)[0],
              moment(scv, moment=4)[0]]

        f.append(fv)

        x1 = x2 + step_size
        x2 = x1 + window_width
        if x2 > w:
            break

    return f
<commit_msg>Compute black white transitions<commit_after>from scipy.stats import moment

def compute_features(roi, window_width=1, step_size=3):
    w = roi.shape[1]
    msk = roi > 0
<<<<<<< HEAD
    f = []

    x1 = 0
    x2 = x1 + window_width
    while True:

        bin = msk[:, x1:x2]
        scv = roi[:, x1:x2]
        # gradient
        gra = bin[0:-2] - bin[1:-1]
        # number of black-white and white-black transitions
        bwt, wbt = transitions(gra)
        # digits not on the contour
        dk = gra == 0

        # foreground fraction
        fgf = bin.sum() / len(bin)

        fv = [fgf,
              bwt,
              wbt,
              dk.sum(),
              moment(scv, moment=1)[0],
              moment(scv, moment=2)[0],
              moment(scv, moment=3)[0],
              moment(scv, moment=4)[0]]

        f.append(fv)

        x1 = x2 + step_size
        x2 = x1 + window_width
        if x2 > w:
            break

    return f

def transitions(bin_img):
    """
    Returns the number of black to white and white to black transitions.
    The two numbers will only be different when the image does not end in the
    same colour as it started.
    """
    black_white_count = 0
    white_black_count = 0
    current_state = bin_img[0][0]
    for lis in bin_img:
        for val in lis:
            if val is not current_state:
                current_state = val
                if val:
                    black_white_count += 1
                else:
                    white_black_count += 1

    return black_white_count, white_black_count
<|endoftext|>


<commit_before>from kafka import KafkaProducer

from .event_emitter import EventEmitter
from .exceptions import ConfigurationError
from .logging import logger as log

__version__ = '2.0.2'

class Relayer(object):
    """
    Arguments:
        logging_topic: desired kafka topic to send logs, this will get modified if a prefix o suffix is set.
    Keyword Arguments:
        kafka_hosts: 'host[:port]' string (or list of 'host[:port]'
            strings) that the producer should contact to bootstrap initial
            cluster metadata. This does not have to be the full node list.
            It just needs to have at least one broker that will respond to a
            Metadata API Request.
        topic_prefix: value to prefix all topics handled by relayer.
            Defaults to empty string.
        topic_suffix: value to suffix all topics handled by relayer.
            Defaults to empty string.
        source: This value will be added as a top level key in your payloads
            when using emit or log. If defined it must be a json serializable
            value. Defaults to topic_prefix + logging_topic + topic_suffix.
        producer_opts: optional dictionary with the configuration
            for http://kafka-python.readthedocs.io/en/master/apidoc/KafkaProducer.html
    """

    def __init__(self, logging_topic, **kwargs):
        self.logging_topic = logging_topic

        if 'kafka_hosts' not in kwargs:
            raise ConfigurationError()

        topic_prefix = kwargs.get('topic_prefix', '')
        topic_suffix = kwargs.get('topic_suffix', '')

        if 'source' not in kwargs:
            self.source = '{0}{1}{2}'.format(topic_prefix, logging_topic, topic_suffix)
        else:
            self.source = kwargs.get('source')

        producer_opts = kwargs.get('producer_opts', {})
        self._producer = KafkaProducer(bootstrap_servers=kwargs.get('kafka_hosts'), **producer_opts)

        self._emitter = EventEmitter(self._producer, topic_prefix=topic_prefix, topic_suffix=topic_suffix)

    def emit(self, event_type, event_subtype, payload, partition_key=None):
        payload = {
            'source': self.source,
            'event_type': event_type,
            'event_subtype': event_subtype,
            'payload': payload
        }
        self._emitter.emit(event_type, payload, partition_key)

    def emit_raw(self, topic, message, partition_key=None):
        self._emitter.emit(topic, message, partition_key)

    def log(self, log_level, payload):
        if dict != type(payload):
            payload = {'message': payload}

        log.debug('relayer_logger_deprecated')
        log.info('relayer_log', log_level=log_level, **payload)  # logger.log isn't working properly

    def flush(self):
        self._emitter.flush()
<commit_msg>bump version to 2.0.3<commit_after>from kafka import KafkaProducer

from .event_emitter import EventEmitter
from .exceptions import ConfigurationError
from .logging import logger as log

__version__ = '2.0.3'

class Relayer(object):
    """
    Arguments:
        logging_topic: desired kafka topic to send logs, this will get modified if a prefix o suffix is set.
    Keyword Arguments:
        kafka_hosts: 'host[:port]' string (or list of 'host[:port]'
            strings) that the producer should contact to bootstrap initial
            cluster metadata. This does not have to be the full node list.
            It just needs to have at least one broker that will respond to a
            Metadata API Request.
        topic_prefix: value to prefix all topics handled by relayer.
            Defaults to empty string.
        topic_suffix: value to suffix all topics handled by relayer.
            Defaults to empty string.
        source: This value will be added as a top level key in your payloads
            when using emit or log. If defined it must be a json serializable
            value. Defaults to topic_prefix + logging_topic + topic_suffix.
        producer_opts: optional dictionary with the configuration
            for http://kafka-python.readthedocs.io/en/master/apidoc/KafkaProducer.html
    """

    def __init__(self, logging_topic, **kwargs):
        self.logging_topic = logging_topic

        if 'kafka_hosts' not in kwargs:
            raise ConfigurationError()

        topic_prefix = kwargs.get('topic_prefix', '')
        topic_suffix = kwargs.get('topic_suffix', '')

        if 'source' not in kwargs:
            self.source = '{0}{1}{2}'.format(topic_prefix, logging_topic, topic_suffix)
        else:
            self.source = kwargs.get('source')

        producer_opts = kwargs.get('producer_opts', {})
        self._producer = KafkaProducer(bootstrap_servers=kwargs.get('kafka_hosts'), **producer_opts)

        self._emitter = EventEmitter(self._producer, topic_prefix=topic_prefix, topic_suffix=topic_suffix)

    def emit(self, event_type, event_subtype, payload, partition_key=None):
        payload = {
            'source': self.source,
            'event_type': event_type,
            'event_subtype': event_subtype,
            'payload': payload
        }
        self._emitter.emit(event_type, payload, partition_key)

    def emit_raw(self, topic, message, partition_key=None):
        self._emitter.emit(topic, message, partition_key)

    def log(self, log_level, payload):
        if dict != type(payload):
            payload = {'message': payload}

        log.debug('relayer_logger_deprecated')
        log.info('relayer_log', log_level=log_level, **payload)  # logger.log isn't working properly

    def flush(self):
        self._emitter.flush()
<|endoftext|>


<commit_before># encoding: utf-8

from datetime import datetime

__author__ = "Tsuyoshi Hombashi"
__copyright__ = "Copyright 2016-{}, {}".format(datetime.now().year, __author__)
__license__ = "MIT License"
__version__ = "0.15.2"
__maintainer__ = __author__
__email__ = "tsuyoshi.hombashi@gmail.com"
<commit_msg>Bump version<commit_after># encoding: utf-8

from datetime import datetime

__author__ = "Tsuyoshi Hombashi"
__copyright__ = "Copyright 2016-{}, {}".format(datetime.now().year, __author__)
__license__ = "MIT License"
__version__ = "0.15.3"
__maintainer__ = __author__
__email__ = "tsuyoshi.hombashi@gmail.com"
<|endoftext|>


<commit_before>import cairocffi
import os
from libqtile import bar
from . import base

BAT_DIR = '/sys/class/power_supply'
CHARGED = 'Full'
CHARGING = 'Charging'
DISCHARGING = 'Discharging'
UNKNOWN = 'Unknown'

BATTERY_INFO_FILES = {
    'energy_now_file': ['energy_now', 'charge_now'],
    'energy_full_file': ['energy_full', 'charge_full'],
    'power_now_file': ['power_now', 'current_now'],
    'status_file': ['status'],
}

def default_icon_path():
    # default icons are in libqtile/resources/battery-icons
    root = os.sep.join(os.path.abspath(__file__).split(os.sep)[:-2])
    return os.path.join(root, 'resources', 'battery-icons')

class _Battery(base._TextBox):
    ''' Base battery class '''

    filenames = {}

    defaults = [
        ('battery_name', 'BAT0', 'ACPI name of a battery, usually BAT0'),
        (
            'status_file',
            'status',
            'Name of status file in'
            ' /sys/class/power_supply/battery_name'
        ),
        (
            'energy_now_file',
            None,
            'Name of file with the '
            'current energy in /sys/class/power_supply/battery_name'
        ),
        (
            'energy_full_file',
            None,
            'Name of file with the maximum'
            ' energy in /sys/class/power_supply/battery_name'
        ),
        (
            'power_now_file',
            None,
            'Name of file with the current'
            ' power draw in /sys/class/power_supply/battery_name'
        ),
        ('update_delay', 1, 'The delay in seconds between updates'),
    ]

    def __init__(self, **config):
        base._TextBox.__init__(self, "BAT", bar.CALCULATED, **config)
        self.add_defaults(_Battery.defaults)

    def _load_file(self, name):
        try:
            path = os.path.join(BAT_DIR, self.battery_name, name)
            with open(path, 'r') as f:
                return f.read().strip()
        except IOError:
            if name == 'current_now':
                return 0
            return False
        except Exception:
            self.log.exception("Failed to get %s" % name)

    def _get_param(self, name):
        if name in self.filenames:
            return self._load_file(self.filenames[name])
        else:
            # Don't have the file name cached, figure it out
            file_list = BATTERY_INFO_FILES.get(name, [])
            if getattr(self, name, None):
                # If a file is manually specified, check it first
                file_list.insert(0, getattr(self, name))

            # Iterate over the possibilities, and return the first valid value
            for file in file_list:
                value = self._load_file(file)
                if not (value in (False, None)):
                    self.filenames[name] = file
                    return value

        # If we made it this far, we don't have a valid file. Just return None.
        return None

    def _get_info(self):
        try:
            info = {
                'stat': self._get_param('status_file'),
                'now': float(self._get_param('energy_now_file')),
                'full': float(self._get_param('energy_full_file')),
                'power': float(self._get_param('power_now_file')),
            }
        except TypeError:
            return False
        return info

class Battery(_Battery):
    """
        A simple but flexible text-based battery widget.
    """
    defaults = [
        ('low_foreground', 'FF0000', 'font color when battery is low'),
        (
            'format',
            '{char} {percent:2.0%} {hour:d}:{min:02d}',
            'Display format'
        ),
        ('charge_char', '^', 'Character to indicate the battery is charging'),
        (
            'discharge_char',
            'V',
            'Character to indicate the battery'
            ' is discharging'
        ),
        (
            'low_percentage',
            0.10,
            "0 < x < 1 at which to indicate battery is low with low_foreground"
        ),
        ('hide_threshold', None, 'Hide the text when there is enough energy'),
    ]

    def __init__(self, **config):
        _Battery.__init__(self, **config)
        self.add_defaults(Battery.defaults)
        self.timeout_add(self.update_delay, self.update)
        self.update()

    def _get_text(self):
        info = self._get_info()
        if info is False:
            return 'Error'

        # Set the charging character
        try:
            # hide the text when it's higher than threshold, but still
            # display `full` when the battery is fully charged.
            if self.hide_threshold and \
                    info['now'] / info['full'] * 100.0 >= \
                    self.hide_threshold and \
                    info['stat'] != CHARGED:
                return ''
            elif info['stat'] == DISCHARGING:
                char = self.discharge_char
                time = info['now'] / info['power']
            elif info['stat'] == CHARGING:
                char = self.charge_char
                time = (info['full'] - info['now']) / info['power']
            else:
                return 'Full'
        except ZeroDivisionError:
            time = -1

        # Calculate the battery percentage and time left
        if time >= 0:
            hour = int(time)
            min = int(time * 60) % 60
        else:
            hour = -1
            min = -1
        percent = info['now'] / info['full']
        if info['stat'] == DISCHARGING and percent < self.low_percentage:
            self.layout.colour = self.low_foreground
        else:
            self.layout.colour = self.foreground

        return self.format.format(
            char=char,
            percent=percent,
            hour=hour,
            min=min
        )

    def update(self):
        if self.configured:
            ntext = self._get_text()
            if ntext != self.text:
                self.text = ntext
                self.bar.draw()
        return True

class BatteryIcon(_Battery):
    ''' Battery life indicator widget '''

    defaults = [
        ('theme_path', default_icon_path(), 'Path of the icons'),
        ('custom_icons', {}, 'dict containing key->filename icon map'),
    ]

    def __init__(self, **config):
        _Battery.__init__(self, **config)
        self.add_defaults(BatteryIcon.defaults)

        if self.theme_path:
            self.width_type = bar.STATIC
            self.width = 0
        self.surfaces = {}
        self.current_icon = 'battery-missing'
        self.icons = dict([(x, '{0}.png'.format(x)) for x in (
            'battery-missing',
            'battery-caution',
            'battery-low',
            'battery-good',
            'battery-full',
            'battery-caution-charging',
            'battery-low-charging',
            'battery-good-charging',
            'battery-full-charging',
            'battery-full-charged',
        )])
        self.icons.update(self.custom_icons)
        self.timeout_add(self.update_delay, self.update)

    def _configure(self, qtile, bar):
        base._TextBox._configure(self, qtile, bar)
        self.setup_images()

    def _get_icon_key(self):
        key = 'battery'
        info = self._get_info()
        if info is False or not info.get('full'):
            key += '-missing'
        else:
            percent = info['now'] / info['full']
            if percent < .2:
                key += '-caution'
            elif percent < .4:
                key += '-low'
            elif percent < .8:
                key += '-good'
            else:
                key += '-full'

            if info['stat'] == CHARGING:
                key += '-charging'
            elif info['stat'] == CHARGED:
                key += '-charged'
        return key

    def update(self):
        if self.configured:
            icon = self._get_icon_key()
            if icon != self.current_icon:
                self.current_icon = icon
                self.draw()
        return True

    def draw(self):
        if self.theme_path:
            self.drawer.clear(self.background or self.bar.background)
            self.drawer.ctx.set_source(self.surfaces[self.current_icon])
            self.drawer.ctx.paint()
            self.drawer.draw(self.offset, self.width)
        else:
            self.text = self.current_icon[8:]
            base._TextBox.draw(self)

    def setup_images(self):
        for key, name in self.icons.items():
            try:
                path = os.path.join(self.theme_path, name)
                img = cairocffi.ImageSurface.create_from_png(path)
            except cairocffi.Error:
                self.theme_path = None
                self.qtile.log.warning('Battery Icon switching to text mode')
                return
            input_width = img.get_width()
            input_height = img.get_height()

            sp = input_height / float(self.bar.height - 1)

            width = input_width / sp
            if width > self.width:
                self.width = int(width) + self.actual_padding * 2

            imgpat = cairocffi.SurfacePattern(img)

            scaler = cairocffi.Matrix()

            scaler.scale(sp, sp)
            scaler.translate(self.actual_padding * -1, 0)
            imgpat.set_matrix(scaler)

            imgpat.set_filter(cairocffi.FILTER_BEST)
            self.surfaces[key] = imgpat
<commit_msg>Fix #379, "CPU usage leak" with battery widget<commit_after>import cairocffi
import os
from libqtile import bar
from . import base

BAT_DIR = '/sys/class/power_supply'
CHARGED = 'Full'
CHARGING = 'Charging'
DISCHARGING = 'Discharging'
UNKNOWN = 'Unknown'

BATTERY_INFO_FILES = {
    'energy_now_file': ['energy_now', 'charge_now'],
    'energy_full_file': ['energy_full', 'charge_full'],
    'power_now_file': ['power_now', 'current_now'],
    'status_file': ['status'],
}

def default_icon_path():
    # default icons are in libqtile/resources/battery-icons
    root = os.sep.join(os.path.abspath(__file__).split(os.sep)[:-2])
    return os.path.join(root, 'resources', 'battery-icons')

class _Battery(base._TextBox):
    ''' Base battery class '''

    filenames = {}

    defaults = [
        ('battery_name', 'BAT0', 'ACPI name of a battery, usually BAT0'),
        (
            'status_file',
            'status',
            'Name of status file in'
            ' /sys/class/power_supply/battery_name'
        ),
        (
            'energy_now_file',
            None,
            'Name of file with the '
            'current energy in /sys/class/power_supply/battery_name'
        ),
        (
            'energy_full_file',
            None,
            'Name of file with the maximum'
            ' energy in /sys/class/power_supply/battery_name'
        ),
        (
            'power_now_file',
            None,
            'Name of file with the current'
            ' power draw in /sys/class/power_supply/battery_name'
        ),
        ('update_delay', 1, 'The delay in seconds between updates'),
    ]

    def __init__(self, **config):
        base._TextBox.__init__(self, "BAT", bar.CALCULATED, **config)
        self.add_defaults(_Battery.defaults)

    def _load_file(self, name):
        try:
            path = os.path.join(BAT_DIR, self.battery_name, name)
            with open(path, 'r') as f:
                return f.read().strip()
        except IOError:
            if name == 'current_now':
                return 0
            return False
        except Exception:
            self.log.exception("Failed to get %s" % name)

    def _get_param(self, name):
        if name in self.filenames and self.filenames[name]:
            return self._load_file(self.filenames[name])
        elif name not in self.filenames:
            # Don't have the file name cached, figure it out

            # Don't modify the global list! Copy with [:]
            file_list = BATTERY_INFO_FILES.get(name, [])[:]

            if getattr(self, name, None):
                # If a file is manually specified, check it first
                file_list.insert(0, getattr(self, name))

            # Iterate over the possibilities, and return the first valid value
            for file in file_list:
                value = self._load_file(file)
                if not (value in (False, None)):
                    self.filenames[name] = file
                    return value

        # If we made it this far, we don't have a valid file.
        # Set it to None to avoid trying the next time.
        self.filenames[name] = None

        return None

    def _get_info(self):
        try:
            info = {
                'stat': self._get_param('status_file'),
                'now': float(self._get_param('energy_now_file')),
                'full': float(self._get_param('energy_full_file')),
                'power': float(self._get_param('power_now_file')),
            }
        except TypeError:
            return False
        return info

class Battery(_Battery):
    """
        A simple but flexible text-based battery widget.
    """
    defaults = [
        ('low_foreground', 'FF0000', 'font color when battery is low'),
        (
            'format',
            '{char} {percent:2.0%} {hour:d}:{min:02d}',
            'Display format'
        ),
        ('charge_char', '^', 'Character to indicate the battery is charging'),
        (
            'discharge_char',
            'V',
            'Character to indicate the battery'
            ' is discharging'
        ),
        (
            'low_percentage',
            0.10,
            "0 < x < 1 at which to indicate battery is low with low_foreground"
        ),
        ('hide_threshold', None, 'Hide the text when there is enough energy'),
    ]

    def __init__(self, **config):
        _Battery.__init__(self, **config)
        self.add_defaults(Battery.defaults)
        self.timeout_add(self.update_delay, self.update)
        self.update()

    def _get_text(self):
        info = self._get_info()
        if info is False:
            return 'Error'

        # Set the charging character
        try:
            # hide the text when it's higher than threshold, but still
            # display `full` when the battery is fully charged.
            if self.hide_threshold and \
                    info['now'] / info['full'] * 100.0 >= \
                    self.hide_threshold and \
                    info['stat'] != CHARGED:
                return ''
            elif info['stat'] == DISCHARGING:
                char = self.discharge_char
                time = info['now'] / info['power']
            elif info['stat'] == CHARGING:
                char = self.charge_char
                time = (info['full'] - info['now']) / info['power']
            else:
                return 'Full'
        except ZeroDivisionError:
            time = -1

        # Calculate the battery percentage and time left
        if time >= 0:
            hour = int(time)
            min = int(time * 60) % 60
        else:
            hour = -1
            min = -1
        percent = info['now'] / info['full']
        if info['stat'] == DISCHARGING and percent < self.low_percentage:
            self.layout.colour = self.low_foreground
        else:
            self.layout.colour = self.foreground

        return self.format.format(
            char=char,
            percent=percent,
            hour=hour,
            min=min
        )

    def update(self):
        if self.configured:
            ntext = self._get_text()
            if ntext != self.text:
                self.text = ntext
                self.bar.draw()
        return True

class BatteryIcon(_Battery):
    ''' Battery life indicator widget '''

    defaults = [
        ('theme_path', default_icon_path(), 'Path of the icons'),
        ('custom_icons', {}, 'dict containing key->filename icon map'),
    ]

    def __init__(self, **config):
        _Battery.__init__(self, **config)
        self.add_defaults(BatteryIcon.defaults)

        if self.theme_path:
            self.width_type = bar.STATIC
            self.width = 0
        self.surfaces = {}
        self.current_icon = 'battery-missing'
        self.icons = dict([(x, '{0}.png'.format(x)) for x in (
            'battery-missing',
            'battery-caution',
            'battery-low',
            'battery-good',
            'battery-full',
            'battery-caution-charging',
            'battery-low-charging',
            'battery-good-charging',
            'battery-full-charging',
            'battery-full-charged',
        )])
        self.icons.update(self.custom_icons)
        self.timeout_add(self.update_delay, self.update)

    def _configure(self, qtile, bar):
        base._TextBox._configure(self, qtile, bar)
        self.setup_images()

    def _get_icon_key(self):
        key = 'battery'
        info = self._get_info()
        if info is False or not info.get('full'):
            key += '-missing'
        else:
            percent = info['now'] / info['full']
            if percent < .2:
                key += '-caution'
            elif percent < .4:
                key += '-low'
            elif percent < .8:
                key += '-good'
            else:
                key += '-full'

            if info['stat'] == CHARGING:
                key += '-charging'
            elif info['stat'] == CHARGED:
                key += '-charged'
        return key

    def update(self):
        if self.configured:
            icon = self._get_icon_key()
            if icon != self.current_icon:
                self.current_icon = icon
                self.draw()
        return True

    def draw(self):
        if self.theme_path:
            self.drawer.clear(self.background or self.bar.background)
            self.drawer.ctx.set_source(self.surfaces[self.current_icon])
            self.drawer.ctx.paint()
            self.drawer.draw(self.offset, self.width)
        else:
            self.text = self.current_icon[8:]
            base._TextBox.draw(self)

    def setup_images(self):
        for key, name in self.icons.items():
            try:
                path = os.path.join(self.theme_path, name)
                img = cairocffi.ImageSurface.create_from_png(path)
            except cairocffi.Error:
                self.theme_path = None
                self.qtile.log.warning('Battery Icon switching to text mode')
                return
            input_width = img.get_width()
            input_height = img.get_height()

            sp = input_height / float(self.bar.height - 1)

            width = input_width / sp
            if width > self.width:
                self.width = int(width) + self.actual_padding * 2

            imgpat = cairocffi.SurfacePattern(img)

            scaler = cairocffi.Matrix()

            scaler.scale(sp, sp)
            scaler.translate(self.actual_padding * -1, 0)
            imgpat.set_matrix(scaler)

            imgpat.set_filter(cairocffi.FILTER_BEST)
            self.surfaces[key] = imgpat
<|endoftext|>