<commit_before>"""
spaceshooter.py
Author: Ethan Adner
Credit:

Assignment:
Write and submit a program that implements the spacewar game:
https://github.com/HHS-IntroProgramming/Spacewar
"""
"""
tutorial4.py
by E. Dennison
"""

from ggame import App, RectangleAsset, ImageAsset, Sprite, LineStyle, Color, Frame
from math import sin, cos, pi

SCREEN_WIDTH = 1024
SCREEN_HEIGHT = 700

"""class Stars(Sprite):

    asset = ImageAsset("images/starfield.jpg")
    width = 512
    height = 512

    def __init__(self, position):
        super().__init__(Stars.asset, position)

"""
class SpaceShip(Sprite):

#    Animated space ship

    asset = ImageAsset("images/four_spaceship_by_albertov_with_thrust.png",
    Frame(227,0,292-227,125), 4, 'vertical')

    def __init__(self, position):
        super().__init__(SpaceShip.asset, position)
        self.vx = 0
        self.vy = 0
        self.vr = .0
        self.thrust = 0
        self.thrustframe = 1

        SpaceGame.listenKeyEvent("keydown", "q", self.clockwise)
        SpaceGame.listenKeyEvent("keyup", "q", self.stopr)
        SpaceGame.listenKeyEvent("keydown", "e", self.cntrclockwise)
        SpaceGame.listenKeyEvent("keyup", "e", self.stopr)
        SpaceGame.listenKeyEvent("keydown", "space", self.thrustOn)
        SpaceGame.listenKeyEvent("keyup", "space", self.thrustOff)

        self.fxcenter = self.fycenter = 0.5

    def step(self):
        self.x += self.vx
        self.y += self.vy
        self.rotation += self.vr
        if self.thrust==1:
            self.vx=.1*cos(self.rotation+1/2*pi)+self.vx
            self.vy=.1*sin(self.rotation-1/2*pi)+self.vy
        if self.thrust == 1:
            self.setImage(self.thrustframe)
            self.thrustframe += 1
            if self.thrustframe == 4:
                self.thrustframe = 1
        else:
            self.setImage(0)

    def thrustOn(self, event):
        self.thrust = 1

    def thrustOff(self, event):
        self.thrust = 0

    def stopr(self, event):
        self.vr=0

    def clockwise(self, event):
        self.vr=.05

    def cntrclockwise(self, event):
        self.vr=-.05

class SpaceShipShoot(SpaceShip):

    asset1=ImageAsset("blast.png")

    def __init__(self, positions):
        super().__init__(SpaceShipShoot.asset1, position)
        self.vsx = 0
        self.vsy = 0

        SpaceGame.listenKeyEvent("keydown", "s", self.shotOn)
        SpaceGame.listenKeyEvent("keyup", "s", self.shotOff)

    def shotOn(self, event):
        return()

class SpaceGame(App):

    #Tutorial4 space game example.

    def __init__(self, width, height):
        super().__init__(width, height)
        black = Color(0, 1)
        noline = LineStyle(0, black)
        bg_asset = ImageAsset("images/starfield.jpg")
        bg_asset2= ImageAsset("sun.png")
        bg1 = Sprite(bg_asset, (0,0))
        bg2 = Sprite(bg_asset, (512,0))
        bg3 = Sprite(bg_asset, (0,512))
        bg4 = Sprite(bg_asset, (512,512))
        bg5 = Sprite(bg_asset, (1024,0))
        bg6 = Sprite(bg_asset, (1024,1024))
        bg7 = Sprite(bg_asset, (1536,1024))
        bg8 = Sprite(bg_asset, (512,512))
        SpaceShip((100,100))

    def step(self):
        for ship in self.getSpritesbyClass(SpaceShip):
            ship.step()

myapp = SpaceGame(SCREEN_WIDTH, SCREEN_HEIGHT)
myapp.run()<commit_msg>Updated from Brython Server: 3/23/2016 9:27:25 AM<commit_after>"""
spaceshooter.py
Author: Ethan Adner
Credit:

Assignment:
Write and submit a program that implements the spacewar game:
https://github.com/HHS-IntroProgramming/Spacewar
"""
"""
tutorial4.py
by E. Dennison
"""

from ggame import App, RectangleAsset, ImageAsset, Sprite, LineStyle, Color, Frame
from math import sin, cos, pi

SCREEN_WIDTH = 1024
SCREEN_HEIGHT = 700

"""class Stars(Sprite):

    asset = ImageAsset("images/starfield.jpg")
    width = 512
    height = 512

    def __init__(self, position):
        super().__init__(Stars.asset, position)

"""
class SpaceShip(Sprite):

#    Animated space ship

    asset = ImageAsset("images/four_spaceship_by_albertov_with_thrust.png",
    Frame(227,0,292-227,125), 4, 'vertical')

    def __init__(self, position):
        super().__init__(SpaceShip.asset, position)
        self.vx = 0
        self.vy = 0
        self.vr = .0
        self.thrust = 0
        self.thrustframe = 1

        SpaceGame.listenKeyEvent("keydown", "q", self.clockwise)
        SpaceGame.listenKeyEvent("keyup", "q", self.stopr)
        SpaceGame.listenKeyEvent("keydown", "e", self.cntrclockwise)
        SpaceGame.listenKeyEvent("keyup", "e", self.stopr)
        SpaceGame.listenKeyEvent("keydown", "space", self.thrustOn)
        SpaceGame.listenKeyEvent("keyup", "space", self.thrustOff)

        self.fxcenter = self.fycenter = 0.5

    def step(self):
        self.x += self.vx
        self.y += self.vy
        self.rotation += self.vr
        if self.thrust==1:
            self.vx=.1*cos(self.rotation+1/2*pi)+self.vx
            self.vy=.1*sin(self.rotation-1/2*pi)+self.vy
        if self.thrust == 1:
            self.setImage(self.thrustframe)
            self.thrustframe += 1
            if self.thrustframe == 4:
                self.thrustframe = 1
        else:
            self.setImage(0)

    def thrustOn(self, event):
        self.thrust = 1

    def thrustOff(self, event):
        self.thrust = 0

    def stopr(self, event):
        self.vr=0

    def clockwise(self, event):
        self.vr=.05

    def cntrclockwise(self, event):
        self.vr=-.05

class SpaceShipShoot(SpaceShip):

    asset1=ImageAsset("blast.png")

    def __init__(self, positions):
        super().__init__(SpaceShipShoot.asset1, position)
        self.vsx = 0
        self.vsy = 0

        SpaceGame.listenKeyEvent("keydown", "s", self.shotOn)
        SpaceGame.listenKeyEvent("keyup", "s", self.shotOff)

    def shotOn(self, event):
        return()

class SpaceGame(App):

    #Tutorial4 space game example.

    def __init__(self, width, height):
        super().__init__(width, height)
        black = Color(0, 1)
        noline = LineStyle(0, black)
        bg_asset = ImageAsset("images/starfield.jpg")
        bg_asset2= ImageAsset("sun.png")
        bg1 = Sprite(bg_asset, (0,0))
        bg2 = Sprite(bg_asset, (512,0))
        bg3 = Sprite(bg_asset, (0,512))
        bg4 = Sprite(bg_asset, (512,512))
        bg5 = Sprite(bg_asset, (1024,0))
        bg6 = Sprite(bg_asset, (1024,1024))
        bg7 = Sprite(bg_asset, (1536,1024))
        bg8 = Sprite(bg_asset, (512,512))
        SpaceShip((100,100))

    def step(self):
        for ship in self.getSpritesbyClass(SpaceShip):
            ship.step()

myapp = SpaceGame(SCREEN_WIDTH, SCREEN_HEIGHT)
myapp.run()<|endoftext|>


<commit_before>"""

variants.py

This file contains functions for reading a set of mapped reads in SAM/BAM
format and discovering variant single nucleotide polymorphism (SNP) sites.
This includes positions that are polymorphic with the sample and positions
where a non-reference base is fixed. We'll assume that the reference is the
Reconstructed Sapiens Reference Sequence (RSRS).

Sam Vohr (svohr@soe.ucsc.edu)
Sun Apr  3 16:12:59 PDT 2016

"""

import pysam
import numpy

def init_obs_tab(ref_seq):
    """
    Makes an empty table for counting observed bases at reference positions.
    """
    return pos_obs

def count_read_matches(pos_obs, read, min_bq):
    """
    For all matched positions in the read, increments the count for the
    observed base in the position table if base quality passes filter.
    """
    for qpos, rpos in read.get_aligned_pairs(matches_only=True):
        qpos = int(qpos)
        rpos = int(rpos)
        if aln.query_qualities[qpos] >= min_bq:
            pos_obs[qpos][read.query_sequence[qpos]] += 1
        else:
            pos_obs[qpos]['N'] += 1
    return pos_obs

def build_obs_tab(pos_obs, reads, min_bq):
    """
    Returns a table of observation counts per base and position.
    """
    for read in reads:
        count_read_matches(pos_obs, read, min_bq)
    return

def _find_variants(pos_obs, ref_seq):
    """
    Returns a list of (position, alternative base(s)) tuples that describes
    where non-reference bases are observed consistently.
    """
    return

def find_variants(reads, ref_seq, min_bq):
    """
    Takes in a list of pysam.AlignedSegments, a reference sequence and
    additional filtering parameters and returns a list of variant positions
    and alternative base(s) for positions where non-reference bases occur.
    """
    pos_obs = init_obs_tab(ref_seq)
    build_obs_tab(pos_obs, reads, min_bq)
    return _find_variants(pos_obs, ref_seq)

<commit_msg>Added TODO for variant discovery.<commit_after>"""

variants.py

This file contains functions for reading a set of mapped reads in SAM/BAM
format and discovering variant single nucleotide polymorphism (SNP) sites.
This includes positions that are polymorphic with the sample and positions
where a non-reference base is fixed. We'll assume that the reference is the
Reconstructed Sapiens Reference Sequence (RSRS).

Sam Vohr (svohr@soe.ucsc.edu)
Sun Apr  3 16:12:59 PDT 2016

"""

import pysam
import numpy

# TODO:
# Figure out if how to store this table.
# 1) Basic python list of Counters?
# 2) numpy array?

def init_obs_tab(ref_seq):
    """
    Makes an empty table for counting observed bases at reference positions.
    """
    return pos_obs

def count_read_matches(pos_obs, read, min_bq):
    """
    For all matched positions in the read, increments the count for the
    observed base in the position table if base quality passes filter.
    """
    for qpos, rpos in read.get_aligned_pairs(matches_only=True):
        qpos = int(qpos)
        rpos = int(rpos)
        if aln.query_qualities[qpos] >= min_bq:
            pos_obs[qpos][read.query_sequence[qpos]] += 1
        else:
            pos_obs[qpos]['N'] += 1
    return pos_obs

def build_obs_tab(pos_obs, reads, min_bq):
    """
    Returns a table of observation counts per base and position.
    """
    for read in reads:
        count_read_matches(pos_obs, read, min_bq)
    return

def _find_variants(pos_obs, ref_seq):
    """
    Returns a list of (position, alternative base(s)) tuples that describes
    where non-reference bases are observed consistently.
    """
    return

def find_variants(reads, ref_seq, min_bq):
    """
    Takes in a list of pysam.AlignedSegments, a reference sequence and
    additional filtering parameters and returns a list of variant positions
    and alternative base(s) for positions where non-reference bases occur.
    """
    pos_obs = init_obs_tab(ref_seq)
    build_obs_tab(pos_obs, reads, min_bq)
    return _find_variants(pos_obs, ref_seq)

<|endoftext|>


<commit_before>"""Support for the Nettigo Air Monitor service."""
from __future__ import annotations

from datetime import timedelta
import logging
from typing import cast

from homeassistant.components.sensor import (
    ATTR_STATE_CLASS,
    DOMAIN as PLATFORM,
    SensorEntity,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import ATTR_DEVICE_CLASS, ATTR_ICON
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import StateType
from homeassistant.helpers.update_coordinator import CoordinatorEntity
from homeassistant.util.dt import utcnow

from . import NAMDataUpdateCoordinator
from .const import (
    ATTR_ENABLED,
    ATTR_LABEL,
    ATTR_UNIT,
    ATTR_UPTIME,
    DOMAIN,
    MIGRATION_SENSORS,
    SENSORS,
)

PARALLEL_UPDATES = 1

_LOGGER = logging.getLogger(__name__)

async def async_setup_entry(
    hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
) -> None:
    """Add a Nettigo Air Monitor entities from a config_entry."""
    coordinator: NAMDataUpdateCoordinator = hass.data[DOMAIN][entry.entry_id]

    # Due to the change of the attribute name of two sensora, it is necessary to migrate
    # the unique_ids to the new names.
    ent_reg = entity_registry.async_get(hass)
    for old_sensor, new_sensor in MIGRATION_SENSORS:
        old_unique_id = f"{coordinator.unique_id}-{old_sensor}"
        new_unique_id = f"{coordinator.unique_id}-{new_sensor}"
        if entity_id := ent_reg.async_get_entity_id(PLATFORM, DOMAIN, old_unique_id):
            _LOGGER.debug(
                "Migrating entity %s from old unique ID '%s' to new unique ID '%s'",
                entity_id,
                old_unique_id,
                new_unique_id,
            )
            ent_reg.async_update_entity(entity_id, new_unique_id=new_unique_id)

    sensors: list[NAMSensor | NAMSensorUptime] = []
    for sensor in SENSORS:
        if getattr(coordinator.data, sensor) is not None:
            if sensor == ATTR_UPTIME:
                sensors.append(NAMSensorUptime(coordinator, sensor))
            else:
                sensors.append(NAMSensor(coordinator, sensor))

    async_add_entities(sensors, False)

class NAMSensor(CoordinatorEntity, SensorEntity):
    """Define an Nettigo Air Monitor sensor."""

    coordinator: NAMDataUpdateCoordinator

    def __init__(self, coordinator: NAMDataUpdateCoordinator, sensor_type: str) -> None:
        """Initialize."""
        super().__init__(coordinator)
        description = SENSORS[sensor_type]
        self._attr_device_class = description[ATTR_DEVICE_CLASS]
        self._attr_device_info = coordinator.device_info
        self._attr_entity_registry_enabled_default = description[ATTR_ENABLED]
        self._attr_icon = description[ATTR_ICON]
        self._attr_name = description[ATTR_LABEL]
        self._attr_state_class = description[ATTR_STATE_CLASS]
        self._attr_unique_id = f"{coordinator.unique_id}-{sensor_type}"
        self._attr_unit_of_measurement = description[ATTR_UNIT]
        self.sensor_type = sensor_type

    @property
    def state(self) -> StateType:
        """Return the state."""
        return cast(StateType, getattr(self.coordinator.data, self.sensor_type))

    @property
    def available(self) -> bool:
        """Return if entity is available."""
        available = super().available

        # For a short time after booting, the device does not return values for all
        # sensors. For this reason, we mark entities for which data is missing as
        # unavailable.
        return (
            available and getattr(self.coordinator.data, self.sensor_type) is not None
        )

class NAMSensorUptime(NAMSensor):
    """Define an Nettigo Air Monitor uptime sensor."""

    @property
    def state(self) -> str:
        """Return the state."""
        uptime_sec = getattr(self.coordinator.data, self.sensor_type)
        return (
            (utcnow() - timedelta(seconds=uptime_sec))
            .replace(microsecond=0)
            .isoformat()
        )
<commit_msg>Fix typo in Nettigo Air Monitor integration (#52182)<commit_after>"""Support for the Nettigo Air Monitor service."""
from __future__ import annotations

from datetime import timedelta
import logging
from typing import cast

from homeassistant.components.sensor import (
    ATTR_STATE_CLASS,
    DOMAIN as PLATFORM,
    SensorEntity,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import ATTR_DEVICE_CLASS, ATTR_ICON
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import StateType
from homeassistant.helpers.update_coordinator import CoordinatorEntity
from homeassistant.util.dt import utcnow

from . import NAMDataUpdateCoordinator
from .const import (
    ATTR_ENABLED,
    ATTR_LABEL,
    ATTR_UNIT,
    ATTR_UPTIME,
    DOMAIN,
    MIGRATION_SENSORS,
    SENSORS,
)

PARALLEL_UPDATES = 1

_LOGGER = logging.getLogger(__name__)

async def async_setup_entry(
    hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
) -> None:
    """Add a Nettigo Air Monitor entities from a config_entry."""
    coordinator: NAMDataUpdateCoordinator = hass.data[DOMAIN][entry.entry_id]

    # Due to the change of the attribute name of two sensors, it is necessary to migrate
    # the unique_ids to the new names.
    ent_reg = entity_registry.async_get(hass)
    for old_sensor, new_sensor in MIGRATION_SENSORS:
        old_unique_id = f"{coordinator.unique_id}-{old_sensor}"
        new_unique_id = f"{coordinator.unique_id}-{new_sensor}"
        if entity_id := ent_reg.async_get_entity_id(PLATFORM, DOMAIN, old_unique_id):
            _LOGGER.debug(
                "Migrating entity %s from old unique ID '%s' to new unique ID '%s'",
                entity_id,
                old_unique_id,
                new_unique_id,
            )
            ent_reg.async_update_entity(entity_id, new_unique_id=new_unique_id)

    sensors: list[NAMSensor | NAMSensorUptime] = []
    for sensor in SENSORS:
        if getattr(coordinator.data, sensor) is not None:
            if sensor == ATTR_UPTIME:
                sensors.append(NAMSensorUptime(coordinator, sensor))
            else:
                sensors.append(NAMSensor(coordinator, sensor))

    async_add_entities(sensors, False)

class NAMSensor(CoordinatorEntity, SensorEntity):
    """Define an Nettigo Air Monitor sensor."""

    coordinator: NAMDataUpdateCoordinator

    def __init__(self, coordinator: NAMDataUpdateCoordinator, sensor_type: str) -> None:
        """Initialize."""
        super().__init__(coordinator)
        description = SENSORS[sensor_type]
        self._attr_device_class = description[ATTR_DEVICE_CLASS]
        self._attr_device_info = coordinator.device_info
        self._attr_entity_registry_enabled_default = description[ATTR_ENABLED]
        self._attr_icon = description[ATTR_ICON]
        self._attr_name = description[ATTR_LABEL]
        self._attr_state_class = description[ATTR_STATE_CLASS]
        self._attr_unique_id = f"{coordinator.unique_id}-{sensor_type}"
        self._attr_unit_of_measurement = description[ATTR_UNIT]
        self.sensor_type = sensor_type

    @property
    def state(self) -> StateType:
        """Return the state."""
        return cast(StateType, getattr(self.coordinator.data, self.sensor_type))

    @property
    def available(self) -> bool:
        """Return if entity is available."""
        available = super().available

        # For a short time after booting, the device does not return values for all
        # sensors. For this reason, we mark entities for which data is missing as
        # unavailable.
        return (
            available and getattr(self.coordinator.data, self.sensor_type) is not None
        )

class NAMSensorUptime(NAMSensor):
    """Define an Nettigo Air Monitor uptime sensor."""

    @property
    def state(self) -> str:
        """Return the state."""
        uptime_sec = getattr(self.coordinator.data, self.sensor_type)
        return (
            (utcnow() - timedelta(seconds=uptime_sec))
            .replace(microsecond=0)
            .isoformat()
        )
<|endoftext|>


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

import sys
from random import choice
import argparse

def parse_arguments():
    ''' parse the arguments '''

    parser = argparse.ArgumentParser()

    parser.add_argument('--words-file',
                        help='file with list of words (default: /usr/share/dict/words)',
                        default='/usr/share/dict/words')

    parser.add_argument('--tlds-file',
                        help='file with list of tlds (default: tlds.txt)',
                        default='tlds.txt')

    parser.add_argument('--tlds',
                        help='(optional) manually specify tlds as comma-separated list',
                        default=False)

    return parser.parse_args()

def get_words(words_file, min_length=1):
    ''' iterate over list of words in text file '''

    words = []

    with open(words_file) as handle:
        for word in handle:
            word = word.strip().lower()
            if len(word) > min_length:
                words.append(word)

    return words

def get_tlds(tlds_file):
    ''' iterate over list of tlds in text file '''

    tlds = []

    with open(tlds_file) as handle:
        for tld in handle:
            tld = tld.split()[0].strip().lower()
            tlds.append(tld)

    return tlds

def get_domains(words, tlds):
    ''' list domains made from words and tlds '''

    for word in words:
        for tld in tlds:
            if word.endswith(tld):
                yield '%s.%s' % (word.rstrip(tld), tld)

if __name__ == '__main__':
    args = parse_arguments()

    words = get_words(args.words_file)

    if not args.tlds:
        tlds = get_tlds(args.tlds_file)
    else:
        tlds = args.tlds.split(',')

    for domain in get_domains(words, tlds):
        print domain
<commit_msg>cleaned up arg descriptions<commit_after>#!/usr/bin/env python

import sys
from random import choice
import argparse

def parse_arguments():
    ''' parse the arguments '''

    p = argparse.ArgumentParser()

    p.add_argument('--words-file',
                   help='file with list of words [/usr/share/dict/words]',
                   default='/usr/share/dict/words')

    p.add_argument('--tlds-file',
                   help='file with list of tlds [tlds.txt]',
                   default='tlds.txt')

    p.add_argument('--tlds',
                   help='manually specify tlds as comma-separated list',
                   default=False)

    return p.parse_args()

def get_words(words_file, min_length=1):
    ''' iterate over list of words in text file '''

    words = []

    with open(words_file) as handle:
        for word in handle:
            word = word.strip().lower()
            if len(word) > min_length:
                words.append(word)

    return words

def get_tlds(tlds_file):
    ''' iterate over list of tlds in text file '''

    tlds = []

    with open(tlds_file) as handle:
        for tld in handle:
            tld = tld.split()[0].strip().lower()
            tlds.append(tld)

    return tlds

def get_domains(words, tlds):
    ''' list domains made from words and tlds '''

    for word in words:
        for tld in tlds:
            if word.endswith(tld):
                yield '%s.%s' % (word.rstrip(tld), tld)

if __name__ == '__main__':
    args = parse_arguments()

    words = get_words(args.words_file)

    if not args.tlds:
        tlds = get_tlds(args.tlds_file)
    else:
        tlds = args.tlds.split(',')

    for domain in get_domains(words, tlds):
        print domain
<|endoftext|>


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

import datetime
import re
import unicodedata
import urllib

import flask

import klupung.models

v0 = flask.Blueprint("v0", __name__, url_prefix="/api/v0")

_PUNCT_RE = re.compile(r'[\t !"#$%&\'()*\-/<=>?@\[\\\]^_`{|},.]+')

class Error(Exception):

    def __init__(self, code, message):
        self.code = code
        self.message = message

class InvalidArgumentError(Error):

    def __init__(self, arg, name, expected=""):
        message = "Invalid value '%s' for argument '%s', " \
            "expected %s." % (arg, name, expected)
        Error.__init__(self, 400, message)

def _slugify(text, delim=u'-'):
    result = []
    for word in _PUNCT_RE.split(text.lower()):
        word = unicodedata.normalize('NFKD', word).encode('ascii', 'ignore')
        if word:
            result.append(word)
    return unicode(delim.join(result))

def _get_uint_arg(name, default):
    arg = flask.request.args.get(name, "")
    arg = arg if arg else default
    try:
        value = int(arg)
    except ValueError:
        raise InvalidArgumentError(arg, name, expected="a positive integer")
    else:
        if value < 0:
            raise InvalidArgumentError(arg, name, expected="a positive integer")
    return value

def _get_choice_arg(name, choices):
    arg = flask.request.args.get(name, "")
    arg = arg if arg else choices[0]
    if arg not in choices:
        raise InvalidArgumentError(arg, name,
                                   expected=" or ".join([repr(s) for s in choices]))
    return arg

def jsonified_resource(model_class=None, resource_mapper=None, model_id=None, sortable_columns={}):
    if model_id is not None:
        resource = resource_mapper(model_class.query.get_or_404(model_id))
        return flask.jsonify(**resource)

    limit = min(_get_uint_arg("limit", 20), 1000)
    offset = _get_uint_arg("offset", 0)

    total_count = 0
    objects = []

    if model_class is not None:
        query = model_class.query

        if sortable_columns:
            field = _get_choice_arg("order_by",
                                    sortable_columns.keys()
                                    + ["-%s" % s for s in sortable_columns.keys()])
            is_descending = field.startswith("-")
            field = field.lstrip("-")
            column_name = sortable_columns[field]
            column = getattr(model_class, column_name)
            if is_descending:
                column = klupung.db.desc(column)
            query = query.order_by(column)

        models = query.limit(limit).offset(offset).all()
        total_count = model_class.query.count()
        objects = [resource_mapper(m) for m in models]

    next_path = None
    prev_path = None

    if limit + offset < total_count:
        next_path_args = flask.request.args.to_dict()
        next_path_args["offset"] = offset + limit
        next_path = "%s?%s" % (flask.request.path, urllib.urlencode(next_path_args))

    if offset > 0:
        prev_path_args = flask.request.args.to_dict()
        prev_path_args["offset"] = max(offset - limit, 0)
        prev_path = "%s?%s" % (flask.request.path, urllib.urlencode(prev_path_args))

    resource = {
        "meta": {
            "limit": limit,
            "next": next_path,
            "offset": offset,
            "previous": prev_path,
            "total_count": total_count,
            },
        "objects": objects,
        }

    return flask.jsonify(**resource)

def PolicymakerResource(policymaker):
    return {
        "id": policymaker.id,
        "abbreviation": policymaker.abbreviation,
        "name": policymaker.name,
        "origin_id": policymaker.abbreviation,
        "slug": _slugify(policymaker.abbreviation),
        "summary": None,
        "resource_uri": flask.url_for(".policymaker_route",
                                      policymaker_id=policymaker.id),
        }

def MeetingResource(meeting):
    return {
        "id": meeting.id,
        "date": str(meeting.start_datetime.date()),
        "minutes": True,
        "number": 1,
        "policymaker": flask.url_for(".policymaker_route",
                                     policymaker_id=meeting.policymaker.id),
        "policymaker_name": meeting.policymaker.name,
        "year": meeting.start_datetime.year,
        "resource_uri": flask.url_for(".meeting_route", meeting_id=meeting.id),
        }

def MeetingDocumentResource(meeting_document):
    return {
        "id": meeting_document.id,
        "last_modified_time": None,
        "meeting": MeetingResource(meeting_document.meeting),
        "organisation": None,
        "origin_id": meeting_document.origin_id,
        "origin_url": meeting_document.origin_url,
        "publish_time": None,
        "type": "minutes",
        "xml_uri": None,
        "resource_uri": flask.url_for(".meeting_document_route",
                                      meeting_document_id=meeting_document.id)
        }

@v0.route("/policymaker/")
@v0.route("/policymaker/<int:policymaker_id>/")
def policymaker_route(policymaker_id=None):
    return jsonified_resource(klupung.models.Policymaker,
                              PolicymakerResource,
                              policymaker_id,
                              {"name": "name"})

@v0.route("/meeting/")
@v0.route("/meeting/<int:meeting_id>/")
def meeting_route(meeting_id=None):
    return jsonified_resource(klupung.models.Meeting,
                              MeetingResource,
                              meeting_id,
                              {"date": "start_datetime",
                               "policymaker": "policymaker_id"})

@v0.route("/meeting_document/")
@v0.route("/meeting_document/<int:meeting_document_id>/")
def meeting_document_route(meeting_document_id=None):
    return jsonified_resource(klupung.models.MeetingDocument,
                              MeetingDocumentResource,
                              meeting_document_id)

@v0.route("/category/")
def category_route():
    return jsonified_resource()

@v0.route("/video/")
def video_route():
    return jsonified_resource()

@v0.route("/district/")
def district_route():
    return jsonified_resource()

@v0.route("/attachment/")
def attachment_route():
    return jsonified_resource()

@v0.errorhandler(Error)
def errorhandler(error):
    return flask.jsonify(error=error.message), error.code
<commit_msg>API: sort resource objects instead of database objects<commit_after># KlupuNG
# Copyright (C) 2013 Koodilehto Osk <http://koodilehto.fi>.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

import datetime
import re
import unicodedata
import urllib

import flask

import klupung.models

v0 = flask.Blueprint("v0", __name__, url_prefix="/api/v0")

_PUNCT_RE = re.compile(r'[\t !"#$%&\'()*\-/<=>?@\[\\\]^_`{|},.]+')

class Error(Exception):

    def __init__(self, code, message):
        self.code = code
        self.message = message

class InvalidArgumentError(Error):

    def __init__(self, arg, name, expected=""):
        message = "Invalid value '%s' for argument '%s', " \
            "expected %s." % (arg, name, expected)
        Error.__init__(self, 400, message)

def _slugify(text, delim=u'-'):
    result = []
    for word in _PUNCT_RE.split(text.lower()):
        word = unicodedata.normalize('NFKD', word).encode('ascii', 'ignore')
        if word:
            result.append(word)
    return unicode(delim.join(result))

def _get_uint_arg(name, default):
    arg = flask.request.args.get(name, "")
    arg = arg if arg else default
    try:
        value = int(arg)
    except ValueError:
        raise InvalidArgumentError(arg, name, expected="a positive integer")
    else:
        if value < 0:
            raise InvalidArgumentError(arg, name, expected="a positive integer")
    return value

def _get_choice_arg(name, choices):
    arg = flask.request.args.get(name, "")
    arg = arg if arg else choices[0]
    if arg not in choices:
        raise InvalidArgumentError(arg, name,
                                   expected=" or ".join([repr(s) for s in choices]))
    return arg

def jsonified_resource(model_class=None, resource_mapper=None, model_id=None, sortable_fields=()):
    if model_id is not None:
        resource = resource_mapper(model_class.query.get_or_404(model_id))
        return flask.jsonify(**resource)

    limit = min(_get_uint_arg("limit", 20), 1000)
    offset = _get_uint_arg("offset", 0)

    total_count = 0
    objects = []

    if model_class is not None:
        models = model_class.query.limit(limit).offset(offset).all()
        total_count = model_class.query.count()
        objects = [resource_mapper(m) for m in models]

    if sortable_fields:
        choices = []
        for field in sortable_fields:
            choices.append(field)
            choices.append("-%s" % field)
        order_by_arg = _get_choice_arg("order_by", choices)
        is_descending = order_by_arg.startswith("-")
        field = order_by_arg.lstrip("-")
        objects.sort(key=lambda o: o[field], reverse=is_descending)

    next_path = None
    prev_path = None

    if limit + offset < total_count:
        next_path_args = flask.request.args.to_dict()
        next_path_args["offset"] = offset + limit
        next_path = "%s?%s" % (flask.request.path, urllib.urlencode(next_path_args))

    if offset > 0:
        prev_path_args = flask.request.args.to_dict()
        prev_path_args["offset"] = max(offset - limit, 0)
        prev_path = "%s?%s" % (flask.request.path, urllib.urlencode(prev_path_args))

    resource = {
        "meta": {
            "limit": limit,
            "next": next_path,
            "offset": offset,
            "previous": prev_path,
            "total_count": total_count,
            },
        "objects": objects,
        }

    return flask.jsonify(**resource)

def PolicymakerResource(policymaker):
    return {
        "id": policymaker.id,
        "abbreviation": policymaker.abbreviation,
        "name": policymaker.name,
        "origin_id": policymaker.abbreviation,
        "slug": _slugify(policymaker.abbreviation),
        "summary": None,
        "resource_uri": flask.url_for(".policymaker_route",
                                      policymaker_id=policymaker.id),
        }

def MeetingResource(meeting):
    return {
        "id": meeting.id,
        "date": str(meeting.start_datetime.date()),
        "minutes": True,
        "number": 1,
        "policymaker": flask.url_for(".policymaker_route",
                                     policymaker_id=meeting.policymaker.id),
        "policymaker_name": meeting.policymaker.name,
        "year": meeting.start_datetime.year,
        "resource_uri": flask.url_for(".meeting_route", meeting_id=meeting.id),
        }

def MeetingDocumentResource(meeting_document):
    return {
        "id": meeting_document.id,
        "last_modified_time": None,
        "meeting": MeetingResource(meeting_document.meeting),
        "organisation": None,
        "origin_id": meeting_document.origin_id,
        "origin_url": meeting_document.origin_url,
        "publish_time": None,
        "type": "minutes",
        "xml_uri": None,
        "resource_uri": flask.url_for(".meeting_document_route",
                                      meeting_document_id=meeting_document.id)
        }

@v0.route("/policymaker/")
@v0.route("/policymaker/<int:policymaker_id>/")
def policymaker_route(policymaker_id=None):
    return jsonified_resource(klupung.models.Policymaker,
                              PolicymakerResource,
                              policymaker_id,
                              ["name"])

@v0.route("/meeting/")
@v0.route("/meeting/<int:meeting_id>/")
def meeting_route(meeting_id=None):
    return jsonified_resource(klupung.models.Meeting,
                              MeetingResource,
                              meeting_id,
                              ["date", "policymaker"])

@v0.route("/meeting_document/")
@v0.route("/meeting_document/<int:meeting_document_id>/")
def meeting_document_route(meeting_document_id=None):
    return jsonified_resource(klupung.models.MeetingDocument,
                              MeetingDocumentResource,
                              meeting_document_id)

@v0.route("/category/")
def category_route():
    return jsonified_resource()

@v0.route("/video/")
def video_route():
    return jsonified_resource()

@v0.route("/district/")
def district_route():
    return jsonified_resource()

@v0.route("/attachment/")
def attachment_route():
    return jsonified_resource()

@v0.errorhandler(Error)
def errorhandler(error):
    return flask.jsonify(error=error.message), error.code
<|endoftext|>


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

import sys, os, re, pkg_resources, subprocess

def mycmp(version1, version2):
    def normalize(v):
        return [int(x) for x in re.sub(r'(\.0+)*$','', v).split(".")]
    return cmp(normalize(version1), normalize(version2))

def check_version1(name):
    try:
        vers = subprocess.Popen([name, '-version'], stdout=subprocess.PIPE).communicate()[0].split('\n')[0]
        vers = vers.replace(': ', ' v')
    except OSError as e:
        if e.errno == os.errno.ENOENT:
            return (name+': not installed')
    return (vers)

def check_version2(name):
    try:
        if name == 'augustus':
            vers = subprocess.Popen([name, '--version'], stderr=subprocess.STDOUT, stdout=subprocess.PIPE).communicate()[0].rstrip()
        elif name == 'bamtools':
            vers = subprocess.Popen([name, '--version'], stdout=subprocess.PIPE).communicate()[0].split('\n')[1]
            vers = vers.replace('bamtools ', 'bamtools v')
        elif name == 'gmap':
            vers = subprocess.Popen([name, '--version'], stderr=subprocess.STDOUT, stdout=subprocess.PIPE).communicate()[0].split('\n')
            for i in vers:
                if i.startswith('GMAP'):
                    vers = i
                    break
            vers = vers.split(' called')[0].replace('version', 'v')
        else:
            vers = subprocess.Popen([name, '--version'], stdout=subprocess.PIPE).communicate()[0].split('\n')[0]
        if 'exonerate' in vers:
            vers = vers.replace('exonerate from ', '')
        if 'AUGUSTUS' in vers:
            vers = vers.split(' is ')[0].replace('(','v').replace(')', '')
        vers = vers.replace('version ', 'v')
    except OSError as e:
        if e.errno == os.errno.ENOENT:
            return (name+': not installed')
    return (vers)

def check_version3(name):
    try:
        vers = subprocess.Popen([name, '-v'], stdout=subprocess.PIPE).communicate()[0].split('\n')[0]
        vers = vers.replace('version open-', 'v')
    except OSError as e:
        if e.errno == os.errno.ENOENT:
            return (name+': not installed')
    return (vers)

def check_version4(name):
    try:
        vers = subprocess.Popen([name, 'version'], stdout=subprocess.PIPE).communicate()[0].split('\n')[0]
        vers = vers.replace('version ', 'v')
        if name == 'ete3':
            vers = 'ete3 v'+vers
    except OSError as e:
        if e.errno == os.errno.ENOENT:
            return (name+': not installed')
    return (vers)

def check_version5(name):
    try:
        if name == 'gmes_petap.pl':
            vers = subprocess.Popen([name], stdout=subprocess.PIPE).communicate()[0].split('\n')
            for i in vers:
                if i.startswith('GeneMark-ES'):
                    vers = i
            vers = vers.replace('version ', 'v')
        elif name == 'blat':
            vers = subprocess.Popen([name], stdout=subprocess.PIPE).communicate()[0].split('\n')[0]
            vers = vers.split(' fast')[0]
            vers = vers.split('Standalone ')[-1].replace('v. ', 'v')
    except OSError as e:
        if e.errno == os.errno.ENOENT:
            return (name+': not installed')
    return (vers)

def check_version6(name):
    try:
        vers = subprocess.Popen([name, '-h'], stdout=subprocess.PIPE).communicate()[0].split('\n')
        for i in vers:
            if i.startswith('# HMMER'):
                vers = i
                break
        vers = vers.split(';')[0].replace('# ', '')
    except OSError as e:
        if e.errno == os.errno.ENOENT:
            return (name+': not installed')
    return (vers)

funannotate = ['numpy', 'pandas', 'matplotlib', 'scipy', 'scikit-learn', 'psutil', 'natsort', 'goatools', 'seaborn', 'biopython']
min_versions = {'numpy': '1.10.0', 'pandas': '0.16.1', 'matplotlib': '1.5.0', 'scipy': '0.17.0', 'scikit-learn': '0.17.0', 'psutil': '4.0.0', 'natsort': '4.0.0', 'goatools': '0.6.4', 'seaborn': '0.7.0', 'biopython': '1.65'}

vers = sys.version
print "-----------------------"
print "Python Version:"
print "-----------------------"
print vers
print "-----------------------"
print "Modules installed:"
print "-----------------------"
matches = []
for x in funannotate:
    try:
        vers = pkg_resources.get_distribution(x).version
        min = min_versions.get(x)
        vers_test = mycmp(vers, min)
        if vers_test < 0:
            print '%s =! ERROR: v%s is installed, need at least v%s' % (x, vers, min)
        else:
            print x,'=>',vers
    except pkg_resources.DistributionNotFound:
        print x,'=! ERROR. Not installed'
print "-----------------------"
print "External Dependencies:"
print "-----------------------"

programs1 = ['tblastn', 'blastp', 'blastn', 'makeblastdb', 'rmblastn'] #-version
programs2 = ['exonerate', 'bedtools', 'bamtools', 'augustus', 'braker.pl', 'samtools','gmap', 'hisat2'] #--version
programs3 = ['RepeatModeler', 'RepeatMasker'] #-v
programs4 = ['diamond', 'ete3', 'kallisto'] #version
programs5 = ['gmes_petap.pl', 'blat'] #no version option at all, a$$holes
for i in programs1:
    print check_version1(i)
for i in programs2:
    print check_version2(i)
for i in programs3:
    print check_version3(i)
for i in programs4:
    print check_version4(i)
for i in programs5:
    print check_version5(i)
print check_version6('hmmsearch')

<commit_msg>update dependency checks<commit_after>#!/usr/bin/env python

import sys, os, re, pkg_resources, subprocess, inspect
from natsort import natsorted
currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
parentdir = os.path.dirname(currentdir)
sys.path.insert(0, parentdir)
import lib.library as lib

def perlVersion():
    proc = subprocess.Popen(['perl', '-e', 'print $];'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    vers = proc.communicate()
    return vers[0].rstrip()

def checkPerlModule(mod):
    proc = subprocess.Popen(['perl', '-M'+mod, '-e', 'print '+mod+'->VERSION . "\n"'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    vers = proc.communicate()
    #stdout in vers[0] and stderr in vers[1]
    if vers[0] != '':
        return vers[0].rstrip()
    elif vers[1].startswith("Can't locate"):
        return False
    else:
        print('This should never happen.')
        sys.exit(1)

def checkPyModule(mod):
    try:
        vers = pkg_resources.get_distribution(mod).version
    except pkg_resources.DistributionNotFound:
        vers = False
    return vers

def mycmp(version1, version2):
    def normalize(v):
        return [int(x) for x in re.sub(r'(\.0+)*$','', v).split(".")]
    return cmp(normalize(version1), normalize(version2))

def check_version1(name):
    try:
        vers = subprocess.Popen([name, '-version'], stdout=subprocess.PIPE).communicate()[0].split('\n')[0]
        vers = vers.replace(': ', ' ')
    except OSError as e:
        if e.errno == os.errno.ENOENT:
            return False
    return (vers)

def check_version2(name):
    try:
        if name == 'augustus':
            vers = subprocess.Popen([name, '--version'], stderr=subprocess.STDOUT, stdout=subprocess.PIPE).communicate()[0].rstrip()
        elif name == 'bamtools':
            vers = subprocess.Popen([name, '--version'], stdout=subprocess.PIPE).communicate()[0].split('\n')[1]
        elif name == 'gmap':
            vers = subprocess.Popen([name, '--version'], stderr=subprocess.STDOUT, stdout=subprocess.PIPE).communicate()[0].split('\n')
            for i in vers:
                if i.startswith('GMAP'):
                    vers = i
                    break
            vers = vers.split(' called')[0].replace('version', '')
            vers = vers.replace('GMAP', '').strip()
        elif name == 'hisat2':
            vers = subprocess.Popen([name, '--version'], stdout=subprocess.PIPE).communicate()[0].split('\n')[0]
            vers = vers.split(' ')[-1]
        else:
            vers = subprocess.Popen([name, '--version'], stdout=subprocess.PIPE).communicate()[0].split('\n')[0]
        if 'exonerate' in vers:
            vers = vers.replace('exonerate from ', '')
        if 'AUGUSTUS' in vers:
            vers = vers.split(' is ')[0].replace('(','').replace(')', '')
            vers = vers.replace('AUGUSTUS', '').strip()
        vers = vers.replace('version ', '')
    except OSError as e:
        if e.errno == os.errno.ENOENT:
            return False
    return (vers)

def check_version3(name):
    try:
        vers = subprocess.Popen([name, '-v'], stdout=subprocess.PIPE).communicate()[0].split('\n')[0]
        vers = vers.replace('version open-', '')
    except OSError as e:
        if e.errno == os.errno.ENOENT:
            return False
    return (vers)

def check_version4(name):
    try:
        vers = subprocess.Popen([name, 'version'], stdout=subprocess.PIPE).communicate()[0].split('\n')[0]
        vers = vers.replace('version ', '')
        if name == 'ete3':
            vers = vers.split(' ')[0]
        elif name == 'kallisto':
            vers = vers.split(' ')[-1]
    except OSError as e:
        if e.errno == os.errno.ENOENT:
            return False
    return (vers)

def check_version5(name):
    try:
        if name == 'gmes_petap.pl':
            vers = subprocess.Popen([name], stdout=subprocess.PIPE).communicate()[0].split('\n')
            for i in vers:
                if i.startswith('GeneMark-ES'):
                    vers = i
            vers = vers.replace('version ', '')
            vers = vers.split(' ')[-1]
        elif name == 'blat':
            vers = subprocess.Popen([name], stdout=subprocess.PIPE).communicate()[0].split('\n')[0]
            vers = vers.split(' fast')[0]
            vers = vers.split('Standalone ')[-1].replace('v. ', 'v')
    except OSError as e:
        if e.errno == os.errno.ENOENT:
            return False
    return (vers)

def check_version6(name):
    try:
        vers = subprocess.Popen([name, '-h'], stdout=subprocess.PIPE).communicate()[0].split('\n')
        for i in vers:
            if i.startswith('# HMMER'):
                vers = i
                break
        vers = vers.split(';')[0].replace('# ', '')
    except OSError as e:
        if e.errno == os.errno.ENOENT:
            return False
    return (vers)

funannotate_perl = ['Getopt::Long', 'Pod::Usage', 'File::Basename', 'threads', 'threads::shared',
           'Thread::Queue', 'Carp', 'Data::Dumper', 'YAML', 'Hash::Merge', 'Logger::Simple', 'Parallel::ForkManager',
           'DBI', 'Text::Soundex', 'Scalar::Util::Numeric', 'Tie::File', 'POSIX', 'Storable', 'Clone', 'Bio::Perl']

funannotate_python = ['numpy', 'pandas', 'matplotlib', 'scipy', 'scikit-learn', 'psutil', 'natsort', 'goatools', 'seaborn', 'biopython']

programs1 = ['tblastn', 'makeblastdb', 'rmblastn'] #-version
programs2 = ['exonerate', 'bedtools', 'bamtools', 'augustus', 'braker.pl', 'samtools', 'gmap', 'hisat2'] #--version
programs3 = ['RepeatModeler', 'RepeatMasker'] #-v
programs4 = ['diamond', 'ete3', 'kallisto'] #version
programs5 = ['gmes_petap.pl', 'blat'] #no version option at all, a$$holes

min_versions = {'numpy': '1.10.0', 'pandas': '0.16.1', 'matplotlib': '1.5.0', 'scipy': '0.17.0', 'scikit-learn': '0.17.0', 'psutil': '4.0.0', 'natsort': '4.0.0', 'goatools': '0.6.4', 'seaborn': '0.7.0', 'biopython': '1.65'}

PyVers = sys.version.split(' ')[0]
PerlVers = perlVersion()
PyDeps = {}
PerlDeps = {}
ExtDeps = {}

#loop through lists and build dictionary of results so you can print out later
print("-------------------------------------------------------")
print("Checking dependencies for %s" % lib.get_version())
print("-------------------------------------------------------")

show = False
if len(sys.argv) > 1:
    if sys.argv[1] == '--show-versions':
        show = True
else:
    print("To print all dependencies and versions: funannotate check --show-versions\n")

print('You are running Python v %s. Now checking python packages...' % PyVers)
for mod in funannotate_python:
    if not mod in PyDeps:
        PyDeps[mod] = checkPyModule(mod)
missing = []
for k,v in natsorted(PyDeps.items()):
    if show:
        print(k+': '+v)
    if not v:
        missing.append(k)
if len(missing) > 0:
    for x in missing:
        print('   ERROR: %s not installed, pip install %s or conda install %s' % (x,x,x))
else:
    print("All %i python packages installed" % len(funannotate_python))
print("\n")

for mod in funannotate_perl:
    if not mod in PerlDeps:
        PerlDeps[mod] = checkPerlModule(mod)

missing = []
print('You are running Perl v %s. Now checking perl modules...' % PerlVers)
for k,v in natsorted(PerlDeps.items()):
    if show:
        print(k+': '+v)
    if not v:
        missing.append(k)
if len(missing) > 0:
    for x in missing:
        print('   ERROR: %s not installed, install with cpanm %s ' % (x,x))
else:
    print("All %i Perl modules installed" % len(funannotate_perl))
print("\n")
print('Checking external dependencies...')
for prog in programs1:
    if not prog in ExtDeps:
        ExtDeps[prog] = check_version1(prog)
for prog in programs2:
    if not prog in ExtDeps:
        ExtDeps[prog] = check_version2(prog)
for prog in programs3:
    if not prog in ExtDeps:
        ExtDeps[prog] = check_version3(prog)
for prog in programs4:
    if not prog in ExtDeps:
        ExtDeps[prog] = check_version4(prog)
for prog in programs5:
    if not prog in ExtDeps:
        ExtDeps[prog] = check_version5(prog)
if not 'hmmsearch' in ExtDeps:
    ExtDeps['hmmsearch'] = check_version6('hmmsearch')

missing = []
for k,v in natsorted(ExtDeps.items()):
    if show:
        print(k+': '+v)
    if not v:
        missing.append(k)
if len(missing) > 0:
    for x in missing:
        print('\tERROR: %s not installed' % (x))
else:
    print("All %i external dependencies are installed" % (len(ExtDeps)))
print("-------------------------------------------------------")

<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
# vim: ai ts=4 sts=4 et sw=4
# spamc - Python spamassassin spamc client library
# Copyright (C) 2015  Andrew Colin Kissa <andrew@topdog.za.net>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
"""
spamc: Python spamassassin spamc client library
client
"""
import os
import errno
import types
import socket

from zlib import compress
# from mimetools import Message
from email.parser import Parser

from spamc.utils import load_backend
from spamc.conn import SpamCTcpConnector, SpamCUnixConnector

from spamc.regex import RESPONSE_RE, SPAM_RE, PART_RE, RULE_RE, SPACE_RE
from spamc.exceptions import SpamCError, SpamCTimeOutError, SpamCResponseError

PROTOCOL_VERSION = 'SPAMC/1.5'

def _check_action(action):
    """check for invalid actions"""
    if isinstance(action, types.StringTypes):
        action = action.lower()

    if action not in ['learn', 'forget', 'report', 'revoke']:
        raise SpamCError('The action option is invalid')
    return action

# pylint: disable=R0912,R0915
def get_response(cmd, conn):
    """Return a response"""
    resp = conn.socket().makefile('rb', -1)
    resp_dict = dict(
        code=0,
        message='',
        isspam=False,
        score=0.0,
        basescore=0.0,
        report=[],
        symbols=[],
        headers={},
    )

    if cmd == 'TELL':
        resp_dict['didset'] = False
        resp_dict['didremove'] = False

    data = resp.read()
    lines = data.split('\r\n')
    for index, line in enumerate(lines):
        if index == 0:
            match = RESPONSE_RE.match(line)
            if not match:
                raise SpamCResponseError(
                    'spamd unrecognized response: %s' % data)
            resp_dict.update(match.groupdict())
            resp_dict['code'] = int(resp_dict['code'])
        else:
            if not line.strip():
                continue
            match = SPAM_RE.match(line)
            if match:
                tmp = match.groupdict()
                resp_dict['score'] = float(tmp['score'])
                resp_dict['basescore'] = float(tmp['basescore'])
                resp_dict['isspam'] = tmp['isspam'] in ['True', 'Yes']
            if not match:
                if cmd == 'SYMBOLS':
                    match = PART_RE.findall(line)
                    for part in match:
                        resp_dict['symbols'].append(part)
            if not match and cmd != 'PROCESS':
                match = RULE_RE.findall(line)
                if match:
                    resp_dict['report'] = []
                    for part in match:
                        score = part[0] + part[1]
                        score = score.strip()
                        resp_dict['report'].append(
                            dict(score=score,
                                 name=part[2],
                                 description=SPACE_RE.sub(" ", part[3])))
            if line.startswith('DidSet:'):
                resp_dict['didset'] = True
            if line.startswith('DidRemove:'):
                resp_dict['didremove'] = True
    if cmd == 'PROCESS':
        resp_dict['message'] = ''.join(lines[4:]) + '\r\n'
    if cmd == 'HEADERS':
        parser = Parser()
        headers = parser.parsestr('\r\n'.join(lines[4:]), headersonly=True)
        for key in headers.keys():
            resp_dict['headers'][key] = headers[key]
    return resp_dict

# pylint: disable=R0902
class SpamC(object):
    """Spamc Client class"""
    # pylint: disable=R0913

    def __init__(self,
                 host=None,
                 port=783,
                 socket_file='/var/run/spamassassin/spamd.sock',
                 user=None,
                 timeout=None,
                 wait_tries=0.3,
                 max_tries=3,
                 backend="thread",
                 gzip=None,
                 compress_level=6,
                 is_ssl=None,
                 **ssl_args):
        """Init"""
        self.host = host
        self.port = port
        self.socket_file = socket_file
        self.user = user
        if isinstance(backend, str):
            self.backend_mod = load_backend(backend)
        else:
            self.backend_mod = backend
        self.max_tries = max_tries
        self.wait_tries = wait_tries
        self.timeout = timeout
        self.gzip = gzip
        self.compress_level = compress_level
        self.is_ssl = is_ssl
        self.ssl_args = ssl_args or {}

    def get_connection(self):
        """Creates a new connection"""
        if self.host is None:
            connector = SpamCUnixConnector
            conn = connector(self.socket_file, self.backend_mod)
        else:
            connector = SpamCTcpConnector
            conn = connector(
                self.host,
                self.port,
                self.backend_mod,
                is_ssl=self.is_ssl,
                **self.ssl_args)
        return conn

    def get_headers(self, cmd, msg_length, extra_headers):
        """Returns the headers string based on command to execute"""
        cmd_header = "%s %s" % (cmd, PROTOCOL_VERSION)
        len_header = "Content-length: %s" % msg_length
        headers = [cmd_header, len_header]
        if self.user:
            user_header = "User: %s" % self.user
            headers.append(user_header)
        if self.gzip:
            headers.append("Compress: zlib")
        if extra_headers is not None:
            for key in extra_headers:
                if key.lower() != 'content-length':
                    headers.append("%s: %s" % (key, extra_headers[key]))
        headers.append('')
        headers.append('')
        return '\r\n'.join(headers)

    # pylint: disable=E1103
    def perform(self, cmd, msg='', extra_headers=None):
        """Perform the call"""
        tries = 0
        while 1:
            conn = None
            try:
                conn = self.get_connection()
                if hasattr(msg, 'read') and hasattr(msg, 'fileno'):
                    msg_length = str(os.fstat(msg.fileno()).st_size)
                elif hasattr(msg, 'read'):
                    msg.seek(0, 2)
                    msg_length = str(msg.tell() + 2)
                else:
                    if msg:
                        try:
                            msg_length = str(len(msg) + 2)
                        except TypeError:
                            conn.close()
                            raise ValueError(
                                'msg param should be a string or file handle')
                    else:
                        msg_length = '2'

                headers = self.get_headers(cmd, msg_length, extra_headers)

                if isinstance(msg, types.StringTypes):
                    if self.gzip and msg:
                        msg = compress(msg + '\r\n', self.compress_level)
                    else:
                        msg = msg + '\r\n'
                    conn.send(headers + msg)
                else:
                    conn.send(headers)
                    if hasattr(msg, 'read'):
                        if hasattr(msg, 'seek'):
                            msg.seek(0)
                        conn.sendfile(msg, self.gzip, self.compress_level)
                conn.send('\r\n')
                try:
                    conn.socket().shutdown(socket.SHUT_WR)
                except socket.error:
                    pass
                return get_response(cmd, conn)
            except socket.gaierror, err:
                if conn is not None:
                    conn.release()
                raise SpamCError(str(err))
            except socket.timeout, err:
                if conn is not None:
                    conn.release()
                raise SpamCTimeOutError(str(err))
            except socket.error, err:
                if conn is not None:
                    conn.close()
                errors = (errno.EAGAIN, errno.EPIPE, errno.EBADF,
                          errno.ECONNRESET)
                if err[0] not in errors or tries >= self.max_tries:
                    raise SpamCError("socket.error: %s" % str(err))
            except BaseException:
                if conn is not None:
                    conn.release()
                raise
            tries += 1
            self.backend_mod.sleep(self.wait_tries)

    def check(self, msg):
        """Check if the passed message is spam or not"""
        return self.perform('CHECK', msg)

    def symbols(self, msg):
        """Check if message is spam or not, and return score plus list
        of symbols hit"""
        return self.perform('SYMBOLS', msg)

    def report(self, msg):
        """Check if message is spam or not, and return score plus report"""
        return self.perform('REPORT', msg)

    def report_ifspam(self, msg):
        """Check if message is spam or not, and return score plus report
        if the message is spam"""
        return self.perform('REPORT_IFSPAM', msg)

    def ping(self):
        """Return a confirmation that spamd is alive"""
        return self.perform('PING')

    def process(self, msg):
        """Check if message is spam or not, and return modified message"""
        return self.perform('PROCESS', msg)

    def headers(self, msg):
        """Check if message is spam or not, and return only modified
        headers, not body"""
        return self.perform('HEADERS', msg)

    def tell(self, msg, action, learnas=''):
        """Tell what type of we are to process and what should be done
        with that message. This includes setting or removing a local
        or a remote database (learning, reporting, forgetting, revoking)."""
        action = _check_action(action)
        mode = learnas.upper()

        headers = {
            'Message-class': '',
            'Set': 'local',
        }

        if action == 'learn':
            if mode == 'SPAM':
                headers['Message-class'] = 'spam'
            elif mode in ['HAM', 'NOTSPAM', 'NOT_SPAM']:
                headers['Message-class'] = 'ham'
            else:
                raise SpamCError('The learnas option is invalid')
        elif action == 'forget':
            del headers['Message-class']
            del headers['Set']
            headers['Remove'] = 'local'
        elif action == 'report':
            headers['Message-class'] = 'spam'
            headers['Set'] = 'local, remote'
        elif action == 'revoke':
            headers['Message-class'] = 'ham'
            headers['Remove'] = 'remote'
        return self.perform('TELL', msg, headers)

    def learn(self, msg, learnas):
        """Learn message as spam/ham or forget"""
        if not isinstance(learnas, types.StringTypes):
            raise SpamCError('The learnas option is invalid')
        if learnas.lower() == 'forget':
            resp = self.tell(msg, 'forget')
        else:
            resp = self.tell(msg, 'learn', learnas)
        return resp

    def revoke(self, msg):
        """Tell spamd message is not spam"""
        return self.tell(msg, 'revoke')
<commit_msg>Use exept as syntax<commit_after># -*- coding: utf-8 -*-
# vim: ai ts=4 sts=4 et sw=4
# spamc - Python spamassassin spamc client library
# Copyright (C) 2015  Andrew Colin Kissa <andrew@topdog.za.net>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
"""
spamc: Python spamassassin spamc client library
client
"""
import os
import errno
import types
import socket

from zlib import compress
# from mimetools import Message
from email.parser import Parser

from spamc.utils import load_backend
from spamc.conn import SpamCTcpConnector, SpamCUnixConnector

from spamc.regex import RESPONSE_RE, SPAM_RE, PART_RE, RULE_RE, SPACE_RE
from spamc.exceptions import SpamCError, SpamCTimeOutError, SpamCResponseError

PROTOCOL_VERSION = 'SPAMC/1.5'

def _check_action(action):
    """check for invalid actions"""
    if isinstance(action, types.StringTypes):
        action = action.lower()

    if action not in ['learn', 'forget', 'report', 'revoke']:
        raise SpamCError('The action option is invalid')
    return action

# pylint: disable=R0912,R0915
def get_response(cmd, conn):
    """Return a response"""
    resp = conn.socket().makefile('rb', -1)
    resp_dict = dict(
        code=0,
        message='',
        isspam=False,
        score=0.0,
        basescore=0.0,
        report=[],
        symbols=[],
        headers={},
    )

    if cmd == 'TELL':
        resp_dict['didset'] = False
        resp_dict['didremove'] = False

    data = resp.read()
    lines = data.split('\r\n')
    for index, line in enumerate(lines):
        if index == 0:
            match = RESPONSE_RE.match(line)
            if not match:
                raise SpamCResponseError(
                    'spamd unrecognized response: %s' % data)
            resp_dict.update(match.groupdict())
            resp_dict['code'] = int(resp_dict['code'])
        else:
            if not line.strip():
                continue
            match = SPAM_RE.match(line)
            if match:
                tmp = match.groupdict()
                resp_dict['score'] = float(tmp['score'])
                resp_dict['basescore'] = float(tmp['basescore'])
                resp_dict['isspam'] = tmp['isspam'] in ['True', 'Yes']
            if not match:
                if cmd == 'SYMBOLS':
                    match = PART_RE.findall(line)
                    for part in match:
                        resp_dict['symbols'].append(part)
            if not match and cmd != 'PROCESS':
                match = RULE_RE.findall(line)
                if match:
                    resp_dict['report'] = []
                    for part in match:
                        score = part[0] + part[1]
                        score = score.strip()
                        resp_dict['report'].append(
                            dict(score=score,
                                 name=part[2],
                                 description=SPACE_RE.sub(" ", part[3])))
            if line.startswith('DidSet:'):
                resp_dict['didset'] = True
            if line.startswith('DidRemove:'):
                resp_dict['didremove'] = True
    if cmd == 'PROCESS':
        resp_dict['message'] = ''.join(lines[4:]) + '\r\n'
    if cmd == 'HEADERS':
        parser = Parser()
        headers = parser.parsestr('\r\n'.join(lines[4:]), headersonly=True)
        for key in headers.keys():
            resp_dict['headers'][key] = headers[key]
    return resp_dict

# pylint: disable=R0902
class SpamC(object):
    """Spamc Client class"""
    # pylint: disable=R0913

    def __init__(self,
                 host=None,
                 port=783,
                 socket_file='/var/run/spamassassin/spamd.sock',
                 user=None,
                 timeout=None,
                 wait_tries=0.3,
                 max_tries=3,
                 backend="thread",
                 gzip=None,
                 compress_level=6,
                 is_ssl=None,
                 **ssl_args):
        """Init"""
        self.host = host
        self.port = port
        self.socket_file = socket_file
        self.user = user
        if isinstance(backend, str):
            self.backend_mod = load_backend(backend)
        else:
            self.backend_mod = backend
        self.max_tries = max_tries
        self.wait_tries = wait_tries
        self.timeout = timeout
        self.gzip = gzip
        self.compress_level = compress_level
        self.is_ssl = is_ssl
        self.ssl_args = ssl_args or {}

    def get_connection(self):
        """Creates a new connection"""
        if self.host is None:
            connector = SpamCUnixConnector
            conn = connector(self.socket_file, self.backend_mod)
        else:
            connector = SpamCTcpConnector
            conn = connector(
                self.host,
                self.port,
                self.backend_mod,
                is_ssl=self.is_ssl,
                **self.ssl_args)
        return conn

    def get_headers(self, cmd, msg_length, extra_headers):
        """Returns the headers string based on command to execute"""
        cmd_header = "%s %s" % (cmd, PROTOCOL_VERSION)
        len_header = "Content-length: %s" % msg_length
        headers = [cmd_header, len_header]
        if self.user:
            user_header = "User: %s" % self.user
            headers.append(user_header)
        if self.gzip:
            headers.append("Compress: zlib")
        if extra_headers is not None:
            for key in extra_headers:
                if key.lower() != 'content-length':
                    headers.append("%s: %s" % (key, extra_headers[key]))
        headers.append('')
        headers.append('')
        return '\r\n'.join(headers)

    # pylint: disable=E1103
    def perform(self, cmd, msg='', extra_headers=None):
        """Perform the call"""
        tries = 0
        while 1:
            conn = None
            try:
                conn = self.get_connection()
                if hasattr(msg, 'read') and hasattr(msg, 'fileno'):
                    msg_length = str(os.fstat(msg.fileno()).st_size)
                elif hasattr(msg, 'read'):
                    msg.seek(0, 2)
                    msg_length = str(msg.tell() + 2)
                else:
                    if msg:
                        try:
                            msg_length = str(len(msg) + 2)
                        except TypeError:
                            conn.close()
                            raise ValueError(
                                'msg param should be a string or file handle')
                    else:
                        msg_length = '2'

                headers = self.get_headers(cmd, msg_length, extra_headers)

                if isinstance(msg, types.StringTypes):
                    if self.gzip and msg:
                        msg = compress(msg + '\r\n', self.compress_level)
                    else:
                        msg = msg + '\r\n'
                    conn.send(headers + msg)
                else:
                    conn.send(headers)
                    if hasattr(msg, 'read'):
                        if hasattr(msg, 'seek'):
                            msg.seek(0)
                        conn.sendfile(msg, self.gzip, self.compress_level)
                conn.send('\r\n')
                try:
                    conn.socket().shutdown(socket.SHUT_WR)
                except socket.error:
                    pass
                return get_response(cmd, conn)
            except socket.gaierror as err:
                if conn is not None:
                    conn.release()
                raise SpamCError(str(err))
            except socket.timeout as err:
                if conn is not None:
                    conn.release()
                raise SpamCTimeOutError(str(err))
            except socket.error as err:
                if conn is not None:
                    conn.close()
                errors = (errno.EAGAIN, errno.EPIPE, errno.EBADF,
                          errno.ECONNRESET)
                if err[0] not in errors or tries >= self.max_tries:
                    raise SpamCError("socket.error: %s" % str(err))
            except BaseException:
                if conn is not None:
                    conn.release()
                raise
            tries += 1
            self.backend_mod.sleep(self.wait_tries)

    def check(self, msg):
        """Check if the passed message is spam or not"""
        return self.perform('CHECK', msg)

    def symbols(self, msg):
        """Check if message is spam or not, and return score plus list
        of symbols hit"""
        return self.perform('SYMBOLS', msg)

    def report(self, msg):
        """Check if message is spam or not, and return score plus report"""
        return self.perform('REPORT', msg)

    def report_ifspam(self, msg):
        """Check if message is spam or not, and return score plus report
        if the message is spam"""
        return self.perform('REPORT_IFSPAM', msg)

    def ping(self):
        """Return a confirmation that spamd is alive"""
        return self.perform('PING')

    def process(self, msg):
        """Check if message is spam or not, and return modified message"""
        return self.perform('PROCESS', msg)

    def headers(self, msg):
        """Check if message is spam or not, and return only modified
        headers, not body"""
        return self.perform('HEADERS', msg)

    def tell(self, msg, action, learnas=''):
        """Tell what type of we are to process and what should be done
        with that message. This includes setting or removing a local
        or a remote database (learning, reporting, forgetting, revoking)."""
        action = _check_action(action)
        mode = learnas.upper()

        headers = {
            'Message-class': '',
            'Set': 'local',
        }

        if action == 'learn':
            if mode == 'SPAM':
                headers['Message-class'] = 'spam'
            elif mode in ['HAM', 'NOTSPAM', 'NOT_SPAM']:
                headers['Message-class'] = 'ham'
            else:
                raise SpamCError('The learnas option is invalid')
        elif action == 'forget':
            del headers['Message-class']
            del headers['Set']
            headers['Remove'] = 'local'
        elif action == 'report':
            headers['Message-class'] = 'spam'
            headers['Set'] = 'local, remote'
        elif action == 'revoke':
            headers['Message-class'] = 'ham'
            headers['Remove'] = 'remote'
        return self.perform('TELL', msg, headers)

    def learn(self, msg, learnas):
        """Learn message as spam/ham or forget"""
        if not isinstance(learnas, types.StringTypes):
            raise SpamCError('The learnas option is invalid')
        if learnas.lower() == 'forget':
            resp = self.tell(msg, 'forget')
        else:
            resp = self.tell(msg, 'learn', learnas)
        return resp

    def revoke(self, msg):
        """Tell spamd message is not spam"""
        return self.tell(msg, 'revoke')
<|endoftext|>


<commit_before>"""
Text normalizing routines.

Adapted from the Helmut project.
https://github.com/okfn/helmut/blob/master/helmut/text.py
"""

import re
from unicodedata import normalize as ucnorm, category

def normalize(text):
    """ Simplify a piece of text to generate a more canonical
    representation. This involves lowercasing, stripping trailing
    spaces, removing symbols, diacritical marks (umlauts) and
    converting all newlines etc. to single spaces.
    """
    text = text.lower()
    decomposed = ucnorm('NFKD', text)
    filtered = []
    for char in decomposed:
        cat = category(char)
        if cat.startswith('C'):
            filtered.append(' ')
        elif cat.startswith('M'):
            # marks, such as umlauts
            continue
        elif cat.startswith('Z'):
            # newlines, non-breaking etc.
            filtered.append(' ')
        elif cat.startswith('S'):
            # symbols, such as currency
            continue
        else:
            filtered.append(char)
    text = ''.join(filtered)
    while '  ' in text:
        text = text.replace('  ', ' ')
    #remove hyphens
    text = text.replace('-', ' ')
    text = text.strip()
    return ucnorm('NFKC', text)

def url_slug(text):
    text = normalize(text)
    text = text.replace(' ', '-')
    text = text.replace('.', '_')
    return text

def tokenize(text, splits='COPZ'):
    token = []
    for c in text:
        if category(c)[0] in splits:
            if len(token):
                yield ''.join(token)
            token = []
        else:
            token.append(c)
    if len(token):
        yield ''.join(token)

PARENS = re.compile('\([^)]*\)')
def clean_parens(raw, normalized=True):
    """
    Normalizes and remove texts in parenthesis from string.
    """
    #remove parens
    val = PARENS.sub(r'', raw).strip()
    if normalized is True:
        return normalize(val)
    else:
        return val
<commit_msg>fix warning<commit_after>"""
Text normalizing routines.

Adapted from the Helmut project.
https://github.com/okfn/helmut/blob/master/helmut/text.py
"""

import re
from unicodedata import normalize as ucnorm, category

def normalize(text):
    """ Simplify a piece of text to generate a more canonical
    representation. This involves lowercasing, stripping trailing
    spaces, removing symbols, diacritical marks (umlauts) and
    converting all newlines etc. to single spaces.
    """
    text = text.lower()
    decomposed = ucnorm('NFKD', text)
    filtered = []
    for char in decomposed:
        cat = category(char)
        if cat.startswith('C'):
            filtered.append(' ')
        elif cat.startswith('M'):
            # marks, such as umlauts
            continue
        elif cat.startswith('Z'):
            # newlines, non-breaking etc.
            filtered.append(' ')
        elif cat.startswith('S'):
            # symbols, such as currency
            continue
        else:
            filtered.append(char)
    text = ''.join(filtered)
    while '  ' in text:
        text = text.replace('  ', ' ')
    #remove hyphens
    text = text.replace('-', ' ')
    text = text.strip()
    return ucnorm('NFKC', text)

def url_slug(text):
    text = normalize(text)
    text = text.replace(' ', '-')
    text = text.replace('.', '_')
    return text

def tokenize(text, splits='COPZ'):
    token = []
    for c in text:
        if category(c)[0] in splits:
            if len(token):
                yield ''.join(token)
            token = []
        else:
            token.append(c)
    if len(token):
        yield ''.join(token)

PARENS = re.compile(r'\([^)]*\)')
def clean_parens(raw, normalized=True):
    """
    Normalizes and remove texts in parenthesis from string.
    """
    #remove parens
    val = PARENS.sub(r'', raw).strip()
    if normalized is True:
        return normalize(val)
    else:
        return val
<|endoftext|>


<commit_before>"""
homeassistant.components.notify.nma
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
NMA (Notify My Android) notification service.

Configuration:

To use the NMA notifier you will need to add something like the following
to your configuration.yaml file.

notify:
  platform: nma
  api_key: YOUR_API_KEY

Variables:

api_key
*Required
Enter the API key for NMA. Go to https://www.notifymyandroid.com and create a
new API key to use with Home Assistant.

Details for the API : https://www.notifymyandroid.com/api.jsp
"""
import logging
import xml.etree.ElementTree as ET

from homeassistant.helpers import validate_config
from homeassistant.components.notify import (
    DOMAIN, ATTR_TITLE, BaseNotificationService)
from homeassistant.const import CONF_API_KEY

_LOGGER = logging.getLogger(__name__)
_RESOURCE = 'https://www.notifymyandroid.com/publicapi/'

def get_service(hass, config):
    """ Get the NMA notification service. """

    if not validate_config(config,
                           {DOMAIN: [CONF_API_KEY]},
                           _LOGGER):
        return None

    try:
        # pylint: disable=unused-variable
        from requests import Session

    except ImportError:
        _LOGGER.exception(
            "Unable to import requests. "
            "Did you maybe not install the 'Requests' package?")

        return None

    nma = Session()
    response = nma.get(_RESOURCE + 'verify',
                       params={"apikey": config[DOMAIN][CONF_API_KEY]})
    tree = ET.fromstring(response.content)

    if tree[0].tag == 'error':
        _LOGGER.error("Wrong API key supplied. %s", tree[0].text)
    else:
        return NmaNotificationService(config[DOMAIN][CONF_API_KEY])

# pylint: disable=too-few-public-methods
class NmaNotificationService(BaseNotificationService):
    """ Implements notification service for NMA. """

    def __init__(self, api_key):
        # pylint: disable=no-name-in-module, unused-variable
        from requests import Session

        self._api_key = api_key
        self._data = {"apikey": self._api_key}

        self.nma = Session()

    def send_message(self, message="", **kwargs):
        """ Send a message to a user. """

        title = kwargs.get(ATTR_TITLE)

        self._data['application'] = 'home-assistant'
        self._data['event'] = title
        self._data['description'] = message
        self._data['priority'] = 0

        response = self.nma.get(_RESOURCE + 'notify',
                                params=self._data)
        tree = ET.fromstring(response.content)

        if tree[0].tag == 'error':
            _LOGGER.exception(
                "Unable to perform request. Error: %s", tree[0].text)
<commit_msg>Move configuration details to docs<commit_after>"""
homeassistant.components.notify.nma
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
NMA (Notify My Android) notification service.

For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/notify.nma.html
"""
import logging
import xml.etree.ElementTree as ET

from homeassistant.helpers import validate_config
from homeassistant.components.notify import (
    DOMAIN, ATTR_TITLE, BaseNotificationService)
from homeassistant.const import CONF_API_KEY

_LOGGER = logging.getLogger(__name__)
_RESOURCE = 'https://www.notifymyandroid.com/publicapi/'

def get_service(hass, config):
    """ Get the NMA notification service. """

    if not validate_config(config,
                           {DOMAIN: [CONF_API_KEY]},
                           _LOGGER):
        return None

    try:
        # pylint: disable=unused-variable
        from requests import Session

    except ImportError:
        _LOGGER.exception(
            "Unable to import requests. "
            "Did you maybe not install the 'Requests' package?")

        return None

    nma = Session()
    response = nma.get(_RESOURCE + 'verify',
                       params={"apikey": config[DOMAIN][CONF_API_KEY]})
    tree = ET.fromstring(response.content)

    if tree[0].tag == 'error':
        _LOGGER.error("Wrong API key supplied. %s", tree[0].text)
    else:
        return NmaNotificationService(config[DOMAIN][CONF_API_KEY])

# pylint: disable=too-few-public-methods
class NmaNotificationService(BaseNotificationService):
    """ Implements notification service for NMA. """

    def __init__(self, api_key):
        # pylint: disable=no-name-in-module, unused-variable
        from requests import Session

        self._api_key = api_key
        self._data = {"apikey": self._api_key}

        self.nma = Session()

    def send_message(self, message="", **kwargs):
        """ Send a message to a user. """

        title = kwargs.get(ATTR_TITLE)

        self._data['application'] = 'home-assistant'
        self._data['event'] = title
        self._data['description'] = message
        self._data['priority'] = 0

        response = self.nma.get(_RESOURCE + 'notify',
                                params=self._data)
        tree = ET.fromstring(response.content)

        if tree[0].tag == 'error':
            _LOGGER.exception(
                "Unable to perform request. Error: %s", tree[0].text)
<|endoftext|>


<commit_before>"""Public API

Anything that is not defined here is **internal** and
unreliable for external use.

Motivation for api.py:
    Storing the API in a module, as opposed to in __init__.py, enables
    use of it internally.

    For example, from `pipeline.py`:
        >> from . import api
        >> api.do_this()

    The important bit is avoiding circular dependencies, where api.py
    is calling upon a module which in turn calls upon api.py.

"""

import logging

from . import schema

from .pipeline import (
    install,
    uninstall,

    ls,
    search,

    Loader,
    discover_loaders,

    register_root,
    register_data,
    register_host,
    register_format,
    register_silo,
    register_family,
    register_loaders_path,
    register_plugins,

    registered_host,
    registered_families,
    registered_loaders_paths,
    registered_formats,
    registered_data,
    registered_root,
    registered_silos,

    deregister_plugins,
    deregister_family,
    deregister_data,
    deregister_loaders_path,

    any_representation,

    fixture,
)

from .lib import (
    format_staging_dir,
    format_shared_dir,
    format_version,

    time,

    find_latest_version,
    parse_version,
)

logging.basicConfig()

__all__ = [
    "install",
    "uninstall",

    "schema",

    "ls",
    "search",

    "Loader",
    "discover_loaders",

    "register_host",
    "register_data",
    "register_format",
    "register_silo",
    "register_family",
    "register_loaders_path",
    "register_plugins",
    "register_root",

    "registered_root",
    "registered_silos",
    "registered_loaders_paths",
    "registered_host",
    "registered_families",
    "registered_formats",
    "registered_data",

    "deregister_plugins",
    "deregister_family",
    "deregister_data",
    "deregister_loaders_path",

    "format_staging_dir",
    "format_shared_dir",
    "format_version",

    "find_latest_version",
    "parse_version",

    "time",

    "any_representation",

    "fixture",
]
<commit_msg>Expose new API member<commit_after>"""Public API

Anything that is not defined here is **internal** and
unreliable for external use.

Motivation for api.py:
    Storing the API in a module, as opposed to in __init__.py, enables
    use of it internally.

    For example, from `pipeline.py`:
        >> from . import api
        >> api.do_this()

    The important bit is avoiding circular dependencies, where api.py
    is calling upon a module which in turn calls upon api.py.

"""

import logging

from . import schema

from .pipeline import (
    install,
    uninstall,

    ls,
    search,

    Loader,
    discover_loaders,

    register_root,
    register_data,
    register_host,
    register_format,
    register_silo,
    register_family,
    register_loaders_path,
    register_plugins,

    registered_host,
    registered_families,
    registered_loaders_paths,
    registered_formats,
    registered_data,
    registered_root,
    registered_silos,

    deregister_plugins,
    deregister_format,
    deregister_family,
    deregister_data,
    deregister_loaders_path,

    any_representation,

    fixture,
)

from .lib import (
    format_staging_dir,
    format_shared_dir,
    format_version,

    time,

    find_latest_version,
    parse_version,
)

logging.basicConfig()

__all__ = [
    "install",
    "uninstall",

    "schema",

    "ls",
    "search",

    "Loader",
    "discover_loaders",

    "register_host",
    "register_data",
    "register_format",
    "register_silo",
    "register_family",
    "register_loaders_path",
    "register_plugins",
    "register_root",

    "registered_root",
    "registered_silos",
    "registered_loaders_paths",
    "registered_host",
    "registered_families",
    "registered_formats",
    "registered_data",

    "deregister_plugins",
    "deregister_family",
    "deregister_data",
    "deregister_loaders_path",

    "format_staging_dir",
    "format_shared_dir",
    "format_version",

    "find_latest_version",
    "parse_version",

    "time",

    "any_representation",

    "fixture",
]
<|endoftext|>