<commit_before>import csv, re, sqlite3, types

#colors = [['Orange Red', '#FF4500'], ['Gold', '#FFD700'], ['Orange', '#FFA500'], ['Tomato', '#FF6347'], ['Deep Pink', '#FF1493'], ['Magenta', '#FF00FF'], ['Salmon', '#FA8072'], ['Sandy Brown', '#F4A460'], ['Khaki', '#F0E68C'], ['Light Cyan', '#E0FFFF'], ['Yellow Green', '#9ACD32'], ['Pale Green', '#98FB98'], ['Dark Violet', '#9400D3'], ['Medium Purple', '#9370DB'], ['Sky Blue', '#87CEEB'], ['Crimson', '#DC143C'], ['Olive', '#808000'], ['Slate Gray', '#708090'], ['Dim Gray', '#696969'], ['Dark Olive Green', '#556B2F'], ['Steel Blue', '#4682B4'], ['Aqua', '#00FFFF'], ['Lime', '#00FF00'], ['Deep Sky Blue', '#00BFFF'], ['Teal', '#008080'], ['Dark Green', '#006400'], ['Medium Blue', '#0000CD'], ['Spring Green', '#00FF7F'], ['Violet', '#EE82EE'], ['Light Blue', '#ADD8E6'], ['Light Grey', '#D3D3D3'], ['Light Pink', '#FFB6C1'], ['Light Salmon', '#FFA07A'], ['Light Steel Blue', '#B0C4DE']]
colors = [['Orange Red', '#FF4500'], ['Gold', '#FFD700'], ['Orange', '#FFA500'], ['Tomato', '#FF6347'], ['Deep Pink', '#FF1493'], ['Magenta', '#FF00FF'], ['Salmon', '#FA8072'], ['Sandy Brown', '#F4A460'], ['Khaki', '#F0E68C'], ['Yellow Green', '#9ACD32'], ['Pale Green', '#98FB98'], ['Dark Violet', '#9400D3'], ['Medium Purple', '#9370DB'], ['Crimson', '#DC143C'], ['Olive', '#808000'], ['Slate Gray', '#708090'], ['Dim Gray', '#696969'], ['Dark Olive Green', '#556B2F'], ['Steel Blue', '#4682B4'], ['Lime', '#00FF00'], ['Deep Sky Blue', '#00BFFF'], ['Teal', '#008080'], ['Dark Green', '#006400'], ['Medium Blue', '#0000CD'], ['Spring Green', '#00FF7F'], ['Light Grey', '#D3D3D3'], ['Light Pink', '#FFB6C1'], ['Light Salmon', '#FFA07A']]

def dateVert(text):
    text = str(text);
    #date structure like 1-Jan-00
    date = re.findall("([0-9]{1,2})[-]([A-Z]{3})[-]([0-9]{2})", text, re.I)
    if len(date)==1:
        mon = {"jan":"01", "feb":"02", "mar":"03", "apr":"04", "may":"05", "jun":"06", "jul":"07", "aug":"08", "sep":"09", "oct":"10", "nov":"11", "dec":"12"}
        yr = ((int)(date[0][2])>=50) and "19" or "20"; #assuming 50-99 is 1900s
        return "%s%s%s%0.2d" % (yr, date[0][2], mon[date[0][1].lower()], int(date[0][0]))
    else:
        #date structure like 1/10/2001
        date = re.findall("(1[0-2]|0?[0-9])[/]([0-3]?[0-9])[/](1[7-9][0-9]{2}|20[0-9]{2})", text)
        if len(date)>0:
            date = [int(x) for x in date[0]]
        else:
            #date structure like 20010110
            if text.isdigit() and len(text)==8 :
                date = [int(text[4:6]), int(text[6:8]), int(text[0:4])]
        if len(date)==3:
            return "%0.4d-%0.2d-%0.2d" % (date[2], date[0], date[1])
        else:
            return text

def patSimple(patent):
    patent = str(patent)
    import re
    pat = re.sub("[^A-Za-z0-9]", "", patent)
    letters = re.findall("[A-Za-z]", pat)
    letters = "".join(letters)
    digits = pat.replace(letters, "")
    if digits.isdigit():
        return '%s%d' % (letters, (int)(digits))
    else:
        return pat

def pat8char(patent):
    patent = str(patent)
    import re
    pat = re.sub("[^A-Za-z0-9]", "", patent)
    letters = re.findall("[A-Za-z]", pat)
    letters = "".join(letters)
    digits = pat.replace(letters, "")
    if digits.isdigit():
        return '%s%s' % (letters, ("%%0.%dd" % (8-len(letters))) % ((int)(digits)))
    else:
        return pat

def patVert(patent, country):
    import re
    patent = str(patent)
    if country=="US":
        if patent.find("/")>0:
            return patent #application
        else:
            if len(patent)==8:
                return patent
            else:
                patTyp = re.findall("[A-Z]+", patent)
                patNum = re.findall("[0-9]+", patent)
                if len(patTyp)==0:
                    patTyp = [""]
                return "%s%s" % (patTyp[0], "%s%s" % ("0"*(8-len(patTyp[0])-len(patNum[0])), patNum[0]))
    else:
        return patent #foreign

def patType(text):
    text = str(text)
    typ = text[0]
    return typ.isdigit() and "U" or typ

def colGrad(col1="#000000", col2="#FF0000", pct=50):
    r = hex((int(col2[1:3], 16) - int(col1[1:3], 16))*pct/100 + int(col1[1:3], 16))[-2:]
    g = hex((int(col2[3:5], 16) - int(col1[3:5], 16))*pct/100 + int(col1[3:5], 16))[-2:]
    b = hex((int(col2[5:7], 16) - int(col1[5:7], 16))*pct/100 + int(col1[5:7], 16))[-2:]
    return ("#%s%s%s" % (r, g, b)).replace("x", "0")

def csvInput(fname):
    return [x for x in csv.reader(open(fname, "rb"))]

def ascit(x, strict=True):
    import unicodedata
    x = x.upper()
    #Solves that {UMLAUT OVER (A)}
    x = re.sub(r"[{].*?[(].*?[)].*?[}]", lambda(x):re.findall("[(](.*?)[)]", x.group())[0], x)
    #remove space(s) + punctuation
    x = re.sub(r" *?[,|-] *?", lambda(x):re.findall(r"[,|-]", x.group())[0], x)
    if strict:
        #remove stuff in between (), {}
        x = re.sub(r"[(].*?[)]|[{].*?[}]", "", x)
        #remove periods, ampersand, etc
        ##x = re.sub(r"[!@#$%^&*.,(){}]", "", x)
        x = re.sub(r"[^A-Za-z0-9 ]", " ", x)
    x = re.sub(r"  +", " ", x)

    #remove duplicates
    x = re.sub(r"[ ,|-]{2,}", lambda(x):re.findall(r"[ ,|-]", x.group())[0], x)
    #remove all unicode
    x = unicodedata.normalize('NFKD', unicode(x)).encode('ascii', 'ignore')
    return x.strip()

def jarow(s1,s2):
    try:
        s1 = s1.upper()
        s2 = s2.upper()
        if s1==s2:
            return 1.0
        if s1=="" or s2=="":
            return 0.0
        short, long = len(s1)>len(s2) and [s2, s1] or [s1, s2]
        for l in range(0, min(5, len(short))):
          if short[l] != long[l]:
            break
        mtch = ""
        mtch2=[]
        dist = len(long)/2-1
        m = 0.0
        for i, x in enumerate(long):
          jx, jy = (lambda x,y: x==y and (x,y+1) or (x,y))(max(0, i-dist), min(len(short), i+dist))
          for j in range(jx, jy):
            if j<len(short) and x == short[j]:
              m+=1
              mtch+=x
              mtch2.extend([[j,x]])
              short=short[:j]+"*"+short[min(len(short), j+1):]
              break
        mtch2 = "".join(x[1] for x in sorted(mtch2))
        t = 0.0
        for i in range(0, len(mtch)):
          if mtch[i]!=mtch2[i]:
            t += 0.5

        d = 0.1
        # this is the jaro-distance
        if m==0:
          d_j = 0
        else:
          d_j = 1/3.0 * ((m/len(short)) + (m/len(long)) + ((m - t)/m))
        return d_j + (l * d * (1 - d_j))
    except:
        return 0

#SPECIFICALLY FOR SEN
def invComp(s1, s2):
    sX = re.split(r" ?[.,] ?", s1)
    sY = re.split(r" ?[.,] ?", s2)
    if len(sX)==2 and len(sY)==2:
        if sX[1].find(sY[1])>-1 or sY[1].find(sX[1])>-1:
            llen = [min(len(sX[i]), len(sY[i])) for i in range(0,2)]
            return sum([jarow(sX[i], sY[i])*llen[i] for i in range(0,2)])/sum(llen)
        else:
            return 0.0
    else:
        return jarow(s1, s2)

def invXMtch(st):
    sts = st.split("|")
    ok = False
    for i in range(0,len(sts)-1):
        for j in range(i+1, len(sts)):
            if invComp(sts[i], sts[j])==0.0:
                ok = True
                break
    return ok

#---------------------

class uQvals:
    def __init__(self):
        self.dList=[]
    def step(self, value):
        self.dList.append(value.upper())
    def finalize(self):
        out = list(set(self.dList))
        return len(out)>1 and "|".join(out) or ""

def quickSQL(c, data, table="", header=False):
    if table=="":
        table = "debug%d" % len([x[0] for x in c.execute("SELECT tbl_name FROM sqlite_master WHERE type='table' order by tbl_name") if len(re.findall(r"debug[0-9]+", x[0]))>0])
    vTp = {types.StringType:"VARCHAR", types.UnicodeType:"VARCHAR", types.IntType:"INTEGER", types.FloatType: "REAL"}
    if header==False:
        c.execute("CREATE TABLE IF NOT EXISTS %s (%s)" % (table, ", ".join(["v%d %s" % (i, vTp[type(x)]) for i,x in enumerate(data[0])])))
        c.executemany("INSERT INTO %s VALUES (%s)" % (table, ", ".join(["?"]*len(data[0]))), data)
    else:
        c.execute("CREATE TABLE IF NOT EXISTS %s (%s)" % (table, ", ".join(["%s %s" % (data[0][i], vTp[type(x)]) for i,x in enumerate(data[1])])))
        c.executemany("INSERT INTO %s VALUES (%s)" % (table, ", ".join(["?"]*len(data[0]))), data[1:])

def flatten(l, ltypes=(list, tuple)):
    ltype = type(l)
    l = list(l)
    i = 0
    while i < len(l):
        while isinstance(l[i], ltypes):
            if not l[i]:
                l.pop(i)
                i -= 1
                break
            else:
                l[i:i + 1] = l[i]
        i += 1
    return ltype(l)

def freq(ln):
    return sorted([[x, ln.count(x)] for x in set(ln)], reverse=True, key=lambda(x): x[1])
<commit_msg>removed ascit function as it was not being used in senAdd<commit_after>import csv, re, sqlite3, types

#colors = [['Orange Red', '#FF4500'], ['Gold', '#FFD700'], ['Orange', '#FFA500'], ['Tomato', '#FF6347'], ['Deep Pink', '#FF1493'], ['Magenta', '#FF00FF'], ['Salmon', '#FA8072'], ['Sandy Brown', '#F4A460'], ['Khaki', '#F0E68C'], ['Light Cyan', '#E0FFFF'], ['Yellow Green', '#9ACD32'], ['Pale Green', '#98FB98'], ['Dark Violet', '#9400D3'], ['Medium Purple', '#9370DB'], ['Sky Blue', '#87CEEB'], ['Crimson', '#DC143C'], ['Olive', '#808000'], ['Slate Gray', '#708090'], ['Dim Gray', '#696969'], ['Dark Olive Green', '#556B2F'], ['Steel Blue', '#4682B4'], ['Aqua', '#00FFFF'], ['Lime', '#00FF00'], ['Deep Sky Blue', '#00BFFF'], ['Teal', '#008080'], ['Dark Green', '#006400'], ['Medium Blue', '#0000CD'], ['Spring Green', '#00FF7F'], ['Violet', '#EE82EE'], ['Light Blue', '#ADD8E6'], ['Light Grey', '#D3D3D3'], ['Light Pink', '#FFB6C1'], ['Light Salmon', '#FFA07A'], ['Light Steel Blue', '#B0C4DE']]
colors = [['Orange Red', '#FF4500'], ['Gold', '#FFD700'], ['Orange', '#FFA500'], ['Tomato', '#FF6347'], ['Deep Pink', '#FF1493'], ['Magenta', '#FF00FF'], ['Salmon', '#FA8072'], ['Sandy Brown', '#F4A460'], ['Khaki', '#F0E68C'], ['Yellow Green', '#9ACD32'], ['Pale Green', '#98FB98'], ['Dark Violet', '#9400D3'], ['Medium Purple', '#9370DB'], ['Crimson', '#DC143C'], ['Olive', '#808000'], ['Slate Gray', '#708090'], ['Dim Gray', '#696969'], ['Dark Olive Green', '#556B2F'], ['Steel Blue', '#4682B4'], ['Lime', '#00FF00'], ['Deep Sky Blue', '#00BFFF'], ['Teal', '#008080'], ['Dark Green', '#006400'], ['Medium Blue', '#0000CD'], ['Spring Green', '#00FF7F'], ['Light Grey', '#D3D3D3'], ['Light Pink', '#FFB6C1'], ['Light Salmon', '#FFA07A']]

def dateVert(text):
    text = str(text);
    #date structure like 1-Jan-00
    date = re.findall("([0-9]{1,2})[-]([A-Z]{3})[-]([0-9]{2})", text, re.I)
    if len(date)==1:
        mon = {"jan":"01", "feb":"02", "mar":"03", "apr":"04", "may":"05", "jun":"06", "jul":"07", "aug":"08", "sep":"09", "oct":"10", "nov":"11", "dec":"12"}
        yr = ((int)(date[0][2])>=50) and "19" or "20"; #assuming 50-99 is 1900s
        return "%s%s%s%0.2d" % (yr, date[0][2], mon[date[0][1].lower()], int(date[0][0]))
    else:
        #date structure like 1/10/2001
        date = re.findall("(1[0-2]|0?[0-9])[/]([0-3]?[0-9])[/](1[7-9][0-9]{2}|20[0-9]{2})", text)
        if len(date)>0:
            date = [int(x) for x in date[0]]
        else:
            #date structure like 20010110
            if text.isdigit() and len(text)==8 :
                date = [int(text[4:6]), int(text[6:8]), int(text[0:4])]
        if len(date)==3:
            return "%0.4d-%0.2d-%0.2d" % (date[2], date[0], date[1])
        else:
            return text

def patSimple(patent):
    patent = str(patent)
    import re
    pat = re.sub("[^A-Za-z0-9]", "", patent)
    letters = re.findall("[A-Za-z]", pat)
    letters = "".join(letters)
    digits = pat.replace(letters, "")
    if digits.isdigit():
        return '%s%d' % (letters, (int)(digits))
    else:
        return pat

def pat8char(patent):
    patent = str(patent)
    import re
    pat = re.sub("[^A-Za-z0-9]", "", patent)
    letters = re.findall("[A-Za-z]", pat)
    letters = "".join(letters)
    digits = pat.replace(letters, "")
    if digits.isdigit():
        return '%s%s' % (letters, ("%%0.%dd" % (8-len(letters))) % ((int)(digits)))
    else:
        return pat

def patVert(patent, country):
    import re
    patent = str(patent)
    if country=="US":
        if patent.find("/")>0:
            return patent #application
        else:
            if len(patent)==8:
                return patent
            else:
                patTyp = re.findall("[A-Z]+", patent)
                patNum = re.findall("[0-9]+", patent)
                if len(patTyp)==0:
                    patTyp = [""]
                return "%s%s" % (patTyp[0], "%s%s" % ("0"*(8-len(patTyp[0])-len(patNum[0])), patNum[0]))
    else:
        return patent #foreign

def patType(text):
    text = str(text)
    typ = text[0]
    return typ.isdigit() and "U" or typ

def colGrad(col1="#000000", col2="#FF0000", pct=50):
    r = hex((int(col2[1:3], 16) - int(col1[1:3], 16))*pct/100 + int(col1[1:3], 16))[-2:]
    g = hex((int(col2[3:5], 16) - int(col1[3:5], 16))*pct/100 + int(col1[3:5], 16))[-2:]
    b = hex((int(col2[5:7], 16) - int(col1[5:7], 16))*pct/100 + int(col1[5:7], 16))[-2:]
    return ("#%s%s%s" % (r, g, b)).replace("x", "0")

def csvInput(fname):
    return [x for x in csv.reader(open(fname, "rb"))]

def jarow(s1,s2):
    try:
        s1 = s1.upper()
        s2 = s2.upper()
        if s1==s2:
            return 1.0
        if s1=="" or s2=="":
            return 0.0
        short, long = len(s1)>len(s2) and [s2, s1] or [s1, s2]
        for l in range(0, min(5, len(short))):
          if short[l] != long[l]:
            break
        mtch = ""
        mtch2=[]
        dist = len(long)/2-1
        m = 0.0
        for i, x in enumerate(long):
          jx, jy = (lambda x,y: x==y and (x,y+1) or (x,y))(max(0, i-dist), min(len(short), i+dist))
          for j in range(jx, jy):
            if j<len(short) and x == short[j]:
              m+=1
              mtch+=x
              mtch2.extend([[j,x]])
              short=short[:j]+"*"+short[min(len(short), j+1):]
              break
        mtch2 = "".join(x[1] for x in sorted(mtch2))
        t = 0.0
        for i in range(0, len(mtch)):
          if mtch[i]!=mtch2[i]:
            t += 0.5

        d = 0.1
        # this is the jaro-distance
        if m==0:
          d_j = 0
        else:
          d_j = 1/3.0 * ((m/len(short)) + (m/len(long)) + ((m - t)/m))
        return d_j + (l * d * (1 - d_j))
    except:
        return 0

#SPECIFICALLY FOR SEN
def invComp(s1, s2):
    sX = re.split(r" ?[.,] ?", s1)
    sY = re.split(r" ?[.,] ?", s2)
    if len(sX)==2 and len(sY)==2:
        if sX[1].find(sY[1])>-1 or sY[1].find(sX[1])>-1:
            llen = [min(len(sX[i]), len(sY[i])) for i in range(0,2)]
            return sum([jarow(sX[i], sY[i])*llen[i] for i in range(0,2)])/sum(llen)
        else:
            return 0.0
    else:
        return jarow(s1, s2)

def invXMtch(st):
    sts = st.split("|")
    ok = False
    for i in range(0,len(sts)-1):
        for j in range(i+1, len(sts)):
            if invComp(sts[i], sts[j])==0.0:
                ok = True
                break
    return ok

#---------------------

class uQvals:
    def __init__(self):
        self.dList=[]
    def step(self, value):
        self.dList.append(value.upper())
    def finalize(self):
        out = list(set(self.dList))
        return len(out)>1 and "|".join(out) or ""

def quickSQL(c, data, table="", header=False):
    if table=="":
        table = "debug%d" % len([x[0] for x in c.execute("SELECT tbl_name FROM sqlite_master WHERE type='table' order by tbl_name") if len(re.findall(r"debug[0-9]+", x[0]))>0])
    vTp = {types.StringType:"VARCHAR", types.UnicodeType:"VARCHAR", types.IntType:"INTEGER", types.FloatType: "REAL"}
    if header==False:
        c.execute("CREATE TABLE IF NOT EXISTS %s (%s)" % (table, ", ".join(["v%d %s" % (i, vTp[type(x)]) for i,x in enumerate(data[0])])))
        c.executemany("INSERT INTO %s VALUES (%s)" % (table, ", ".join(["?"]*len(data[0]))), data)
    else:
        c.execute("CREATE TABLE IF NOT EXISTS %s (%s)" % (table, ", ".join(["%s %s" % (data[0][i], vTp[type(x)]) for i,x in enumerate(data[1])])))
        c.executemany("INSERT INTO %s VALUES (%s)" % (table, ", ".join(["?"]*len(data[0]))), data[1:])

def flatten(l, ltypes=(list, tuple)):
    ltype = type(l)
    l = list(l)
    i = 0
    while i < len(l):
        while isinstance(l[i], ltypes):
            if not l[i]:
                l.pop(i)
                i -= 1
                break
            else:
                l[i:i + 1] = l[i]
        i += 1
    return ltype(l)

def freq(ln):
    return sorted([[x, ln.count(x)] for x in set(ln)], reverse=True, key=lambda(x): x[1])
<|endoftext|>


<commit_before>"""Functions to store a submission and send it for evaluation"""

import shutil
import os

from . import sql, VmcheckerError

SOURCES_FILE = 'sources.zip'

def store(archive, assignment_id, user_id, upload = None):
    """Stores archive into the corresponding location.

    Submission is stored at:
        <assignment.repository>/<submission_id>/<SOURCES_FILE>

    @param archive path to the archive
    @param assignment_id the assignment solved
    @param user_id the author of the submission
    @param upload if not None a `datetime' object containg the upload time
    @return a pair (submission_id, path)

    """

    try:
        transaction = sql.connection.begin()

        # reads the assignment from the repository
        select = sql.assignments.select().where(
                sql.assignments.c.id == assignment_id)
        assignment = sql.connection.execute(select).fetchone()

        # creates a new submission
        insert = sql.submissions.insert().values(
                assignment_id = assignment_id,
                user_id = user_id,
                upload = upload,
                grade = assignment.maxgrade)
        result = sql.connection.execute(insert)

        submission_id = result.last_inserted_ids()[0]
        location = os.path.join(assignment.repository, str(submission_id))

        if os.path.lexists(location):
            # cleans old files left from a failed
            # transaction
            shutil.rmtree(location)

        # copy fles
        os.makedirs(location)
        shutil.copy(archive, os.path.join(location, SOURCES_FILE))

        transaction.commit()
        return submission_id, location
    except VmcheckerError:
        transaction.rollback()
        raise

<commit_msg>archive -> sources<commit_after>"""Functions to store a submission and send it for evaluation"""

import shutil
import os

from . import sql, VmcheckerError

SOURCES_FILE = 'sources.zip'

def store(sources, assignment_id, user_id, upload = None):
    """Stores sources into the corresponding location.

    Submission is stored at:
        <assignment.repository>/<submission_id>/<SOURCES_FILE>

    @param sources path to the sources
    @param assignment_id the assignment solved
    @param user_id the author of the submission
    @param upload if not None a `datetime' object containg the upload time
    @return a pair (submission_id, path)

    """

    try:
        transaction = sql.connection.begin()

        # reads the assignment from the repository
        select = sql.assignments.select().where(
                sql.assignments.c.id == assignment_id)
        assignment = sql.connection.execute(select).fetchone()

        # creates a new submission
        insert = sql.submissions.insert().values(
                assignment_id = assignment_id,
                user_id = user_id,
                upload = upload,
                grade = assignment.maxgrade)
        result = sql.connection.execute(insert)

        submission_id = result.last_inserted_ids()[0]
        location = os.path.join(assignment.repository, str(submission_id))

        if os.path.lexists(location):
            # cleans old files left from a failed
            # transaction
            shutil.rmtree(location)

        # copy fles
        os.makedirs(location)
        shutil.copy(sources, os.path.join(location, SOURCES_FILE))

        transaction.commit()
        return submission_id, location
    except VmcheckerError:
        transaction.rollback()
        raise
<|endoftext|>


<commit_before>from __future__ import absolute_import, division, print_function

from glue.core import Subset
from glue.external.echo import (CallbackProperty, SelectionCallbackProperty,
                                delay_callback)
from glue.core.state_objects import StateAttributeLimitsHelper
from glue.core.data_combo_helper import ComponentIDComboHelper
from ..common.layer_state import VispyLayerState

__all__ = ['VolumeLayerState']

class VolumeLayerState(VispyLayerState):
    """
    A state object for volume layers
    """

    attribute = SelectionCallbackProperty()
    vmin = CallbackProperty()
    vmax = CallbackProperty()
    subset_mode = CallbackProperty('data')
    limits_cache = CallbackProperty({})

    def __init__(self, layer=None, **kwargs):

        super(VolumeLayerState, self).__init__(layer=layer)

        if self.layer is not None:

            self.color = self.layer.style.color
            self.alpha = self.layer.style.alpha

        self.att_helper = ComponentIDComboHelper(self, 'attribute')

        self.lim_helper = StateAttributeLimitsHelper(self, attribute='attribute',
                                                     lower='vmin', upper='vmax',
                                                     cache=self.limits_cache)

        self.add_callback('layer', self._on_layer_change)
        if layer is not None:
            self._on_layer_change()

        if isinstance(self.layer, Subset):
            self.vmin = 0
            self.vmin = 1

        self.update_from_dict(kwargs)

    def _on_layer_change(self, layer=None):

        with delay_callback(self, 'vmin', 'vmin'):

            if self.layer is None:
                self.att_helper.set_multiple_data([])
            else:
                self.att_helper.set_multiple_data([self.layer])

    def update_priority(self, name):
        return 0 if name.endswith(('vmin', 'vmax')) else 1
<commit_msg>Fix typo in volume layer state<commit_after>from __future__ import absolute_import, division, print_function

from glue.core import Subset
from glue.external.echo import (CallbackProperty, SelectionCallbackProperty,
                                delay_callback)
from glue.core.state_objects import StateAttributeLimitsHelper
from glue.core.data_combo_helper import ComponentIDComboHelper
from ..common.layer_state import VispyLayerState

__all__ = ['VolumeLayerState']

class VolumeLayerState(VispyLayerState):
    """
    A state object for volume layers
    """

    attribute = SelectionCallbackProperty()
    vmin = CallbackProperty()
    vmax = CallbackProperty()
    subset_mode = CallbackProperty('data')
    limits_cache = CallbackProperty({})

    def __init__(self, layer=None, **kwargs):

        super(VolumeLayerState, self).__init__(layer=layer)

        if self.layer is not None:

            self.color = self.layer.style.color
            self.alpha = self.layer.style.alpha

        self.att_helper = ComponentIDComboHelper(self, 'attribute')

        self.lim_helper = StateAttributeLimitsHelper(self, attribute='attribute',
                                                     lower='vmin', upper='vmax',
                                                     cache=self.limits_cache)

        self.add_callback('layer', self._on_layer_change)
        if layer is not None:
            self._on_layer_change()

        if isinstance(self.layer, Subset):
            self.vmin = 0
            self.vmax = 1

        self.update_from_dict(kwargs)

    def _on_layer_change(self, layer=None):

        with delay_callback(self, 'vmin', 'vmin'):

            if self.layer is None:
                self.att_helper.set_multiple_data([])
            else:
                self.att_helper.set_multiple_data([self.layer])

    def update_priority(self, name):
        return 0 if name.endswith(('vmin', 'vmax')) else 1
<|endoftext|>


<commit_before>"""
A simple wrapper around the 'experimental' Google Places API, documented
here: http://code.google.com/apis/maps/documentation/places/. This library
also makes use of the v3 Maps API for geocoding.

Prerequisites: A Google API key with Places activated against it. Please
check the Google API console, here: http://code.google.com/apis/console

NOTE: Please ensure that you read the Google terms of service (labeled 'Limits
and Requirements' on the documentation url) prior to using this library in a
production environment.

@author: sam@slimkrazy.com
"""

try:
    import json
except ImportError:
    import simplejson as json
import urllib
import urllib2

import types

__all__ = ['GooglePlaces', 'GooglePlacesError', 'GooglePlacesAttributeError',
           'geocode_location']
__version__ = '0.8.0'
__author__ = 'Samuel Adu'
__email__ = 'sam@slimkrazy.com'

def _fetch_remote_json(service_url, params={}, use_http_post=False):
    """Retrieves a JSON object from a URL."""
    if not use_http_post:
        encoded_data = urllib.urlencode(params)
        query_url = (service_url if service_url.endswith('?') else
                     '%s?' % service_url)
        request_url = query_url + encoded_data
        request = urllib2.Request(request_url)
    else:
        request_url = service_url
        request = urllib2.Request(service_url, data=params)
    response = urllib2.urlopen(request)
    return (request_url, json.load(response))

def geocode_location(location, sensor=False):
    """Converts a human-readable location to lat-lng.

    Returns a dict with lat and lng keys.

    keyword arguments:
    location -- A human-readable location, e.g 'London, England'
    sensor   -- Boolean flag denoting if the location came from a device using
                its' location sensor (default False)

    raises:
    GooglePlacesError -- if the geocoder fails to find a location.
    """

    url, geo_response = _fetch_remote_json(
            GooglePlaces.GEOCODE_API_URL,
            {'address': location, 'sensor': str(sensor).lower()})
    _validate_response(url, geo_response)
    if geo_response['status'] == GooglePlaces.RESPONSE_STATUS_ZERO_RESULTS:
        error_detail = ('Lat/Lng for location \'%s\' can\'t be determined.' %
                        location)
        raise GooglePlacesError, error_detail
    return geo_response['results'][0]['geometry']['location']

def _get_place_details(reference, api_key, sensor=False):
    """Gets a detailed place response.

    keyword arguments:
    reference -- The unique Google reference for the required place.
    """
    url, detail_response = _fetch_remote_json(GooglePlaces.DETAIL_API_URL,
                                              {'reference': reference,
                                               'sensor': str(sensor).lower(),
                                               'key': api_key})
    _validate_response(url, detail_response)
    return detail_response['result']

def _validate_response(url, response):
    """Validates that the response from Google was successful."""
    if response['status'] not in [GooglePlaces.RESPONSE_STATUS_OK,
                                  GooglePlaces.RESPONSE_STATUS_ZERO_RESULTS]:
        error_detail = ('Request to URL %s failed with response code: %s' %
                        (url, response['status']))
        raise GooglePlacesError, error_detail

class GooglePlacesError(Exception):
    pass

class GooglePlacesAttributeError(AttributeError):
    """Exception thrown when a detailed property is unavailable.

    A search query from the places API returns only a summary of the Place.
    in order to get full details, a further API call must be made using
    the place reference. This exception will be thrown when a property made
    available by only the detailed API call is looked up against the summary
    object.

    An explicit call to get_details() must be made on the summary object in
    order to convert a summary object to a detailed object.
    """
    # I could spend forever muling between this design decision and creating
    # a PlaceSummary object as well as a Place object. I'm leaning towards this
    # method in order to keep the API as simple as possible.
    pass

class GooglePlaces(object):
    """A wrapper around the Google Places Query API."""

    GEOCODE_API_URL = 'https://maps.googleapis.com/maps/api/geocode/json?'
    QUERY_API_URL = 'https://maps.googleapis.com/maps/api/place/search/json?'
    DETAIL_API_URL = ('https://maps.googleapis.com/maps/api/place/details/' +
                      'json?')
    CHECKIN_API_URL = ('https://maps.googleapis.com/maps/api/place/check-in/' +
                       'json?sensor=%s&key=%s')
    MAXIMUM_SEARCH_RADIUS = 50000
    RESPONSE_STATUS_OK = 'OK'
    RESPONSE_STATUS_ZERO_RESULTS = 'ZERO_RESULTS'

    def __init__(self, api_key):
        self._api_key = api_key
        self._sensor = False
        self._request_params = None

    def query(self, location=None, lat_lng=None, keyword=None, radius=3200,
              rankby="prominence", sensor=False, types=[]):
        """Perform a search using the Google Places API.

        One of either location or lat_lng are required, the rest of the keyword
        arguments are optional.

        keyword arguments:
        location -- A human readable location, e.g 'London, England'
                    (default None)
        lat_lng  -- A dict containing the following keys: lat, lng
                    (default None)
        keyword  -- A term to be matched against all available fields, including
                    but not limited to name, type, and address (default None)
        radius   -- The radius (in meters) around the location/lat_lng to
                    restrict the search to. The maximum is 50000 meters.
                    (default 3200)
        rankby   -- Specifies the order in which results are listed :
                    'prominence' (default) or 'distance' (imply no radius argument)
        sensor   -- Indicates whether or not the Place request came from a
                    device using a location sensor (default False)
        types    -- An optional list of types, restricting the results to
                    Places (default [])
        """
        if location is None and lat_lng is None:
            raise ValueError('One of location or lat_lng must be passed in.')
        self._sensor = sensor
        self._lat_lng = (lat_lng if lat_lng is not None
                         else geocode_location(location))
        radius = (radius if radius <= GooglePlaces.MAXIMUM_SEARCH_RADIUS
                  else GooglePlaces.MAXIMUM_SEARCH_RADIUS)
        lat_lng_str = '%(lat)s,%(lng)s' % self._lat_lng
        self._request_params = {'location': lat_lng_str}
        if rankby == "prominence":
            self._request_params['radius'] = radius
        else:
            self._request_params['rankby'] = rankby
        if len(types) > 0:
            self._request_params['types'] = '|'.join(types)
        if keyword is not None:
            self._request_params['keyword'] = keyword
        self._add_required_param_keys()
        url, places_response = _fetch_remote_json(
                GooglePlaces.QUERY_API_URL, self._request_params)
        _validate_response(url, places_response)
        return GooglePlacesSearchResult(self, places_response)

    def checkin(self, reference, sensor=False):
        """Checks in a user to a place.

        keyword arguments:
        reference -- The unique Google reference for the relevant place.
        sensor    -- Boolean flag denoting if the location came from a
                         device using its' location sensor (default False)
        """
        data = {'reference': reference}
        url, checkin_response = _fetch_remote_json(
                GooglePlaces.CHECKIN_API_URL % (str(sensor).lower(),
                        self.api_key), json.dumps(data), use_http_post=True)
        _validate_response(url, checkin_response)

    def get_place(self, reference, sensor=False):
        """Gets a detailed place object.

        keyword arguments:
        reference -- The unique Google reference for the required place.
        sensor    -- Boolean flag denoting if the location came from a
                         device using its' location sensor (default False)
        """
        place_details = _get_place_details(reference, self.api_key, sensor)
        return Place(self, place_details)

    def _add_required_param_keys(self):
        self._request_params['key'] = self.api_key
        self._request_params['sensor'] = str(self.sensor).lower()

    @property
    def request_params(self):
        return self._request_params

    @property
    def api_key(self):
        return self._api_key

    @property
    def sensor(self):
        return self._sensor

class GooglePlacesSearchResult(object):
    """Wrapper around the Google Places API query JSON response."""

    def __init__(self, query_instance, response):
        self._places = []
        for place in response['results']:
            self._places.append(Place(query_instance, place))
        self._html_attributions = response['html_attributions']

    @property
    def places(self):
        return self._places

    @property
    def html_attributions(self):
        """Returns the HTML attributions for the specified response.

        Any returned HTML attributions MUST be displayed as-is, in accordance
        with the requirements as found in the documentation. Please see the
        module comments for links to the relevant url.
        """
        return self._html_attributions

    @property
    def has_attributions(self):
        """Returns a flag denoting if the response had any html attributions."""
        return len(self.html_attributions) > 0

class Place(object):
    """
    Represents a place from the results of a Google Places API query.
    """
    def __init__(self, query_instance, place_data):
        self._query_instance = query_instance
        self._id = place_data['id']
        self._reference = place_data['reference']
        self._name = place_data['name']
        self._vicinity = place_data['vicinity']
        self._geo_location = place_data['geometry']['location']
        self._rating = place_data.get('rating')
        self._types = place_data.get('types')
        self._icon = place_data.get('icon')
        if place_data.get('address_components') is None:
            self._details = None
        else:
            self._details = place_data

    @property
    def reference(self):
        """Returns contains a unique token for the place.

        The token can be used to retrieve additional information about this
        place when invoking the getPlace method on an GooglePlaces instance.

        You can store this token and use it at any time in future to refresh
        cached data about this Place, but the same token is not guaranteed to
        be returned for any given Place across different searches."""
        return self._reference

    @property
    def id(self):
        """Returns the unique stable identifier denoting this place.

        This identifier may not be used to retrieve information about this
        place, but is guaranteed to be valid across sessions. It can be used
        to consolidate data about this Place, and to verify the identity of a
        Place across separate searches.
        """
        return self._id

    @property
    def icon(self):
        """Returns the URL of a recommended icon for display."""
        return self._icon

    @property
    def types(self):
        """Returns a list of feature types describing the given result."""
        return self._types

    @property
    def geo_location(self):
        """Returns the lat lng co-ordinates of the place.

        A dict with the keys 'lat' and 'lng' will be returned.
        """
        return self._geo_location

    @property
    def name(self):
        """Returns the human-readable name of the place."""
        return self._name

    @property
    def vicinity(self):
        """Returns a feature name of a nearby location.

        Often this feature refers to a street or neighborhood within the given
        results.
        """
        return self._vicinity

    @property
    def rating(self):
        """Returns the Place's rating, from 0.0 to 5.0, based on user reviews.

        This method will return None for places that have no rating.
        """
        return self._rating

    # The following properties require a further API call in order to be
    # available.
    @property
    def details(self):
        """Returns the JSON response from Google Places Detail search API."""
        self._validate_status()
        return self._details

    @property
    def formatted_address(self):
        """Returns a string containing the human-readable address of this place.

        Often this address is equivalent to the "postal address," which
        sometimes differs from country to country. (Note that some countries,
        such as the United Kingdom, do not allow distribution of complete postal
        addresses due to licensing restrictions.)
        """
        self._validate_status()
        return self.details.get('formatted_address')

    @property
    def local_phone_number(self):
        """Returns the Place's phone number in its local format."""
        self._validate_status()
        return self.details.get('formatted_phone_number')

    @property
    def international_phone_number(self):
        self._validate_status()
        return self.details.get('international_phone_number')

    @property
    def website(self):
        """Retuns the authoritative website for this Place."""
        self._validate_status()
        return self.details.get('website')

    @property
    def url(self):
        """Contains the official Google Place Page URL of this establishment.

        Applications must link to or embed the Google Place page on any screen
        that shows detailed results about this Place to the user.
        """
        self._validate_status()
        return self.details.get('url')

    @property
    def html_attributions(self):
        """Returns the HTML attributions for the specified response.

        Any returned HTML attributions MUST be displayed as-is, in accordance
        with the requirements as found in the documentation. Please see the
        module comments for links to the relevant url.
        """
        self._validate_status()
        return self.details.get('html_attributions', [])

    @property
    def has_attributions(self):
        """Returns a flag denoting if the response had any html attributions."""
        return (False if self._details is None else
                len(self.html_attributions) > 0)

    def checkin(self):
        """Checks in an anonynomous user in."""
        self._query_instance.checkin(self.reference,
                                     self._query_instance.sensor)

    def get_details(self):
        """Retrieves full information on the place matching the reference.

        Further attributes will be made available on the instance once this
        method has been invoked.
        """
        if self._details is None:
            self._details = _get_place_details(
                    self.reference, self._query_instance.api_key,
                    self._query_instance.sensor)

    def _validate_status(self):
        if self._details is None:
            error_detail = ('The attribute requested is only available after ' +
                    'an explicit call to get_details() is made.')
            raise GooglePlacesAttributeError, error_detail
<commit_msg>Error handle for rankby is added<commit_after>"""
A simple wrapper around the 'experimental' Google Places API, documented
here: http://code.google.com/apis/maps/documentation/places/. This library
also makes use of the v3 Maps API for geocoding.

Prerequisites: A Google API key with Places activated against it. Please
check the Google API console, here: http://code.google.com/apis/console

NOTE: Please ensure that you read the Google terms of service (labeled 'Limits
and Requirements' on the documentation url) prior to using this library in a
production environment.

@author: sam@slimkrazy.com
"""

try:
    import json
except ImportError:
    import simplejson as json
import urllib
import urllib2

import types

__all__ = ['GooglePlaces', 'GooglePlacesError', 'GooglePlacesAttributeError',
           'geocode_location']
__version__ = '0.8.0'
__author__ = 'Samuel Adu'
__email__ = 'sam@slimkrazy.com'

def _fetch_remote_json(service_url, params={}, use_http_post=False):
    """Retrieves a JSON object from a URL."""
    if not use_http_post:
        encoded_data = urllib.urlencode(params)
        query_url = (service_url if service_url.endswith('?') else
                     '%s?' % service_url)
        request_url = query_url + encoded_data
        request = urllib2.Request(request_url)
    else:
        request_url = service_url
        request = urllib2.Request(service_url, data=params)
    response = urllib2.urlopen(request)
    return (request_url, json.load(response))

def geocode_location(location, sensor=False):
    """Converts a human-readable location to lat-lng.

    Returns a dict with lat and lng keys.

    keyword arguments:
    location -- A human-readable location, e.g 'London, England'
    sensor   -- Boolean flag denoting if the location came from a device using
                its' location sensor (default False)

    raises:
    GooglePlacesError -- if the geocoder fails to find a location.
    """

    url, geo_response = _fetch_remote_json(
            GooglePlaces.GEOCODE_API_URL,
            {'address': location, 'sensor': str(sensor).lower()})
    _validate_response(url, geo_response)
    if geo_response['status'] == GooglePlaces.RESPONSE_STATUS_ZERO_RESULTS:
        error_detail = ('Lat/Lng for location \'%s\' can\'t be determined.' %
                        location)
        raise GooglePlacesError, error_detail
    return geo_response['results'][0]['geometry']['location']

def _get_place_details(reference, api_key, sensor=False):
    """Gets a detailed place response.

    keyword arguments:
    reference -- The unique Google reference for the required place.
    """
    url, detail_response = _fetch_remote_json(GooglePlaces.DETAIL_API_URL,
                                              {'reference': reference,
                                               'sensor': str(sensor).lower(),
                                               'key': api_key})
    _validate_response(url, detail_response)
    return detail_response['result']

def _validate_response(url, response):
    """Validates that the response from Google was successful."""
    if response['status'] not in [GooglePlaces.RESPONSE_STATUS_OK,
                                  GooglePlaces.RESPONSE_STATUS_ZERO_RESULTS]:
        error_detail = ('Request to URL %s failed with response code: %s' %
                        (url, response['status']))
        raise GooglePlacesError, error_detail

class GooglePlacesError(Exception):
    pass

class GooglePlacesAttributeError(AttributeError):
    """Exception thrown when a detailed property is unavailable.

    A search query from the places API returns only a summary of the Place.
    in order to get full details, a further API call must be made using
    the place reference. This exception will be thrown when a property made
    available by only the detailed API call is looked up against the summary
    object.

    An explicit call to get_details() must be made on the summary object in
    order to convert a summary object to a detailed object.
    """
    # I could spend forever muling between this design decision and creating
    # a PlaceSummary object as well as a Place object. I'm leaning towards this
    # method in order to keep the API as simple as possible.
    pass

class GooglePlaces(object):
    """A wrapper around the Google Places Query API."""

    GEOCODE_API_URL = 'https://maps.googleapis.com/maps/api/geocode/json?'
    QUERY_API_URL = 'https://maps.googleapis.com/maps/api/place/search/json?'
    DETAIL_API_URL = ('https://maps.googleapis.com/maps/api/place/details/' +
                      'json?')
    CHECKIN_API_URL = ('https://maps.googleapis.com/maps/api/place/check-in/' +
                       'json?sensor=%s&key=%s')
    MAXIMUM_SEARCH_RADIUS = 50000
    RESPONSE_STATUS_OK = 'OK'
    RESPONSE_STATUS_ZERO_RESULTS = 'ZERO_RESULTS'

    def __init__(self, api_key):
        self._api_key = api_key
        self._sensor = False
        self._request_params = None

    def query(self, location=None, lat_lng=None, keyword=None, radius=3200,
              rankby="prominence", sensor=False, types=[]):
        """Perform a search using the Google Places API.

        One of either location or lat_lng are required, the rest of the keyword
        arguments are optional.

        keyword arguments:
        location -- A human readable location, e.g 'London, England'
                    (default None)
        lat_lng  -- A dict containing the following keys: lat, lng
                    (default None)
        keyword  -- A term to be matched against all available fields, including
                    but not limited to name, type, and address (default None)
        radius   -- The radius (in meters) around the location/lat_lng to
                    restrict the search to. The maximum is 50000 meters.
                    (default 3200)
        rankby   -- Specifies the order in which results are listed :
                    'prominence' (default) or 'distance' (imply no radius argument)
        sensor   -- Indicates whether or not the Place request came from a
                    device using a location sensor (default False)
        types    -- An optional list of types, restricting the results to
                    Places (default [])
        """
        if location is None and lat_lng is None:
            raise ValueError('One of location or lat_lng must be passed in.')
        if rankby == "distance":
            if keyword is None and types == []:
                raise ValueError('When rankby = "distance", at least one in keyword or types is required.')
        self._sensor = sensor
        self._lat_lng = (lat_lng if lat_lng is not None
                         else geocode_location(location))
        radius = (radius if radius <= GooglePlaces.MAXIMUM_SEARCH_RADIUS
                  else GooglePlaces.MAXIMUM_SEARCH_RADIUS)
        lat_lng_str = '%(lat)s,%(lng)s' % self._lat_lng
        self._request_params = {'location': lat_lng_str}
        if rankby == "prominence":
            self._request_params['radius'] = radius
        else:
            self._request_params['rankby'] = rankby
        if len(types) > 0:
            self._request_params['types'] = '|'.join(types)
        if keyword is not None:
            self._request_params['keyword'] = keyword
        self._add_required_param_keys()
        url, places_response = _fetch_remote_json(
                GooglePlaces.QUERY_API_URL, self._request_params)
        _validate_response(url, places_response)
        return GooglePlacesSearchResult(self, places_response)

    def checkin(self, reference, sensor=False):
        """Checks in a user to a place.

        keyword arguments:
        reference -- The unique Google reference for the relevant place.
        sensor    -- Boolean flag denoting if the location came from a
                         device using its' location sensor (default False)
        """
        data = {'reference': reference}
        url, checkin_response = _fetch_remote_json(
                GooglePlaces.CHECKIN_API_URL % (str(sensor).lower(),
                        self.api_key), json.dumps(data), use_http_post=True)
        _validate_response(url, checkin_response)

    def get_place(self, reference, sensor=False):
        """Gets a detailed place object.

        keyword arguments:
        reference -- The unique Google reference for the required place.
        sensor    -- Boolean flag denoting if the location came from a
                         device using its' location sensor (default False)
        """
        place_details = _get_place_details(reference, self.api_key, sensor)
        return Place(self, place_details)

    def _add_required_param_keys(self):
        self._request_params['key'] = self.api_key
        self._request_params['sensor'] = str(self.sensor).lower()

    @property
    def request_params(self):
        return self._request_params

    @property
    def api_key(self):
        return self._api_key

    @property
    def sensor(self):
        return self._sensor

class GooglePlacesSearchResult(object):
    """Wrapper around the Google Places API query JSON response."""

    def __init__(self, query_instance, response):
        self._places = []
        for place in response['results']:
            self._places.append(Place(query_instance, place))
        self._html_attributions = response['html_attributions']

    @property
    def places(self):
        return self._places

    @property
    def html_attributions(self):
        """Returns the HTML attributions for the specified response.

        Any returned HTML attributions MUST be displayed as-is, in accordance
        with the requirements as found in the documentation. Please see the
        module comments for links to the relevant url.
        """
        return self._html_attributions

    @property
    def has_attributions(self):
        """Returns a flag denoting if the response had any html attributions."""
        return len(self.html_attributions) > 0

class Place(object):
    """
    Represents a place from the results of a Google Places API query.
    """
    def __init__(self, query_instance, place_data):
        self._query_instance = query_instance
        self._id = place_data['id']
        self._reference = place_data['reference']
        self._name = place_data['name']
        self._vicinity = place_data['vicinity']
        self._geo_location = place_data['geometry']['location']
        self._rating = place_data.get('rating')
        self._types = place_data.get('types')
        self._icon = place_data.get('icon')
        if place_data.get('address_components') is None:
            self._details = None
        else:
            self._details = place_data

    @property
    def reference(self):
        """Returns contains a unique token for the place.

        The token can be used to retrieve additional information about this
        place when invoking the getPlace method on an GooglePlaces instance.

        You can store this token and use it at any time in future to refresh
        cached data about this Place, but the same token is not guaranteed to
        be returned for any given Place across different searches."""
        return self._reference

    @property
    def id(self):
        """Returns the unique stable identifier denoting this place.

        This identifier may not be used to retrieve information about this
        place, but is guaranteed to be valid across sessions. It can be used
        to consolidate data about this Place, and to verify the identity of a
        Place across separate searches.
        """
        return self._id

    @property
    def icon(self):
        """Returns the URL of a recommended icon for display."""
        return self._icon

    @property
    def types(self):
        """Returns a list of feature types describing the given result."""
        return self._types

    @property
    def geo_location(self):
        """Returns the lat lng co-ordinates of the place.

        A dict with the keys 'lat' and 'lng' will be returned.
        """
        return self._geo_location

    @property
    def name(self):
        """Returns the human-readable name of the place."""
        return self._name

    @property
    def vicinity(self):
        """Returns a feature name of a nearby location.

        Often this feature refers to a street or neighborhood within the given
        results.
        """
        return self._vicinity

    @property
    def rating(self):
        """Returns the Place's rating, from 0.0 to 5.0, based on user reviews.

        This method will return None for places that have no rating.
        """
        return self._rating

    # The following properties require a further API call in order to be
    # available.
    @property
    def details(self):
        """Returns the JSON response from Google Places Detail search API."""
        self._validate_status()
        return self._details

    @property
    def formatted_address(self):
        """Returns a string containing the human-readable address of this place.

        Often this address is equivalent to the "postal address," which
        sometimes differs from country to country. (Note that some countries,
        such as the United Kingdom, do not allow distribution of complete postal
        addresses due to licensing restrictions.)
        """
        self._validate_status()
        return self.details.get('formatted_address')

    @property
    def local_phone_number(self):
        """Returns the Place's phone number in its local format."""
        self._validate_status()
        return self.details.get('formatted_phone_number')

    @property
    def international_phone_number(self):
        self._validate_status()
        return self.details.get('international_phone_number')

    @property
    def website(self):
        """Retuns the authoritative website for this Place."""
        self._validate_status()
        return self.details.get('website')

    @property
    def url(self):
        """Contains the official Google Place Page URL of this establishment.

        Applications must link to or embed the Google Place page on any screen
        that shows detailed results about this Place to the user.
        """
        self._validate_status()
        return self.details.get('url')

    @property
    def html_attributions(self):
        """Returns the HTML attributions for the specified response.

        Any returned HTML attributions MUST be displayed as-is, in accordance
        with the requirements as found in the documentation. Please see the
        module comments for links to the relevant url.
        """
        self._validate_status()
        return self.details.get('html_attributions', [])

    @property
    def has_attributions(self):
        """Returns a flag denoting if the response had any html attributions."""
        return (False if self._details is None else
                len(self.html_attributions) > 0)

    def checkin(self):
        """Checks in an anonynomous user in."""
        self._query_instance.checkin(self.reference,
                                     self._query_instance.sensor)

    def get_details(self):
        """Retrieves full information on the place matching the reference.

        Further attributes will be made available on the instance once this
        method has been invoked.
        """
        if self._details is None:
            self._details = _get_place_details(
                    self.reference, self._query_instance.api_key,
                    self._query_instance.sensor)

    def _validate_status(self):
        if self._details is None:
            error_detail = ('The attribute requested is only available after ' +
                    'an explicit call to get_details() is made.')
            raise GooglePlacesAttributeError, error_detail
<|endoftext|>


<commit_before>"""
Functions to process content of lxml nodes.
"""
from StringIO import StringIO
import lxml.html

from text import normalize_space as normalize_space_func, find_number

def get_node_text(node, smart=False, normalize_space=True):
    """
    Extract text content of the `node` and all its descendants.

    In smart mode `get_node_text` insert spaces between <tag><another tag>
    and also ignores content of the script and style tags.

    In non-smart mode this func just return text_content() of node
    with normalized spaces
    """

    if smart:
        value = ' '.join(node.xpath(
            './descendant-or-self::*[name() != "script" and '\
            'name() != "style"]/text()[normalize-space()]'))
    else:
        value = node.text_content()
    if normalize_space:
        value = normalize_space_func(value)
    return value

def find_node_number(node, ignore_spaces=False):
    """
    Find number in text content of the `node`.
    """

    return find_number(get_node_text(node), ignore_spaces=ignore_spaces)

def truncate_tail(node, xpath):
    """
    Find sub-node by its xpath and remove it and all adjacent nodes following
    after found node.
    """

    subnode = node.xpath(xpath)[0]
    for item in subnode.xpath('following-sibling::*'):
        item.getparent().remove(item)
    subnode.getparent().remove(subnode)

def drop_node(node, xpath):
    """
    Find sub-node by its xpath and remove it.
    """

    for item in node.xpath(xpath):
        item.getparent().remove(item)

def parse_html(html, encoding='utf-8'):
    """
    Parse html into ElementTree node.
    """

    parser = lxml.html.HTMLParser(encoding=encoding)
    return lxml.html.fromstring(html, parser=parser)

def render_html(node, encoding='utf-8'):
    return lxml.html.tostring(node, encoding=encoding)

def truncate_html(html, limit, encoding='utf-8'):
    """
    Truncate html data to specified length and then fix broken tags.
    """

    if not isinstance(html, unicode):
        html = html.decode(encoding)
    truncated_html = html[:limit]
    elem = parse_html(truncated_html, encoding=encoding)
    fixed_html = render_html(elem, encoding=encoding)
    return fixed_html
<commit_msg>Remove explicit lxml import in lxml_tools<commit_after>"""
Functions to process content of lxml nodes.
"""
from StringIO import StringIO

from text import normalize_space as normalize_space_func, find_number

def get_node_text(node, smart=False, normalize_space=True):
    """
    Extract text content of the `node` and all its descendants.

    In smart mode `get_node_text` insert spaces between <tag><another tag>
    and also ignores content of the script and style tags.

    In non-smart mode this func just return text_content() of node
    with normalized spaces
    """

    if smart:
        value = ' '.join(node.xpath(
            './descendant-or-self::*[name() != "script" and '\
            'name() != "style"]/text()[normalize-space()]'))
    else:
        value = node.text_content()
    if normalize_space:
        value = normalize_space_func(value)
    return value

def find_node_number(node, ignore_spaces=False):
    """
    Find number in text content of the `node`.
    """

    return find_number(get_node_text(node), ignore_spaces=ignore_spaces)

def truncate_tail(node, xpath):
    """
    Find sub-node by its xpath and remove it and all adjacent nodes following
    after found node.
    """

    subnode = node.xpath(xpath)[0]
    for item in subnode.xpath('following-sibling::*'):
        item.getparent().remove(item)
    subnode.getparent().remove(subnode)

def drop_node(node, xpath):
    """
    Find sub-node by its xpath and remove it.
    """

    for item in node.xpath(xpath):
        item.getparent().remove(item)

def parse_html(html, encoding='utf-8'):
    """
    Parse html into ElementTree node.
    """
    import lxml.html

    parser = lxml.html.HTMLParser(encoding=encoding)
    return lxml.html.fromstring(html, parser=parser)

def render_html(node, encoding='utf-8'):
    import lxml.html

    return lxml.html.tostring(node, encoding=encoding)

def truncate_html(html, limit, encoding='utf-8'):
    """
    Truncate html data to specified length and then fix broken tags.
    """

    if not isinstance(html, unicode):
        html = html.decode(encoding)
    truncated_html = html[:limit]
    elem = parse_html(truncated_html, encoding=encoding)
    fixed_html = render_html(elem, encoding=encoding)
    return fixed_html
<|endoftext|>


<commit_before>import re
import httplib
from logging import getLogger
from flask import request
from flask import abort as flask_abort
from ..auth.roles import require_user
from ..auth.roles import require_admin
from .models import Object
from .models import create_object
from .models import get_objects_of_type
from .models import get_object_children
from .models import ensure_unique_slug

logger = getLogger(__name__)

OBJ_ACTION_ATTR = '_warehaus_object_action'
TYPE_ACTION_ATTR = '_warehaus_type_action'

def object_action(method, name):
    '''When defined in a type `T`, this decorator creates an action which can be
    invoked on objects with type `T`.
    The `method` argument is the HTTP verb (`GET`, `POST`, etc.) and the `name`
    argument is the action name to be called through an HTTP URL. Make sure to
    keep `name` plain-ascii so that actions can be placed in URLs through command
    line.
    '''
    def decorator(func):
        setattr(func, OBJ_ACTION_ATTR, dict(method=method, name=name))
        return func
    return decorator

def type_action(method, name):
    '''Same as `object_action` but for type objects. The action can be invoked
    on type objects rather than objects.
    '''
    def decorator(func):
        setattr(func, TYPE_ACTION_ATTR, dict(method=method, name=name))
        return func
    return decorator

def get_object_action(func):
    return getattr(func, OBJ_ACTION_ATTR, None)

def get_type_action(func):
    return getattr(func, TYPE_ACTION_ATTR, None)

class TypeClass(object):
    TYPE_VENDOR = None
    TYPE_NAME = None
    USER_CONTROLLABLE = False

    @classmethod
    def type_key(cls):
        '''Returns a unique `type_key` for this type class. You should
        not override this method normally.'''
        return '{}-{}'.format(cls.TYPE_VENDOR, cls.TYPE_NAME)

    @classmethod
    def display_name(cls):
        return cls.type_key()

    @classmethod
    def description(cls):
        return ''

    def create_type_object(self, parent, slug, display_name=None):
        display_name = display_name if display_name is not None else self.display_name()
        ensure_unique_slug(parent, slug)
        type_object = create_object(
            type         = None, # Type objects have no type
            parent       = parent,
            slug         = slug,
            type_key     = self.type_key(),
            display_name = display_name,
        )
        type_object.save()
        self.ensure_subtypes(type_object)
        return type_object

    #----------------------------------------------------------------#
    # Automatic sub-type creation                                    #
    #----------------------------------------------------------------#

    def subtypes(self):
        '''A type-class can define sub-type-classes.
        A sub-type-class is a type-class that is automatically created for
        instances of the type-class. These sub-types are required for the
        type-object's normal operation and can later on be controlled and
        queried by users.

        For example, a `Server` object might need a `Disk` sub-object.
        Such a sub-type holds objects which relate to objects of type
        `Server` and the `Server` objects can't exist without their `Disk`
        sub-objects. A user might query the sub-types directly or even
        define user-defined attributes to add more information by users.

        Defining a sub-type-class would ensure the sub-types are
        automatically created when the type-object is being created. The
        type-objects can be accessed as child objects of the type object.

        This method should return a dict of the format

            {slug -> TypeClass instance}

        where `slug` will be the `slug` of the new sub type-object.
        '''
        return {}

    def ensure_subtypes(self, type_object):
        '''Creates type-class instances as defined in `sub_type_classes`.'''
        for slug, typeclass in self.subtypes().iteritems():
            typeclass.create_type_object(parent=type_object, slug=slug)

    #----------------------------------------------------------------#
    # Actions supported on all objects and type-objects              #
    #----------------------------------------------------------------#

    @object_action('GET', '')
    def get_object(self, obj):
        '''Returns the object from the database. This action is automatically
        supported for all objects of all types.
        '''
        require_user()
        return obj.as_dict()

    @type_action('GET', '')
    def get_type(self, typeobj):
        '''Same as `get_object` but for type objects.'''
        require_user()
        return typeobj.as_dict()

    @type_action('GET', 'objects')
    def get_objects_of_type(self, typeobj):
        '''Returns all objects of this type object.'''
        require_user()
        return dict(objects=list(obj.as_dict() for obj in get_objects_of_type(typeobj)))

    @type_action('GET', 'children')
    def get_type_children(self, typeobj):
        '''Get all type-objects which are children of this type-object.'''
        require_user()
        return dict(children=list(child.as_dict() for child in get_object_children(typeobj)))

    @type_action('DELETE', '')
    def delete_type(self, typeobj):
        '''Deletes this object.'''
        require_admin()
        typeobj.delete()
        return None, httplib.NO_CONTENT

    #----------------------------------------------------------------#
    # User-based attribute support                                   #
    #----------------------------------------------------------------#

    @type_action('POST', 'attrs')
    def add_attribute(self, typeobj):
        '''Add an attribute to this type-object. After this attribute has been
        added, users can get/set this attribute from all objects of this type.
        '''
        require_admin()
        new_attr = request.json['attr']
        if 'attrs' in typeobj:
            if any(attr['slug'] == new_attr['slug'] for attr in typeobj.attrs):
                flask_abort(httplib.CONFLICT, "There's already an attribute with slug '{}'".format(new_attr['slug']))
            typeobj.attrs.append(new_attr)
        else:
            typeobj.attrs = [new_attr]
        typeobj.save()
        return typeobj.as_dict()

    @type_action('PUT', 'attrs')
    def update_attribute(self, typeobj):
        '''Update an attribute's definition.'''
        require_admin()
        attr_slug = request.json['slug']
        updated_attr = request.json['updated_attr']
        if 'slug' not in updated_attr:
            flask_abort(httplib.BAD_REQUEST, 'Updated attribute must have a "slug" property')
        if 'attrs' not in typeobj or not any(attr['slug'] == attr_slug for attr in typeobj.attrs):
            flask_abort(httplib.NOT_FOUND, 'No such attribute {!r}'.format(updated_attr['slug']))
        if (attr_slug != updated_attr['slug']) and any(attr['slug'] == updated_attr['slug'] for attr in typeobj.attrs):
            flask_abort(httplib.CONFLICT, "There's already an attribute with slug '{}'".format(updated_attr['slug']))
        typeobj.attrs = [updated_attr if attr['slug'] == attr_slug else attr for attr in typeobj.attrs]
        typeobj.save()
        return typeobj.as_dict()

    @type_action('DELETE', 'attrs')
    def delete_attribute(self, typeobj):
        '''Delete a user-defined attribute.'''
        require_admin()
        attr_slug = request.json['slug']
        if 'attrs' in typeobj:
            typeobj.attrs = list(attr for attr in typeobj.attrs if attr['slug'] != attr_slug)
            typeobj.save()
        return typeobj.as_dict()

    def _check_typeobj_has_attr(self, typeobj, attr_slug):
        if attr_slug not in typeobj.get('attrs', {}):
            flask_abort(httplib.BAD_REQUEST, "Objects of type {!r} don't have the {!r} attribute".format(typeobj.display_name['singular'], attr_Slug))

    @object_action('PUT', 'attrs')
    def set_attr(self, obj):
        '''Sets a user-attribute for an object.'''
        require_user()
        attr_slug = request.json['slug']
        attr_value = request.json['value']
        lab = obj.get_parent_object()
        typeobj = obj.get_type_object()
        self._check_typeobj_has_attr(typeobj, attr_slug)
        if 'attrs' in obj:
            obj.attrs[attr_slug] = attr_value
        else:
            obj.attrs = {attr_slug: attr_value}
        obj.save()
        create_event(
            obj_id = obj.id,
            user_id = current_identity.id,
            interested_ids = [obj.id, lab.id],
            title = 'Set the **{}** attribute of **{}**'.format(typeobj.attrs[attr_slug]['display_name'], obj.display_name),
            content = attr_value,
        )
        return obj.as_dict()

    @object_action('DELETE', 'attrs')
    def delete_attr(self, obj):
        '''Remove a user-defined attribute from an object.'''
        require_user()
        lab = obj.get_parent_object()
        typeobj = obj.get_type_object()
        self._check_typeobj_has_attr(typeobj, attr_slug)
        attr_slug = request.json['slug']
        if 'attrs' in obj and attr_slug in obj.attrs:
            del obj.attrs[attr_slug]
            obj.save()
        create_event(
            obj_id = obj.id,
            user_id = current_identity.id,
            interested_ids = [obj.id, lab.id],
            title = 'Removed the **{}** attribute from **{}**'.format(typeobj.attrs[attr_slug]['display_name'], obj.display_name),
        )
        return obj.as_dict()
<commit_msg>Fix crash in user-attributes APIs<commit_after>import re
import httplib
from logging import getLogger
from flask import request
from flask import abort as flask_abort
from flask_jwt import current_identity
from ..auth.roles import require_user
from ..auth.roles import require_admin
from ..events.models import create_event
from .models import Object
from .models import create_object
from .models import get_objects_of_type
from .models import get_object_children
from .models import ensure_unique_slug

logger = getLogger(__name__)

OBJ_ACTION_ATTR = '_warehaus_object_action'
TYPE_ACTION_ATTR = '_warehaus_type_action'

def object_action(method, name):
    '''When defined in a type `T`, this decorator creates an action which can be
    invoked on objects with type `T`.
    The `method` argument is the HTTP verb (`GET`, `POST`, etc.) and the `name`
    argument is the action name to be called through an HTTP URL. Make sure to
    keep `name` plain-ascii so that actions can be placed in URLs through command
    line.
    '''
    def decorator(func):
        setattr(func, OBJ_ACTION_ATTR, dict(method=method, name=name))
        return func
    return decorator

def type_action(method, name):
    '''Same as `object_action` but for type objects. The action can be invoked
    on type objects rather than objects.
    '''
    def decorator(func):
        setattr(func, TYPE_ACTION_ATTR, dict(method=method, name=name))
        return func
    return decorator

def get_object_action(func):
    return getattr(func, OBJ_ACTION_ATTR, None)

def get_type_action(func):
    return getattr(func, TYPE_ACTION_ATTR, None)

class TypeClass(object):
    TYPE_VENDOR = None
    TYPE_NAME = None
    USER_CONTROLLABLE = False

    @classmethod
    def type_key(cls):
        '''Returns a unique `type_key` for this type class. You should
        not override this method normally.'''
        return '{}-{}'.format(cls.TYPE_VENDOR, cls.TYPE_NAME)

    @classmethod
    def display_name(cls):
        return cls.type_key()

    @classmethod
    def description(cls):
        return ''

    def create_type_object(self, parent, slug, display_name=None):
        display_name = display_name if display_name is not None else self.display_name()
        ensure_unique_slug(parent, slug)
        type_object = create_object(
            type         = None, # Type objects have no type
            parent       = parent,
            slug         = slug,
            type_key     = self.type_key(),
            display_name = display_name,
        )
        type_object.save()
        self.ensure_subtypes(type_object)
        return type_object

    #----------------------------------------------------------------#
    # Automatic sub-type creation                                    #
    #----------------------------------------------------------------#

    def subtypes(self):
        '''A type-class can define sub-type-classes.
        A sub-type-class is a type-class that is automatically created for
        instances of the type-class. These sub-types are required for the
        type-object's normal operation and can later on be controlled and
        queried by users.

        For example, a `Server` object might need a `Disk` sub-object.
        Such a sub-type holds objects which relate to objects of type
        `Server` and the `Server` objects can't exist without their `Disk`
        sub-objects. A user might query the sub-types directly or even
        define user-defined attributes to add more information by users.

        Defining a sub-type-class would ensure the sub-types are
        automatically created when the type-object is being created. The
        type-objects can be accessed as child objects of the type object.

        This method should return a dict of the format

            {slug -> TypeClass instance}

        where `slug` will be the `slug` of the new sub type-object.
        '''
        return {}

    def ensure_subtypes(self, type_object):
        '''Creates type-class instances as defined in `sub_type_classes`.'''
        for slug, typeclass in self.subtypes().iteritems():
            typeclass.create_type_object(parent=type_object, slug=slug)

    #----------------------------------------------------------------#
    # Actions supported on all objects and type-objects              #
    #----------------------------------------------------------------#

    @object_action('GET', '')
    def get_object(self, obj):
        '''Returns the object from the database. This action is automatically
        supported for all objects of all types.
        '''
        require_user()
        return obj.as_dict()

    @type_action('GET', '')
    def get_type(self, typeobj):
        '''Same as `get_object` but for type objects.'''
        require_user()
        return typeobj.as_dict()

    @type_action('GET', 'objects')
    def get_objects_of_type(self, typeobj):
        '''Returns all objects of this type object.'''
        require_user()
        return dict(objects=list(obj.as_dict() for obj in get_objects_of_type(typeobj)))

    @type_action('GET', 'children')
    def get_type_children(self, typeobj):
        '''Get all type-objects which are children of this type-object.'''
        require_user()
        return dict(children=list(child.as_dict() for child in get_object_children(typeobj)))

    @type_action('DELETE', '')
    def delete_type(self, typeobj):
        '''Deletes this object.'''
        require_admin()
        typeobj.delete()
        return None, httplib.NO_CONTENT

    #----------------------------------------------------------------#
    # User-based attribute support                                   #
    #----------------------------------------------------------------#

    @type_action('POST', 'attrs')
    def add_attribute(self, typeobj):
        '''Add an attribute to this type-object. After this attribute has been
        added, users can get/set this attribute from all objects of this type.
        '''
        require_admin()
        new_attr = request.json['attr']
        if 'attrs' in typeobj:
            if any(attr['slug'] == new_attr['slug'] for attr in typeobj.attrs):
                flask_abort(httplib.CONFLICT, "There's already an attribute with slug '{}'".format(new_attr['slug']))
            typeobj.attrs.append(new_attr)
        else:
            typeobj.attrs = [new_attr]
        typeobj.save()
        return typeobj.as_dict()

    @type_action('PUT', 'attrs')
    def update_attribute(self, typeobj):
        '''Update an attribute's definition.'''
        require_admin()
        attr_slug = request.json['slug']
        updated_attr = request.json['updated_attr']
        if 'slug' not in updated_attr:
            flask_abort(httplib.BAD_REQUEST, 'Updated attribute must have a "slug" property')
        if 'attrs' not in typeobj or not any(attr['slug'] == attr_slug for attr in typeobj.attrs):
            flask_abort(httplib.NOT_FOUND, 'No such attribute {!r}'.format(updated_attr['slug']))
        if (attr_slug != updated_attr['slug']) and any(attr['slug'] == updated_attr['slug'] for attr in typeobj.attrs):
            flask_abort(httplib.CONFLICT, "There's already an attribute with slug '{}'".format(updated_attr['slug']))
        typeobj.attrs = [updated_attr if attr['slug'] == attr_slug else attr for attr in typeobj.attrs]
        typeobj.save()
        return typeobj.as_dict()

    @type_action('DELETE', 'attrs')
    def delete_attribute(self, typeobj):
        '''Delete a user-defined attribute.'''
        require_admin()
        attr_slug = request.json['slug']
        if 'attrs' in typeobj:
            typeobj.attrs = list(attr for attr in typeobj.attrs if attr['slug'] != attr_slug)
            typeobj.save()
        return typeobj.as_dict()

    def _get_typeobj_attr(self, typeobj, attr_slug):
        if 'attrs' in typeobj:
            for attr in typeobj.attrs:
                if attr['slug'] == attr_slug:
                    return attr
        flask_abort(httplib.NOT_FOUND, "Objects of type {!r} don't have the {!r} attribute".format(typeobj.display_name['singular'], attr_slug))

    @object_action('PUT', 'attrs')
    def set_attr(self, obj):
        '''Sets a user-attribute for an object.'''
        require_user()
        attr_slug = request.json['slug']
        attr_value = request.json['value']
        lab = obj.get_parent_object()
        typeobj = obj.get_type_object()
        attr_type = self._get_typeobj_attr(typeobj, attr_slug)
        if 'attrs' in obj:
            obj.attrs[attr_slug] = attr_value
        else:
            obj.attrs = {attr_slug: attr_value}
        obj.save()
        create_event(
            obj_id = obj.id,
            user_id = current_identity.id,
            interested_ids = [obj.id, lab.id],
            title = 'Set the **{}** attribute of **{}**'.format(attr_type['display_name'], obj.display_name),
            content = attr_value,
        )
        return obj.as_dict()

    @object_action('DELETE', 'attrs')
    def delete_attr(self, obj):
        '''Remove a user-defined attribute from an object.'''
        require_user()
        lab = obj.get_parent_object()
        typeobj = obj.get_type_object()
        attr_type = self._get_typeobj_attr(typeobj, attr_slug)
        attr_slug = request.json['slug']
        if 'attrs' in obj and attr_slug in obj.attrs:
            del obj.attrs[attr_slug]
            obj.save()
        create_event(
            obj_id = obj.id,
            user_id = current_identity.id,
            interested_ids = [obj.id, lab.id],
            title = 'Removed the **{}** attribute from **{}**'.format(attr_type['display_name'], obj.display_name),
        )
        return obj.as_dict()
<|endoftext|>