<commit_before>from marshmallow import Schema

from . import fields, validate

from skylines.lib.formatter.units import DISTANCE_UNITS, SPEED_UNITS, LIFT_UNITS, ALTITUDE_UNITS

class AircraftModelSchema(Schema):
    id = fields.Integer(dump_only=True)
    name = fields.String(required=True, strip=True, validate=validate.Length(max=64))
    index = fields.Integer(attribute='dmst_index')

class AirportSchema(Schema):
    id = fields.Integer(dump_only=True)
    name = fields.String(required=True, strip=True, validate=validate.Length(max=255))
    countryCode = fields.String(attribute='country_code', dump_only=True)

class ClubSchema(Schema):
    id = fields.Integer(dump_only=True)
    name = fields.String(required=True, strip=True, validate=(
        validate.NotEmpty(),
        validate.Length(min=1, max=255),
    ))
    website = fields.URL()

class UserSchema(Schema):
    id = fields.Integer(dump_only=True)
    email = fields.Email(attribute='email_address', validate=validate.Length(max=255))
    firstName = fields.String(attribute='first_name', strip=True, validate=(
        validate.NotEmpty(),
        validate.Length(min=1, max=255),
    ))
    lastName = fields.String(attribute='last_name', strip=True, validate=(
        validate.NotEmpty(),
        validate.Length(min=1, max=255),
    ))
    name = fields.String(dump_only=True)
    trackingCallsign = fields.String(attribute='tracking_callsign', strip=True, validate=validate.Length(max=5))
    trackingDelay = fields.Integer(attribute='tracking_delay', validate=validate.Range(min=0, max=60))
    distanceUnit = fields.Integer(attribute='distance_unit', validate=validate.Range(min=0, max=len(DISTANCE_UNITS) - 1))
    speedUnit = fields.Integer(attribute='speed_unit', validate=validate.Range(min=0, max=len(SPEED_UNITS) - 1))
    liftUnit = fields.Integer(attribute='lift_unit', validate=validate.Range(min=0, max=len(LIFT_UNITS) - 1))
    altitudeUnit = fields.Integer(attribute='altitude_unit', validate=validate.Range(min=0, max=len(ALTITUDE_UNITS) - 1))

class IGCFileSchema(Schema):
    ownerId = fields.Integer(attribute='owner_id')
    owner = fields.Nested(UserSchema, only=('id', 'name'))

    filename = fields.String(strip=True)

    registration = fields.String(strip=True, validate=validate.Length(max=32))
    competitionId = fields.String(attribute='competition_id', strip=True, validate=validate.Length(max=5))
    model = fields.String(strip=True, validate=validate.Length(max=64))

    class Meta:
        load_only = ('ownerId',)
        dump_only = ('owner',)

class FlightSchema(Schema):
    timeCreated = fields.DateTime(attribute='time_created')

    pilotId = fields.Integer(attribute='pilot_id', allow_none=True)
    pilot = fields.Nested(UserSchema, only=('id', 'name'))
    pilotName = fields.String(attribute='pilot_name', strip=True, allow_none=True, validate=validate.Length(max=255))

    copilotId = fields.Integer(attribute='co_pilot_id', allow_none=True)
    copilot = fields.Nested(UserSchema, attribute='co_pilot', only=('id', 'name'))
    copilotName = fields.String(attribute='co_pilot_name', strip=True, allow_none=True, validate=validate.Length(max=255))

    clubId = fields.Integer(attribute='club_id', allow_none=True)
    club = fields.Nested(ClubSchema, only=('id', 'name'))

    modelId = fields.Integer(attribute='model_id', allow_none=True)
    model = fields.Nested(AircraftModelSchema)
    registration = fields.String(strip=True, validate=validate.Length(max=32))
    competitionId = fields.String(attribute='competition_id', strip=True, validate=validate.Length(max=5))

    scoreDate = fields.Date(attribute='date_local')

    takeoffTime = fields.DateTime(attribute='takeoff_time')
    scoreStartTime = fields.DateTime(attribute='scoring_start_time')
    scoreEndTime = fields.DateTime(attribute='scoring_end_time')
    landingTime = fields.DateTime(attribute='landing_time')

    takeoffAirportId = fields.Integer(attribute='takeoff_airport_id', allow_none=True)
    takeoffAirport = fields.Nested(AirportSchema, attribute='takeoff_airport', only=('id', 'name', 'countryCode'))

    landingAirportId = fields.Integer(attribute='landing_airport_id', allow_none=True)
    landingAirport = fields.Nested(AirportSchema, attribute='landing_airport', only=('id', 'name', 'countryCode'))

    distance = fields.Integer(attribute='olc_classic_distance')
    triangleDistance = fields.Integer(attribute='olc_triangle_distance')
    score = fields.Float(attribute='olc_plus_score')

    igcFile = fields.Nested(IGCFileSchema, attribute='igc_file', only=('registration', 'competitionId', 'model'))

    class Meta:
        load_only = ('pilotId', 'copilotId', 'clubId', 'modelId', 'takeoffAirportId', 'landingAirportId')
        dump_only = ('pilot', 'copilot', 'club', 'model', 'takeoffAirport', 'landingAirport', 'igcFile')

class FlightCommentSchema(Schema):
    user = fields.Nested(UserSchema, only=('id', 'name'))
    text = fields.String(required=True)
<commit_msg>schemas/FlightSchema: Fix "score" attribute<commit_after>from marshmallow import Schema

from . import fields, validate

from skylines.lib.formatter.units import DISTANCE_UNITS, SPEED_UNITS, LIFT_UNITS, ALTITUDE_UNITS

class AircraftModelSchema(Schema):
    id = fields.Integer(dump_only=True)
    name = fields.String(required=True, strip=True, validate=validate.Length(max=64))
    index = fields.Integer(attribute='dmst_index')

class AirportSchema(Schema):
    id = fields.Integer(dump_only=True)
    name = fields.String(required=True, strip=True, validate=validate.Length(max=255))
    countryCode = fields.String(attribute='country_code', dump_only=True)

class ClubSchema(Schema):
    id = fields.Integer(dump_only=True)
    name = fields.String(required=True, strip=True, validate=(
        validate.NotEmpty(),
        validate.Length(min=1, max=255),
    ))
    website = fields.URL()

class UserSchema(Schema):
    id = fields.Integer(dump_only=True)
    email = fields.Email(attribute='email_address', validate=validate.Length(max=255))
    firstName = fields.String(attribute='first_name', strip=True, validate=(
        validate.NotEmpty(),
        validate.Length(min=1, max=255),
    ))
    lastName = fields.String(attribute='last_name', strip=True, validate=(
        validate.NotEmpty(),
        validate.Length(min=1, max=255),
    ))
    name = fields.String(dump_only=True)
    trackingCallsign = fields.String(attribute='tracking_callsign', strip=True, validate=validate.Length(max=5))
    trackingDelay = fields.Integer(attribute='tracking_delay', validate=validate.Range(min=0, max=60))
    distanceUnit = fields.Integer(attribute='distance_unit', validate=validate.Range(min=0, max=len(DISTANCE_UNITS) - 1))
    speedUnit = fields.Integer(attribute='speed_unit', validate=validate.Range(min=0, max=len(SPEED_UNITS) - 1))
    liftUnit = fields.Integer(attribute='lift_unit', validate=validate.Range(min=0, max=len(LIFT_UNITS) - 1))
    altitudeUnit = fields.Integer(attribute='altitude_unit', validate=validate.Range(min=0, max=len(ALTITUDE_UNITS) - 1))

class IGCFileSchema(Schema):
    ownerId = fields.Integer(attribute='owner_id')
    owner = fields.Nested(UserSchema, only=('id', 'name'))

    filename = fields.String(strip=True)

    registration = fields.String(strip=True, validate=validate.Length(max=32))
    competitionId = fields.String(attribute='competition_id', strip=True, validate=validate.Length(max=5))
    model = fields.String(strip=True, validate=validate.Length(max=64))

    class Meta:
        load_only = ('ownerId',)
        dump_only = ('owner',)

class FlightSchema(Schema):
    timeCreated = fields.DateTime(attribute='time_created')

    pilotId = fields.Integer(attribute='pilot_id', allow_none=True)
    pilot = fields.Nested(UserSchema, only=('id', 'name'))
    pilotName = fields.String(attribute='pilot_name', strip=True, allow_none=True, validate=validate.Length(max=255))

    copilotId = fields.Integer(attribute='co_pilot_id', allow_none=True)
    copilot = fields.Nested(UserSchema, attribute='co_pilot', only=('id', 'name'))
    copilotName = fields.String(attribute='co_pilot_name', strip=True, allow_none=True, validate=validate.Length(max=255))

    clubId = fields.Integer(attribute='club_id', allow_none=True)
    club = fields.Nested(ClubSchema, only=('id', 'name'))

    modelId = fields.Integer(attribute='model_id', allow_none=True)
    model = fields.Nested(AircraftModelSchema)
    registration = fields.String(strip=True, validate=validate.Length(max=32))
    competitionId = fields.String(attribute='competition_id', strip=True, validate=validate.Length(max=5))

    scoreDate = fields.Date(attribute='date_local')

    takeoffTime = fields.DateTime(attribute='takeoff_time')
    scoreStartTime = fields.DateTime(attribute='scoring_start_time')
    scoreEndTime = fields.DateTime(attribute='scoring_end_time')
    landingTime = fields.DateTime(attribute='landing_time')

    takeoffAirportId = fields.Integer(attribute='takeoff_airport_id', allow_none=True)
    takeoffAirport = fields.Nested(AirportSchema, attribute='takeoff_airport', only=('id', 'name', 'countryCode'))

    landingAirportId = fields.Integer(attribute='landing_airport_id', allow_none=True)
    landingAirport = fields.Nested(AirportSchema, attribute='landing_airport', only=('id', 'name', 'countryCode'))

    distance = fields.Integer(attribute='olc_classic_distance')
    triangleDistance = fields.Integer(attribute='olc_triangle_distance')
    rawScore = fields.Float(attribute='olc_plus_score')
    score = fields.Float(attribute='index_score')

    igcFile = fields.Nested(IGCFileSchema, attribute='igc_file', only=('registration', 'competitionId', 'model'))

    class Meta:
        load_only = ('pilotId', 'copilotId', 'clubId', 'modelId', 'takeoffAirportId', 'landingAirportId')
        dump_only = ('pilot', 'copilot', 'club', 'model', 'takeoffAirport', 'landingAirport', 'igcFile')

class FlightCommentSchema(Schema):
    user = fields.Nested(UserSchema, only=('id', 'name'))
    text = fields.String(required=True)
<|endoftext|>


<commit_before>"""
Support for Homekit device discovery.

For more details about this component, please refer to the documentation at
https://home-assistant.io/components/homekit_controller/
"""
import json
import logging
import os

from homeassistant.components.discovery import SERVICE_HOMEKIT
from homeassistant.helpers import discovery
from homeassistant.helpers.entity import Entity
from homeassistant.helpers.event import call_later

REQUIREMENTS = ['homekit==0.12.2']

DOMAIN = 'homekit_controller'
HOMEKIT_DIR = '.homekit'

# Mapping from Homekit type to component.
HOMEKIT_ACCESSORY_DISPATCH = {
    'lightbulb': 'light',
    'outlet': 'switch',
    'switch': 'switch',
    'thermostat': 'climate',
    'security-system': 'alarm_control_panel',
    'garage-door-opener': 'cover',
    'window': 'cover',
    'window-covering': 'cover',
    'lock-mechanism': 'lock',
    'motion': 'binary_sensor',
}

HOMEKIT_IGNORE = [
    'BSB002',
    'Home Assistant Bridge',
    'TRADFRI gateway'
]

KNOWN_ACCESSORIES = "{}-accessories".format(DOMAIN)
KNOWN_DEVICES = "{}-devices".format(DOMAIN)
CONTROLLER = "{}-controller".format(DOMAIN)

_LOGGER = logging.getLogger(__name__)

REQUEST_TIMEOUT = 5  # seconds
RETRY_INTERVAL = 60  # seconds

PAIRING_FILE = "pairing.json"

def get_serial(accessory):
    """Obtain the serial number of a HomeKit device."""
    # pylint: disable=import-error
    from homekit.model.services import ServicesTypes
    from homekit.model.characteristics import CharacteristicsTypes

    for service in accessory['services']:
        if ServicesTypes.get_short(service['type']) != \
           'accessory-information':
            continue
        for characteristic in service['characteristics']:
            ctype = CharacteristicsTypes.get_short(
                characteristic['type'])
            if ctype != 'serial-number':
                continue
            return characteristic['value']
    return None

def escape_characteristic_name(char_name):
    """Escape any dash or dots in a characteristics name."""
    return char_name.replace('-', '_').replace('.', '_')

class HKDevice():
    """HomeKit device."""

    def __init__(self, hass, host, port, model, hkid, config_num, config):
        """Initialise a generic HomeKit device."""
        _LOGGER.info("Setting up Homekit device %s", model)
        self.hass = hass
        self.controller = hass.data[CONTROLLER]

        self.host = host
        self.port = port
        self.model = model
        self.hkid = hkid
        self.config_num = config_num
        self.config = config
        self.configurator = hass.components.configurator
        self._connection_warning_logged = False

        self.pairing = self.controller.pairings.get(hkid)

        if self.pairing is not None:
            self.accessory_setup()
        else:
            self.configure()

    def accessory_setup(self):
        """Handle setup of a HomeKit accessory."""
        # pylint: disable=import-error
        from homekit.model.services import ServicesTypes
        from homekit.exceptions import AccessoryDisconnectedError

        self.pairing.pairing_data['AccessoryIP'] = self.host
        self.pairing.pairing_data['AccessoryPort'] = self.port

        try:
            data = self.pairing.list_accessories_and_characteristics()
        except AccessoryDisconnectedError:
            call_later(
                self.hass, RETRY_INTERVAL, lambda _: self.accessory_setup())
            return
        for accessory in data:
            serial = get_serial(accessory)
            if serial in self.hass.data[KNOWN_ACCESSORIES]:
                continue
            self.hass.data[KNOWN_ACCESSORIES][serial] = self
            aid = accessory['aid']
            for service in accessory['services']:
                devtype = ServicesTypes.get_short(service['type'])
                _LOGGER.debug("Found %s", devtype)
                service_info = {'serial': serial,
                                'aid': aid,
                                'iid': service['iid'],
                                'model': self.model,
                                'device-type': devtype}
                component = HOMEKIT_ACCESSORY_DISPATCH.get(devtype, None)
                if component is not None:
                    discovery.load_platform(self.hass, component, DOMAIN,
                                            service_info, self.config)

    def device_config_callback(self, callback_data):
        """Handle initial pairing."""
        import homekit  # pylint: disable=import-error
        code = callback_data.get('code').strip()
        try:
            self.controller.perform_pairing(self.hkid, self.hkid, code)
        except homekit.UnavailableError:
            error_msg = "This accessory is already paired to another device. \
                         Please reset the accessory and try again."
            _configurator = self.hass.data[DOMAIN+self.hkid]
            self.configurator.notify_errors(_configurator, error_msg)
            return
        except homekit.AuthenticationError:
            error_msg = "Incorrect HomeKit code for {}. Please check it and \
                         try again.".format(self.model)
            _configurator = self.hass.data[DOMAIN+self.hkid]
            self.configurator.notify_errors(_configurator, error_msg)
            return
        except homekit.UnknownError:
            error_msg = "Received an unknown error. Please file a bug."
            _configurator = self.hass.data[DOMAIN+self.hkid]
            self.configurator.notify_errors(_configurator, error_msg)
            raise

        self.pairing = self.controller.pairings.get(self.hkid)
        if self.pairing is not None:
            pairing_file = os.path.join(
                self.hass.config.path(),
                HOMEKIT_DIR,
                PAIRING_FILE,
            )
            self.controller.save_data(pairing_file)
            _configurator = self.hass.data[DOMAIN+self.hkid]
            self.configurator.request_done(_configurator)
            self.accessory_setup()
        else:
            error_msg = "Unable to pair, please try again"
            _configurator = self.hass.data[DOMAIN+self.hkid]
            self.configurator.notify_errors(_configurator, error_msg)

    def configure(self):
        """Obtain the pairing code for a HomeKit device."""
        description = "Please enter the HomeKit code for your {}".format(
            self.model)
        self.hass.data[DOMAIN+self.hkid] = \
            self.configurator.request_config(self.model,
                                             self.device_config_callback,
                                             description=description,
                                             submit_caption="submit",
                                             fields=[{'id': 'code',
                                                      'name': 'HomeKit code',
                                                      'type': 'string'}])

class HomeKitEntity(Entity):
    """Representation of a Home Assistant HomeKit device."""

    def __init__(self, accessory, devinfo):
        """Initialise a generic HomeKit device."""
        self._name = accessory.model
        self._accessory = accessory
        self._aid = devinfo['aid']
        self._iid = devinfo['iid']
        self._address = "homekit-{}-{}".format(devinfo['serial'], self._iid)
        self._features = 0
        self._chars = {}
        self.setup()

    def setup(self):
        """Configure an entity baed on its HomeKit characterstics metadata."""
        # pylint: disable=import-error
        from homekit.model.characteristics import CharacteristicsTypes

        pairing_data = self._accessory.pairing.pairing_data

        get_uuid = CharacteristicsTypes.get_uuid
        characteristic_types = [
            get_uuid(c) for c in self.get_characteristic_types()
        ]

        self._chars_to_poll = []
        self._chars = {}
        self._char_names = {}

        for accessory in pairing_data.get('accessories', []):
            if accessory['aid'] != self._aid:
                continue
            for service in accessory['services']:
                if service['iid'] != self._iid:
                    continue
                for char in service['characteristics']:
                    uuid = CharacteristicsTypes.get_uuid(char['type'])
                    if uuid not in characteristic_types:
                        continue
                    self._setup_characteristic(char)

    def _setup_characteristic(self, char):
        """Configure an entity based on a HomeKit characteristics metadata."""
        # pylint: disable=import-error
        from homekit.model.characteristics import CharacteristicsTypes

        # Build up a list of (aid, iid) tuples to poll on update()
        self._chars_to_poll.append((self._aid, char['iid']))

        # Build a map of ctype -> iid
        short_name = CharacteristicsTypes.get_short(char['type'])
        self._chars[short_name] = char['iid']
        self._char_names[char['iid']] = short_name

        # Callback to allow entity to configure itself based on this
        # characteristics metadata (valid values, value ranges, features, etc)
        setup_fn_name = escape_characteristic_name(short_name)
        setup_fn = getattr(self, '_setup_{}'.format(setup_fn_name), None)
        if not setup_fn:
            return
        # pylint: disable=not-callable
        setup_fn(char)

    def update(self):
        """Obtain a HomeKit device's state."""
        # pylint: disable=import-error
        from homekit.exceptions import AccessoryDisconnectedError

        pairing = self._accessory.pairing

        try:
            new_values_dict = pairing.get_characteristics(self._chars_to_poll)
        except AccessoryDisconnectedError:
            return

        for (_, iid), result in new_values_dict.items():
            if 'value' not in result:
                continue
            # Callback to update the entity with this characteristic value
            char_name = escape_characteristic_name(self._char_names[iid])
            update_fn = getattr(self, '_update_{}'.format(char_name), None)
            if not update_fn:
                continue
            # pylint: disable=not-callable
            update_fn(result['value'])

    @property
    def unique_id(self):
        """Return the ID of this device."""
        return self._address

    @property
    def name(self):
        """Return the name of the device if any."""
        return self._name

    @property
    def available(self) -> bool:
        """Return True if entity is available."""
        return self._accessory.pairing is not None

    def get_characteristic_types(self):
        """Define the homekit characteristics the entity cares about."""
        raise NotImplementedError

    def update_characteristics(self, characteristics):
        """Synchronise a HomeKit device state with Home Assistant."""
        pass

    def put_characteristics(self, characteristics):
        """Control a HomeKit device state from Home Assistant."""
        chars = []
        for row in characteristics:
            chars.append((
                row['aid'],
                row['iid'],
                row['value'],
            ))

        self._accessory.pairing.put_characteristics(chars)

def setup(hass, config):
    """Set up for Homekit devices."""
    # pylint: disable=import-error
    import homekit
    from homekit.controller import Pairing

    hass.data[CONTROLLER] = controller = homekit.Controller()

    data_dir = os.path.join(hass.config.path(), HOMEKIT_DIR)
    if not os.path.isdir(data_dir):
        os.mkdir(data_dir)

    pairing_file = os.path.join(data_dir, PAIRING_FILE)
    if os.path.exists(pairing_file):
        controller.load_data(pairing_file)

    # Migrate any existing pairings to the new internal homekit_python format
    for device in os.listdir(data_dir):
        if not device.startswith('hk-'):
            continue
        alias = device[3:]
        if alias in controller.pairings:
            continue
        with open(os.path.join(data_dir, device)) as pairing_data_fp:
            pairing_data = json.load(pairing_data_fp)
        controller.pairings[alias] = Pairing(pairing_data)
        controller.save_data(pairing_file)

    def discovery_dispatch(service, discovery_info):
        """Dispatcher for Homekit discovery events."""
        # model, id
        host = discovery_info['host']
        port = discovery_info['port']
        model = discovery_info['properties']['md']
        hkid = discovery_info['properties']['id']
        config_num = int(discovery_info['properties']['c#'])

        if model in HOMEKIT_IGNORE:
            return

        # Only register a device once, but rescan if the config has changed
        if hkid in hass.data[KNOWN_DEVICES]:
            device = hass.data[KNOWN_DEVICES][hkid]
            if config_num > device.config_num and \
               device.pairing_info is not None:
                device.accessory_setup()
            return

        _LOGGER.debug('Discovered unique device %s', hkid)
        device = HKDevice(hass, host, port, model, hkid, config_num, config)
        hass.data[KNOWN_DEVICES][hkid] = device

    hass.data[KNOWN_ACCESSORIES] = {}
    hass.data[KNOWN_DEVICES] = {}
    discovery.listen(hass, SERVICE_HOMEKIT, discovery_dispatch)
    return True
<commit_msg>Fix homekit_controller non-standard hk characteristics (#20824)<commit_after>"""
Support for Homekit device discovery.

For more details about this component, please refer to the documentation at
https://home-assistant.io/components/homekit_controller/
"""
import json
import logging
import os

from homeassistant.components.discovery import SERVICE_HOMEKIT
from homeassistant.helpers import discovery
from homeassistant.helpers.entity import Entity
from homeassistant.helpers.event import call_later

REQUIREMENTS = ['homekit==0.12.2']

DOMAIN = 'homekit_controller'
HOMEKIT_DIR = '.homekit'

# Mapping from Homekit type to component.
HOMEKIT_ACCESSORY_DISPATCH = {
    'lightbulb': 'light',
    'outlet': 'switch',
    'switch': 'switch',
    'thermostat': 'climate',
    'security-system': 'alarm_control_panel',
    'garage-door-opener': 'cover',
    'window': 'cover',
    'window-covering': 'cover',
    'lock-mechanism': 'lock',
    'motion': 'binary_sensor',
}

HOMEKIT_IGNORE = [
    'BSB002',
    'Home Assistant Bridge',
    'TRADFRI gateway'
]

KNOWN_ACCESSORIES = "{}-accessories".format(DOMAIN)
KNOWN_DEVICES = "{}-devices".format(DOMAIN)
CONTROLLER = "{}-controller".format(DOMAIN)

_LOGGER = logging.getLogger(__name__)

REQUEST_TIMEOUT = 5  # seconds
RETRY_INTERVAL = 60  # seconds

PAIRING_FILE = "pairing.json"

def get_serial(accessory):
    """Obtain the serial number of a HomeKit device."""
    # pylint: disable=import-error
    from homekit.model.services import ServicesTypes
    from homekit.model.characteristics import CharacteristicsTypes

    for service in accessory['services']:
        if ServicesTypes.get_short(service['type']) != \
           'accessory-information':
            continue
        for characteristic in service['characteristics']:
            ctype = CharacteristicsTypes.get_short(
                characteristic['type'])
            if ctype != 'serial-number':
                continue
            return characteristic['value']
    return None

def escape_characteristic_name(char_name):
    """Escape any dash or dots in a characteristics name."""
    return char_name.replace('-', '_').replace('.', '_')

class HKDevice():
    """HomeKit device."""

    def __init__(self, hass, host, port, model, hkid, config_num, config):
        """Initialise a generic HomeKit device."""
        _LOGGER.info("Setting up Homekit device %s", model)
        self.hass = hass
        self.controller = hass.data[CONTROLLER]

        self.host = host
        self.port = port
        self.model = model
        self.hkid = hkid
        self.config_num = config_num
        self.config = config
        self.configurator = hass.components.configurator
        self._connection_warning_logged = False

        self.pairing = self.controller.pairings.get(hkid)

        if self.pairing is not None:
            self.accessory_setup()
        else:
            self.configure()

    def accessory_setup(self):
        """Handle setup of a HomeKit accessory."""
        # pylint: disable=import-error
        from homekit.model.services import ServicesTypes
        from homekit.exceptions import AccessoryDisconnectedError

        self.pairing.pairing_data['AccessoryIP'] = self.host
        self.pairing.pairing_data['AccessoryPort'] = self.port

        try:
            data = self.pairing.list_accessories_and_characteristics()
        except AccessoryDisconnectedError:
            call_later(
                self.hass, RETRY_INTERVAL, lambda _: self.accessory_setup())
            return
        for accessory in data:
            serial = get_serial(accessory)
            if serial in self.hass.data[KNOWN_ACCESSORIES]:
                continue
            self.hass.data[KNOWN_ACCESSORIES][serial] = self
            aid = accessory['aid']
            for service in accessory['services']:
                devtype = ServicesTypes.get_short(service['type'])
                _LOGGER.debug("Found %s", devtype)
                service_info = {'serial': serial,
                                'aid': aid,
                                'iid': service['iid'],
                                'model': self.model,
                                'device-type': devtype}
                component = HOMEKIT_ACCESSORY_DISPATCH.get(devtype, None)
                if component is not None:
                    discovery.load_platform(self.hass, component, DOMAIN,
                                            service_info, self.config)

    def device_config_callback(self, callback_data):
        """Handle initial pairing."""
        import homekit  # pylint: disable=import-error
        code = callback_data.get('code').strip()
        try:
            self.controller.perform_pairing(self.hkid, self.hkid, code)
        except homekit.UnavailableError:
            error_msg = "This accessory is already paired to another device. \
                         Please reset the accessory and try again."
            _configurator = self.hass.data[DOMAIN+self.hkid]
            self.configurator.notify_errors(_configurator, error_msg)
            return
        except homekit.AuthenticationError:
            error_msg = "Incorrect HomeKit code for {}. Please check it and \
                         try again.".format(self.model)
            _configurator = self.hass.data[DOMAIN+self.hkid]
            self.configurator.notify_errors(_configurator, error_msg)
            return
        except homekit.UnknownError:
            error_msg = "Received an unknown error. Please file a bug."
            _configurator = self.hass.data[DOMAIN+self.hkid]
            self.configurator.notify_errors(_configurator, error_msg)
            raise

        self.pairing = self.controller.pairings.get(self.hkid)
        if self.pairing is not None:
            pairing_file = os.path.join(
                self.hass.config.path(),
                HOMEKIT_DIR,
                PAIRING_FILE,
            )
            self.controller.save_data(pairing_file)
            _configurator = self.hass.data[DOMAIN+self.hkid]
            self.configurator.request_done(_configurator)
            self.accessory_setup()
        else:
            error_msg = "Unable to pair, please try again"
            _configurator = self.hass.data[DOMAIN+self.hkid]
            self.configurator.notify_errors(_configurator, error_msg)

    def configure(self):
        """Obtain the pairing code for a HomeKit device."""
        description = "Please enter the HomeKit code for your {}".format(
            self.model)
        self.hass.data[DOMAIN+self.hkid] = \
            self.configurator.request_config(self.model,
                                             self.device_config_callback,
                                             description=description,
                                             submit_caption="submit",
                                             fields=[{'id': 'code',
                                                      'name': 'HomeKit code',
                                                      'type': 'string'}])

class HomeKitEntity(Entity):
    """Representation of a Home Assistant HomeKit device."""

    def __init__(self, accessory, devinfo):
        """Initialise a generic HomeKit device."""
        self._name = accessory.model
        self._accessory = accessory
        self._aid = devinfo['aid']
        self._iid = devinfo['iid']
        self._address = "homekit-{}-{}".format(devinfo['serial'], self._iid)
        self._features = 0
        self._chars = {}
        self.setup()

    def setup(self):
        """Configure an entity baed on its HomeKit characterstics metadata."""
        # pylint: disable=import-error
        from homekit.model.characteristics import CharacteristicsTypes

        pairing_data = self._accessory.pairing.pairing_data

        get_uuid = CharacteristicsTypes.get_uuid
        characteristic_types = [
            get_uuid(c) for c in self.get_characteristic_types()
        ]

        self._chars_to_poll = []
        self._chars = {}
        self._char_names = {}

        for accessory in pairing_data.get('accessories', []):
            if accessory['aid'] != self._aid:
                continue
            for service in accessory['services']:
                if service['iid'] != self._iid:
                    continue
                for char in service['characteristics']:
                    try:
                        uuid = CharacteristicsTypes.get_uuid(char['type'])
                    except KeyError:
                        # If a KeyError is raised its a non-standard
                        # characteristic. We must ignore it in this case.
                        continue
                    if uuid not in characteristic_types:
                        continue
                    self._setup_characteristic(char)

    def _setup_characteristic(self, char):
        """Configure an entity based on a HomeKit characteristics metadata."""
        # pylint: disable=import-error
        from homekit.model.characteristics import CharacteristicsTypes

        # Build up a list of (aid, iid) tuples to poll on update()
        self._chars_to_poll.append((self._aid, char['iid']))

        # Build a map of ctype -> iid
        short_name = CharacteristicsTypes.get_short(char['type'])
        self._chars[short_name] = char['iid']
        self._char_names[char['iid']] = short_name

        # Callback to allow entity to configure itself based on this
        # characteristics metadata (valid values, value ranges, features, etc)
        setup_fn_name = escape_characteristic_name(short_name)
        setup_fn = getattr(self, '_setup_{}'.format(setup_fn_name), None)
        if not setup_fn:
            return
        # pylint: disable=not-callable
        setup_fn(char)

    def update(self):
        """Obtain a HomeKit device's state."""
        # pylint: disable=import-error
        from homekit.exceptions import AccessoryDisconnectedError

        pairing = self._accessory.pairing

        try:
            new_values_dict = pairing.get_characteristics(self._chars_to_poll)
        except AccessoryDisconnectedError:
            return

        for (_, iid), result in new_values_dict.items():
            if 'value' not in result:
                continue
            # Callback to update the entity with this characteristic value
            char_name = escape_characteristic_name(self._char_names[iid])
            update_fn = getattr(self, '_update_{}'.format(char_name), None)
            if not update_fn:
                continue
            # pylint: disable=not-callable
            update_fn(result['value'])

    @property
    def unique_id(self):
        """Return the ID of this device."""
        return self._address

    @property
    def name(self):
        """Return the name of the device if any."""
        return self._name

    @property
    def available(self) -> bool:
        """Return True if entity is available."""
        return self._accessory.pairing is not None

    def get_characteristic_types(self):
        """Define the homekit characteristics the entity cares about."""
        raise NotImplementedError

    def update_characteristics(self, characteristics):
        """Synchronise a HomeKit device state with Home Assistant."""
        pass

    def put_characteristics(self, characteristics):
        """Control a HomeKit device state from Home Assistant."""
        chars = []
        for row in characteristics:
            chars.append((
                row['aid'],
                row['iid'],
                row['value'],
            ))

        self._accessory.pairing.put_characteristics(chars)

def setup(hass, config):
    """Set up for Homekit devices."""
    # pylint: disable=import-error
    import homekit
    from homekit.controller import Pairing

    hass.data[CONTROLLER] = controller = homekit.Controller()

    data_dir = os.path.join(hass.config.path(), HOMEKIT_DIR)
    if not os.path.isdir(data_dir):
        os.mkdir(data_dir)

    pairing_file = os.path.join(data_dir, PAIRING_FILE)
    if os.path.exists(pairing_file):
        controller.load_data(pairing_file)

    # Migrate any existing pairings to the new internal homekit_python format
    for device in os.listdir(data_dir):
        if not device.startswith('hk-'):
            continue
        alias = device[3:]
        if alias in controller.pairings:
            continue
        with open(os.path.join(data_dir, device)) as pairing_data_fp:
            pairing_data = json.load(pairing_data_fp)
        controller.pairings[alias] = Pairing(pairing_data)
        controller.save_data(pairing_file)

    def discovery_dispatch(service, discovery_info):
        """Dispatcher for Homekit discovery events."""
        # model, id
        host = discovery_info['host']
        port = discovery_info['port']
        model = discovery_info['properties']['md']
        hkid = discovery_info['properties']['id']
        config_num = int(discovery_info['properties']['c#'])

        if model in HOMEKIT_IGNORE:
            return

        # Only register a device once, but rescan if the config has changed
        if hkid in hass.data[KNOWN_DEVICES]:
            device = hass.data[KNOWN_DEVICES][hkid]
            if config_num > device.config_num and \
               device.pairing_info is not None:
                device.accessory_setup()
            return

        _LOGGER.debug('Discovered unique device %s', hkid)
        device = HKDevice(hass, host, port, model, hkid, config_num, config)
        hass.data[KNOWN_DEVICES][hkid] = device

    hass.data[KNOWN_ACCESSORIES] = {}
    hass.data[KNOWN_DEVICES] = {}
    discovery.listen(hass, SERVICE_HOMEKIT, discovery_dispatch)
    return True
<|endoftext|>


<commit_before>__author__ = 'sachinpatney'

from common import IMonaTask
from common import Mona
from common import Timeline
import urllib2, random

template = "Microsoft stock closed at {0}, {1}, {2}.{3}"
motivate = [' Come on people we can do better!', ' OK. Clearly you guys need to work harder.']
praise = [' Great job guys!', ' Well done! Go treat yourself to some coffee.']

class StockTicker(IMonaTask):
    def __run__(self, time):
        if  True or (time[0] == '1' and time[1] == '15'):
            result = urllib2.urlopen("http://finance.yahoo.com/d/quotes.csv?s=MSFT&f=spc1").read()
            result = result.strip().split(',')

            dir = 'down'

            if float(result[2]) > 0:
                dir = 'up'

            msg = template.format(result[1].replace('.',' point '), dir, result[2].replace('.',' point ').replace('-', ''),'')
            Mona.speak(msg);
            Timeline.add_item('Mona', 'Stock update', template.format(result[1], dir, result[2], random.choice(motivate)), '', 'fa-bar-chart', 'success')

            if dir == 'up':
                Mona.speak(random.choice(praise))
            else:
                Mona.speak(random.choice(motivate))<commit_msg>updating script<commit_after>__author__ = 'sachinpatney'

from common import IMonaTask
from common import Mona
from common import Timeline
import urllib2, random

template = "Microsoft stock closed at {0}, {1}, {2}.{3}"
motivate = [' Come on people we can do better!', ' OK. Clearly you guys need to work harder.']
praise = [' Great job guys!', ' Well done! Go treat yourself to some coffee.']

class StockTicker(IMonaTask):
    def __run__(self, time):
        if  True or (time[0] == '1' and time[1] == '15'):
            result = urllib2.urlopen("http://finance.yahoo.com/d/quotes.csv?s=MSFT&f=spc1").read()
            result = result.strip().split(',')

            dir = 'down'

            if float(result[2]) > 0:
                dir = 'up'

            msg = template.format(result[1].replace('.',' point '), dir, result[2].replace('.',' point ').replace('-', ''),'')
            Mona.speak(msg);
            Timeline.add_item('Mona', 'Stock update', template.format(result[1], dir, result[2].replace('-', ''), random.choice(motivate)), '', 'fa-bar-chart', 'success')

            if dir == 'up':
                Mona.speak(random.choice(praise))
            else:
                Mona.speak(random.choice(motivate))<|endoftext|>


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

"""

py2neo - Python library for accessing Neo4j via REST interface

---

Copyright 2011 Three Steps Beyond LLP

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

	http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

"""

import httplib2
import json

class Direction:

	BOTH     = 'all'
	INCOMING = 'incoming'
	OUTGOING = 'outgoing'

class ReturnFilter:

	ALL                = 'all'
	ALL_BUT_START_NODE = 'all_but_start_node'

class Resource:
	"""
	Web service resource class, nothing here specific to Neo4j but designed to
	work with a well-behaved hypermedia web service; used here as a base class
	for objects represented within the neo4j web service
	"""

	_read_headers = {
		'Accept': "application/json"
	}
	_write_headers = {
		'Accept': "application/json",
		'Content-Type': "application/json"
	}

	def __init__(self, uri, http=None):
		"""
		Creates a new Resource instance

		Parameters:
			uri  - the root URI for this resource
			http - optional httplib2.Http() object to use for requests

		"""
		self.uri = uri
		self._http = http or httplib2.Http()
		self._index = None

	def lookup(self, key):
		"""
		Looks up a value in the resource index by key; will lazily load
		resource index if required
		"""
		if(self._index == None):
			self._index = self._get(self.uri)
		if key in self._index:
			return self._index[key]
		else:
			return None

	def _get(self, uri):
		"""
		Issues an HTTP GET request

		Parameters:
			uri  - the URI of the resource to GET
			args - optional dictionary of URI template substitution values

		Result (dependent on HTTP status code):
			200 - returns value created from returned json content
			204 - returns None
			404 - raises a KeyError against the specified URI
			??? - raises a SystemError with the HTTP response

		"""
		response, content = self._http.request(uri, 'GET', None, self._read_headers)
		if response.status == 200:
			return json.loads(content)
		elif response.status == 204:
			return None
		elif response.status == 404:
			raise KeyError(uri)
		else:
			raise SystemError(response)

	def _post(self, uri, data):
		"""
		Issues an HTTP POST request

		Parameters:
			uri  - the URI of the resource to POST to
			data - value to be converted to json and passed in request payload
			args - optional dictionary of URI template substitution values

		Result (dependent on HTTP status code):
			200 - returns value created from returned json content
			201 - returns value from "Location" header
			400 - raises a ValueError against the specified data
			404 - raises a KeyError against the specified URI
			??? - raises a SystemError with the HTTP response

		"""
		data = {} if data == None else json.dumps(data)
		response, content = self._http.request(uri, 'POST', data, self._write_headers)
		if response.status == 200:
			return json.loads(content)
		elif response.status == 201:
			return response['location']
		elif response.status == 400:
			raise ValueError(data)
		elif response.status == 404:
			raise KeyError(uri)
		else:
			raise SystemError(response)

	def _put(self, uri, data):
		"""
		Issues an HTTP PUT request

		Parameters:
			uri  - the URI of the resource to PUT
			data - value to be converted to json and passed in request payload
			args - optional dictionary of URI template substitution values

		Result (dependent on HTTP status code):
			204 - success (no return value)
			400 - raises a ValueError against the specified data
			404 - raises a KeyError against the specified URI
			??? - raises a SystemError with the HTTP response

		"""
		data = {} if data == None else json.dumps(data)
		response, content = self._http.request(uri, 'PUT', data, self._write_headers)
		if response.status == 204:
			pass
		elif response.status == 400:
			raise ValueError(data)
		elif response.status == 404:
			raise KeyError(uri)
		else:
			raise SystemError(response)

	def _delete(self, uri):
		"""
		Issues an HTTP DELETE request

		Parameters:
			uri  - the URI of the resource to DELETE
			args - optional dictionary of URI template substitution values

		Result (dependent on HTTP status code):
			204 - success (no return value)
			404 - raises a KeyError against the specified URI
			??? - raises a SystemError with the HTTP response

		"""
		response, content = self._http.request(uri, 'DELETE', None, self._read_headers)
		if response.status == 204:
			pass
		elif response.status == 404:
			raise KeyError(uri)
		else:
			raise SystemError(response)

	def __repr__(self):
		return '%s(%s)' % (self.__class__.__name__, repr(self.uri))

class GraphDatabaseService(Resource):

	def __init__(self, uri, http=None):
		Resource.__init__(self, uri, http)

	def create_node(self, properties=None):
		return Node(self._post(self.lookup('node'), properties), self._http)

	def get_reference_node(self):
		return Node(self.lookup('reference_node'), self._http)

	def get_relationship_types(self):
		return self._get(self.lookup('relationship_types'))

	def get_node_indexes(self):
		indexes = self._get(self.lookup('node_index'))
		# replace with map()
		for i in indexes:
			index = indexes[i]
			indexes[i] = NodeIndex(index['template'], self._http)
		return indexes

	def get_relationship_indexes(self):
		indexes = self._get(self.lookup('relationship_index'))
		# replace with map()
		for i in indexes:
			index = indexes[i]
			indexes[i] = RelationshipIndex(index['template'], self._http)
		return indexes

class PropertyContainer(Resource):

	def __init__(self, uri, http=None):
		Resource.__init__(self, uri, http)

	def set_properties(self, properties):
		self._put(self.lookup('properties'), properties)

	def get_properties(self):
		return self._get(self.lookup('properties'))

	def remove_properties(self):
		self._delete(self.lookup('properties'))

	def __setitem__(self, key, value):
		self._put(self.lookup('property').format(key=key), value)

	def __getitem__(self, key):
		return self._get(self.lookup('property').format(key=key))

	def __delitem__(self, key):
		self._delete(self.lookup('property').format(key=key))

class Node(PropertyContainer):

	def __init__(self, uri, http=None):
		PropertyContainer.__init__(self, uri, http)

	def delete(self):
		self._delete(self._index['self'])

	def create_relationship_to(self, other_node, type, data=None):
		return Relationship(self._post(self.lookup('create_relationship'), {
			'to': str(other_node),
			'type': type,
			'data': data
		}), self._http)

	def get_relationships(self, direction, *types):
		if len(types) == 0:
			uri = self.lookup(direction + '_relationships')
		else:
			uri = self.lookup(direction + '_typed_relationships').replace('{-list|&|types}', '&'.join(types))
		return [Relationship(rel['self'], self._http) for rel in self._get(uri)]

	def get_related_nodes(self, direction, *types):
		if len(types) == 0:
			uri = self.lookup(direction + '_relationships')
		else:
			uri = self.lookup(direction + '_typed_relationships').replace('{-list|&|types}', '&'.join(types))
		return [Node(rel['start'] if rel['end'] == self.uri else rel['end'], self._http) for rel in self._get(uri)]

	def get_node_traverser(self):
		return NodeTraverser(self.lookup('traverse').format(returnType='node'), self._http)

class Relationship(PropertyContainer):

	def __init__(self, uri, http=None):
		PropertyContainer.__init__(self, uri, http)
		self.type = self.lookup('type')
		self.data = self.lookup('data')

	def delete(self):
		self._delete(self.lookup('self'))

	def get_start_node(self):
		return Node(self.lookup('start'), self._http)

	def get_end_node(self):
		return Node(self.lookup('end'), self._http)

class Index(Resource):

	def __init__(self, uri, http=None):
		Resource.__init__(self, uri, http)

	def _search(self, key, value):
		return self._get(self.uri.format(key=key, value=value))

	def add(self, entity, key, value):
		self._post(self.uri.format(key=key, value=value), entity.uri)

class NodeIndex(Index):

	def search(self, key, value):
		return [Node(item['self'], self._http) for item in self._search(key, value)]

class RelationshipIndex(Index):

	def search(self, key, value):
		return [Relationship(item['self'], self._http) for item in self._search(key, value)]

class Traverser(Resource):

	class Order:

		BREADTH_FIRST = 'breadth_first'
		DEPTH_FIRST   = 'depth_first'

	def __init__(self, uri, http=None):
		Resource.__init__(self, uri, http)
		self._criteria = {
			'order': Traverser.Order.DEPTH_FIRST,
			'uniqueness': 'node_path'
		}

	def set_max_depth(self, max_depth):
		if 'prune_evaluator' in self._criteria:
			del self._criteria['prune_evaluator']
		self._criteria['max_depth'] = max_depth

	def set_prune_evaluator(self, language, body):
		if 'max_depth' in self._criteria:
			del self._criteria['max_depth']
		self._criteria['prune_evaluator'] = {
			'language': language,
			'body': body
		}

	def set_return_filter(self, language, name):
		self._criteria['return_filter'] = {
			'language': language,
			'name': name
		}

	def add_relationship(self, type, direction=None):
		if 'relationships' not in self._criteria:
			self._criteria['relationships'] = []
		if direction:
			self._criteria['relationships'].append({
				'type': type,
				'direction': direction
			})
		else:
			self._criteria['relationships'].append({
				'type': type
			})

	def remove_relationship(self, type):
		if 'relationships' in self._criteria:
			self._criteria['relationships'] = [item for item in self._criteria['relationships'] if item['type'] != type]
			if self._criteria['relationships'] == []:
				del self._criteria['relationships']

	def _traverse(self, order):
		self._criteria['order'] = order
		return self._post(self.uri, self._criteria)

class NodeTraverser(Traverser):

	def traverse_depth_first(self):
		return [Node(item['self'], self._http) for item in self._traverse(Traverser.Order.DEPTH_FIRST)]

	def traverse_breadth_first(self):
		return [Node(item['self'], self._http) for item in self._traverse(Traverser.Order.BREADTH_FIRST)]

<commit_msg>Added file name to top comment<commit_after>#!/usr/bin/env python

"""

py2neo - Python library for accessing Neo4j via REST interface

---

Copyright 2011 Three Steps Beyond LLP

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

	http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

---

neo4j.py

"""

import httplib2
import json

class Direction:

	BOTH     = 'all'
	INCOMING = 'incoming'
	OUTGOING = 'outgoing'

class ReturnFilter:

	ALL                = 'all'
	ALL_BUT_START_NODE = 'all_but_start_node'

class Resource:
	"""
	Web service resource class, nothing here specific to Neo4j but designed to
	work with a well-behaved hypermedia web service; used here as a base class
	for objects represented within the neo4j web service
	"""

	_read_headers = {
		'Accept': "application/json"
	}
	_write_headers = {
		'Accept': "application/json",
		'Content-Type': "application/json"
	}

	def __init__(self, uri, http=None):
		"""
		Creates a new Resource instance

		Parameters:
			uri  - the root URI for this resource
			http - optional httplib2.Http() object to use for requests

		"""
		self.uri = uri
		self._http = http or httplib2.Http()
		self._index = None

	def lookup(self, key):
		"""
		Looks up a value in the resource index by key; will lazily load
		resource index if required
		"""
		if(self._index == None):
			self._index = self._get(self.uri)
		if key in self._index:
			return self._index[key]
		else:
			return None

	def _get(self, uri):
		"""
		Issues an HTTP GET request

		Parameters:
			uri  - the URI of the resource to GET
			args - optional dictionary of URI template substitution values

		Result (dependent on HTTP status code):
			200 - returns value created from returned json content
			204 - returns None
			404 - raises a KeyError against the specified URI
			??? - raises a SystemError with the HTTP response

		"""
		response, content = self._http.request(uri, 'GET', None, self._read_headers)
		if response.status == 200:
			return json.loads(content)
		elif response.status == 204:
			return None
		elif response.status == 404:
			raise KeyError(uri)
		else:
			raise SystemError(response)

	def _post(self, uri, data):
		"""
		Issues an HTTP POST request

		Parameters:
			uri  - the URI of the resource to POST to
			data - value to be converted to json and passed in request payload
			args - optional dictionary of URI template substitution values

		Result (dependent on HTTP status code):
			200 - returns value created from returned json content
			201 - returns value from "Location" header
			400 - raises a ValueError against the specified data
			404 - raises a KeyError against the specified URI
			??? - raises a SystemError with the HTTP response

		"""
		data = {} if data == None else json.dumps(data)
		response, content = self._http.request(uri, 'POST', data, self._write_headers)
		if response.status == 200:
			return json.loads(content)
		elif response.status == 201:
			return response['location']
		elif response.status == 400:
			raise ValueError(data)
		elif response.status == 404:
			raise KeyError(uri)
		else:
			raise SystemError(response)

	def _put(self, uri, data):
		"""
		Issues an HTTP PUT request

		Parameters:
			uri  - the URI of the resource to PUT
			data - value to be converted to json and passed in request payload
			args - optional dictionary of URI template substitution values

		Result (dependent on HTTP status code):
			204 - success (no return value)
			400 - raises a ValueError against the specified data
			404 - raises a KeyError against the specified URI
			??? - raises a SystemError with the HTTP response

		"""
		data = {} if data == None else json.dumps(data)
		response, content = self._http.request(uri, 'PUT', data, self._write_headers)
		if response.status == 204:
			pass
		elif response.status == 400:
			raise ValueError(data)
		elif response.status == 404:
			raise KeyError(uri)
		else:
			raise SystemError(response)

	def _delete(self, uri):
		"""
		Issues an HTTP DELETE request

		Parameters:
			uri  - the URI of the resource to DELETE
			args - optional dictionary of URI template substitution values

		Result (dependent on HTTP status code):
			204 - success (no return value)
			404 - raises a KeyError against the specified URI
			??? - raises a SystemError with the HTTP response

		"""
		response, content = self._http.request(uri, 'DELETE', None, self._read_headers)
		if response.status == 204:
			pass
		elif response.status == 404:
			raise KeyError(uri)
		else:
			raise SystemError(response)

	def __repr__(self):
		return '%s(%s)' % (self.__class__.__name__, repr(self.uri))

class GraphDatabaseService(Resource):

	def __init__(self, uri, http=None):
		Resource.__init__(self, uri, http)

	def create_node(self, properties=None):
		return Node(self._post(self.lookup('node'), properties), self._http)

	def get_reference_node(self):
		return Node(self.lookup('reference_node'), self._http)

	def get_relationship_types(self):
		return self._get(self.lookup('relationship_types'))

	def get_node_indexes(self):
		indexes = self._get(self.lookup('node_index'))
		# replace with map()
		for i in indexes:
			index = indexes[i]
			indexes[i] = NodeIndex(index['template'], self._http)
		return indexes

	def get_relationship_indexes(self):
		indexes = self._get(self.lookup('relationship_index'))
		# replace with map()
		for i in indexes:
			index = indexes[i]
			indexes[i] = RelationshipIndex(index['template'], self._http)
		return indexes

class PropertyContainer(Resource):

	def __init__(self, uri, http=None):
		Resource.__init__(self, uri, http)

	def set_properties(self, properties):
		self._put(self.lookup('properties'), properties)

	def get_properties(self):
		return self._get(self.lookup('properties'))

	def remove_properties(self):
		self._delete(self.lookup('properties'))

	def __setitem__(self, key, value):
		self._put(self.lookup('property').format(key=key), value)

	def __getitem__(self, key):
		return self._get(self.lookup('property').format(key=key))

	def __delitem__(self, key):
		self._delete(self.lookup('property').format(key=key))

class Node(PropertyContainer):

	def __init__(self, uri, http=None):
		PropertyContainer.__init__(self, uri, http)

	def delete(self):
		self._delete(self._index['self'])

	def create_relationship_to(self, other_node, type, data=None):
		return Relationship(self._post(self.lookup('create_relationship'), {
			'to': str(other_node),
			'type': type,
			'data': data
		}), self._http)

	def get_relationships(self, direction, *types):
		if len(types) == 0:
			uri = self.lookup(direction + '_relationships')
		else:
			uri = self.lookup(direction + '_typed_relationships').replace('{-list|&|types}', '&'.join(types))
		return [Relationship(rel['self'], self._http) for rel in self._get(uri)]

	def get_related_nodes(self, direction, *types):
		if len(types) == 0:
			uri = self.lookup(direction + '_relationships')
		else:
			uri = self.lookup(direction + '_typed_relationships').replace('{-list|&|types}', '&'.join(types))
		return [Node(rel['start'] if rel['end'] == self.uri else rel['end'], self._http) for rel in self._get(uri)]

	def get_node_traverser(self):
		return NodeTraverser(self.lookup('traverse').format(returnType='node'), self._http)

class Relationship(PropertyContainer):

	def __init__(self, uri, http=None):
		PropertyContainer.__init__(self, uri, http)
		self.type = self.lookup('type')
		self.data = self.lookup('data')

	def delete(self):
		self._delete(self.lookup('self'))

	def get_start_node(self):
		return Node(self.lookup('start'), self._http)

	def get_end_node(self):
		return Node(self.lookup('end'), self._http)

class Index(Resource):

	def __init__(self, uri, http=None):
		Resource.__init__(self, uri, http)

	def _search(self, key, value):
		return self._get(self.uri.format(key=key, value=value))

	def add(self, entity, key, value):
		self._post(self.uri.format(key=key, value=value), entity.uri)

class NodeIndex(Index):

	def search(self, key, value):
		return [Node(item['self'], self._http) for item in self._search(key, value)]

class RelationshipIndex(Index):

	def search(self, key, value):
		return [Relationship(item['self'], self._http) for item in self._search(key, value)]

class Traverser(Resource):

	class Order:

		BREADTH_FIRST = 'breadth_first'
		DEPTH_FIRST   = 'depth_first'

	def __init__(self, uri, http=None):
		Resource.__init__(self, uri, http)
		self._criteria = {
			'order': Traverser.Order.DEPTH_FIRST,
			'uniqueness': 'node_path'
		}

	def set_max_depth(self, max_depth):
		if 'prune_evaluator' in self._criteria:
			del self._criteria['prune_evaluator']
		self._criteria['max_depth'] = max_depth

	def set_prune_evaluator(self, language, body):
		if 'max_depth' in self._criteria:
			del self._criteria['max_depth']
		self._criteria['prune_evaluator'] = {
			'language': language,
			'body': body
		}

	def set_return_filter(self, language, name):
		self._criteria['return_filter'] = {
			'language': language,
			'name': name
		}

	def add_relationship(self, type, direction=None):
		if 'relationships' not in self._criteria:
			self._criteria['relationships'] = []
		if direction:
			self._criteria['relationships'].append({
				'type': type,
				'direction': direction
			})
		else:
			self._criteria['relationships'].append({
				'type': type
			})

	def remove_relationship(self, type):
		if 'relationships' in self._criteria:
			self._criteria['relationships'] = [item for item in self._criteria['relationships'] if item['type'] != type]
			if self._criteria['relationships'] == []:
				del self._criteria['relationships']

	def _traverse(self, order):
		self._criteria['order'] = order
		return self._post(self.uri, self._criteria)

class NodeTraverser(Traverser):

	def traverse_depth_first(self):
		return [Node(item['self'], self._http) for item in self._traverse(Traverser.Order.DEPTH_FIRST)]

	def traverse_breadth_first(self):
		return [Node(item['self'], self._http) for item in self._traverse(Traverser.Order.BREADTH_FIRST)]

<|endoftext|>


<commit_before>#!/usr/local/bin/python
from optparse import OptionParser
from BCBio import GFF
from Bio.Seq import Seq
from Bio import SeqIO
from Bio.Alphabet import generic_dna
from Bio.SeqRecord import SeqRecord
import subprocess
import os
import sys

def lookupSequences(files):
    gtf_file = open(files['gtf_file'])
    records = []
    for rec in GFF.parse(gtf_file):
        chrom = rec.id
        for feature in rec.features:
            if feature.sub_features == []:
                seq = lookup_sequence(files, feature, chrom)
                id = feature.qualifiers['transcript_id'][0]
                strand = feature.strand

            else:
                seq = Seq("", generic_dna)
                id = feature.id
                for subf in feature.sub_features:
                    seq = seq + lookup_sequence(files, subf, chrom)
                strand = subf.strand
            if strand is -1:
                seq = seq.reverse_complement()

            records.append(SeqRecord(seq, id=id))
    SeqIO.write(records, sys.stdout, "fasta")

def lookup_sequence(files, feature, chrom):
    """
    use samtools to look up the sequence
    """
    args = [files['samtools'], "faidx", files['seq_file'], str(chrom) +
            ":" + str(int(str(feature.location.start))+1) + "-" +
            str(feature.location.end)]

    child = subprocess.Popen(args, stdout=subprocess.PIPE)
    seq = ""
    for line in child.stdout:
        if line.strip()[0] == ">":
            continue
        seq = seq + line.strip()
    seq = Seq(seq, generic_dna)

    return seq

def which(program):

    def is_exe(fpath):
        return os.path.exists(fpath) and os.access(fpath, os.X_OK)

    fpath, fname = os.path.split(program)
    if fpath:
        if is_exe(program):
            return program
    else:
        for path in os.environ["PATH"].split(os.pathsep):
            exe_file = os.path.join(path, program)
            if is_exe(exe_file):
                return exe_file

    return None

def main():
    usage = "usage: gtf2fasta seq_file gtf_file"
    parser = OptionParser()
    (options, args) = parser.parse_args()
    samtools = which("samtools")

    if samtools is None:
        print "samtools must executable, add it to your path or " \
              "download it from http://samtools.sourceforge.net/"
        exit(-1)

    files = {}
    files['samtools'] = samtools

    if len(args) != 2:
        print usage
        exit(-1)

    files['seq_file'] = args[0]
    files['gtf_file'] = args[1]

    if not os.path.exists(files['seq_file']):
        print "seq_file does not exist"
        print usage
        exit(-1)

    if not os.path.exists(files['gtf_file']):
        print "gtf_file does not exist"
        print usage
        exit(-1)

    lookupSequences(files)

if __name__ == "__main__":
    main()
<commit_msg>Remove gtf2fasta as it has been superceded by better implementations.<commit_after><|endoftext|>


<commit_before>import sys
from meta import CurrentSession

REMOVE_FROM_DO = "removeFromDO"

def remove_from_do(id):
    MINIMUM_ID_LENGTH = 5
    MAX_COLS_TO_PRINT = 50

    if len(id) < MINIMUM_ID_LENGTH:
        print("The identifier '{}' is too short (minimum {} characters)".format(id, MINIMUM_ID_LENGTH))
        return

    session = CurrentSession().get()

    numtables = session.execute(
        "SELECT count(*) FROM observatory.obs_table WHERE id LIKE '{}%'"
        .format(id)).fetchone()[0]
    print(" --> This will delete {} entries from observatory.OBS_TABLE".format(numtables))
    for table in session.execute("SELECT id FROM observatory.obs_table WHERE id LIKE '{}%'".format(id)).fetchall():
        print("\t" + table[0])

    numcols = session.execute(
        "SELECT count(*) FROM observatory.obs_column WHERE id LIKE '{}%'"
        .format(id)).fetchone()[0]
    print(" --> This will delete {} entries from observatory.OBS_COLUMNS".format(numcols))
    for column in session.execute(
            "SELECT id FROM observatory.obs_column WHERE id LIKE '{}%'".format(id)).fetchmany(MAX_COLS_TO_PRINT):
        print("\t" + column[0])
    if numcols > MAX_COLS_TO_PRINT:
        print("\t... ({} more)".format(numcols - MAX_COLS_TO_PRINT))
    print(" --> This will drop {} tables from the 'observatory' schema".format(session.execute(
        "SELECT count(*) FROM observatory.obs_table WHERE id LIKE '{}%'".format(id)).fetchone()[0]))

    yn = input("Continue? (Y/N) ")

    if yn != "Y":
        return

    for table in session.execute(
            "SELECT tablename FROM observatory.obs_table WHERE id LIKE '{}%'".format(id)).fetchall():
        session.execute("DROP TABLE observatory.{}".format(table[0]))
        print("Table {} dropped".format(table[0]))
    session.execute("DELETE FROM observatory.obs_table WHERE id LIKE '{}%'".format(id))
    print("Deleted {} entries from observatory.OBS_TABLE".format(numtables))
    session.execute("DELETE FROM observatory.obs_column WHERE id LIKE '{}%'".format(id))
    print("Deleted {} entries from observatory.OBS_COLUMNS".format(numcols))

    session.execute("COMMIT")

def print_remove_from_do_help():
    print("$python tools.py removeFromDO id_of_data_to_remove")

if __name__ == "__main__":
    if (len(sys.argv) == 1 or "?" in sys.argv[1]):
        # print all helps here
        print_remove_from_do_help()
    elif REMOVE_FROM_DO == sys.argv[1]:
        if len(sys.argv) == 3:
            remove_from_do(sys.argv[2])
        else:
            print_remove_from_do_help()
<commit_msg>Expliciting imports<commit_after>import sys
from .meta import CurrentSession

REMOVE_FROM_DO = "removeFromDO"

def remove_from_do(id):
    MINIMUM_ID_LENGTH = 5
    MAX_COLS_TO_PRINT = 50

    if len(id) < MINIMUM_ID_LENGTH:
        print("The identifier '{}' is too short (minimum {} characters)".format(id, MINIMUM_ID_LENGTH))
        return

    session = CurrentSession().get()

    numtables = session.execute(
        "SELECT count(*) FROM observatory.obs_table WHERE id LIKE '{}%'"
        .format(id)).fetchone()[0]
    print(" --> This will delete {} entries from observatory.OBS_TABLE".format(numtables))
    for table in session.execute("SELECT id FROM observatory.obs_table WHERE id LIKE '{}%'".format(id)).fetchall():
        print("\t" + table[0])

    numcols = session.execute(
        "SELECT count(*) FROM observatory.obs_column WHERE id LIKE '{}%'"
        .format(id)).fetchone()[0]
    print(" --> This will delete {} entries from observatory.OBS_COLUMNS".format(numcols))
    for column in session.execute(
            "SELECT id FROM observatory.obs_column WHERE id LIKE '{}%'".format(id)).fetchmany(MAX_COLS_TO_PRINT):
        print("\t" + column[0])
    if numcols > MAX_COLS_TO_PRINT:
        print("\t... ({} more)".format(numcols - MAX_COLS_TO_PRINT))
    print(" --> This will drop {} tables from the 'observatory' schema".format(session.execute(
        "SELECT count(*) FROM observatory.obs_table WHERE id LIKE '{}%'".format(id)).fetchone()[0]))

    yn = input("Continue? (Y/N) ")

    if yn != "Y":
        return

    for table in session.execute(
            "SELECT tablename FROM observatory.obs_table WHERE id LIKE '{}%'".format(id)).fetchall():
        session.execute("DROP TABLE observatory.{}".format(table[0]))
        print("Table {} dropped".format(table[0]))
    session.execute("DELETE FROM observatory.obs_table WHERE id LIKE '{}%'".format(id))
    print("Deleted {} entries from observatory.OBS_TABLE".format(numtables))
    session.execute("DELETE FROM observatory.obs_column WHERE id LIKE '{}%'".format(id))
    print("Deleted {} entries from observatory.OBS_COLUMNS".format(numcols))

    session.execute("COMMIT")

def print_remove_from_do_help():
    print("$python tools.py removeFromDO id_of_data_to_remove")

if __name__ == "__main__":
    if (len(sys.argv) == 1 or "?" in sys.argv[1]):
        # print all helps here
        print_remove_from_do_help()
    elif REMOVE_FROM_DO == sys.argv[1]:
        if len(sys.argv) == 3:
            remove_from_do(sys.argv[2])
        else:
            print_remove_from_do_help()
<|endoftext|>


<commit_before>__version__ = '0.4'
<commit_msg>Release 0.4.1; Upgrade to newer unofficial release of VersionOne.SDK.Python.<commit_after>__version__ = '0.4.1'
<|endoftext|>


<commit_before># pylint: disable=C0111,R0902,R0904,R0912,R0913,R0915,E1101
# Smartsheet Python SDK.
#
# Copyright 2016 Smartsheet.com, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License"): you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.

from __future__ import absolute_import

from .auto_number_format import AutoNumberFormat
from .filter import Filter
from ..types import TypedList
from ..util import prep
import json
import logging
import six

class Column(object):

    """Smartsheet Column data model."""

    def __init__(self, props=None, base_obj=None):
        """Initialize the Column model."""
        self._base = None
        if base_obj is not None:
            self._base = base_obj
        self._pre_request_filter = None
        self._log = logging.getLogger(__name__)

        self.allowed_values = {
            'symbol': [
                'STAR',
                'FLAG',
                'HARVEY_BALLS',
                'PRIORITY',
                'RYG',
                'PRIORITY_HML',
                'DECISION_SYMBOLS',
                'DECISION_SHAPES',
                'VCR',
                'RYGB',
                'RYGG',
                'WEATHER',
                'PROGRESS',
                'ARROWS_3_WAY',
                'ARROWS_4_WAY',
                'ARROWS_5_WAY',
                'DIRECTIONS_3_WAY',
                'DIRECTIONS_4_WAY',
                'SKI',
                'SIGNAL',
                'STAR_RATING',
                'HEARTS',
                'MONEY',
                'EFFORT',
                'PAIN'],
            'system_column_type': [
                'AUTO_NUMBER',
                'MODIFIED_DATE',
                'MODIFIED_BY',
                'CREATED_DATE',
                'CREATED_BY'],
            '_type': [
                'TEXT_NUMBER',
                'DATE',
                'DATETIME',
                'CONTACT_LIST',
                'CHECKBOX',
                'PICKLIST',
                'DURATION',
                'PREDECESSOR',
                'ABSTRACT_DATETIME']}

        self._auto_number_format = None
        self.__filter = None
        self.__format = None
        self._hidden = None
        self.__id = None
        self._index = None
        self._locked = None
        self._locked_for_user = None
        self._options = TypedList(str)
        self._primary = None
        self._symbol = None
        self._system_column_type = None
        self._tags = TypedList(str)
        self._title = None
        self.__type = None
        self._width = None

        if props:
            # account for alternate variable names from raw API response
            if 'autoNumberFormat' in props:
                self.auto_number_format = props[
                    'autoNumberFormat']
            if 'auto_number_format' in props:
                self.auto_number_format = props[
                    'auto_number_format']
            if 'filter' in props:
                self._filter = props['filter']
            if '_filter' in props:
                self._filter = props['_filter']
            if 'format' in props:
                self._format = props['format']
            if '_format' in props:
                self._format = props['_format']
            if 'hidden' in props:
                self.hidden = props['hidden']
            if 'id' in props:
                self._id = props['id']
            if '_id' in props:
                self._id = props['_id']
            if 'index' in props:
                self.index = props['index']
            if 'locked' in props:
                self.locked = props['locked']
            if 'lockedForUser' in props:
                self.locked_for_user = props['lockedForUser']
            if 'locked_for_user' in props:
                self.locked_for_user = props['locked_for_user']
            if 'options' in props:
                self.options = props['options']
            if 'primary' in props:
                self.primary = props['primary']
            if 'symbol' in props:
                self.symbol = props['symbol']
            if 'systemColumnType' in props:
                self.system_column_type = props[
                    'systemColumnType']
            if 'system_column_type' in props:
                self.system_column_type = props[
                    'system_column_type']
            if 'tags' in props:
                self.tags = props['tags']
            if 'title' in props:
                self.title = props['title']
            if 'type' in props:
                self._type = props['type']
            if '_type' in props:
                self._type = props['_type']
            if 'width' in props:
                self.width = props['width']
        # requests package Response object
        self.request_response = None
        self.__initialized = True

    def __getattr__(self, key):
        if key == 'filter':
            return self._filter
        elif key == 'format':
            return self._format
        elif key == 'id':
            return self._id
        elif key == 'type':
            return self._type
        else:
            raise AttributeError(key)

    @property
    def auto_number_format(self):
        return self._auto_number_format

    @auto_number_format.setter
    def auto_number_format(self, value):
        if isinstance(value, AutoNumberFormat):
            self._auto_number_format = value
        else:
            self._auto_number_format = AutoNumberFormat(value, self._base)

    @property
    def _filter(self):
        return self.__filter

    @_filter.setter
    def _filter(self, value):
        if isinstance(value, Filter):
            self.__filter = value
        else:
            self.__filter = Filter(value, self._base)

    @property
    def _format(self):
        return self.__format

    @_format.setter
    def _format(self, value):
        if isinstance(value, six.string_types):
            self.__format = value

    @property
    def hidden(self):
        return self._hidden

    @hidden.setter
    def hidden(self, value):
        if isinstance(value, bool):
            self._hidden = value

    @property
    def _id(self):
        return self.__id

    @_id.setter
    def _id(self, value):
        if isinstance(value, six.integer_types):
            self.__id = value

    @property
    def index(self):
        return self._index

    @index.setter
    def index(self, value):
        if isinstance(value, six.integer_types):
            self._index = value

    @property
    def locked(self):
        return self._locked

    @locked.setter
    def locked(self, value):
        if isinstance(value, bool):
            self._locked = value

    @property
    def locked_for_user(self):
        return self._locked_for_user

    @locked_for_user.setter
    def locked_for_user(self, value):
        if isinstance(value, bool):
            self._locked_for_user = value

    @property
    def options(self):
        return self._options

    @options.setter
    def options(self, value):
        if isinstance(value, list):
            self._options.purge()
            self._options.extend([
                (str(x)
                 if not isinstance(x, str) else x) for x in value
            ])
        elif isinstance(value, TypedList):
            self._options.purge()
            self._options = value.to_list()
        elif isinstance(value, str):
            self._options.purge()
            self._options.append(value)

    @property
    def primary(self):
        return self._primary

    @primary.setter
    def primary(self, value):
        if isinstance(value, bool):
            self._primary = value

    @property
    def symbol(self):
        return self._symbol

    @symbol.setter
    def symbol(self, value):
        if isinstance(value, six.string_types):
            if value not in self.allowed_values['symbol']:
                raise ValueError(
                    ("`{0}` is an invalid value for Column`symbol`,"
                     " must be one of {1}").format(
                         value, self.allowed_values['symbol']))
            self._symbol = value

    @property
    def system_column_type(self):
        return self._system_column_type

    @system_column_type.setter
    def system_column_type(self, value):
        if isinstance(value, six.string_types):
            if value not in self.allowed_values['system_column_type']:
                raise ValueError(
                    ("`{0}` is an invalid value for Column`system_column_type`,"
                     " must be one of {1}").format(
                         value, self.allowed_values['system_column_type']))
            self._system_column_type = value

    @property
    def tags(self):
        return self._tags

    @tags.setter
    def tags(self, value):
        if isinstance(value, list):
            self._tags.purge()
            self._tags.extend([
                (str(x)
                 if not isinstance(x, str) else x) for x in value
            ])
        elif isinstance(value, TypedList):
            self._tags.purge()
            self._tags = value.to_list()
        elif isinstance(value, str):
            self._tags.purge()
            self._tags.append(value)

    @property
    def title(self):
        return self._title

    @title.setter
    def title(self, value):
        if isinstance(value, six.string_types):
            self._title = value

    @property
    def _type(self):
        return self.__type

    @_type.setter
    def _type(self, value):
        if isinstance(value, six.string_types):
            if value not in self.allowed_values['_type']:
                raise ValueError(
                    ("`{0}` is an invalid value for Column`_type`,"
                     " must be one of {1}").format(
                         value, self.allowed_values['_type']))
            self.__type = value

    @property
    def width(self):
        return self._width

    @width.setter
    def width(self, value):
        if isinstance(value, six.integer_types):
            self._width = value

    @property
    def pre_request_filter(self):
        return self._pre_request_filter

    @pre_request_filter.setter
    def pre_request_filter(self, value):
        if self.auto_number_format is not None:
            self.auto_number_format.pre_request_filter = value
        if self._filter is not None:
            self._filter.pre_request_filter = value
        self._pre_request_filter = value

    def to_dict(self, op_id=None, method=None):
        req_filter = self.pre_request_filter
        if req_filter:
            if self.auto_number_format is not None:
                self.auto_number_format.pre_request_filter = req_filter
            if self._filter is not None:
                self._filter.pre_request_filter = req_filter

        obj = {
            'autoNumberFormat': prep(self._auto_number_format),
            'filter': prep(self.__filter),
            'format': prep(self.__format),
            'hidden': prep(self._hidden),
            'id': prep(self.__id),
            'index': prep(self._index),
            'locked': prep(self._locked),
            'lockedForUser': prep(self._locked_for_user),
            'options': prep(self._options),
            'primary': prep(self._primary),
            'symbol': prep(self._symbol),
            'systemColumnType': prep(self._system_column_type),
            'tags': prep(self._tags),
            'title': prep(self._title),
            'type': prep(self.__type),
            'width': prep(self._width)}
        return self._apply_pre_request_filter(obj)

    def _apply_pre_request_filter(self, obj):
        if self.pre_request_filter == 'add_columns':
            permitted = ['title', 'type', 'symbol',
                         'options', 'index', 'systemColumnType', 'autoNumberFormat',
                         'width', 'locked']
            all_keys = list(obj.keys())
            for key in all_keys:
                if key not in permitted:
                    self._log.debug(
                        'deleting %s from obj (filter: %s)',
                        key, self.pre_request_filter)
                    del obj[key]

        if self.pre_request_filter == 'create_sheet':
            permitted = ['title', 'primary', 'type',
                         'symbol', 'options', 'systemColumnType', 'autoNumberFormat',
                         'width']
            all_keys = list(obj.keys())
            for key in all_keys:
                if key not in permitted:
                    self._log.debug(
                        'deleting %s from obj (filter: %s)',
                        key, self.pre_request_filter)
                    del obj[key]

        if self.pre_request_filter == 'create_sheet_in_folder':
            permitted = ['title', 'primary', 'type',
                         'symbol', 'options', 'systemColumnType', 'autoNumberFormat',
                         'width']
            all_keys = list(obj.keys())
            for key in all_keys:
                if key not in permitted:
                    self._log.debug(
                        'deleting %s from obj (filter: %s)',
                        key, self.pre_request_filter)
                    del obj[key]

        if self.pre_request_filter == 'create_sheet_in_workspace':
            permitted = ['title', 'primary', 'type',
                         'symbol', 'options', 'systemColumnType', 'autoNumberFormat',
                         'width']
            all_keys = list(obj.keys())
            for key in all_keys:
                if key not in permitted:
                    self._log.debug(
                        'deleting %s from obj (filter: %s)',
                        key, self.pre_request_filter)
                    del obj[key]

        if self.pre_request_filter == 'update_column':
            permitted = ['index', 'title', 'type', 'symbol',
                         'options', 'systemColumnType', 'autoNumberFormat', 'width',
                         'locked']
            all_keys = list(obj.keys())
            for key in all_keys:
                if key not in permitted:
                    self._log.debug(
                        'deleting %s from obj (filter: %s)',
                        key, self.pre_request_filter)
                    del obj[key]

            if self.type != 'PICKLIST':
                del obj['options']

        return obj

    def to_json(self):
        return json.dumps(self.to_dict(), indent=2)

    def __str__(self):
        return json.dumps(self.to_dict())
<commit_msg>API 2.0.17 updates<commit_after># pylint: disable=C0111,R0902,R0904,R0912,R0913,R0915,E1101
# Smartsheet Python SDK.
#
# Copyright 2016 Smartsheet.com, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License"): you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.

from __future__ import absolute_import

from .auto_number_format import AutoNumberFormat
from .filter import Filter
from .contact import Contact
from ..types import TypedList
from ..util import prep
import json
import logging
import six

class Column(object):

    """Smartsheet Column data model."""

    def __init__(self, props=None, base_obj=None):
        """Initialize the Column model."""
        self._base = None
        if base_obj is not None:
            self._base = base_obj
        self._pre_request_filter = None
        self._log = logging.getLogger(__name__)

        self.allowed_values = {
            'symbol': [
                'STAR',
                'FLAG',
                'HARVEY_BALLS',
                'PRIORITY',
                'RYG',
                'PRIORITY_HML',
                'DECISION_SYMBOLS',
                'DECISION_SHAPES',
                'VCR',
                'RYGB',
                'RYGG',
                'WEATHER',
                'PROGRESS',
                'ARROWS_3_WAY',
                'ARROWS_4_WAY',
                'ARROWS_5_WAY',
                'DIRECTIONS_3_WAY',
                'DIRECTIONS_4_WAY',
                'SKI',
                'SIGNAL',
                'STAR_RATING',
                'HEARTS',
                'MONEY',
                'EFFORT',
                'PAIN'],
            'system_column_type': [
                'AUTO_NUMBER',
                'MODIFIED_DATE',
                'MODIFIED_BY',
                'CREATED_DATE',
                'CREATED_BY'],
            '_type': [
                'TEXT_NUMBER',
                'DATE',
                'DATETIME',
                'CONTACT_LIST',
                'CHECKBOX',
                'PICKLIST',
                'DURATION',
                'PREDECESSOR',
                'ABSTRACT_DATETIME']}

        self._auto_number_format = None
        self._contact_options = TypedList(Contact)
        self.__filter = None
        self.__format = None
        self._hidden = None
        self.__id = None
        self._index = None
        self._locked = None
        self._locked_for_user = None
        self._options = TypedList(str)
        self._primary = None
        self._symbol = None
        self._system_column_type = None
        self._tags = TypedList(str)
        self._title = None
        self.__type = None
        self._width = None

        if props:
            # account for alternate variable names from raw API response
            if 'autoNumberFormat' in props:
                self.auto_number_format = props[
                    'autoNumberFormat']
            if 'auto_number_format' in props:
                self.auto_number_format = props[
                    'auto_number_format']
            if 'contactOptions' in props:
                self.contact_options = props['contactOptions']
            if 'contact_options' in props:
                self.contact_options = props['contact_options']
            if 'filter' in props:
                self._filter = props['filter']
            if '_filter' in props:
                self._filter = props['_filter']
            if 'format' in props:
                self._format = props['format']
            if '_format' in props:
                self._format = props['_format']
            if 'hidden' in props:
                self.hidden = props['hidden']
            if 'id' in props:
                self._id = props['id']
            if '_id' in props:
                self._id = props['_id']
            if 'index' in props:
                self.index = props['index']
            if 'locked' in props:
                self.locked = props['locked']
            if 'lockedForUser' in props:
                self.locked_for_user = props['lockedForUser']
            if 'locked_for_user' in props:
                self.locked_for_user = props['locked_for_user']
            if 'options' in props:
                self.options = props['options']
            if 'primary' in props:
                self.primary = props['primary']
            if 'symbol' in props:
                self.symbol = props['symbol']
            if 'systemColumnType' in props:
                self.system_column_type = props[
                    'systemColumnType']
            if 'system_column_type' in props:
                self.system_column_type = props[
                    'system_column_type']
            if 'tags' in props:
                self.tags = props['tags']
            if 'title' in props:
                self.title = props['title']
            if 'type' in props:
                self._type = props['type']
            if '_type' in props:
                self._type = props['_type']
            if 'width' in props:
                self.width = props['width']
        # requests package Response object
        self.request_response = None
        self.__initialized = True

    def __getattr__(self, key):
        if key == 'filter':
            return self._filter
        elif key == 'format':
            return self._format
        elif key == 'id':
            return self._id
        elif key == 'type':
            return self._type
        else:
            raise AttributeError(key)

    @property
    def auto_number_format(self):
        return self._auto_number_format

    @auto_number_format.setter
    def auto_number_format(self, value):
        if isinstance(value, AutoNumberFormat):
            self._auto_number_format = value
        else:
            self._auto_number_format = AutoNumberFormat(value, self._base)

    @property
    def contact_options(self):
        return self._contact_options

    @contact_options.setter
    def contact_options(self, value):
        if isinstance(value, list):
            self._contact_options.purge()
            self._contact_options.extend([
                (Contact(x)
                 if not isinstance(x, Contact) else x) for x in value
            ])
        elif isinstance(value, TypedList):
            self._contact_options.purge()
            self._contact_options = value.to_list()
        elif isinstance(value, Contact):
            self._contact_options.purge()
            self._contact_options.append(value)

    @property
    def _filter(self):
        return self.__filter

    @_filter.setter
    def _filter(self, value):
        if isinstance(value, Filter):
            self.__filter = value
        else:
            self.__filter = Filter(value, self._base)

    @property
    def _format(self):
        return self.__format

    @_format.setter
    def _format(self, value):
        if isinstance(value, six.string_types):
            self.__format = value

    @property
    def hidden(self):
        return self._hidden

    @hidden.setter
    def hidden(self, value):
        if isinstance(value, bool):
            self._hidden = value

    @property
    def _id(self):
        return self.__id

    @_id.setter
    def _id(self, value):
        if isinstance(value, six.integer_types):
            self.__id = value

    @property
    def index(self):
        return self._index

    @index.setter
    def index(self, value):
        if isinstance(value, six.integer_types):
            self._index = value

    @property
    def locked(self):
        return self._locked

    @locked.setter
    def locked(self, value):
        if isinstance(value, bool):
            self._locked = value

    @property
    def locked_for_user(self):
        return self._locked_for_user

    @locked_for_user.setter
    def locked_for_user(self, value):
        if isinstance(value, bool):
            self._locked_for_user = value

    @property
    def options(self):
        return self._options

    @options.setter
    def options(self, value):
        if isinstance(value, list):
            self._options.purge()
            self._options.extend([
                (str(x)
                 if not isinstance(x, str) else x) for x in value
            ])
        elif isinstance(value, TypedList):
            self._options.purge()
            self._options = value.to_list()
        elif isinstance(value, str):
            self._options.purge()
            self._options.append(value)

    @property
    def primary(self):
        return self._primary

    @primary.setter
    def primary(self, value):
        if isinstance(value, bool):
            self._primary = value

    @property
    def symbol(self):
        return self._symbol

    @symbol.setter
    def symbol(self, value):
        if isinstance(value, six.string_types):
            if value not in self.allowed_values['symbol']:
                raise ValueError(
                    ("`{0}` is an invalid value for Column`symbol`,"
                     " must be one of {1}").format(
                         value, self.allowed_values['symbol']))
            self._symbol = value

    @property
    def system_column_type(self):
        return self._system_column_type

    @system_column_type.setter
    def system_column_type(self, value):
        if isinstance(value, six.string_types):
            if value not in self.allowed_values['system_column_type']:
                raise ValueError(
                    ("`{0}` is an invalid value for Column`system_column_type`,"
                     " must be one of {1}").format(
                         value, self.allowed_values['system_column_type']))
            self._system_column_type = value

    @property
    def tags(self):
        return self._tags

    @tags.setter
    def tags(self, value):
        if isinstance(value, list):
            self._tags.purge()
            self._tags.extend([
                (str(x)
                 if not isinstance(x, str) else x) for x in value
            ])
        elif isinstance(value, TypedList):
            self._tags.purge()
            self._tags = value.to_list()
        elif isinstance(value, str):
            self._tags.purge()
            self._tags.append(value)

    @property
    def title(self):
        return self._title

    @title.setter
    def title(self, value):
        if isinstance(value, six.string_types):
            self._title = value

    @property
    def _type(self):
        return self.__type

    @_type.setter
    def _type(self, value):
        if isinstance(value, six.string_types):
            if value not in self.allowed_values['_type']:
                raise ValueError(
                    ("`{0}` is an invalid value for Column`_type`,"
                     " must be one of {1}").format(
                         value, self.allowed_values['_type']))
            self.__type = value

    @property
    def width(self):
        return self._width

    @width.setter
    def width(self, value):
        if isinstance(value, six.integer_types):
            self._width = value

    @property
    def pre_request_filter(self):
        return self._pre_request_filter

    @pre_request_filter.setter
    def pre_request_filter(self, value):
        if self.auto_number_format is not None:
            self.auto_number_format.pre_request_filter = value
        if self._filter is not None:
            self._filter.pre_request_filter = value
        self._pre_request_filter = value

    def to_dict(self, op_id=None, method=None):
        req_filter = self.pre_request_filter
        if req_filter:
            if self.auto_number_format is not None:
                self.auto_number_format.pre_request_filter = req_filter
            if self._filter is not None:
                self._filter.pre_request_filter = req_filter

        obj = {
            'autoNumberFormat': prep(self._auto_number_format),
            'contactOptions': prep(self._contact_options),
            'filter': prep(self.__filter),
            'format': prep(self.__format),
            'hidden': prep(self._hidden),
            'id': prep(self.__id),
            'index': prep(self._index),
            'locked': prep(self._locked),
            'lockedForUser': prep(self._locked_for_user),
            'options': prep(self._options),
            'primary': prep(self._primary),
            'symbol': prep(self._symbol),
            'systemColumnType': prep(self._system_column_type),
            'tags': prep(self._tags),
            'title': prep(self._title),
            'type': prep(self.__type),
            'width': prep(self._width)}
        return self._apply_pre_request_filter(obj)

    def _apply_pre_request_filter(self, obj):
        if self.pre_request_filter == 'add_columns':
            permitted = ['title', 'type', 'symbol',
                         'options', 'index', 'systemColumnType', 'autoNumberFormat',
                         'width', 'locked', 'contactOptions']
            all_keys = list(obj.keys())
            for key in all_keys:
                if key not in permitted:
                    self._log.debug(
                        'deleting %s from obj (filter: %s)',
                        key, self.pre_request_filter)
                    del obj[key]

        if self.pre_request_filter == 'create_sheet':
            permitted = ['title', 'primary', 'type',
                         'symbol', 'options', 'systemColumnType', 'autoNumberFormat',
                         'width']
            all_keys = list(obj.keys())
            for key in all_keys:
                if key not in permitted:
                    self._log.debug(
                        'deleting %s from obj (filter: %s)',
                        key, self.pre_request_filter)
                    del obj[key]

        if self.pre_request_filter == 'create_sheet_in_folder':
            permitted = ['title', 'primary', 'type',
                         'symbol', 'options', 'systemColumnType', 'autoNumberFormat',
                         'width']
            all_keys = list(obj.keys())
            for key in all_keys:
                if key not in permitted:
                    self._log.debug(
                        'deleting %s from obj (filter: %s)',
                        key, self.pre_request_filter)
                    del obj[key]

        if self.pre_request_filter == 'create_sheet_in_workspace':
            permitted = ['title', 'primary', 'type',
                         'symbol', 'options', 'systemColumnType', 'autoNumberFormat',
                         'width']
            all_keys = list(obj.keys())
            for key in all_keys:
                if key not in permitted:
                    self._log.debug(
                        'deleting %s from obj (filter: %s)',
                        key, self.pre_request_filter)
                    del obj[key]

        if self.pre_request_filter == 'update_column':
            permitted = ['index', 'title', 'type', 'symbol',
                         'options', 'systemColumnType', 'autoNumberFormat', 'width',
                         'locked', 'contactOptions']
            all_keys = list(obj.keys())
            for key in all_keys:
                if key not in permitted:
                    self._log.debug(
                        'deleting %s from obj (filter: %s)',
                        key, self.pre_request_filter)
                    del obj[key]

            if self.type != 'PICKLIST':
                del obj['options']

        return obj

    def to_json(self):
        return json.dumps(self.to_dict(), indent=2)

    def __str__(self):
        return json.dumps(self.to_dict())
<|endoftext|>