<commit_before>import requests
import re
import os
base = os.path.join(os.path.dirname(os.path.realpath(__file__)), '../../')

def parse_txt_files(txt_files=None):
    import re
    import os
    if not txt_files:
        txt_files = sorted([f for f in os.listdir(base+'.crawler_data/seattle_police_internal_affairs_closed_cases/txts')])
    opa_files = []
    for filename in txt_files:
    #for filename in files:
        f = open('txts/'+filename, 'r')

        opa_file = str(f.read()).replace('\n', ' ').replace('  ', ' ')
        if not opa_file:
            continue
        print opa_file
        opa_file_dict = {}
        regex =  re.search('Complaint Number(?P<num>.*?)Issued', opa_file)

        opa_file_dict['Complaint number'] = regex.group('num').strip(' :').replace(' ', '') if regex else filename[:filename.find('ccs')]
        regex = re.search('Issued Date(?P<date>.*?)Named', opa_file)
        opa_file_dict['Issued date'] = regex.group('date').strip(' :') if regex else None
        regex = re.search('lssued Date(?P<date>.*?)Named', opa_file)
        if regex:
            opa_file_dict['Issued date'] = regex.group('date').strip(' :')

        regex = re.search('OPA Finding(?P<findings>.*?)Final', opa_file)
        opa_file_dict['OPA finding'] = regex.group('findings').strip(' :') if regex else None

        regex = re.search('FINDINGS(?P<findings>.*?)NOTE', opa_file,  re.MULTILINE|re.DOTALL)
        if regex:
            opa_file_dict['Findings'] = regex.group('findings').strip(' :\n').replace('\n', '')
        regex = re.search('Final Discipline\s*(?P<discipline>.*?)INCIDENT', opa_file)
        opa_file_dict['Final discipline'] = regex.group('discipline').strip(' :') if regex else None
        regex = re.search('INCIDENT SYNOPSIS(?P<synopsis>.*?)(Complaint|COMPLAINT)', opa_file,  re.MULTILINE|re.DOTALL)
        opa_file_dict['Incident synopsis'] = regex.group('synopsis').strip(' :\n').replace('\n', '') if regex else None
        regex = re.search('COMPLAINT(?P<complaint>.*?)(Complaint|INVESTIGATION)', opa_file,  re.MULTILINE|re.DOTALL)
        opa_file_dict['Complaint'] = regex.group('complaint').strip(' :\n').replace('\n', '') if regex else None
        regex = re.search('INVESTIGATION(?P<investigation>.*?)(Complaint|ANALYSIS)', opa_file,  re.MULTILINE|re.DOTALL)
        opa_file_dict['Investigation'] = regex.group('investigation').strip(' :\n').replace('\n', '') if regex else None
        regex = re.search('ANALYSIS AND CONCLUSION(?P<analysis>.*?)(Complaint|FINDINGS)', opa_file,  re.MULTILINE|re.DOTALL)
        opa_file_dict['Analysis and conclusion'] = regex.group('analysis').strip(' :\n').replace('\n', '') if regex else None
        opa_file_dict['txt'] = filename
        opa_file_dict['pdf'] = filename[:-4]+'.pdf'
        try:
            # Get the entire findings section
            f = open('txts/'+filename, 'r')

            opa_file2 = f.read()
            import re
            m = re.search('Issued(.*?)Complaint', opa_file2,  re.MULTILINE|re.DOTALL)
            if m:
                section = m.group()
                lines = section.split('\n')[3:-3]
                structured_version = []
                current = None
                opa_file_dict['is_sustained'] = False
                for i, line in enumerate(lines):
                    if line.startswith('Named Employee'):
                        if current:
                            structured_version.append(current)
                        current = {'heading': line.strip(), 'allegations': []}
                    if line.startswith('Allegation'):
                        allegation_structure = {'heading': line.strip()}
                        allegation_structure['allegation'] = lines[i+2].strip()
                        j = 0
                        while True:
                            j += 1
                            the_line = lines[i + 2 + j]
                            if not the_line:
                                break
                            allegation_structure['allegation'] += ' '+the_line.strip()

                        current['allegations'].append(allegation_structure)
                    if line.startswith('OPA Finding'):
                        current['allegations'][-1]['opa_finding'] = lines[i+2].strip()
                        if current['allegations'][-1]['opa_finding'] == 'Sustained':
                            opa_file_dict['is_sustained'] = True
                    if line.startswith('Final Discipline'):
                        current['final_discipline'] = lines[i+2].strip()
                structured_version.append(current)
            opa_file_dict['Summarized results'] = structured_version
        except Exception, e:
            opa_file_dict['parsing_error'] = e
        opa_files.append(opa_file_dict)
        f.close()
    import sys

    reload(sys)
    sys.setdefaultencoding('utf8')
    print opa_files
    import rethinkdb as r
    conn = r.connect( "localhost", 28015).repl()
    db = r.db('opa')
    try:
        db.table_create('closed_case_summaries', primary_key='Complaint number').run(conn)
    except:
        pass
    try:
        db.table_create('closed_case_summaries_subscribers', primary_key='email').run(conn)
    except:
        pass
    db.table('closed_case_summaries').insert(opa_files, conflict='update').run(conn)
    the_html = '
'
    columns = ['Issued date', 'Complaint number', 'Complaint', 'Incident synopsis', 'Investigation', 'Analysis and conclusion', 'OPA finding', 'Final discipline']
    from dateutil.parser import parse
    import datetime
    mindate = datetime.date(datetime.MINYEAR, 1, 1)
    opa_files = sorted(opa_files, key=lambda x: parse(x['Issued date']).date() if '/' in x['Issued date'] else mindate, reverse=True)

def download():
    os.system('mkdir %s.crawler_data' % (base))
    os.system('mkdir %s.crawler_data/seattle_police_internal_affairs_closed_cases/' % (base))
    os.system('mkdir %s.crawler_data/seattle_police_internal_affairs_closed_cases/pdfs/' % (base))
    os.system('mkdir %s.crawler_data/seattle_police_internal_affairs_closed_cases/txts/' % (base))
    html = requests.get('http://www.seattle.gov/opa/closed-case-summaries').text
    os.system('mkdir pdfs')
    files = re.findall('ClosedCaseSummaries/(?P<filename>.*?)\.pdf', html)
    print files
    for f in files:
        if not f+'.pdf' in os.listdir(base+'seattle_police_internal_affairs_closed_cases/pdfs'):
            os.system('wget -O /home/ubuntu/redactvideodotorg/opa_closed_case_summaries/pdfs/%s.pdf http://www.seattle.gov/Documents/Departments/OPA/ClosedCaseSummaries/%s.pdf' % (f, f))
    import os
    #os.system('rm /home/ubuntu/redactvideodotorg/opa_closed_case_summaries/txts/*')
    os.system('mkdir /home/ubuntu/redactvideodotorg/opa_closed_case_summaries/txts')
    files = sorted([f for f in os.listdir('/home/ubuntu/redactvideodotorg/opa_closed_case_summaries/pdfs')])
    new_files = []
    for filename in files:
        print filename
        #os.system('pdf2txt.py pdfs/%s > txts/%s' % (filename, filename[:-4]+'.txt'))
        if not filename[:-4]+'.txt' in os.listdir('/home/ubuntu/redactvideodotorg/opa_closed_case_summaries/txts'):
            print 'converting'
            os.system('pdf2txt.py -A /home/ubuntu/redactvideodotorg/opa_closed_case_summaries/pdfs/%s > /home/ubuntu/redactvideodotorg/opa_closed_case_summaries/txts/%s' % (filename, filename[:-4]+'.txt'))
            new_files.append(filename[:-4]+'.txt')
    parse_txt_files(new_files)

if __name__ == "__main__":
    download()
<commit_msg>auto commit<commit_after>import requests
import re
import os
base = os.path.join(os.path.dirname(os.path.realpath(__file__)), '../../')

def parse_txt_files(txt_files=None):
    import re
    import os
    if not txt_files:
        txt_files = sorted([f for f in os.listdir(base+'.crawler_data/seattle_police_internal_affairs_closed_cases/txts')])
    opa_files = []
    for filename in txt_files:
    #for filename in files:
        f = open('txts/'+filename, 'r')

        opa_file = str(f.read()).replace('\n', ' ').replace('  ', ' ')
        if not opa_file:
            continue
        print opa_file
        opa_file_dict = {}
        regex =  re.search('Complaint Number(?P<num>.*?)Issued', opa_file)

        opa_file_dict['Complaint number'] = regex.group('num').strip(' :').replace(' ', '') if regex else filename[:filename.find('ccs')]
        regex = re.search('Issued Date(?P<date>.*?)Named', opa_file)
        opa_file_dict['Issued date'] = regex.group('date').strip(' :') if regex else None
        regex = re.search('lssued Date(?P<date>.*?)Named', opa_file)
        if regex:
            opa_file_dict['Issued date'] = regex.group('date').strip(' :')

        regex = re.search('OPA Finding(?P<findings>.*?)Final', opa_file)
        opa_file_dict['OPA finding'] = regex.group('findings').strip(' :') if regex else None

        regex = re.search('FINDINGS(?P<findings>.*?)NOTE', opa_file,  re.MULTILINE|re.DOTALL)
        if regex:
            opa_file_dict['Findings'] = regex.group('findings').strip(' :\n').replace('\n', '')
        regex = re.search('Final Discipline\s*(?P<discipline>.*?)INCIDENT', opa_file)
        opa_file_dict['Final discipline'] = regex.group('discipline').strip(' :') if regex else None
        regex = re.search('INCIDENT SYNOPSIS(?P<synopsis>.*?)(Complaint|COMPLAINT)', opa_file,  re.MULTILINE|re.DOTALL)
        opa_file_dict['Incident synopsis'] = regex.group('synopsis').strip(' :\n').replace('\n', '') if regex else None
        regex = re.search('COMPLAINT(?P<complaint>.*?)(Complaint|INVESTIGATION)', opa_file,  re.MULTILINE|re.DOTALL)
        opa_file_dict['Complaint'] = regex.group('complaint').strip(' :\n').replace('\n', '') if regex else None
        regex = re.search('INVESTIGATION(?P<investigation>.*?)(Complaint|ANALYSIS)', opa_file,  re.MULTILINE|re.DOTALL)
        opa_file_dict['Investigation'] = regex.group('investigation').strip(' :\n').replace('\n', '') if regex else None
        regex = re.search('ANALYSIS AND CONCLUSION(?P<analysis>.*?)(Complaint|FINDINGS)', opa_file,  re.MULTILINE|re.DOTALL)
        opa_file_dict['Analysis and conclusion'] = regex.group('analysis').strip(' :\n').replace('\n', '') if regex else None
        opa_file_dict['txt'] = filename
        opa_file_dict['pdf'] = filename[:-4]+'.pdf'
        try:
            # Get the entire findings section
            f = open('txts/'+filename, 'r')

            opa_file2 = f.read()
            import re
            m = re.search('Issued(.*?)Complaint', opa_file2,  re.MULTILINE|re.DOTALL)
            if m:
                section = m.group()
                lines = section.split('\n')[3:-3]
                structured_version = []
                current = None
                opa_file_dict['is_sustained'] = False
                for i, line in enumerate(lines):
                    if line.startswith('Named Employee'):
                        if current:
                            structured_version.append(current)
                        current = {'heading': line.strip(), 'allegations': []}
                    if line.startswith('Allegation'):
                        allegation_structure = {'heading': line.strip()}
                        allegation_structure['allegation'] = lines[i+2].strip()
                        j = 0
                        while True:
                            j += 1
                            the_line = lines[i + 2 + j]
                            if not the_line:
                                break
                            allegation_structure['allegation'] += ' '+the_line.strip()

                        current['allegations'].append(allegation_structure)
                    if line.startswith('OPA Finding'):
                        current['allegations'][-1]['opa_finding'] = lines[i+2].strip()
                        if current['allegations'][-1]['opa_finding'] == 'Sustained':
                            opa_file_dict['is_sustained'] = True
                    if line.startswith('Final Discipline'):
                        current['final_discipline'] = lines[i+2].strip()
                structured_version.append(current)
            opa_file_dict['Summarized results'] = structured_version
        except Exception, e:
            opa_file_dict['parsing_error'] = e
        opa_files.append(opa_file_dict)
        f.close()
    import sys

    reload(sys)
    sys.setdefaultencoding('utf8')
    print opa_files
    import rethinkdb as r
    conn = r.connect( "localhost", 28015).repl()
    db = r.db('public')

    db.table('closed_case_summaries').insert(opa_files, conflict='update').run(conn)
    the_html = '
'
    columns = ['Issued date', 'Complaint number', 'Complaint', 'Incident synopsis', 'Investigation', 'Analysis and conclusion', 'OPA finding', 'Final discipline']
    from dateutil.parser import parse
    import datetime
    mindate = datetime.date(datetime.MINYEAR, 1, 1)
    opa_files = sorted(opa_files, key=lambda x: parse(x['Issued date']).date() if '/' in x['Issued date'] else mindate, reverse=True)

def download():
    os.system('mkdir %s.crawler_data' % (base))
    os.system('mkdir %s.crawler_data/seattle_police_internal_affairs_closed_cases/' % (base))
    os.system('mkdir %s.crawler_data/seattle_police_internal_affairs_closed_cases/pdfs/' % (base))
    os.system('mkdir %s.crawler_data/seattle_police_internal_affairs_closed_cases/txts/' % (base))
    html = requests.get('http://www.seattle.gov/opa/closed-case-summaries').text
    os.system('mkdir pdfs')
    files = re.findall('ClosedCaseSummaries/(?P<filename>.*?)\.pdf', html)
    print files
    for f in files:
        if not f+'.pdf' in os.listdir(base+'seattle_police_internal_affairs_closed_cases/pdfs'):
            os.system('wget -O /home/ubuntu/redactvideodotorg/opa_closed_case_summaries/pdfs/%s.pdf http://www.seattle.gov/Documents/Departments/OPA/ClosedCaseSummaries/%s.pdf' % (f, f))
    import os
    #os.system('rm /home/ubuntu/redactvideodotorg/opa_closed_case_summaries/txts/*')
    os.system('mkdir /home/ubuntu/redactvideodotorg/opa_closed_case_summaries/txts')
    files = sorted([f for f in os.listdir('/home/ubuntu/redactvideodotorg/opa_closed_case_summaries/pdfs')])
    new_files = []
    for filename in files:
        print filename
        #os.system('pdf2txt.py pdfs/%s > txts/%s' % (filename, filename[:-4]+'.txt'))
        if not filename[:-4]+'.txt' in os.listdir('/home/ubuntu/redactvideodotorg/opa_closed_case_summaries/txts'):
            print 'converting'
            os.system('pdf2txt.py -A /home/ubuntu/redactvideodotorg/opa_closed_case_summaries/pdfs/%s > /home/ubuntu/redactvideodotorg/opa_closed_case_summaries/txts/%s' % (filename, filename[:-4]+'.txt'))
            new_files.append(filename[:-4]+'.txt')
    parse_txt_files(new_files)

if __name__ == "__main__":
    download()
<|endoftext|>


<commit_before>#!/usr/bin/env python2.5
#
# Copyright 2008 the Melange authors.
#
# 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.

"""Generic cleaning methods.
"""

import re

from HTMLParser import HTMLParseError

from html5lib import HTMLParser
from html5lib import sanitizer
from html5lib.html5parser import ParseError

from google.appengine.api import users

from django import forms
from django.core import validators
from django.utils.translation import ugettext

from soc.models.user import User
from soc.logic import validate
from soc.logic import user

DEF_VALID_SHIPPING_CHARS = re.compile('^[A-Za-z0-9\s-]+$')

DEF_LINK_ID_IN_USE = ugettext(
    'This link ID is already in use, please specify another one')

DEF_NO_RIGHTS_FOR_ACL = ugettext(
    'You do not have the required rights for that ACL.')

DEF_ORGANZIATION_NOT_ACTIVE = ugettext(
    "This organization is not active or doesn't exist.")

DEF_NO_SUCH_DOCUMENT = ugettext(
    "There is no such document with that link ID under this entity.")

DEF_MUST_BE_ABOVE_AGE_LIMIT = ugettext(
    "To sign up as a student for this program, you "
    "must be at least %d years of age, as of %s.")

DEF_MUST_BE_ABOVE_LIMIT = ugettext(
    "Must be at least %d characters, it has %d characters.")

DEF_MUST_BE_UNDER_LIMIT = ugettext(
    "Must be under %d characters, it has %d characters.")

DEF_2_LETTER_STATE = ugettext(
    "State should be 2-letter field since country is '%s'.")

DEF_INVALID_SHIPPING_CHARS = ugettext(
    'Invalid characters, only A-z, 0-9, - and whitespace are allowed. '
    'See also '
    'Issue 903, in particular comment 16. '
    'Please do not create a new issue about this.')

DEF_ROLE_TARGET_COUNTRY = "United States"

DEF_ROLE_COUNTRY_PAIRS = [("res_country", "res_state"),
                          ("ship_country", "ship_state")]

def check_field_is_empty(field_name):
  """Returns decorator that bypasses cleaning for empty fields.
  """

  def decorator(fun):
    """Decorator that checks if a field is empty if so doesn't do the cleaning.

    Note Django will capture errors concerning required fields that are empty.
    """
    from functools import wraps

    @wraps(fun)
    def wrapper(self):
      """Decorator wrapper method.
      """
      field_content = self.cleaned_data.get(field_name)

      if not field_content:
        # field has no content so bail out
        return None
      else:
        # field has contents
        return fun(self)
    return wrapper

  return decorator

def clean_empty_field(field_name):
  """Incorporates the check_field_is_empty as regular cleaner.
  """

  @check_field_is_empty(field_name)
  def wrapper(self):
    """Decorator wrapper method.
    """
    return self.cleaned_data.get(field_name)

  return wrapper

def clean_email(field_name):
  """Checks if the field_name value is in an email format.
  """
  @check_field_is_empty(field_name)
  def wrapper(self):
    """Decorator wrapper method.
    """
    # convert to lowercase for user comfort
    email = self.cleaned_data.get(field_name)
    validator = validators.validate_email

    try:
      validator(email)
    except forms.ValidationError, e:
      if e.code == 'invalid':
        msg = ugettext(u'Enter a valid email address.')
        raise forms.ValidationError(msg, code='invalid')
    return email

  return wrapper

def clean_link_id(field_name):
  """Checks if the field_name value is in a valid link ID format.
  """

  @check_field_is_empty(field_name)
  def wrapper(self):
    """Decorator wrapper method.
    """
    # convert to lowercase for user comfort
    link_id = self.cleaned_data.get(field_name).lower()
    if not validate.isLinkIdFormatValid(link_id):
      raise forms.ValidationError("This link ID is in wrong format.",
                                  code='invalid')
    return link_id
  return wrapper

def clean_scope_path(field_name):
  """Checks if the field_name value is in a valid scope path format.
  """

  @check_field_is_empty(field_name)
  def wrapper(self):
    """Decorator wrapper method.
    """
    # convert to lowercase for user comfort
    scope_path = self.cleaned_data.get(field_name).lower()
    if not validate.isScopePathFormatValid(scope_path):
      raise forms.ValidationError("This scope path is in wrong format.")
    return scope_path
  return wrapper

def clean_existing_user(field_name):
  """Check if the field_name field is a valid user.
  """

  @check_field_is_empty(field_name)
  def wrapped(self):
    """Decorator wrapper method.
    """
    link_id = clean_link_id(field_name)(self)

    user_entity = User.get_by_key_name(link_id)

    if not user_entity:
      # user does not exist
      raise forms.ValidationError("This user does not exist.")

    return user_entity
  return wrapped

def clean_user_is_current(field_name, as_user=True):
  """Check if the field_name value is a valid link_id and resembles the
     current user.
  """

  @check_field_is_empty(field_name)
  def wrapped(self):
    """Decorator wrapper method.
    """
    link_id = clean_link_id(field_name)(self)

    user_entity = user.current()
    # pylint: disable=E1103
    if not user_entity or user_entity.link_id != link_id:
      # this user is not the current user
      raise forms.ValidationError("This user is not you.")

    return user_entity if as_user else link_id
  return wrapped

def clean_user_not_exist(field_name):
  """Check if the field_name value is a valid link_id and a user with the
     link id does not exist.
  """

  @check_field_is_empty(field_name)
  def wrapped(self):
    """Decorator wrapper method.
    """
    link_id = clean_link_id(field_name)(self)

    user_entity = User.get_by_key_name(link_id)

    if user_entity:
      # user exists already
      raise forms.ValidationError("There is already a user with this link id.")

    return link_id
  return wrapped

def clean_users_not_same(field_name):
  """Check if the field_name field is a valid user and is not
     equal to the current user.
  """

  @check_field_is_empty(field_name)
  def wrapped(self):
    """Decorator wrapper method.
    """
    clean_user_field = clean_existing_user(field_name)
    user_entity = clean_user_field(self)

    current_user_entity = user.current()
    # pylint: disable=E1103
    if user_entity.key() == current_user_entity.key():
      # users are equal
      raise forms.ValidationError("You cannot enter yourself here.")

    return user_entity
  return wrapped

def clean_user_account(field_name):
  """Returns the User with the given field_name value.
  """

  @check_field_is_empty(field_name)
  def wrapped(self):
    """Decorator wrapper method.
    """
    email_adress = self.cleaned_data[field_name]
    return users.User(email_adress)

  return wrapped

def clean_user_account_not_in_use(field_name):
  """Check if the field_name value contains an email
     address that hasn't been used for an existing account.
  """

  @check_field_is_empty(field_name)
  def wrapped(self):
    """Decorator wrapper method.
    """
    email_adress = self.cleaned_data.get(field_name).lower()

    # get the user account for this email and check if it's in use
    user_account = users.User(email_adress)

    user_entity = User.all().filter('account', user_account).get()

    if user_entity or user.isFormerAccount(user_account):
      raise forms.ValidationError("There is already a user "
          "with this email address.")

    return user_account
  return wrapped

def clean_valid_shipping_chars(field_name):
  """Clean method for cleaning a field that must comply with Google's character
  requirements for shipping.
  """

  @check_field_is_empty(field_name)
  def wrapper(self):
    """Decorator wrapper method.
    """
    value = self.cleaned_data.get(field_name)

    if value and not DEF_VALID_SHIPPING_CHARS.match(value):
      raise forms.ValidationError(DEF_INVALID_SHIPPING_CHARS)

    return value
  return wrapper

def clean_content_length(field_name, min_length=0, max_length=500):
  """Clean method for cleaning a field which must contain at least min and
     not more then max length characters.

  Args:
    field_name: the name of the field needed cleaning
    min_length: the minimum amount of allowed characters
    max_length: the maximum amount of allowed characters
  """

  @check_field_is_empty(field_name)
  def wrapper(self):
    """Decorator wrapper method.
    """

    value = self.cleaned_data[field_name]
    value_length = len(value)

    if value_length < min_length:
      raise forms.ValidationError(DEF_MUST_BE_ABOVE_LIMIT %(
          min_length, value_length))

    if value_length > max_length:
      raise forms.ValidationError(DEF_MUST_BE_UNDER_LIMIT %(
          max_length, value_length))

    return value
  return wrapper

def clean_phone_number(field_name):
  """Clean method for cleaning a field that may only contain numerical values.
  """

  @check_field_is_empty(field_name)
  def wrapper(self):
    """Decorator wrapped method.
    """

    value = self.cleaned_data.get(field_name)

    # allow for a '+' prefix which means '00'
    if value[0] == '+':
      value = '00' + value[1:]

    if not value.isdigit():
      raise forms.ValidationError("Only numerical characters are allowed")

    return value
  return wrapper

def clean_feed_url(field_name):
  """Clean method for cleaning feed url.
  """

  def wrapper(self):
    """Decorator wrapped method.
    """
    feed_url = self.cleaned_data.get(field_name)

    if feed_url == '':
      # feed url not supplied (which is OK), so do not try to validate it
      return None

    if not validate.isFeedURLValid(feed_url):
      raise forms.ValidationError('This URL is not a valid ATOM or RSS feed.')

    return feed_url
  return wrapper

def clean_birth_date(field_name):
  """Clean method for cleaning birth date.

  Args:
    field_name: the name of the field needed cleaning
    program: program entity that the field refers to
    check_age: whether the birth date should be checked against the minimal
      date for the program
  """

  def wrapper(form):
    """Decorator wrapped method.
    """
    birth_date = form.cleaned_data.get(field_name)

    if form.program and not validate.isAgeSufficientForProgram(
        birth_date, form.program):
      raise forms.ValidationError(
          'Your age does not allow you to participate in the program.')

    return birth_date
  return wrapper

def sanitize_html_string(content):
  """Sanitizes the given html string.

  Raises:
    forms.ValidationError in case of an error.
  """
  try:
    parser = HTMLParser(tokenizer=sanitizer.HTMLSanitizer)
    parsed = parser.parseFragment(content, encoding='utf-8')
    cleaned_content = ''.join([tag.toxml() for tag in parsed.childNodes])
  except (HTMLParseError, ParseError), msg:
    raise forms.ValidationError(msg)

  try:
    content = cleaned_content.decode("utf-8")
  except Exception, e:
    raise forms.ValidationError(str(e))

  return content

def clean_html_content(field_name):
  """Clean method for cleaning HTML content.
  """

  @check_field_is_empty(field_name)
  def wrapped(self):
    """Decorator wrapper method.
    """
    content = self.cleaned_data.get(field_name)

    # clean_html_content is called when writing data into GAE rather than
    # when reading data from GAE. This short-circuiting of the sanitizer
    # only affects html authored by developers. The isDeveloper test for
    # example allows developers to add javascript.
    if user.isDeveloper():
      return content

    content = sanitize_html_string(content)

    return content

  return wrapped

def clean_url(field_name):
  """Clean method for cleaning a field belonging to a LinkProperty.
  """

  @check_field_is_empty(field_name)
  def wrapped(self):
    """Decorator wrapper method.
    """

    value = self.cleaned_data.get(field_name)
    validator = validators.URLValidator()

    # call the Django URLField cleaning method to
    # properly clean/validate this field
    try:
      validator(value)
    except forms.ValidationError, e:
      if e.code == 'invalid':
        msg = ugettext(u'Enter a valid URL.')
        raise forms.ValidationError(msg, code='invalid')
    return value
  return wrapped

def clean_irc(field_name):
  """Clean method for cleaning an irc field.
  """

  @check_field_is_empty(field_name)
  def wrapped(self):
    """Decorator wrapper method.
    """

    value = self.cleaned_data.get(field_name)
    validator = validators.URLValidator()

    to_clean = value

    if value.startswith("irc://"):
      to_clean = value.replace("irc://", "http://", 1)

    # call the Django URLField cleaning method to
    # properly clean/validate this field
    try:
      validator(to_clean)
    except forms.ValidationError, e:
      if e.code == 'invalid':
        msg = ugettext(u'Enter a valid URL or irc:// url.')
        raise forms.ValidationError(msg, code='invalid')
    return value
  return wrapped

def clean_mailto(field_name):
  @check_field_is_empty(field_name)
  def wrapped(self):
    """Decorator wrapper method.
    """

    value = self.cleaned_data.get(field_name)
    validator = validators.URLValidator()

    to_clean = value

    if value.startswith("mailto:"):
      to_clean = value.replace("mailto:", "", 1)
      validator = validators.validate_email

    # call the Django URLField cleaning method to
    # properly clean/validate this field
    try:
      validator(to_clean)
    except forms.ValidationError, e:
      if e.code == 'invalid':
        msg = ugettext(u'Enter a valid URL or mailto: link.')
        raise forms.ValidationError(msg, code='invalid')
    return value
  return wrapped

def str2set(string_field, separator=','):
  """Clean method for cleaning comma separated strings.

  Obtains the separated string from the form and returns it as
  a set of strings.
  """

  def wrapper(self):
    """Decorator wrapper method.
    """
    cleaned_data = self.cleaned_data

    string_data = cleaned_data.get(string_field)

    list_data = []
    for string in string_data.split(separator):
      string_strip = string.strip()
      if string_strip and string_strip not in list_data:
        list_data.append(string_strip)

    return list_data

  return wrapper
<commit_msg>We do not have to decode the unicode string again since we already have our data from html5lib in utf-8 encoded format.<commit_after>#!/usr/bin/env python2.5
#
# Copyright 2008 the Melange authors.
#
# 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.

"""Generic cleaning methods.
"""

import re

from HTMLParser import HTMLParseError

from html5lib import HTMLParser
from html5lib import sanitizer
from html5lib.html5parser import ParseError

from google.appengine.api import users

from django import forms
from django.core import validators
from django.utils.translation import ugettext

from soc.models.user import User
from soc.logic import validate
from soc.logic import user

DEF_VALID_SHIPPING_CHARS = re.compile('^[A-Za-z0-9\s-]+$')

DEF_LINK_ID_IN_USE = ugettext(
    'This link ID is already in use, please specify another one')

DEF_NO_RIGHTS_FOR_ACL = ugettext(
    'You do not have the required rights for that ACL.')

DEF_ORGANZIATION_NOT_ACTIVE = ugettext(
    "This organization is not active or doesn't exist.")

DEF_NO_SUCH_DOCUMENT = ugettext(
    "There is no such document with that link ID under this entity.")

DEF_MUST_BE_ABOVE_AGE_LIMIT = ugettext(
    "To sign up as a student for this program, you "
    "must be at least %d years of age, as of %s.")

DEF_MUST_BE_ABOVE_LIMIT = ugettext(
    "Must be at least %d characters, it has %d characters.")

DEF_MUST_BE_UNDER_LIMIT = ugettext(
    "Must be under %d characters, it has %d characters.")

DEF_2_LETTER_STATE = ugettext(
    "State should be 2-letter field since country is '%s'.")

DEF_INVALID_SHIPPING_CHARS = ugettext(
    'Invalid characters, only A-z, 0-9, - and whitespace are allowed. '
    'See also '
    'Issue 903, in particular comment 16. '
    'Please do not create a new issue about this.')

DEF_ROLE_TARGET_COUNTRY = "United States"

DEF_ROLE_COUNTRY_PAIRS = [("res_country", "res_state"),
                          ("ship_country", "ship_state")]

def check_field_is_empty(field_name):
  """Returns decorator that bypasses cleaning for empty fields.
  """

  def decorator(fun):
    """Decorator that checks if a field is empty if so doesn't do the cleaning.

    Note Django will capture errors concerning required fields that are empty.
    """
    from functools import wraps

    @wraps(fun)
    def wrapper(self):
      """Decorator wrapper method.
      """
      field_content = self.cleaned_data.get(field_name)

      if not field_content:
        # field has no content so bail out
        return None
      else:
        # field has contents
        return fun(self)
    return wrapper

  return decorator

def clean_empty_field(field_name):
  """Incorporates the check_field_is_empty as regular cleaner.
  """

  @check_field_is_empty(field_name)
  def wrapper(self):
    """Decorator wrapper method.
    """
    return self.cleaned_data.get(field_name)

  return wrapper

def clean_email(field_name):
  """Checks if the field_name value is in an email format.
  """
  @check_field_is_empty(field_name)
  def wrapper(self):
    """Decorator wrapper method.
    """
    # convert to lowercase for user comfort
    email = self.cleaned_data.get(field_name)
    validator = validators.validate_email

    try:
      validator(email)
    except forms.ValidationError, e:
      if e.code == 'invalid':
        msg = ugettext(u'Enter a valid email address.')
        raise forms.ValidationError(msg, code='invalid')
    return email

  return wrapper

def clean_link_id(field_name):
  """Checks if the field_name value is in a valid link ID format.
  """

  @check_field_is_empty(field_name)
  def wrapper(self):
    """Decorator wrapper method.
    """
    # convert to lowercase for user comfort
    link_id = self.cleaned_data.get(field_name).lower()
    if not validate.isLinkIdFormatValid(link_id):
      raise forms.ValidationError("This link ID is in wrong format.",
                                  code='invalid')
    return link_id
  return wrapper

def clean_scope_path(field_name):
  """Checks if the field_name value is in a valid scope path format.
  """

  @check_field_is_empty(field_name)
  def wrapper(self):
    """Decorator wrapper method.
    """
    # convert to lowercase for user comfort
    scope_path = self.cleaned_data.get(field_name).lower()
    if not validate.isScopePathFormatValid(scope_path):
      raise forms.ValidationError("This scope path is in wrong format.")
    return scope_path
  return wrapper

def clean_existing_user(field_name):
  """Check if the field_name field is a valid user.
  """

  @check_field_is_empty(field_name)
  def wrapped(self):
    """Decorator wrapper method.
    """
    link_id = clean_link_id(field_name)(self)

    user_entity = User.get_by_key_name(link_id)

    if not user_entity:
      # user does not exist
      raise forms.ValidationError("This user does not exist.")

    return user_entity
  return wrapped

def clean_user_is_current(field_name, as_user=True):
  """Check if the field_name value is a valid link_id and resembles the
     current user.
  """

  @check_field_is_empty(field_name)
  def wrapped(self):
    """Decorator wrapper method.
    """
    link_id = clean_link_id(field_name)(self)

    user_entity = user.current()
    # pylint: disable=E1103
    if not user_entity or user_entity.link_id != link_id:
      # this user is not the current user
      raise forms.ValidationError("This user is not you.")

    return user_entity if as_user else link_id
  return wrapped

def clean_user_not_exist(field_name):
  """Check if the field_name value is a valid link_id and a user with the
     link id does not exist.
  """

  @check_field_is_empty(field_name)
  def wrapped(self):
    """Decorator wrapper method.
    """
    link_id = clean_link_id(field_name)(self)

    user_entity = User.get_by_key_name(link_id)

    if user_entity:
      # user exists already
      raise forms.ValidationError("There is already a user with this link id.")

    return link_id
  return wrapped

def clean_users_not_same(field_name):
  """Check if the field_name field is a valid user and is not
     equal to the current user.
  """

  @check_field_is_empty(field_name)
  def wrapped(self):
    """Decorator wrapper method.
    """
    clean_user_field = clean_existing_user(field_name)
    user_entity = clean_user_field(self)

    current_user_entity = user.current()
    # pylint: disable=E1103
    if user_entity.key() == current_user_entity.key():
      # users are equal
      raise forms.ValidationError("You cannot enter yourself here.")

    return user_entity
  return wrapped

def clean_user_account(field_name):
  """Returns the User with the given field_name value.
  """

  @check_field_is_empty(field_name)
  def wrapped(self):
    """Decorator wrapper method.
    """
    email_adress = self.cleaned_data[field_name]
    return users.User(email_adress)

  return wrapped

def clean_user_account_not_in_use(field_name):
  """Check if the field_name value contains an email
     address that hasn't been used for an existing account.
  """

  @check_field_is_empty(field_name)
  def wrapped(self):
    """Decorator wrapper method.
    """
    email_adress = self.cleaned_data.get(field_name).lower()

    # get the user account for this email and check if it's in use
    user_account = users.User(email_adress)

    user_entity = User.all().filter('account', user_account).get()

    if user_entity or user.isFormerAccount(user_account):
      raise forms.ValidationError("There is already a user "
          "with this email address.")

    return user_account
  return wrapped

def clean_valid_shipping_chars(field_name):
  """Clean method for cleaning a field that must comply with Google's character
  requirements for shipping.
  """

  @check_field_is_empty(field_name)
  def wrapper(self):
    """Decorator wrapper method.
    """
    value = self.cleaned_data.get(field_name)

    if value and not DEF_VALID_SHIPPING_CHARS.match(value):
      raise forms.ValidationError(DEF_INVALID_SHIPPING_CHARS)

    return value
  return wrapper

def clean_content_length(field_name, min_length=0, max_length=500):
  """Clean method for cleaning a field which must contain at least min and
     not more then max length characters.

  Args:
    field_name: the name of the field needed cleaning
    min_length: the minimum amount of allowed characters
    max_length: the maximum amount of allowed characters
  """

  @check_field_is_empty(field_name)
  def wrapper(self):
    """Decorator wrapper method.
    """

    value = self.cleaned_data[field_name]
    value_length = len(value)

    if value_length < min_length:
      raise forms.ValidationError(DEF_MUST_BE_ABOVE_LIMIT %(
          min_length, value_length))

    if value_length > max_length:
      raise forms.ValidationError(DEF_MUST_BE_UNDER_LIMIT %(
          max_length, value_length))

    return value
  return wrapper

def clean_phone_number(field_name):
  """Clean method for cleaning a field that may only contain numerical values.
  """

  @check_field_is_empty(field_name)
  def wrapper(self):
    """Decorator wrapped method.
    """

    value = self.cleaned_data.get(field_name)

    # allow for a '+' prefix which means '00'
    if value[0] == '+':
      value = '00' + value[1:]

    if not value.isdigit():
      raise forms.ValidationError("Only numerical characters are allowed")

    return value
  return wrapper

def clean_feed_url(field_name):
  """Clean method for cleaning feed url.
  """

  def wrapper(self):
    """Decorator wrapped method.
    """
    feed_url = self.cleaned_data.get(field_name)

    if feed_url == '':
      # feed url not supplied (which is OK), so do not try to validate it
      return None

    if not validate.isFeedURLValid(feed_url):
      raise forms.ValidationError('This URL is not a valid ATOM or RSS feed.')

    return feed_url
  return wrapper

def clean_birth_date(field_name):
  """Clean method for cleaning birth date.

  Args:
    field_name: the name of the field needed cleaning
    program: program entity that the field refers to
    check_age: whether the birth date should be checked against the minimal
      date for the program
  """

  def wrapper(form):
    """Decorator wrapped method.
    """
    birth_date = form.cleaned_data.get(field_name)

    if form.program and not validate.isAgeSufficientForProgram(
        birth_date, form.program):
      raise forms.ValidationError(
          'Your age does not allow you to participate in the program.')

    return birth_date
  return wrapper

def sanitize_html_string(content):
  """Sanitizes the given html string.

  Raises:
    forms.ValidationError in case of an error.
  """
  try:
    parser = HTMLParser(tokenizer=sanitizer.HTMLSanitizer)
    parsed = parser.parseFragment(content, encoding='utf-8')
    cleaned_content = ''.join([tag.toxml() for tag in parsed.childNodes])
  except (HTMLParseError, ParseError), msg:
    raise forms.ValidationError(msg)

  return cleaned_content

def clean_html_content(field_name):
  """Clean method for cleaning HTML content.
  """

  @check_field_is_empty(field_name)
  def wrapped(self):
    """Decorator wrapper method.
    """
    content = self.cleaned_data.get(field_name)

    # clean_html_content is called when writing data into GAE rather than
    # when reading data from GAE. This short-circuiting of the sanitizer
    # only affects html authored by developers. The isDeveloper test for
    # example allows developers to add javascript.
    if user.isDeveloper():
      return content

    content = sanitize_html_string(content)

    return content

  return wrapped

def clean_url(field_name):
  """Clean method for cleaning a field belonging to a LinkProperty.
  """

  @check_field_is_empty(field_name)
  def wrapped(self):
    """Decorator wrapper method.
    """

    value = self.cleaned_data.get(field_name)
    validator = validators.URLValidator()

    # call the Django URLField cleaning method to
    # properly clean/validate this field
    try:
      validator(value)
    except forms.ValidationError, e:
      if e.code == 'invalid':
        msg = ugettext(u'Enter a valid URL.')
        raise forms.ValidationError(msg, code='invalid')
    return value
  return wrapped

def clean_irc(field_name):
  """Clean method for cleaning an irc field.
  """

  @check_field_is_empty(field_name)
  def wrapped(self):
    """Decorator wrapper method.
    """

    value = self.cleaned_data.get(field_name)
    validator = validators.URLValidator()

    to_clean = value

    if value.startswith("irc://"):
      to_clean = value.replace("irc://", "http://", 1)

    # call the Django URLField cleaning method to
    # properly clean/validate this field
    try:
      validator(to_clean)
    except forms.ValidationError, e:
      if e.code == 'invalid':
        msg = ugettext(u'Enter a valid URL or irc:// url.')
        raise forms.ValidationError(msg, code='invalid')
    return value
  return wrapped

def clean_mailto(field_name):
  @check_field_is_empty(field_name)
  def wrapped(self):
    """Decorator wrapper method.
    """

    value = self.cleaned_data.get(field_name)
    validator = validators.URLValidator()

    to_clean = value

    if value.startswith("mailto:"):
      to_clean = value.replace("mailto:", "", 1)
      validator = validators.validate_email

    # call the Django URLField cleaning method to
    # properly clean/validate this field
    try:
      validator(to_clean)
    except forms.ValidationError, e:
      if e.code == 'invalid':
        msg = ugettext(u'Enter a valid URL or mailto: link.')
        raise forms.ValidationError(msg, code='invalid')
    return value
  return wrapped

def str2set(string_field, separator=','):
  """Clean method for cleaning comma separated strings.

  Obtains the separated string from the form and returns it as
  a set of strings.
  """

  def wrapper(self):
    """Decorator wrapper method.
    """
    cleaned_data = self.cleaned_data

    string_data = cleaned_data.get(string_field)

    list_data = []
    for string in string_data.split(separator):
      string_strip = string.strip()
      if string_strip and string_strip not in list_data:
        list_data.append(string_strip)

    return list_data

  return wrapper
<|endoftext|>


<commit_before><commit_msg>Added watched entries page.<commit_after><|endoftext|>


<commit_before>import os
from flask import Flask, render_template, request, url_for, redirect
from flask.ext.sqlalchemy import SQLAlchemy
import requests
import urllib2
import json

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = os.environ['DATABASE_URL']
#app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/book.db'
#app.debug = True
db = SQLAlchemy(app)

class Book(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(200))
    isbn = db.Column(db.Integer)

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

    def __repr__(self):
        return '<TITLE %r>' % self.title

@app.route('/')
def home():
    all_books = Book.query.all()
    return render_template("home.html", all_books=all_books)

@app.route('/insert', methods=['GET', 'POST'])
def insert():
    if request.method == 'POST':
        try:
            isbn = request.form['isbn']
            google_url = 'https://www.googleapis.com/books/v1/volumes?q=%s+isbn' % isbn
            response = requests.get(google_url)
            html = response.text
            data = json.loads(html)
            title = data['items']['volumeInfo']['title']
            book = Book(isbn)
            book.title = title
            db.session.add(book)
            db.session.commit()
            return redirect(url_for('home'))
        except ValueError as error:
            return error
    return render_template("insert.html")

@app.route('/delete/{id}')
def delete():
    return render_template("insert.html")<commit_msg>quick fix<commit_after>import os
from flask import Flask, render_template, request, url_for, redirect
from flask.ext.sqlalchemy import SQLAlchemy
import requests
import urllib2
import json

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = os.environ['DATABASE_URL']
#app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/book.db'
#app.debug = True
db = SQLAlchemy(app)

class Book(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(200))
    isbn = db.Column(db.Integer)

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

    def __repr__(self):
        return '<TITLE %r>' % self.title

@app.route('/')
def home():
    all_books = Book.query.all()
    return render_template("home.html", all_books=all_books)

@app.route('/insert', methods=['GET', 'POST'])
def insert():
    if request.method == 'POST':
        try:
            isbn = request.form['isbn']
            google_url = 'https://www.googleapis.com/books/v1/volumes?q=%s+isbn' % isbn
            response = requests.get(google_url)
            html = response.text
            data = json.loads(html)
            return data
            title = data['items']['volumeInfo']['title']
            book = Book(isbn)
            book.title = title
            db.session.add(book)
            db.session.commit()
            return redirect(url_for('home'))
        except ValueError as error:
            return error
    return render_template("insert.html")

@app.route('/delete/{id}')
def delete():
    return render_template("insert.html")<|endoftext|>


<commit_before>"""Cloud Foundry test"""
from flask import Flask
import os

app = Flask(__name__)

# On CF, get the port number from the environment variable VCAP_APP_PORT
# When running this app on the local machine, default the port to 8080
port = int(os.getenv('VCAP_APP_PORT', 8080))
address = (os.getenv('CF_INSTANCE_IP'))
@app.route('/')
def hello_world():
    return 'Hello World! I am running on port ' + str(port)
    print "running at %d" % (address)
if __name__ == '__main__':
    app.run(host='0.0.0.0', port=port)
<commit_msg>Adding address with return<commit_after>"""Cloud Foundry test"""
from flask import Flask
import os

app = Flask(__name__)

# On CF, get the port number from the environment variable VCAP_APP_PORT
# When running this app on the local machine, default the port to 8080
port = int(os.getenv('VCAP_APP_PORT', 8080))
address = (os.getenv('CF_INSTANCE_IP'))
@app.route('/')
def hello_world():
    return 'Hello World! I am running on port ' + str(port), str(address)

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=port)
<|endoftext|>


<commit_before>import os
from flask import Flask
from Flask import render_template

app = Flask(__name__)

@app.route('/')
def hello():
    return render_template('index.html')<commit_msg>fixed import error<commit_after>import os
from flask import Flask
from flask import render_template

app = Flask(__name__)

@app.route('/')
def hello():
    return render_template('index.html')<|endoftext|>


<commit_before>"""
Support for the LIFX platform that implements lights.

For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/light.lifx/
"""
import colorsys
import logging

import voluptuous as vol

from homeassistant.components.light import (
    ATTR_BRIGHTNESS, ATTR_COLOR_TEMP, ATTR_RGB_COLOR, ATTR_TRANSITION,
    SUPPORT_BRIGHTNESS, SUPPORT_COLOR_TEMP, SUPPORT_RGB_COLOR,
    SUPPORT_TRANSITION, Light, PLATFORM_SCHEMA)
from homeassistant.helpers.event import track_time_change
import homeassistant.helpers.config_validation as cv

_LOGGER = logging.getLogger(__name__)

REQUIREMENTS = ['liffylights==0.9.4']

BYTE_MAX = 255

CONF_BROADCAST = 'broadcast'
CONF_SERVER = 'server'

SHORT_MAX = 65535

TEMP_MAX = 9000
TEMP_MAX_HASS = 500
TEMP_MIN = 2500
TEMP_MIN_HASS = 154

SUPPORT_LIFX = (SUPPORT_BRIGHTNESS | SUPPORT_COLOR_TEMP | SUPPORT_RGB_COLOR |
                SUPPORT_TRANSITION)

PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
    vol.Optional(CONF_SERVER, default=None): cv.string,
    vol.Optional(CONF_BROADCAST, default=None): cv.string,
})

# pylint: disable=unused-argument
def setup_platform(hass, config, add_devices, discovery_info=None):
    """Setup the LIFX platform."""
    server_addr = config.get(CONF_SERVER)
    broadcast_addr = config.get(CONF_BROADCAST)

    lifx_library = LIFX(add_devices, server_addr, broadcast_addr)

    # Register our poll service
    track_time_change(hass, lifx_library.poll, second=[10, 40])

    lifx_library.probe()

class LIFX(object):
    """Representation of a LIFX light."""

    def __init__(self, add_devices_callback, server_addr=None,
                 broadcast_addr=None):
        """Initialize the light."""
        import liffylights

        self._devices = []

        self._add_devices_callback = add_devices_callback

        self._liffylights = liffylights.LiffyLights(
            self.on_device, self.on_power, self.on_color, server_addr,
            broadcast_addr)

    def find_bulb(self, ipaddr):
        """Search for bulbs."""
        bulb = None
        for device in self._devices:
            if device.ipaddr == ipaddr:
                bulb = device
                break
        return bulb

    def on_device(self, ipaddr, name, power, hue, sat, bri, kel):
        """Initialize the light."""
        bulb = self.find_bulb(ipaddr)

        if bulb is None:
            _LOGGER.debug("new bulb %s %s %d %d %d %d %d",
                          ipaddr, name, power, hue, sat, bri, kel)
            bulb = LIFXLight(
                self._liffylights, ipaddr, name, power, hue, sat, bri, kel)
            self._devices.append(bulb)
            self._add_devices_callback([bulb])
        else:
            _LOGGER.debug("update bulb %s %s %d %d %d %d %d",
                          ipaddr, name, power, hue, sat, bri, kel)
            bulb.set_power(power)
            bulb.set_color(hue, sat, bri, kel)
            bulb.update_ha_state()

    def on_color(self, ipaddr, hue, sat, bri, kel):
        """Initialize the light."""
        bulb = self.find_bulb(ipaddr)

        if bulb is not None:
            bulb.set_color(hue, sat, bri, kel)
            bulb.update_ha_state()

    def on_power(self, ipaddr, power):
        """Initialize the light."""
        bulb = self.find_bulb(ipaddr)

        if bulb is not None:
            bulb.set_power(power)
            bulb.update_ha_state()

    # pylint: disable=unused-argument
    def poll(self, now):
        """Polling for the light."""
        self.probe()

    def probe(self, address=None):
        """Probe the light."""
        self._liffylights.probe(address)

def convert_rgb_to_hsv(rgb):
    """Convert Home Assistant RGB values to HSV values."""
    red, green, blue = [_ / BYTE_MAX for _ in rgb]

    hue, saturation, brightness = colorsys.rgb_to_hsv(red, green, blue)

    return [int(hue * SHORT_MAX),
            int(saturation * SHORT_MAX),
            int(brightness * SHORT_MAX)]

class LIFXLight(Light):
    """Representation of a LIFX light."""

    def __init__(self, liffy, ipaddr, name, power, hue, saturation, brightness,
                 kelvin):
        """Initialize the light."""
        _LOGGER.debug("LIFXLight: %s %s", ipaddr, name)

        self._liffylights = liffy
        self._ip = ipaddr
        self.set_name(name)
        self.set_power(power)
        self.set_color(hue, saturation, brightness, kelvin)

    @property
    def should_poll(self):
        """No polling needed for LIFX light."""
        return False

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

    @property
    def ipaddr(self):
        """Return the IP address of the device."""
        return self._ip

    @property
    def rgb_color(self):
        """Return the RGB value."""
        _LOGGER.debug(
            "rgb_color: [%d %d %d]", self._rgb[0], self._rgb[1], self._rgb[2])
        return self._rgb

    @property
    def brightness(self):
        """Return the brightness of this light between 0..255."""
        brightness = int(self._bri / (BYTE_MAX + 1))
        _LOGGER.debug("brightness: %d", brightness)
        return brightness

    @property
    def color_temp(self):
        """Return the color temperature."""
        temperature = int(TEMP_MIN_HASS + (TEMP_MAX_HASS - TEMP_MIN_HASS) *
                          (self._kel - TEMP_MIN) / (TEMP_MAX - TEMP_MIN))

        _LOGGER.debug("color_temp: %d", temperature)
        return temperature

    @property
    def is_on(self):
        """Return true if device is on."""
        _LOGGER.debug("is_on: %d", self._power)
        return self._power != 0

    @property
    def supported_features(self):
        """Flag supported features."""
        return SUPPORT_LIFX

    def turn_on(self, **kwargs):
        """Turn the device on."""
        if ATTR_TRANSITION in kwargs:
            fade = kwargs[ATTR_TRANSITION] * 1000
        else:
            fade = 0

        if ATTR_RGB_COLOR in kwargs:
            hue, saturation, brightness = \
                convert_rgb_to_hsv(kwargs[ATTR_RGB_COLOR])
        else:
            hue = self._hue
            saturation = self._sat
            brightness = self._bri

        if ATTR_BRIGHTNESS in kwargs:
            brightness = kwargs[ATTR_BRIGHTNESS] * (BYTE_MAX + 1)
        else:
            brightness = self._bri

        if ATTR_COLOR_TEMP in kwargs:
            # pylint: disable=fixme
            # TODO: Use color_temperature_mired_to_kelvin from util.color
            kelvin = int(((TEMP_MAX - TEMP_MIN) *
                          (kwargs[ATTR_COLOR_TEMP] - TEMP_MIN_HASS) /
                          (TEMP_MAX_HASS - TEMP_MIN_HASS)) + TEMP_MIN)
        else:
            kelvin = self._kel

        _LOGGER.debug("turn_on: %s (%d) %d %d %d %d %d",
                      self._ip, self._power,
                      hue, saturation, brightness, kelvin, fade)

        if self._power == 0:
            self._liffylights.set_power(self._ip, 65535, fade)

        self._liffylights.set_color(self._ip, hue, saturation,
                                    brightness, kelvin, fade)

    def turn_off(self, **kwargs):
        """Turn the device off."""
        if ATTR_TRANSITION in kwargs:
            fade = kwargs[ATTR_TRANSITION] * 1000
        else:
            fade = 0

        _LOGGER.debug("turn_off: %s %d", self._ip, fade)
        self._liffylights.set_power(self._ip, 0, fade)

    def set_name(self, name):
        """Set name of the light."""
        self._name = name

    def set_power(self, power):
        """Set power state value."""
        _LOGGER.debug("set_power: %d", power)
        self._power = (power != 0)

    def set_color(self, hue, sat, bri, kel):
        """Set color state values."""
        self._hue = hue
        self._sat = sat
        self._bri = bri
        self._kel = kel

        red, green, blue = colorsys.hsv_to_rgb(hue / SHORT_MAX,
                                               sat / SHORT_MAX,
                                               bri / SHORT_MAX)

        red = int(red * BYTE_MAX)
        green = int(green * BYTE_MAX)
        blue = int(blue * BYTE_MAX)

        _LOGGER.debug("set_color: %d %d %d %d [%d %d %d]",
                      hue, sat, bri, kel, red, green, blue)

        self._rgb = [red, green, blue]
<commit_msg>Fix colortemp conversion for lifx lights (#6087)<commit_after>"""
Support for the LIFX platform that implements lights.

For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/light.lifx/
"""
import colorsys
import logging

import voluptuous as vol

from homeassistant.components.light import (
    ATTR_BRIGHTNESS, ATTR_COLOR_TEMP, ATTR_RGB_COLOR, ATTR_TRANSITION,
    SUPPORT_BRIGHTNESS, SUPPORT_COLOR_TEMP, SUPPORT_RGB_COLOR,
    SUPPORT_TRANSITION, Light, PLATFORM_SCHEMA)
from homeassistant.helpers.event import track_time_change
from homeassistant.util.color import (
    color_temperature_mired_to_kelvin, color_temperature_kelvin_to_mired)
import homeassistant.helpers.config_validation as cv

_LOGGER = logging.getLogger(__name__)

REQUIREMENTS = ['liffylights==0.9.4']

BYTE_MAX = 255

CONF_BROADCAST = 'broadcast'
CONF_SERVER = 'server'

SHORT_MAX = 65535

TEMP_MAX = 9000
TEMP_MAX_HASS = 500
TEMP_MIN = 2500
TEMP_MIN_HASS = 154

SUPPORT_LIFX = (SUPPORT_BRIGHTNESS | SUPPORT_COLOR_TEMP | SUPPORT_RGB_COLOR |
                SUPPORT_TRANSITION)

PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
    vol.Optional(CONF_SERVER, default=None): cv.string,
    vol.Optional(CONF_BROADCAST, default=None): cv.string,
})

# pylint: disable=unused-argument
def setup_platform(hass, config, add_devices, discovery_info=None):
    """Setup the LIFX platform."""
    server_addr = config.get(CONF_SERVER)
    broadcast_addr = config.get(CONF_BROADCAST)

    lifx_library = LIFX(add_devices, server_addr, broadcast_addr)

    # Register our poll service
    track_time_change(hass, lifx_library.poll, second=[10, 40])

    lifx_library.probe()

class LIFX(object):
    """Representation of a LIFX light."""

    def __init__(self, add_devices_callback, server_addr=None,
                 broadcast_addr=None):
        """Initialize the light."""
        import liffylights

        self._devices = []

        self._add_devices_callback = add_devices_callback

        self._liffylights = liffylights.LiffyLights(
            self.on_device, self.on_power, self.on_color, server_addr,
            broadcast_addr)

    def find_bulb(self, ipaddr):
        """Search for bulbs."""
        bulb = None
        for device in self._devices:
            if device.ipaddr == ipaddr:
                bulb = device
                break
        return bulb

    def on_device(self, ipaddr, name, power, hue, sat, bri, kel):
        """Initialize the light."""
        bulb = self.find_bulb(ipaddr)

        if bulb is None:
            _LOGGER.debug("new bulb %s %s %d %d %d %d %d",
                          ipaddr, name, power, hue, sat, bri, kel)
            bulb = LIFXLight(
                self._liffylights, ipaddr, name, power, hue, sat, bri, kel)
            self._devices.append(bulb)
            self._add_devices_callback([bulb])
        else:
            _LOGGER.debug("update bulb %s %s %d %d %d %d %d",
                          ipaddr, name, power, hue, sat, bri, kel)
            bulb.set_power(power)
            bulb.set_color(hue, sat, bri, kel)
            bulb.update_ha_state()

    def on_color(self, ipaddr, hue, sat, bri, kel):
        """Initialize the light."""
        bulb = self.find_bulb(ipaddr)

        if bulb is not None:
            bulb.set_color(hue, sat, bri, kel)
            bulb.update_ha_state()

    def on_power(self, ipaddr, power):
        """Initialize the light."""
        bulb = self.find_bulb(ipaddr)

        if bulb is not None:
            bulb.set_power(power)
            bulb.update_ha_state()

    # pylint: disable=unused-argument
    def poll(self, now):
        """Polling for the light."""
        self.probe()

    def probe(self, address=None):
        """Probe the light."""
        self._liffylights.probe(address)

def convert_rgb_to_hsv(rgb):
    """Convert Home Assistant RGB values to HSV values."""
    red, green, blue = [_ / BYTE_MAX for _ in rgb]

    hue, saturation, brightness = colorsys.rgb_to_hsv(red, green, blue)

    return [int(hue * SHORT_MAX),
            int(saturation * SHORT_MAX),
            int(brightness * SHORT_MAX)]

class LIFXLight(Light):
    """Representation of a LIFX light."""

    def __init__(self, liffy, ipaddr, name, power, hue, saturation, brightness,
                 kelvin):
        """Initialize the light."""
        _LOGGER.debug("LIFXLight: %s %s", ipaddr, name)

        self._liffylights = liffy
        self._ip = ipaddr
        self.set_name(name)
        self.set_power(power)
        self.set_color(hue, saturation, brightness, kelvin)

    @property
    def should_poll(self):
        """No polling needed for LIFX light."""
        return False

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

    @property
    def ipaddr(self):
        """Return the IP address of the device."""
        return self._ip

    @property
    def rgb_color(self):
        """Return the RGB value."""
        _LOGGER.debug(
            "rgb_color: [%d %d %d]", self._rgb[0], self._rgb[1], self._rgb[2])
        return self._rgb

    @property
    def brightness(self):
        """Return the brightness of this light between 0..255."""
        brightness = int(self._bri / (BYTE_MAX + 1))
        _LOGGER.debug("brightness: %d", brightness)
        return brightness

    @property
    def color_temp(self):
        """Return the color temperature."""
        temperature = color_temperature_kelvin_to_mired(self._kel)

        _LOGGER.debug("color_temp: %d", temperature)
        return temperature

    @property
    def is_on(self):
        """Return true if device is on."""
        _LOGGER.debug("is_on: %d", self._power)
        return self._power != 0

    @property
    def supported_features(self):
        """Flag supported features."""
        return SUPPORT_LIFX

    def turn_on(self, **kwargs):
        """Turn the device on."""
        if ATTR_TRANSITION in kwargs:
            fade = kwargs[ATTR_TRANSITION] * 1000
        else:
            fade = 0

        if ATTR_RGB_COLOR in kwargs:
            hue, saturation, brightness = \
                convert_rgb_to_hsv(kwargs[ATTR_RGB_COLOR])
        else:
            hue = self._hue
            saturation = self._sat
            brightness = self._bri

        if ATTR_BRIGHTNESS in kwargs:
            brightness = kwargs[ATTR_BRIGHTNESS] * (BYTE_MAX + 1)
        else:
            brightness = self._bri

        if ATTR_COLOR_TEMP in kwargs:
            kelvin = int(color_temperature_mired_to_kelvin(
                kwargs[ATTR_COLOR_TEMP]))
        else:
            kelvin = self._kel

        _LOGGER.debug("turn_on: %s (%d) %d %d %d %d %d",
                      self._ip, self._power,
                      hue, saturation, brightness, kelvin, fade)

        if self._power == 0:
            self._liffylights.set_power(self._ip, 65535, fade)

        self._liffylights.set_color(self._ip, hue, saturation,
                                    brightness, kelvin, fade)

    def turn_off(self, **kwargs):
        """Turn the device off."""
        if ATTR_TRANSITION in kwargs:
            fade = kwargs[ATTR_TRANSITION] * 1000
        else:
            fade = 0

        _LOGGER.debug("turn_off: %s %d", self._ip, fade)
        self._liffylights.set_power(self._ip, 0, fade)

    def set_name(self, name):
        """Set name of the light."""
        self._name = name

    def set_power(self, power):
        """Set power state value."""
        _LOGGER.debug("set_power: %d", power)
        self._power = (power != 0)

    def set_color(self, hue, sat, bri, kel):
        """Set color state values."""
        self._hue = hue
        self._sat = sat
        self._bri = bri
        self._kel = kel

        red, green, blue = colorsys.hsv_to_rgb(hue / SHORT_MAX,
                                               sat / SHORT_MAX,
                                               bri / SHORT_MAX)

        red = int(red * BYTE_MAX)
        green = int(green * BYTE_MAX)
        blue = int(blue * BYTE_MAX)

        _LOGGER.debug("set_color: %d %d %d %d [%d %d %d]",
                      hue, sat, bri, kel, red, green, blue)

        self._rgb = [red, green, blue]
<|endoftext|>


<commit_before>
"""
homeassistant.components.light.lifx
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
LIFX platform that implements lights

Configuration:

light:
  # platform name
  platform: lifx
  # optional server address
  # only needed if using more than one network interface
  # (omit if you are unsure)
  server: 192.168.1.3
  # optional broadcast address, set to reach all LIFX bulbs
  # (omit if you are unsure)
  broadcast: 192.168.1.255

"""
# pylint: disable=missing-docstring

import liffylights
import logging
import colorsys
from homeassistant.helpers.event import track_time_change
from homeassistant.components.light import \
    (Light, ATTR_BRIGHTNESS, ATTR_RGB_COLOR, ATTR_COLOR_TEMP)

_LOGGER = logging.getLogger(__name__)

REQUIREMENTS = ['liffylights==0.1']
DEPENDENCIES = []

CONF_SERVER = "server"        # server address configuration item
CONF_BROADCAST = "broadcast"  # broadcast address configuration item
SHORT_MAX = 65535             # short int maximum
BYTE_MAX = 255                # byte maximum
TEMP_MIN = 2500               # lifx minimum temperature
TEMP_MAX = 9000               # lifx maximum temperature
TEMP_MIN_HASS = 154           # home assistant minimum temperature
TEMP_MAX_HASS = 500           # home assistant maximum temperature

class lifx_api():
    def __init__(self, add_devices_callback,
                 server_addr=None, broadcast_addr=None):
        self._devices = []

        self._add_devices_callback = add_devices_callback

        self._liffylights = liffylights(self.on_device,
                                        self.on_power,
                                        self.on_color,
                                        server_addr,
                                        broadcast_addr)

    def find_bulb(self, ipaddr):
        bulb = None
        for device in self._devices:
            if device.ipaddr == ipaddr:
                bulb = device
                break
        return bulb

    def on_device(self, ipaddr, name, power, hue, sat, bri, kel):
        bulb = self.find_bulb(ipaddr)

        if bulb is None:
            bulb = LIFXLight(self._liffylights, ipaddr, name,
                             power, hue, sat, bri, kel)
            self._devices.append(bulb)
            self._add_devices_callback([bulb])

    def on_color(self, ipaddr, hue, sat, bri, kel):
        bulb = self.find_bulb(ipaddr)

        if bulb is not None:
            bulb.set_color(hue, sat, bri, kel)
            bulb.update_ha_state()

    def on_power(self, ipaddr, power):
        bulb = self.find_bulb(ipaddr)

        if bulb is not None:
            bulb.set_power(power)
            bulb.update_ha_state()

    def poll(self, now):
        self.probe()

    def probe(self, address=None):
        self._liffylights.probe(address)

    def state(self, power):
        return "on" if power else "off"

# pylint: disable=unused-argument
def setup_platform(hass, config, add_devices_callback, discovery_info=None):
    """ Set up platform. """
    server_addr = config.get(CONF_SERVER, None)
    broadcast_addr = config.get(CONF_BROADCAST, None)

    lifx_library = lifx_api(add_devices_callback, server_addr, broadcast_addr)

    # register our poll service
    track_time_change(hass, lifx_library.poll, second=10)

    lifx_library.probe()

def convert_rgb_to_hsv(rgb):
    """ Convert HASS RGB values to HSV values. """
    red, green, blue = [_ / BYTE_MAX for _ in rgb]

    hue, saturation, brightness = colorsys.rgb_to_hsv(red, green, blue)

    return [int(hue * SHORT_MAX),
            int(saturation * SHORT_MAX),
            int(brightness * SHORT_MAX)]

# pylint: disable=too-many-instance-attributes
class LIFXLight(Light):
    """ Provides LIFX light. """
    # pylint: disable=too-many-arguments
    def __init__(self, liffylights, ipaddr, name, power, hue,
                 saturation, brightness, kelvin):
        self._liffylights = liffylights
        self._ip = ipaddr
        self.set_name(name)
        self.set_power(power)
        self.set_color(hue, saturation, brightness, kelvin)

    @property
    def should_poll(self):
        """ No polling needed for LIFX light. """
        return False

    @property
    def name(self):
        """ Returns the name of the device. """
        return self._name

    @property
    def ipaddr(self):
        """ Returns the ip of the device. """
        return self._ip

    @property
    def rgb_color(self):
        """ Returns RGB value. """
        return self._rgb

    @property
    def brightness(self):
        """ Returns brightness of this light between 0..255. """
        return int(self._bri / (BYTE_MAX + 1))

    @property
    def color_temp(self):
        """ Returns color temperature. """
        return int(TEMP_MIN_HASS + (TEMP_MAX_HASS - TEMP_MIN_HASS) *
                   (self._kel - TEMP_MIN) / (TEMP_MAX - TEMP_MIN))

    @property
    def is_on(self):
        """ True if device is on. """
        return self._power != 0

    def turn_on(self, **kwargs):
        """ Turn the device on. """
        if ATTR_BRIGHTNESS in kwargs:
            brightness = kwargs[ATTR_BRIGHTNESS] * (BYTE_MAX + 1)
        else:
            brightness = self._bri

        if ATTR_RGB_COLOR in kwargs:
            hue, saturation, brightness = \
                convert_rgb_to_hsv(kwargs[ATTR_RGB_COLOR])
        else:
            hue = self._hue
            saturation = self._sat
            brightness = self._bri

        if ATTR_COLOR_TEMP in kwargs:
            kelvin = int(((TEMP_MAX - TEMP_MIN) *
                          (kwargs[ATTR_COLOR_TEMP] - TEMP_MIN_HASS) /
                          (TEMP_MAX_HASS - TEMP_MIN_HASS)) + TEMP_MIN)
        else:
            kelvin = self._kel

        if self._power == 0:
            self._liffylights.set_power(self._ip, 65535)

        self._liffylights.set_color(self._ip, hue, saturation,
                                    brightness, kelvin)

    def turn_off(self, **kwargs):
        """ Turn the device off. """
        self._liffylights.set_power(self._ip, 0)

    def set_name(self, name):
        """ Set name. """
        self._name = name

    def set_power(self, power):
        """ Set power state value. """
        self._power = (power != 0)

    def set_color(self, hue, sat, bri, kel):
        """ Set color state values. """
        self._hue = hue
        self._sat = sat
        self._bri = bri
        self._kel = kel

        red, green, blue = colorsys.hsv_to_rgb(hue / SHORT_MAX,
                                               sat / SHORT_MAX,
                                               bri / SHORT_MAX)

        self._rgb = [int(red * BYTE_MAX),
                     int(green * BYTE_MAX),
                     int(blue * BYTE_MAX)]
<commit_msg>Bump version liffylights<commit_after>
"""
homeassistant.components.light.lifx
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
LIFX platform that implements lights

Configuration:

light:
  # platform name
  platform: lifx
  # optional server address
  # only needed if using more than one network interface
  # (omit if you are unsure)
  server: 192.168.1.3
  # optional broadcast address, set to reach all LIFX bulbs
  # (omit if you are unsure)
  broadcast: 192.168.1.255

"""
# pylint: disable=missing-docstring

import liffylights
import logging
import colorsys
from homeassistant.helpers.event import track_time_change
from homeassistant.components.light import \
    (Light, ATTR_BRIGHTNESS, ATTR_RGB_COLOR, ATTR_COLOR_TEMP)

_LOGGER = logging.getLogger(__name__)

REQUIREMENTS = ['liffylights==0.3']
DEPENDENCIES = []

CONF_SERVER = "server"        # server address configuration item
CONF_BROADCAST = "broadcast"  # broadcast address configuration item
SHORT_MAX = 65535             # short int maximum
BYTE_MAX = 255                # byte maximum
TEMP_MIN = 2500               # lifx minimum temperature
TEMP_MAX = 9000               # lifx maximum temperature
TEMP_MIN_HASS = 154           # home assistant minimum temperature
TEMP_MAX_HASS = 500           # home assistant maximum temperature

class lifx_api():
    def __init__(self, add_devices_callback,
                 server_addr=None, broadcast_addr=None):
        self._devices = []

        self._add_devices_callback = add_devices_callback

        self._liffylights = liffylights(self.on_device,
                                        self.on_power,
                                        self.on_color,
                                        server_addr,
                                        broadcast_addr)

    def find_bulb(self, ipaddr):
        bulb = None
        for device in self._devices:
            if device.ipaddr == ipaddr:
                bulb = device
                break
        return bulb

    def on_device(self, ipaddr, name, power, hue, sat, bri, kel):
        bulb = self.find_bulb(ipaddr)

        if bulb is None:
            bulb = LIFXLight(self._liffylights, ipaddr, name,
                             power, hue, sat, bri, kel)
            self._devices.append(bulb)
            self._add_devices_callback([bulb])

    def on_color(self, ipaddr, hue, sat, bri, kel):
        bulb = self.find_bulb(ipaddr)

        if bulb is not None:
            bulb.set_color(hue, sat, bri, kel)
            bulb.update_ha_state()

    def on_power(self, ipaddr, power):
        bulb = self.find_bulb(ipaddr)

        if bulb is not None:
            bulb.set_power(power)
            bulb.update_ha_state()

    def poll(self, now):
        self.probe()

    def probe(self, address=None):
        self._liffylights.probe(address)

    def state(self, power):
        return "on" if power else "off"

# pylint: disable=unused-argument
def setup_platform(hass, config, add_devices_callback, discovery_info=None):
    """ Set up platform. """
    server_addr = config.get(CONF_SERVER, None)
    broadcast_addr = config.get(CONF_BROADCAST, None)

    lifx_library = lifx_api(add_devices_callback, server_addr, broadcast_addr)

    # register our poll service
    track_time_change(hass, lifx_library.poll, second=10)

    lifx_library.probe()

def convert_rgb_to_hsv(rgb):
    """ Convert HASS RGB values to HSV values. """
    red, green, blue = [_ / BYTE_MAX for _ in rgb]

    hue, saturation, brightness = colorsys.rgb_to_hsv(red, green, blue)

    return [int(hue * SHORT_MAX),
            int(saturation * SHORT_MAX),
            int(brightness * SHORT_MAX)]

# pylint: disable=too-many-instance-attributes
class LIFXLight(Light):
    """ Provides LIFX light. """
    # pylint: disable=too-many-arguments
    def __init__(self, liffylights, ipaddr, name, power, hue,
                 saturation, brightness, kelvin):
        self._liffylights = liffylights
        self._ip = ipaddr
        self.set_name(name)
        self.set_power(power)
        self.set_color(hue, saturation, brightness, kelvin)

    @property
    def should_poll(self):
        """ No polling needed for LIFX light. """
        return False

    @property
    def name(self):
        """ Returns the name of the device. """
        return self._name

    @property
    def ipaddr(self):
        """ Returns the ip of the device. """
        return self._ip

    @property
    def rgb_color(self):
        """ Returns RGB value. """
        return self._rgb

    @property
    def brightness(self):
        """ Returns brightness of this light between 0..255. """
        return int(self._bri / (BYTE_MAX + 1))

    @property
    def color_temp(self):
        """ Returns color temperature. """
        return int(TEMP_MIN_HASS + (TEMP_MAX_HASS - TEMP_MIN_HASS) *
                   (self._kel - TEMP_MIN) / (TEMP_MAX - TEMP_MIN))

    @property
    def is_on(self):
        """ True if device is on. """
        return self._power != 0

    def turn_on(self, **kwargs):
        """ Turn the device on. """
        if ATTR_BRIGHTNESS in kwargs:
            brightness = kwargs[ATTR_BRIGHTNESS] * (BYTE_MAX + 1)
        else:
            brightness = self._bri

        if ATTR_RGB_COLOR in kwargs:
            hue, saturation, brightness = \
                convert_rgb_to_hsv(kwargs[ATTR_RGB_COLOR])
        else:
            hue = self._hue
            saturation = self._sat
            brightness = self._bri

        if ATTR_COLOR_TEMP in kwargs:
            kelvin = int(((TEMP_MAX - TEMP_MIN) *
                          (kwargs[ATTR_COLOR_TEMP] - TEMP_MIN_HASS) /
                          (TEMP_MAX_HASS - TEMP_MIN_HASS)) + TEMP_MIN)
        else:
            kelvin = self._kel

        if self._power == 0:
            self._liffylights.set_power(self._ip, 65535)

        self._liffylights.set_color(self._ip, hue, saturation,
                                    brightness, kelvin)

    def turn_off(self, **kwargs):
        """ Turn the device off. """
        self._liffylights.set_power(self._ip, 0)

    def set_name(self, name):
        """ Set name. """
        self._name = name

    def set_power(self, power):
        """ Set power state value. """
        self._power = (power != 0)

    def set_color(self, hue, sat, bri, kel):
        """ Set color state values. """
        self._hue = hue
        self._sat = sat
        self._bri = bri
        self._kel = kel

        red, green, blue = colorsys.hsv_to_rgb(hue / SHORT_MAX,
                                               sat / SHORT_MAX,
                                               bri / SHORT_MAX)

        self._rgb = [int(red * BYTE_MAX),
                     int(green * BYTE_MAX),
                     int(blue * BYTE_MAX)]
<|endoftext|>