<commit_before>import datetime
import json
import time
from uuid import uuid4
import random

from wranglertools import fdnDCIC

def create_ffmeta_awsem(workflow, app_name, input_files=None, parameters=None, title=None, uuid=None,
                        output_files=None, award='1U01CA200059-01', lab='4dn-dcic-lab',
                        run_status='started', run_platform='Tibanna', run_url='', **kwargs):

    input_files = [] if input_files is None else input_files
    parameters = [] if parameters is None else parameters

    if title is None:
        title = app_name + " run " + str(datetime.datetime.now())

    return WorkflowRunMetadata(workflow=workflow, app_name=app_name, input_files=input_files,
                               parameters=parameters, uuid=uuid, award=award,
                               lab=lab, run_platform=run_platform, run_url=run_url,
                               title=title, output_files=output_files, run_status=run_status)

def create_ffmeta(sbg, workflow, input_files=None, parameters=None, title=None, sbg_task_id=None,
                  sbg_mounted_volume_ids=None, sbg_import_ids=None, sbg_export_ids=None, uuid=None,
                  award='1U01CA200059-01', lab='4dn-dcic-lab', run_platform='SBG',
                  output_files=None, run_status='started', **kwargs):

    input_files = [] if input_files is None else input_files
    parameters = [] if parameters is None else parameters
    # TODO: this probably is not right
    sbg_export_ids = [] if sbg_export_ids is None else sbg_export_ids

    if title is None:
        title = sbg.app_name + " run " + str(datetime.datetime.now())

    if sbg_task_id is None:
        sbg_task_id = sbg.task_id

    if not sbg_mounted_volume_ids:
        try:
            sbg.volume_list[0]['name']
            sbg_mounted_volume_ids = [x['name'] for x in sbg.volume_list]
        except:
            sbg_mounted_volume_ids = [x for x in sbg.volume_list]

    if not sbg_import_ids:
        sbg_import_ids = sbg.import_id_list

    if not output_files:
        output_files = sbg.export_report
    else:
        # self.output_files may contain e.g. file_format and file_type information.
        for of in output_files:
            for of2 in sbg.export_report:
                if of['workflow_argument_name'] == of2['workflow_argument_name']:
                    for k, v in of2.iteritems():
                        of[k] = v

    return WorkflowRunMetadata(workflow, sbg.app_name, input_files, parameters,
                               sbg_task_id, sbg_import_ids, sbg_export_ids,
                               sbg_mounted_volume_ids, uuid,
                               award, lab, run_platform, title, output_files, run_status, **kwargs)

class WorkflowRunMetadata(object):
    '''
    fourfront metadata
    '''

    def __init__(self, workflow, app_name, input_files=[],
                 parameters=[], sbg_task_id=None,
                 sbg_import_ids=None, sbg_export_ids=None,
                 sbg_mounted_volume_ids=None, uuid=None,
                 award='1U01CA200059-01', lab='4dn-dcic-lab',
                 run_platform='SBG', title=None, output_files=None,
                 run_status='started',
                 run_url='', **kwargs):
        """Class for WorkflowRun that matches the 4DN Metadata schema
        Workflow (uuid of the workflow to run) has to be given.
        Workflow_run uuid is auto-generated when the object is created.
        """
        self.sbg_app_name = app_name
        self.run_status = run_status
        self.uuid = uuid if uuid else str(uuid4())
        self.workflow = workflow
        self.run_platform = run_platform
        if run_url:
            self.run_url = run_url
        if sbg_task_id is None:
            self.sbg_task_id = ''
        else:
            self.sbg_task_id = sbg_task_id

        if sbg_mounted_volume_ids is None:
            self.sbg_mounted_volume_ids = []
        else:
            self.sbg_mounted_volume_ids = sbg_mounted_volume_ids
        if sbg_import_ids is None:
            self.sbg_import_ids = []
        else:
            self.sbg_import_ids = sbg_import_ids
        if sbg_export_ids is None:
            self.sbg_export_ids = []
        else:
            self.sbg_export_ids = sbg_export_ids

        self.title = title
        self.input_files = input_files
        if output_files:
            self.output_files = output_files
        self.parameters = parameters
        self.award = award
        self.lab = lab

    def append_outputfile(self, outjson):
        self.output_files.append(outjson)

    def append_volumes(self, sbg_volume):
        self.sbg_mounted_volume_ids.append(sbg_volume.id)

    def as_dict(self):
        return self.__dict__

    def toJSON(self):
        return json.dumps(self, default=lambda o: o.__dict__, sort_keys=True, indent=4)

    def post(self, key, type_name='workflow_run_sbg'):
        return post_to_metadata(self.as_dict(), type_name, key=key)

    def post_plain_wrf(self, key, type_name='workflow_run'):
        from copy import deepcopy
        data = deepcopy(self.as_dict())
        print(data)
        for akey in data.keys():
            if akey.startswith("sbg"):
                del data[akey]
        print("snipped")
        print(data)

        return post_to_metadata(data, type_name, key=key)

class ProcessedFileMetadata(object):
    def __init__(self, uuid=None, accession=None, file_format='', lab='4dn-dcic-lab',
                 award='1U01CA200059-01', status='to be uploaded by workflow'):
        self.uuid = uuid if uuid else str(uuid4())
        self.accession = accession if accession else generate_rand_accession()
        self.status = status
        self.lab = lab
        self.award = award
        self.file_format = file_format

    def as_dict(self):
        return self.__dict__

    def toJSON(self):
        return json.dumps(self, default=lambda o: o.__dict__, sort_keys=True, indent=4)

    def post(self, key):
        return post_to_metadata(self.as_dict(), "file_processed", key=key)

def fdn_connection(key='', connection=None):
    assert key or connection

    if not connection:
        try:
            fdn_key = fdnDCIC.FDN_Key(key, 'default')
            connection = fdnDCIC.FDN_Connection(fdn_key)
        except Exception as e:
            raise Exception("Unable to connect to server with check keys : %s" % e)
    return connection

def patch_metadata(patch_item, obj_id='', key='', connection=None):
    '''
    obj_id can be uuid or @id for most object
    '''

    connection = fdn_connection(key, connection)

    obj_id = obj_id if obj_id else patch_item['uuid']

    try:
        response = fdnDCIC.patch_FDN(obj_id, connection, patch_item)

        if response.get('status') == 'error':
            raise Exception("error %s \n unable to patch obj: %s \n with  data: %s" %
                            (response, obj_id, patch_item))
    except Exception as e:
        raise Exception("error %s \nunable to patch object %s \ndata: %s" % (e, obj_id, patch_item))
    return response

def get_metadata(obj_id, key='', connection=None, frame="object"):
    connection = fdn_connection(key, connection)
    res = fdnDCIC.get_FDN(obj_id, connection, frame=frame)
    retry = 1
    sleep = [2, 4, 12]
    while 'error' in res.get('@type', []) and retry < 3:
        time.sleep(sleep[retry])
        retry += 1
        res = fdnDCIC.get_FDN(obj_id, connection, frame=frame)

    return res

def post_to_metadata(post_item, schema_name, key='', connection=None):
    connection = fdn_connection(key, connection)

    try:
        response = fdnDCIC.new_FDN(connection, schema_name, post_item)
        if (response.get('status') == 'error' and response.get('detail') == 'UUID conflict'):
            # item already posted lets patch instead
            response = patch_metadata(post_item, connection=connection)
        elif response.get('status') == 'error':
            raise Exception("error %s \n unable to post data to schema %s, data: %s" %
                            (response, schema_name, post_item))
    except Exception as e:
        raise Exception("error %s \nunable to post data to schema %s, data: %s" %
                        (e, schema_name, post_item))
    return response

def delete_field(post_json, del_field, connection=None):
    """Does a put to delete the given field."""
    my_uuid = post_json.get("uuid")
    my_accession = post_json.get("accesion")
    raw_json = fdnDCIC.get_FDN(my_uuid, connection, frame="raw")
    # check if the uuid is in the raw_json
    if not raw_json.get("uuid"):
        raw_json["uuid"] = my_uuid
    # if there is an accession, add it to raw so it does not created again
    if my_accession:
        if not raw_json.get("accession"):
            raw_json["accession"] = my_accession
    # remove field from the raw_json
    if raw_json.get(del_field):
        del raw_json[del_field]
    # Do the put with raw_json
    try:
        response = fdnDCIC.put_FDN(my_uuid, connection, raw_json)
        if response.get('status') == 'error':
            raise Exception("error %s \n unable to delete field: %s \n of  item: %s" %
                            (response, del_field, my_uuid))
    except Exception as e:
        raise Exception("error %s \n unable to delete field: %s \n of  item: %s" %
                        (e, del_field, my_uuid))
    return response

def generate_rand_accession():
    rand_accession = ''
    for i in xrange(7):
        r = random.choice('ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789')
        rand_accession += r
    accession = "4DNFI"+rand_accession
    return accession
<commit_msg>added app_name to ff_metadata in addition to sbg_app_name<commit_after>import datetime
import json
import time
from uuid import uuid4
import random

from wranglertools import fdnDCIC

def create_ffmeta_awsem(workflow, app_name, input_files=None, parameters=None, title=None, uuid=None,
                        output_files=None, award='1U01CA200059-01', lab='4dn-dcic-lab',
                        run_status='started', run_platform='Tibanna', run_url='', **kwargs):

    input_files = [] if input_files is None else input_files
    parameters = [] if parameters is None else parameters

    if title is None:
        title = app_name + " run " + str(datetime.datetime.now())

    return WorkflowRunMetadata(workflow=workflow, app_name=app_name, input_files=input_files,
                               parameters=parameters, uuid=uuid, award=award,
                               lab=lab, run_platform=run_platform, run_url=run_url,
                               title=title, output_files=output_files, run_status=run_status)

def create_ffmeta(sbg, workflow, input_files=None, parameters=None, title=None, sbg_task_id=None,
                  sbg_mounted_volume_ids=None, sbg_import_ids=None, sbg_export_ids=None, uuid=None,
                  award='1U01CA200059-01', lab='4dn-dcic-lab', run_platform='SBG',
                  output_files=None, run_status='started', **kwargs):

    input_files = [] if input_files is None else input_files
    parameters = [] if parameters is None else parameters
    # TODO: this probably is not right
    sbg_export_ids = [] if sbg_export_ids is None else sbg_export_ids

    if title is None:
        title = sbg.app_name + " run " + str(datetime.datetime.now())

    if sbg_task_id is None:
        sbg_task_id = sbg.task_id

    if not sbg_mounted_volume_ids:
        try:
            sbg.volume_list[0]['name']
            sbg_mounted_volume_ids = [x['name'] for x in sbg.volume_list]
        except:
            sbg_mounted_volume_ids = [x for x in sbg.volume_list]

    if not sbg_import_ids:
        sbg_import_ids = sbg.import_id_list

    if not output_files:
        output_files = sbg.export_report
    else:
        # self.output_files may contain e.g. file_format and file_type information.
        for of in output_files:
            for of2 in sbg.export_report:
                if of['workflow_argument_name'] == of2['workflow_argument_name']:
                    for k, v in of2.iteritems():
                        of[k] = v

    return WorkflowRunMetadata(workflow, sbg.app_name, input_files, parameters,
                               sbg_task_id, sbg_import_ids, sbg_export_ids,
                               sbg_mounted_volume_ids, uuid,
                               award, lab, run_platform, title, output_files, run_status, **kwargs)

class WorkflowRunMetadata(object):
    '''
    fourfront metadata
    '''

    def __init__(self, workflow, app_name, input_files=[],
                 parameters=[], sbg_task_id=None,
                 sbg_import_ids=None, sbg_export_ids=None,
                 sbg_mounted_volume_ids=None, uuid=None,
                 award='1U01CA200059-01', lab='4dn-dcic-lab',
                 run_platform='SBG', title=None, output_files=None,
                 run_status='started',
                 run_url='', **kwargs):
        """Class for WorkflowRun that matches the 4DN Metadata schema
        Workflow (uuid of the workflow to run) has to be given.
        Workflow_run uuid is auto-generated when the object is created.
        """
        self.sbg_app_name = app_name
        self.app_name = app_name
        self.run_status = run_status
        self.uuid = uuid if uuid else str(uuid4())
        self.workflow = workflow
        self.run_platform = run_platform
        if run_url:
            self.run_url = run_url
        if sbg_task_id is None:
            self.sbg_task_id = ''
        else:
            self.sbg_task_id = sbg_task_id

        if sbg_mounted_volume_ids is None:
            self.sbg_mounted_volume_ids = []
        else:
            self.sbg_mounted_volume_ids = sbg_mounted_volume_ids
        if sbg_import_ids is None:
            self.sbg_import_ids = []
        else:
            self.sbg_import_ids = sbg_import_ids
        if sbg_export_ids is None:
            self.sbg_export_ids = []
        else:
            self.sbg_export_ids = sbg_export_ids

        self.title = title
        self.input_files = input_files
        if output_files:
            self.output_files = output_files
        self.parameters = parameters
        self.award = award
        self.lab = lab

    def append_outputfile(self, outjson):
        self.output_files.append(outjson)

    def append_volumes(self, sbg_volume):
        self.sbg_mounted_volume_ids.append(sbg_volume.id)

    def as_dict(self):
        return self.__dict__

    def toJSON(self):
        return json.dumps(self, default=lambda o: o.__dict__, sort_keys=True, indent=4)

    def post(self, key, type_name='workflow_run_sbg'):
        return post_to_metadata(self.as_dict(), type_name, key=key)

    def post_plain_wrf(self, key, type_name='workflow_run'):
        from copy import deepcopy
        data = deepcopy(self.as_dict())
        print(data)
        for akey in data.keys():
            if akey.startswith("sbg"):
                del data[akey]
        print("snipped")
        print(data)

        return post_to_metadata(data, type_name, key=key)

class ProcessedFileMetadata(object):
    def __init__(self, uuid=None, accession=None, file_format='', lab='4dn-dcic-lab',
                 award='1U01CA200059-01', status='to be uploaded by workflow'):
        self.uuid = uuid if uuid else str(uuid4())
        self.accession = accession if accession else generate_rand_accession()
        self.status = status
        self.lab = lab
        self.award = award
        self.file_format = file_format

    def as_dict(self):
        return self.__dict__

    def toJSON(self):
        return json.dumps(self, default=lambda o: o.__dict__, sort_keys=True, indent=4)

    def post(self, key):
        return post_to_metadata(self.as_dict(), "file_processed", key=key)

def fdn_connection(key='', connection=None):
    assert key or connection

    if not connection:
        try:
            fdn_key = fdnDCIC.FDN_Key(key, 'default')
            connection = fdnDCIC.FDN_Connection(fdn_key)
        except Exception as e:
            raise Exception("Unable to connect to server with check keys : %s" % e)
    return connection

def patch_metadata(patch_item, obj_id='', key='', connection=None):
    '''
    obj_id can be uuid or @id for most object
    '''

    connection = fdn_connection(key, connection)

    obj_id = obj_id if obj_id else patch_item['uuid']

    try:
        response = fdnDCIC.patch_FDN(obj_id, connection, patch_item)

        if response.get('status') == 'error':
            raise Exception("error %s \n unable to patch obj: %s \n with  data: %s" %
                            (response, obj_id, patch_item))
    except Exception as e:
        raise Exception("error %s \nunable to patch object %s \ndata: %s" % (e, obj_id, patch_item))
    return response

def get_metadata(obj_id, key='', connection=None, frame="object"):
    connection = fdn_connection(key, connection)
    res = fdnDCIC.get_FDN(obj_id, connection, frame=frame)
    retry = 1
    sleep = [2, 4, 12]
    while 'error' in res.get('@type', []) and retry < 3:
        time.sleep(sleep[retry])
        retry += 1
        res = fdnDCIC.get_FDN(obj_id, connection, frame=frame)

    return res

def post_to_metadata(post_item, schema_name, key='', connection=None):
    connection = fdn_connection(key, connection)

    try:
        response = fdnDCIC.new_FDN(connection, schema_name, post_item)
        if (response.get('status') == 'error' and response.get('detail') == 'UUID conflict'):
            # item already posted lets patch instead
            response = patch_metadata(post_item, connection=connection)
        elif response.get('status') == 'error':
            raise Exception("error %s \n unable to post data to schema %s, data: %s" %
                            (response, schema_name, post_item))
    except Exception as e:
        raise Exception("error %s \nunable to post data to schema %s, data: %s" %
                        (e, schema_name, post_item))
    return response

def delete_field(post_json, del_field, connection=None):
    """Does a put to delete the given field."""
    my_uuid = post_json.get("uuid")
    my_accession = post_json.get("accesion")
    raw_json = fdnDCIC.get_FDN(my_uuid, connection, frame="raw")
    # check if the uuid is in the raw_json
    if not raw_json.get("uuid"):
        raw_json["uuid"] = my_uuid
    # if there is an accession, add it to raw so it does not created again
    if my_accession:
        if not raw_json.get("accession"):
            raw_json["accession"] = my_accession
    # remove field from the raw_json
    if raw_json.get(del_field):
        del raw_json[del_field]
    # Do the put with raw_json
    try:
        response = fdnDCIC.put_FDN(my_uuid, connection, raw_json)
        if response.get('status') == 'error':
            raise Exception("error %s \n unable to delete field: %s \n of  item: %s" %
                            (response, del_field, my_uuid))
    except Exception as e:
        raise Exception("error %s \n unable to delete field: %s \n of  item: %s" %
                        (e, del_field, my_uuid))
    return response

def generate_rand_accession():
    rand_accession = ''
    for i in xrange(7):
        r = random.choice('ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789')
        rand_accession += r
    accession = "4DNFI"+rand_accession
    return accession
<|endoftext|>


<commit_before>#FLM: Input TrueType Hints
# coding: utf-8

__copyright__ = __license__ =  """
Copyright (c) 2015 Adobe Systems Incorporated. All rights reserved.

Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
"""

__doc__ = """
Input TrueType Hints

This FontLab macro will read an external simple text file `tthints` containing
TrueType instructions and hinted point indexes or point coordinates for a number
of glyphs, and will apply this data to the glyphs of an open VFB.

==================================================
Versions:

v1.4 - Apr 17 2015 - Remove unneeded coord_option, now that hints expressed with
                     point coordinates are saved as 'tthints' instead of 'tthints_coords'.
v1.3 - Mar 24 2015 - Enable reading 'tthints_coords' file with coordinates.
v1.2 - Mar 23 2015 - Enable instructions in x-direction.
v1.1 - Sep 07 2013 - Enable the reading of 'tthints' files with an optional
					 column for glyph color mark.
v1.0 - Jan 07 2013 - Initial release.
"""

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

debugMode = False

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

vAlignLinkTop = 1
vAlignLinkBottom = 2
hSingleLink = 3
vSingleLink = 4
hDoubleLink = 5
vDoubleLink = 6
hAlignLinkNear = 7
vAlignLinkNear = 8
hInterpolateLink = 13
vInterpolateLink = 14
hMidDelta = 20
vMidDelta = 21
hFinDelta = 22
vFinDelta = 23

deltas = [hMidDelta, hFinDelta, vMidDelta, vFinDelta]
interpolations = [hInterpolateLink, vInterpolateLink]
links = [hSingleLink, hDoubleLink, vSingleLink, vDoubleLink]
alignments = [vAlignLinkTop, vAlignLinkNear, vAlignLinkBottom, hAlignLinkNear]

#----------------------------------------
fuzziness = 2
# Defines area to search for a point that might have moved in TT transformation.
# 0 =  1 possibility (the exact point coordinates)
# 1 =  9 possibilities (1 step in each direction from original point)
# 2 = 25 possibilities (2 steps in each direction)
# 3 = 49 possibilities (3 steps in each direction) etc.

pointErrors = {}
fuzzyPoints = {}
#----------------------------------------

import os
from FL import *
import itertools

def readTTHintsFile(filePath):
	file = open(filePath, "r")
	data = file.read()
	file.close()
	lines = data.splitlines()

	ttHintsList = []

	for i in range(len(lines)):
		line = lines[i]
		# Skip over blank lines
		stripline = line.strip()
		if not stripline:
			continue
		# Skip over comments
		if line.find('#') >= 0:
			continue
		else:
			ttHintsList.append(line)

	return ttHintsList

def findFuzzyPoint(glyphName, point, pointDict, fuzziness):
	'''
	Finds points that fall inside a fuzzy area around
	the original coordinate. If only one point is found
	in that area, the point index will be returned.
	Otherwise returns None.

	Solves off-by-one issues.
	'''

	fuzzyX = range(point[0]-fuzziness, point[0]+fuzziness+1,)
	fuzzyY = range(point[1]-fuzziness, point[1]+fuzziness+1,)
	possibleFuzzyPoints = [fuzzyCoords for fuzzyCoords in itertools.product(fuzzyX, fuzzyY)]
	allPoints = pointDict.keys()
	overlap = set(allPoints) & set(possibleFuzzyPoints)

	if len(overlap) == 1:
		# make sure that only one point is found within the fuzzy area
		oldPoint = list(overlap)[0]
		pointIndex = pointDict[oldPoint]
		fuzzyPoints.setdefault(glyphName, [])
		if not (oldPoint, point) in fuzzyPoints[glyphName]:
			print '\tINFO: In glyph {}, point #{} has changed from {} to {}.'.format(glyphName, pointIndex, oldPoint, point)
			fuzzyPoints[glyphName].append((oldPoint, point))

		return pointIndex
	else:
		return None

def transformCommandList(glyph, raw_commandList):
	'''
	Transforms a list of commands with point coordinates
	to an list of commands with point indexes, for instance:

		input:  [4, (155, 181), (180, 249), 0, -1]
		output: [4, 6, 9, 0, -1]

		input:  [3, 'BL', (83, 0), 0, -1]
		output: [3, 34, 0, 0, -1]

	Also is used to check validity of point coordinates, and
	transforming sidebearing flags to point indexes.

	'''

	# pointDict = {(point.x, point.y): pointIndex for pointIndex, point in enumerate(glyph.nodes)}
	pointDict = dict(((point.x, point.y), pointIndex) for pointIndex, point in enumerate(glyph.nodes))
	output = []

	for item in raw_commandList:
		if item == 'BL':
			'left sidebearing hinted'
			output.append(len(glyph))
		elif item == 'BR':
			'right sidebearing hinted'
			output.append(len(glyph) + 1)
		elif isinstance(item, tuple):
			'point coordinates'
			pointIndex = pointDict.get(item, None)

			if pointIndex == None:
				# Try fuzziness if no exact coordinate match is found:
				fuzzyPointIndex = findFuzzyPoint(glyph.name, item, pointDict, fuzziness)
				if fuzzyPointIndex != None:
					pointIndex = fuzzyPointIndex
				else:
					pointErrors.setdefault(glyph.name, [])
					if not item in pointErrors[glyph.name]:
						print '\tERROR: point %s does not exist in glyph %s.' % (item, glyph.name)
						pointErrors[glyph.name].append(item)

			output.append(pointIndex)
		else:
			'other hinting data, integers'
			output.append(item)

	if None in output:
		# a point was not found at all, so no hinting recipe is returned
		return []
	else:
		return output

def applyTTHints(ttHintsList):
	glyphsHinted = 0
	for line in ttHintsList:
		hintItems = line.split("\t")

		if len(hintItems) == 3:
			'line contains glyph name, hint info and mark color'
			pass

		elif len(hintItems) == 2:
			'line does not contain mark color'
			hintItems.append(80) # green

		else:
			print "ERROR: This hint definition does not have the correct format\n\t%s" % line
			continue

		gName, gHintsString, gMark = hintItems
		gIndex = fl.font.FindGlyph(gName)

		if gIndex != -1:
			glyph = fl.font[gName]
		else:
			print "ERROR: Glyph %s not found in the font." % gName
			continue

		if not len(gHintsString.strip()):
			print "WARNING: There are no hints defined for glyph %s." % gName
			continue

		gHintsList = gHintsString.split(";")

		tth = TTH(glyph)
		tth.LoadProgram(glyph)
		tth.ResetProgram()

		if debugMode:
			print gName

		readingError = False
		for commandString in gHintsList:
			raw_commandList = list(eval(commandString))

			commandType = raw_commandList[0]
			commandList = transformCommandList(glyph, raw_commandList)

			if not commandList:
				readingError = True
				continue

			if len(commandList) < 3:
				print "ERROR: A hint definition for glyph %s does not have enough parameters: %s" % (gName, commandString)
				continue

			# Create the TTHCommand
			try:
				ttc = TTHCommand(commandType)
			except RuntimeError:
				print "ERROR: A hint definition for glyph %s has an invalid command type: %s\n\t\tThe first value must be within the range %s-%s." % (gName, commandType, vAlignLinkTop, vFinDelta)
				continue

			paramError = False

			if commandType in deltas:
				nodes = [commandList[1]]
			elif commandType in links:
				nodes = commandList[1:3]
			elif commandType in alignments + interpolations:
				nodes = commandList[1:-1]
			else:
				print "WARNING: Hint type %d in glyph %s is not supported." % (commandType, gName)
				paramError = True
				nodes = []

			for nodeIndex in nodes:
				try:
					gNode = glyph.nodes[nodeIndex]
				except IndexError:
					if nodeIndex in range(len(glyph), len(glyph)+2):
						pass
					else:
						print "ERROR: A hint definition for glyph %s is referencing an invalid node index: %s" % (gName, nodeIndex)
						paramError = True
						break

			for i, item in enumerate(commandList[1:]):
				ttc.params[i] = item

			if not paramError:
				tth.commands.append(ttc)

		if readingError:
			print '\tProblems with reading hinting recipe of glyph %s\n' % (gName)

		if len(tth.commands):
			tth.SaveProgram(glyph)
			glyph.mark = int(gMark)
			fl.UpdateGlyph(gIndex)
			glyphsHinted += 1

	if glyphsHinted > 0:
		fl.font.modified = 1

def run(parentDir):
	kTTHintsFileName = "tthints"

	tthintsFilePath = os.path.join(parentDir, kTTHintsFileName)
	if os.path.exists(tthintsFilePath):
		print 'Reading', tthintsFilePath
		ttHintsList = readTTHintsFile(tthintsFilePath)
	else:
		print "Could not find the %s file at %s" % (kTTHintsFileName, tthintsFilePath)
		return

	if len(ttHintsList):
		applyTTHints(ttHintsList)
		print "TT hints added."
	else:
		print "The %s file at %s has no hinting data." % (kTTHintsFileName, tthintsFilePath)
		return

def preRun():
	# Clear the Output window
	fl.output = '\n'

	if fl.count == 0:
		print "Open a font first."
		return

	font = fl.font

	if len(font) == 0:
		print "The font has no glyphs."
		return

	try:
		parentDir = os.path.dirname(os.path.realpath(font.file_name))
	except AttributeError:
		print "The font has not been saved. Please save the font and try again."
		return

	run(parentDir)

if __name__ == "__main__":
	preRun()
<commit_msg>Mark glyphs orange if reading hints is not error-free.<commit_after>#FLM: Input TrueType Hints
# coding: utf-8

__copyright__ = __license__ =  """
Copyright (c) 2015 Adobe Systems Incorporated. All rights reserved.

Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
"""

__doc__ = """
Input TrueType Hints

This FontLab macro will read an external simple text file `tthints` containing
TrueType instructions and hinted point indexes or point coordinates for a number
of glyphs, and will apply this data to the glyphs of an open VFB.

==================================================
Versions:

v1.4 - Apr 17 2015 - Remove unneeded coord_option, now that hints expressed with
					 point coordinates are saved as 'tthints' instead of 'tthints_coords'.
v1.3 - Mar 24 2015 - Enable reading 'tthints_coords' file with coordinates.
v1.2 - Mar 23 2015 - Enable instructions in x-direction.
v1.1 - Sep 07 2013 - Enable the reading of 'tthints' files with an optional
					 column for glyph color mark.
v1.0 - Jan 07 2013 - Initial release.
"""

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

debugMode = False

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

vAlignLinkTop = 1
vAlignLinkBottom = 2
hSingleLink = 3
vSingleLink = 4
hDoubleLink = 5
vDoubleLink = 6
hAlignLinkNear = 7
vAlignLinkNear = 8
hInterpolateLink = 13
vInterpolateLink = 14
hMidDelta = 20
vMidDelta = 21
hFinDelta = 22
vFinDelta = 23

deltas = [hMidDelta, hFinDelta, vMidDelta, vFinDelta]
interpolations = [hInterpolateLink, vInterpolateLink]
links = [hSingleLink, hDoubleLink, vSingleLink, vDoubleLink]
alignments = [vAlignLinkTop, vAlignLinkNear, vAlignLinkBottom, hAlignLinkNear]

#----------------------------------------
fuzziness = 2
# Defines area to search for a point that might have moved in TT transformation.
# 0 =  1 possibility (the exact point coordinates)
# 1 =  9 possibilities (1 step in each direction from original point)
# 2 = 25 possibilities (2 steps in each direction)
# 3 = 49 possibilities (3 steps in each direction) etc.

pointErrors = {}
fuzzyPoints = {}
#----------------------------------------

import os
from FL import *
import itertools

def readTTHintsFile(filePath):
	file = open(filePath, "r")
	data = file.read()
	file.close()
	lines = data.splitlines()

	ttHintsList = []

	for i in range(len(lines)):
		line = lines[i]
		# Skip over blank lines
		stripline = line.strip()
		if not stripline:
			continue
		# Skip over comments
		if line.find('#') >= 0:
			continue
		else:
			ttHintsList.append(line)

	return ttHintsList

def findFuzzyPoint(glyphName, point, pointDict, fuzziness):
	'''
	Finds points that fall inside a fuzzy area around
	the original coordinate. If only one point is found
	in that area, the point index will be returned.
	Otherwise returns None.

	Solves off-by-one issues.
	'''

	fuzzyX = range(point[0]-fuzziness, point[0]+fuzziness+1,)
	fuzzyY = range(point[1]-fuzziness, point[1]+fuzziness+1,)
	possibleFuzzyPoints = [fuzzyCoords for fuzzyCoords in itertools.product(fuzzyX, fuzzyY)]
	allPoints = pointDict.keys()
	overlap = set(allPoints) & set(possibleFuzzyPoints)

	if len(overlap) == 1:
		# make sure that only one point is found within the fuzzy area
		oldPoint = list(overlap)[0]
		pointIndex = pointDict[oldPoint]
		fuzzyPoints.setdefault(glyphName, [])
		if not (oldPoint, point) in fuzzyPoints[glyphName]:
			print '\tINFO: In glyph {}, point #{} has changed from {} to {}.'.format(glyphName, pointIndex, oldPoint, point)
			fuzzyPoints[glyphName].append((oldPoint, point))

		return pointIndex
	else:
		return None

def transformCommandList(glyph, raw_commandList):
	'''
	Transforms a list of commands with point coordinates
	to an list of commands with point indexes, for instance:

		input:  [4, (155, 181), (180, 249), 0, -1]
		output: [4, 6, 9, 0, -1]

		input:  [3, 'BL', (83, 0), 0, -1]
		output: [3, 34, 0, 0, -1]

	Also is used to check validity of point coordinates, and
	transforming sidebearing flags to point indexes.

	'''

	# pointDict = {(point.x, point.y): pointIndex for pointIndex, point in enumerate(glyph.nodes)}
	pointDict = dict(((point.x, point.y), pointIndex) for pointIndex, point in enumerate(glyph.nodes))
	output = []

	for item in raw_commandList:
		if item == 'BL':
			'left sidebearing hinted'
			output.append(len(glyph))
		elif item == 'BR':
			'right sidebearing hinted'
			output.append(len(glyph) + 1)
		elif isinstance(item, tuple):
			'point coordinates'
			pointIndex = pointDict.get(item, None)

			if pointIndex == None:
				# Try fuzziness if no exact coordinate match is found:
				fuzzyPointIndex = findFuzzyPoint(glyph.name, item, pointDict, fuzziness)
				if fuzzyPointIndex != None:
					pointIndex = fuzzyPointIndex
				else:
					pointErrors.setdefault(glyph.name, [])
					if not item in pointErrors[glyph.name]:
						print '\tERROR: point %s does not exist in glyph %s.' % (item, glyph.name)
						pointErrors[glyph.name].append(item)

			output.append(pointIndex)
		else:
			'other hinting data, integers'
			output.append(item)

	if None in output:
		# a point was not found at all, so no hinting recipe is returned
		return []
	else:
		return output

def applyTTHints(ttHintsList):
	glyphsHinted = 0
	for line in ttHintsList:
		hintItems = line.split("\t")

		if len(hintItems) == 3:
			'line contains glyph name, hint info and mark color'
			pass

		elif len(hintItems) == 2:
			'line does not contain mark color'
			hintItems.append(80) # green

		else:
			print "ERROR: This hint definition does not have the correct format\n\t%s" % line
			continue

		gName, gHintsString, gMark = hintItems
		gIndex = fl.font.FindGlyph(gName)

		if gIndex != -1:
			glyph = fl.font[gName]
		else:
			print "ERROR: Glyph %s not found in the font." % gName
			continue

		if not len(gHintsString.strip()):
			print "WARNING: There are no hints defined for glyph %s." % gName
			continue

		gHintsList = gHintsString.split(";")

		tth = TTH(glyph)
		tth.LoadProgram(glyph)
		tth.ResetProgram()

		if debugMode:
			print gName

		readingError = False
		for commandString in gHintsList:
			raw_commandList = list(eval(commandString))

			commandType = raw_commandList[0]
			commandList = transformCommandList(glyph, raw_commandList)

			if not commandList:
				readingError = True
				continue

			if len(commandList) < 3:
				print "ERROR: A hint definition for glyph %s does not have enough parameters: %s" % (gName, commandString)
				continue

			# Create the TTHCommand
			try:
				ttc = TTHCommand(commandType)
			except RuntimeError:
				print "ERROR: A hint definition for glyph %s has an invalid command type: %s\n\t\tThe first value must be within the range %s-%s." % (gName, commandType, vAlignLinkTop, vFinDelta)
				continue

			paramError = False

			if commandType in deltas:
				nodes = [commandList[1]]
			elif commandType in links:
				nodes = commandList[1:3]
			elif commandType in alignments + interpolations:
				nodes = commandList[1:-1]
			else:
				print "WARNING: Hint type %d in glyph %s is not supported." % (commandType, gName)
				paramError = True
				nodes = []

			for nodeIndex in nodes:
				try:
					gNode = glyph.nodes[nodeIndex]
				except IndexError:
					if nodeIndex in range(len(glyph), len(glyph)+2):
						pass
					else:
						print "ERROR: A hint definition for glyph %s is referencing an invalid node index: %s" % (gName, nodeIndex)
						paramError = True
						break

			for i, item in enumerate(commandList[1:]):
				ttc.params[i] = item

			if not paramError:
				tth.commands.append(ttc)

		if readingError:
			print '\tProblems with reading hinting recipe of glyph %s\n' % (gName)

		if len(tth.commands):
			tth.SaveProgram(glyph)
			if readingError:
				glyph.mark = 12
			else:
				glyph.mark = int(gMark)
			fl.UpdateGlyph(gIndex)
			glyphsHinted += 1

	if glyphsHinted > 0:
		fl.font.modified = 1

def run(parentDir):
	kTTHintsFileName = "tthints"

	tthintsFilePath = os.path.join(parentDir, kTTHintsFileName)
	if os.path.exists(tthintsFilePath):
		print 'Reading', tthintsFilePath
		ttHintsList = readTTHintsFile(tthintsFilePath)
	else:
		print "Could not find the %s file at %s" % (kTTHintsFileName, tthintsFilePath)
		return

	if len(ttHintsList):
		applyTTHints(ttHintsList)
		print "TT hints added."
	else:
		print "The %s file at %s has no hinting data." % (kTTHintsFileName, tthintsFilePath)
		return

def preRun():
	# Clear the Output window
	fl.output = '\n'

	if fl.count == 0:
		print "Open a font first."
		return

	font = fl.font

	if len(font) == 0:
		print "The font has no glyphs."
		return

	try:
		parentDir = os.path.dirname(os.path.realpath(font.file_name))
	except AttributeError:
		print "The font has not been saved. Please save the font and try again."
		return

	run(parentDir)

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


<commit_before># -*- coding: utf-8 -*-
#
# Copyright (C) 2014 Alexander Shorin
# All rights reserved.
#
# This software is licensed as described in the file LICENSE, which
# you should have received as part of this distribution.
#

import aiocouchdb.feeds
import aiocouchdb.tests.utils as utils

class FeedTestCase(utils.TestCase):

    def test_read_chunks(self):
        resp = self.mock_response(data=[b'foo\r\n', b'bar\r\n'])

        feed = aiocouchdb.feeds.Feed(resp, loop=self.loop)
        self.assertTrue(feed.is_active())

        result = self.run_loop(feed.next())
        self.assertEqual(b'foo', result)

        result = self.run_loop(feed.next())
        self.assertEqual(b'bar', result)

        result = self.run_loop(feed.next())
        self.assertEqual(None, result)
        self.assertFalse(feed.is_active())

    def test_ignore_empty_chunks(self):
        resp = self.mock_response(data=[b'foo\r\n', b'\r\n',  b'\r\n'
                                        b'\r\n',  b'\r\n', b'bar\r\n'])

        feed = aiocouchdb.feeds.Feed(resp, loop=self.loop)
        self.assertTrue(feed.is_active())

        result = self.run_loop(feed.next())
        self.assertEqual(b'foo', result)

        result = self.run_loop(feed.next())
        self.assertEqual(b'bar', result)

        result = self.run_loop(feed.next())
        self.assertEqual(None, result)
        self.assertFalse(feed.is_active())

    def test_read_json_chunks(self):
        resp = self.mock_response(data=[b'{"foo": true}\r\n',
                                        b'{"bar": null}\r\n'])

        feed = aiocouchdb.feeds.JsonFeed(resp, loop=self.loop)
        self.assertTrue(feed.is_active())

        result = self.run_loop(feed.next())
        self.assertEqual({'foo': True}, result)

        result = self.run_loop(feed.next())
        self.assertEqual({'bar': None}, result)

        result = self.run_loop(feed.next())
        self.assertEqual(None, result)
        self.assertFalse(feed.is_active())

    def test_read_empty_json_feed(self):
        resp = self.mock_response()

        feed = aiocouchdb.feeds.JsonFeed(resp, loop=self.loop)
        self.assertTrue(feed.is_active())

        result = self.run_loop(feed.next())
        self.assertEqual(None, result)

        self.assertFalse(feed.is_active())

    def test_calling_inactive_feed_returns_none(self):
        resp = self.mock_response()

        feed = aiocouchdb.feeds.JsonFeed(resp, loop=self.loop)
        self.assertTrue(feed.is_active())

        self.run_loop(feed.next())

        self.assertFalse(feed.is_active())

        result = self.run_loop(feed.next())
        self.assertEqual(None, result)

    def test_close_resp_on_feed_end(self):
        resp = self.mock_response()

        feed = aiocouchdb.feeds.JsonFeed(resp, loop=self.loop)
        self.assertTrue(feed.is_active())

        self.run_loop(feed.next())

        self.assertFalse(feed.is_active())
        self.assertTrue(resp.close.called)

    def test_force_close_resp_on_error(self):
        resp = self.mock_response(err=ValueError)

        feed = aiocouchdb.feeds.JsonFeed(resp, loop=self.loop)
        self.assertTrue(feed.is_active())

        self.assertRaises(ValueError,
                          self.loop.run_until_complete,
                          feed.next())

        self.assertFalse(feed.is_active())
        resp.close.assert_called_with(force=True)
<commit_msg>Add missed JsonFeed test case<commit_after># -*- coding: utf-8 -*-
#
# Copyright (C) 2014 Alexander Shorin
# All rights reserved.
#
# This software is licensed as described in the file LICENSE, which
# you should have received as part of this distribution.
#

import aiocouchdb.feeds
import aiocouchdb.tests.utils as utils

class FeedTestCase(utils.TestCase):

    def test_read_chunks(self):
        resp = self.mock_response(data=[b'foo\r\n', b'bar\r\n'])

        feed = aiocouchdb.feeds.Feed(resp, loop=self.loop)
        self.assertTrue(feed.is_active())

        result = self.run_loop(feed.next())
        self.assertEqual(b'foo', result)

        result = self.run_loop(feed.next())
        self.assertEqual(b'bar', result)

        result = self.run_loop(feed.next())
        self.assertEqual(None, result)
        self.assertFalse(feed.is_active())

    def test_ignore_empty_chunks(self):
        resp = self.mock_response(data=[b'foo\r\n', b'\r\n',  b'\r\n'
                                        b'\r\n',  b'\r\n', b'bar\r\n'])

        feed = aiocouchdb.feeds.Feed(resp, loop=self.loop)
        self.assertTrue(feed.is_active())

        result = self.run_loop(feed.next())
        self.assertEqual(b'foo', result)

        result = self.run_loop(feed.next())
        self.assertEqual(b'bar', result)

        result = self.run_loop(feed.next())
        self.assertEqual(None, result)
        self.assertFalse(feed.is_active())

    def test_read_json_chunks(self):
        resp = self.mock_response(data=[b'{"foo": true}\r\n',
                                        b'{"bar": null}\r\n'])

        feed = aiocouchdb.feeds.JsonFeed(resp, loop=self.loop)
        self.assertTrue(feed.is_active())

        result = self.run_loop(feed.next())
        self.assertEqual({'foo': True}, result)

        result = self.run_loop(feed.next())
        self.assertEqual({'bar': None}, result)

        result = self.run_loop(feed.next())
        self.assertEqual(None, result)
        self.assertFalse(feed.is_active())

    def test_read_empty_json_feed(self):
        resp = self.mock_response()

        feed = aiocouchdb.feeds.JsonFeed(resp, loop=self.loop)
        self.assertTrue(feed.is_active())

        result = self.run_loop(feed.next())
        self.assertEqual(None, result)

        self.assertFalse(feed.is_active())

    def test_calling_inactive_feed_returns_none(self):
        resp = self.mock_response()

        feed = aiocouchdb.feeds.JsonFeed(resp, loop=self.loop)
        self.assertTrue(feed.is_active())

        self.run_loop(feed.next())

        self.assertFalse(feed.is_active())

        result = self.run_loop(feed.next())
        self.assertEqual(None, result)

    def test_close_resp_on_feed_end(self):
        resp = self.mock_response()

        feed = aiocouchdb.feeds.JsonFeed(resp, loop=self.loop)
        self.assertTrue(feed.is_active())

        self.run_loop(feed.next())

        self.assertFalse(feed.is_active())
        self.assertTrue(resp.close.called)

    def test_force_close_resp_on_error(self):
        resp = self.mock_response(err=ValueError)

        feed = aiocouchdb.feeds.JsonFeed(resp, loop=self.loop)
        self.assertTrue(feed.is_active())

        self.assertRaises(ValueError,
                          self.loop.run_until_complete,
                          feed.next())

        self.assertFalse(feed.is_active())
        resp.close.assert_called_with(force=True)

class JsonFeedTestCase(utils.TestCase):

    def test_read_json_chunks(self):
        resp = self.mock_response(data=[b'"foo"\r\n', b'{"bar": "baz"}\r\n'])

        feed = aiocouchdb.feeds.JsonFeed(resp, loop=self.loop)
        self.assertTrue(feed.is_active())

        result = self.run_loop(feed.next())
        self.assertEqual('foo', result)

        result = self.run_loop(feed.next())
        self.assertEqual({'bar': 'baz'}, result)

        result = self.run_loop(feed.next())
        self.assertEqual(None, result)
        self.assertFalse(feed.is_active())
<|endoftext|>


<commit_before># Copyright (c) 2012 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

"""Presubmit script for Chromium JS resources.

See chrome/browser/resources/PRESUBMIT.py
"""

class JSChecker(object):
  def __init__(self, input_api, output_api, file_filter=None):
    self.input_api = input_api
    self.output_api = output_api
    self.file_filter = file_filter

  def RegexCheck(self, line_number, line, regex, message):
    """Searches for |regex| in |line| to check for a particular style
       violation, returning a message like the one below if the regex matches.
       The |regex| must have exactly one capturing group so that the relevant
       part of |line| can be highlighted. If more groups are needed, use
       "(?:...)" to make a non-capturing group. Sample message:

       line 6: Use var instead of const.
           const foo = bar();
           ^^^^^
    """
    match = self.input_api.re.search(regex, line)
    if match:
      assert len(match.groups()) == 1
      start = match.start(1)
      length = match.end(1) - start
      return '  line %d: %s\n%s\n%s' % (
          line_number,
          message,
          line,
          self.error_highlight(start, length))
    return ''

  def ChromeSendCheck(self, i, line):
    """Checks for a particular misuse of 'chrome.send'."""
    return self.RegexCheck(i, line, r"chrome\.send\('[^']+'\s*(, \[\])\)",
        'Passing an empty array to chrome.send is unnecessary.')

  def ConstCheck(self, i, line):
    """Check for use of the 'const' keyword."""
    if self.input_api.re.search(r'\*\s+@const', line):
      # Probably a JsDoc line
      return ''

    return self.RegexCheck(i, line, r'(?:^|\s|\()(const)\s',
        'Use var instead of const.')

  def GetElementByIdCheck(self, i, line):
    """Checks for use of 'document.getElementById' instead of '$'."""
    return self.RegexCheck(i, line, r"(document\.getElementById)\('",
        "Use $('id') instead of document.getElementById('id')")

  def error_highlight(self, start, length):
    """Takes a start position and a length, and produces a row of '^'s to
       highlight the corresponding part of a string.
    """
    return start * ' ' + length * '^'

  def _makeErrorOrWarning(self, error_text, filename):
    """Takes a few lines of text indicating a style violation and turns it into
       a PresubmitError (if |filename| is in a directory where we've already
       taken out all the style guide violations) or a PresubmitPromptWarning
       (if it's in a directory where we haven't done that yet).
    """
    # TODO(tbreisacher): Once we've cleaned up the style nits in all of
    # resources/ we can get rid of this function.
    path = self.input_api.os_path
    resources = self.input_api.PresubmitLocalPath()
    dirs = (
        path.join(resources, 'extensions'),
        path.join(resources, 'help'),
        path.join(resources, 'net_internals'),
        path.join(resources, 'ntp4'),
        path.join(resources, 'options2'),
        path.join(resources, 'sync_promo'),
        path.join(resources, 'uber'),
    )
    if filename.startswith(dirs):
      return self.output_api.PresubmitError(error_text)
    else:
      return self.output_api.PresubmitPromptWarning(error_text)

  def RunChecks(self):
    """Check for violations of the Chromium JavaScript style guide. See
       http://chromium.org/developers/web-development-style-guide#TOC-JavaScript
    """

    import sys
    import warnings
    old_path = sys.path
    old_filters = warnings.filters

    try:
      closure_linter_path = self.input_api.os_path.join(
          self.input_api.change.RepositoryRoot(),
          "third_party",
          "closure_linter")
      gflags_path = self.input_api.os_path.join(
          self.input_api.change.RepositoryRoot(),
          "third_party",
          "python_gflags")

      sys.path.insert(0, closure_linter_path)
      sys.path.insert(0, gflags_path)

      warnings.filterwarnings('ignore', category=DeprecationWarning)

      from closure_linter import checker, errors
      from closure_linter.common import errorhandler

    finally:
      sys.path = old_path
      warnings.filters = old_filters

    class ErrorHandlerImpl(errorhandler.ErrorHandler):
      """Filters out errors that don't apply to Chromium JavaScript code."""

      def __init__(self, re):
        self._errors = []
        self.re = re

      def HandleFile(self, filename, first_token):
        self._filename = filename

      def HandleError(self, error):
        if (self._valid(error)):
          error.filename = self._filename
          self._errors.append(error)

      def GetErrors(self):
        return self._errors

      def HasErrors(self):
        return bool(self._errors)

      def _valid(self, error):
        """Check whether an error is valid. Most errors are valid, with a few
           exceptions which are listed here.
        """

        is_grit_statement = bool(
            self.re.search("</?(include|if)", error.token.line))

        return not is_grit_statement and error.code not in [
            errors.COMMA_AT_END_OF_LITERAL,
            errors.JSDOC_ILLEGAL_QUESTION_WITH_PIPE,
            errors.JSDOC_TAG_DESCRIPTION_ENDS_WITH_INVALID_CHARACTER,
            errors.LINE_TOO_LONG,
        ]

    results = []

    affected_files = self.input_api.change.AffectedFiles(
        file_filter=self.file_filter,
        include_deletes=False)
    affected_js_files = filter(lambda f: f.LocalPath().endswith('.js'),
                               affected_files)
    for f in affected_js_files:
      error_lines = []

      # Check for the following:
      # * document.getElementById()
      # * the 'const' keyword
      # * Passing an empty array to 'chrome.send()'
      for i, line in enumerate(f.NewContents(), start=1):
        error_lines += filter(None, [
            self.ChromeSendCheck(i, line),
            self.ConstCheck(i, line),
            self.GetElementByIdCheck(i, line),
        ])

      # Use closure_linter to check for several different errors
      error_handler = ErrorHandlerImpl(self.input_api.re)
      js_checker = checker.JavaScriptStyleChecker(error_handler)
      js_checker.Check(self.input_api.os_path.join(
          self.input_api.change.RepositoryRoot(),
          f.LocalPath()))

      for error in error_handler.GetErrors():
        highlight = self.error_highlight(
            error.token.start_index, error.token.length)
        error_msg = '  line %d: E%04d: %s\n%s\n%s' % (
            error.token.line_number,
            error.code,
            error.message,
            error.token.line.rstrip(),
            highlight)
        error_lines.append(error_msg)

      if error_lines:
        error_lines = [
            'Found JavaScript style violations in %s:' %
            f.LocalPath()] + error_lines
        results.append(self._makeErrorOrWarning(
            '\n'.join(error_lines), f.AbsoluteLocalPath()))

    if results:
      results.append(self.output_api.PresubmitNotifyResult(
          'See the JavaScript style guide at '
          'http://www.chromium.org/developers/web-development-style-guide'
          '#TOC-JavaScript and if you have any feedback about the JavaScript '
          'PRESUBMIT check, contact tbreisacher@chromium.org'))

    return results
<commit_msg>Enable JS checks as errors in print_preview<commit_after># Copyright (c) 2012 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

"""Presubmit script for Chromium JS resources.

See chrome/browser/resources/PRESUBMIT.py
"""

class JSChecker(object):
  def __init__(self, input_api, output_api, file_filter=None):
    self.input_api = input_api
    self.output_api = output_api
    self.file_filter = file_filter

  def RegexCheck(self, line_number, line, regex, message):
    """Searches for |regex| in |line| to check for a particular style
       violation, returning a message like the one below if the regex matches.
       The |regex| must have exactly one capturing group so that the relevant
       part of |line| can be highlighted. If more groups are needed, use
       "(?:...)" to make a non-capturing group. Sample message:

       line 6: Use var instead of const.
           const foo = bar();
           ^^^^^
    """
    match = self.input_api.re.search(regex, line)
    if match:
      assert len(match.groups()) == 1
      start = match.start(1)
      length = match.end(1) - start
      return '  line %d: %s\n%s\n%s' % (
          line_number,
          message,
          line,
          self.error_highlight(start, length))
    return ''

  def ChromeSendCheck(self, i, line):
    """Checks for a particular misuse of 'chrome.send'."""
    return self.RegexCheck(i, line, r"chrome\.send\('[^']+'\s*(, \[\])\)",
        'Passing an empty array to chrome.send is unnecessary.')

  def ConstCheck(self, i, line):
    """Check for use of the 'const' keyword."""
    if self.input_api.re.search(r'\*\s+@const', line):
      # Probably a JsDoc line
      return ''

    return self.RegexCheck(i, line, r'(?:^|\s|\()(const)\s',
        'Use var instead of const.')

  def GetElementByIdCheck(self, i, line):
    """Checks for use of 'document.getElementById' instead of '$'."""
    return self.RegexCheck(i, line, r"(document\.getElementById)\('",
        "Use $('id') instead of document.getElementById('id')")

  def error_highlight(self, start, length):
    """Takes a start position and a length, and produces a row of '^'s to
       highlight the corresponding part of a string.
    """
    return start * ' ' + length * '^'

  def _makeErrorOrWarning(self, error_text, filename):
    """Takes a few lines of text indicating a style violation and turns it into
       a PresubmitError (if |filename| is in a directory where we've already
       taken out all the style guide violations) or a PresubmitPromptWarning
       (if it's in a directory where we haven't done that yet).
    """
    # TODO(tbreisacher): Once we've cleaned up the style nits in all of
    # resources/ we can get rid of this function.
    path = self.input_api.os_path
    resources = self.input_api.PresubmitLocalPath()
    dirs = (
        path.join(resources, 'extensions'),
        path.join(resources, 'help'),
        path.join(resources, 'net_internals'),
        path.join(resources, 'ntp4'),
        path.join(resources, 'options2'),
        path.join(resources, 'print_preview'),
        path.join(resources, 'sync_promo'),
        path.join(resources, 'uber'),
    )
    if filename.startswith(dirs):
      return self.output_api.PresubmitError(error_text)
    else:
      return self.output_api.PresubmitPromptWarning(error_text)

  def RunChecks(self):
    """Check for violations of the Chromium JavaScript style guide. See
       http://chromium.org/developers/web-development-style-guide#TOC-JavaScript
    """

    import sys
    import warnings
    old_path = sys.path
    old_filters = warnings.filters

    try:
      closure_linter_path = self.input_api.os_path.join(
          self.input_api.change.RepositoryRoot(),
          "third_party",
          "closure_linter")
      gflags_path = self.input_api.os_path.join(
          self.input_api.change.RepositoryRoot(),
          "third_party",
          "python_gflags")

      sys.path.insert(0, closure_linter_path)
      sys.path.insert(0, gflags_path)

      warnings.filterwarnings('ignore', category=DeprecationWarning)

      from closure_linter import checker, errors
      from closure_linter.common import errorhandler

    finally:
      sys.path = old_path
      warnings.filters = old_filters

    class ErrorHandlerImpl(errorhandler.ErrorHandler):
      """Filters out errors that don't apply to Chromium JavaScript code."""

      def __init__(self, re):
        self._errors = []
        self.re = re

      def HandleFile(self, filename, first_token):
        self._filename = filename

      def HandleError(self, error):
        if (self._valid(error)):
          error.filename = self._filename
          self._errors.append(error)

      def GetErrors(self):
        return self._errors

      def HasErrors(self):
        return bool(self._errors)

      def _valid(self, error):
        """Check whether an error is valid. Most errors are valid, with a few
           exceptions which are listed here.
        """

        is_grit_statement = bool(
            self.re.search("</?(include|if)", error.token.line))

        return not is_grit_statement and error.code not in [
            errors.COMMA_AT_END_OF_LITERAL,
            errors.JSDOC_ILLEGAL_QUESTION_WITH_PIPE,
            errors.JSDOC_TAG_DESCRIPTION_ENDS_WITH_INVALID_CHARACTER,
            errors.LINE_TOO_LONG,
        ]

    results = []

    affected_files = self.input_api.change.AffectedFiles(
        file_filter=self.file_filter,
        include_deletes=False)
    affected_js_files = filter(lambda f: f.LocalPath().endswith('.js'),
                               affected_files)
    for f in affected_js_files:
      error_lines = []

      # Check for the following:
      # * document.getElementById()
      # * the 'const' keyword
      # * Passing an empty array to 'chrome.send()'
      for i, line in enumerate(f.NewContents(), start=1):
        error_lines += filter(None, [
            self.ChromeSendCheck(i, line),
            self.ConstCheck(i, line),
            self.GetElementByIdCheck(i, line),
        ])

      # Use closure_linter to check for several different errors
      error_handler = ErrorHandlerImpl(self.input_api.re)
      js_checker = checker.JavaScriptStyleChecker(error_handler)
      js_checker.Check(self.input_api.os_path.join(
          self.input_api.change.RepositoryRoot(),
          f.LocalPath()))

      for error in error_handler.GetErrors():
        highlight = self.error_highlight(
            error.token.start_index, error.token.length)
        error_msg = '  line %d: E%04d: %s\n%s\n%s' % (
            error.token.line_number,
            error.code,
            error.message,
            error.token.line.rstrip(),
            highlight)
        error_lines.append(error_msg)

      if error_lines:
        error_lines = [
            'Found JavaScript style violations in %s:' %
            f.LocalPath()] + error_lines
        results.append(self._makeErrorOrWarning(
            '\n'.join(error_lines), f.AbsoluteLocalPath()))

    if results:
      results.append(self.output_api.PresubmitNotifyResult(
          'See the JavaScript style guide at '
          'http://www.chromium.org/developers/web-development-style-guide'
          '#TOC-JavaScript and if you have any feedback about the JavaScript '
          'PRESUBMIT check, contact tbreisacher@chromium.org'))

    return results
<|endoftext|>


<commit_before>from decimal import Decimal

from uber._version import __version__  # noqa: F401

def on_load():
    """
    Called by sideboard when the uber plugin is loaded.
    """
    # Note: The following imports have side effects
    from uber import config  # noqa: F401
    from uber import api  # noqa: F401
    from uber import automated_emails  # noqa: F401
    from uber import custom_tags  # noqa: F401
    from uber import jinja  # noqa: F401
    from uber import menu  # noqa: F401
    from uber import models  # noqa: F401
    from uber import model_checks  # noqa: F401
    from uber import sep_commands  # noqa: F401
    from uber import server  # noqa: F401
    from uber import tasks  # noqa: F401

    # TODO: There's almost certainly a better way to ensure directories
    #       exist before they're accessed. Perhaps we could nest these
    #       under a [directories] section in the config, and ensure those
    #       directories exist?
    import os
    from uber.config import c

    directories = [
        c.UPLOADED_FILES_DIR,
        c.GUESTS_BIO_PICS_DIR,
        c.GUESTS_INVENTORY_DIR,
        c.GUESTS_STAGE_PLOTS_DIR,
        c.GUESTS_W9_FORMS_DIR,
        c.MITS_PICTURE_DIR,
        c.MIVS_GAME_IMAGE_DIR,
    ]
    for directory in directories:
        if not os.path.exists(directory):
            os.makedirs(directory)

# sideboard must be imported AFTER the on_load() function is declared,
# otherwise on_load() won't exist yet when sideboard looks for it.
import sideboard  # noqa: E402

# NOTE: this will decrease the precision of some serialized decimal.Decimals
sideboard.lib.serializer.register(Decimal, lambda n: float(n))
<commit_msg>Revert uploaded file directory creation. This should be done by the deployment script, to ensure it happens at the right time<commit_after>from decimal import Decimal

from uber._version import __version__  # noqa: F401

def on_load():
    """
    Called by sideboard when the uber plugin is loaded.
    """
    # Note: The following imports have side effects
    from uber import config  # noqa: F401
    from uber import api  # noqa: F401
    from uber import automated_emails  # noqa: F401
    from uber import custom_tags  # noqa: F401
    from uber import jinja  # noqa: F401
    from uber import menu  # noqa: F401
    from uber import models  # noqa: F401
    from uber import model_checks  # noqa: F401
    from uber import sep_commands  # noqa: F401
    from uber import server  # noqa: F401
    from uber import tasks  # noqa: F401

# sideboard must be imported AFTER the on_load() function is declared,
# otherwise on_load() won't exist yet when sideboard looks for it.
import sideboard  # noqa: E402

# NOTE: this will decrease the precision of some serialized decimal.Decimals
sideboard.lib.serializer.register(Decimal, lambda n: float(n))
<|endoftext|>


<commit_before>'''Facilities for building terms.'''

from aterm import exceptions
from aterm import terms

class _Singleton(type):
	'''Metaclass for the Singleton design pattern. Based on
	http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/102187
	'''

	def __init__(mcs, name, bases, dic):
		super(_Singleton, mcs).__init__(name, bases, dic)
		mcs.__instance = None

	def __call__(mcs, *args, **kargs):
		if mcs.__instance is None:
			mcs.__instance = super(_Singleton, mcs).__call__(*args, **kargs)
		return mcs.__instance

class Factory(object):
	'''An Factory is responsible for make new Terms, either by parsing
	from string or stream, or via one the of the "make" methods.'''

	__metaclass__ = _Singleton

	# TODO: implement maximal sharing

	MAX_PARSE_CACHE_LEN = 512

	def __init__(self):
		self.parseCache = {}

	def makeInt(self, value, annotations = None):
		'''Creates a new integer literal term'''
		return terms.Integer(self, value, annotations)

	def makeReal(self, value, annotations = None):
		'''Creates a new real literal term'''
		return terms.Real(self, value, annotations)

	def makeStr(self, value, annotations = None):
		'''Creates a new string literal term'''
		return terms.String(self, value, annotations)

	def makeNil(self, annotations = None):
		'''Creates a new empty list term'''
		return terms.Nil(self, annotations)

	def makeCons(self, head, tail = None, annotations = None):
		'''Creates a new extended list term'''
		return terms.Cons(self, head, tail, annotations)

	def makeList(self, seq, annotations = None):
		'''Creates a new list from a sequence.'''
		accum = self.makeNil()
		for i in xrange(len(seq) - 1, -1, -1):
			accum = self.makeCons(seq[i], accum)
		if annotations is not None:
			accum = accum.setAnnotations(annotations)
		return accum

	# TODO: add a makeTuple method

	def makeAppl(self, name, args = None, annotations = None):
		'''Creates a new appplication term'''
		return terms.Application(self, name, args, annotations)

	def makeWildcard(self, annotations = None):
		'''Creates a new wildcard term'''
		return terms.Wildcard(self, annotations)

	def makeVar(self, name, pattern, annotations = None):
		'''Creates a new variable term'''
		return terms.Variable(self, name, pattern, annotations)

	def coerce(self, value, name = None):
		'''Coerce an object to a term. Value must be an int, a float, a string,
		a sequence of terms, or a term.'''

		if isinstance(value, terms.Term):
			return value
		elif isinstance(value, int):
			return self.makeInt(value)
		elif isinstance(value, float):
			return self.makeReal(value)
		elif isinstance(value, basestring):
			return self.makeStr(value)
		elif isinstance(value, list):
			return self.makeList(value)
		elif isinstance(value, tuple):
			return self.makeList(value)
		else:
			msg = "argument"
			if not name is None:
				msg += " " + name
			msg += " is neither a term, a literal, or a list: "
			msg += repr(value)
			raise TypeError(msg)

	def readFromTextFile(self, fp):
		'''Creates a new term by parsing from a text stream.'''

		from aterm.lexer import Lexer
		from aterm.parser import Parser
		from antlr import ANTLRException

		try:
			lexer = Lexer(fp)
			parser = Parser(lexer, factory = self)
			return parser.aterm()
		except ANTLRException, ex:
			raise exceptions.ParseException(str(ex))

	def parse(self, buf):
		'''Creates a new term by parsing a string.'''

		try:
			return self.parseCache[buf]
		except KeyError:
			try:
				from cStringIO import StringIO
			except ImportError:
				from StringIO import StringIO

			fp = StringIO(buf)
			result = self.readFromTextFile(fp)

			if len(self.parseCache) > self.MAX_PARSE_CACHE_LEN:
				# TODO: use a LRU cache policy
				self.parseCache.clear()
			self.parseCache[buf] = result

			return result

	def match(self, pattern, other, args = None, kargs = None):
		'''Matches the term to a string pattern and a list of arguments.
		First the string pattern is parsed into an Term. .'''

		return self.parse(pattern).match(other, args, kargs)

	def make(self, pattern, *args, **kargs):
		'''Creates a new term from a string pattern and a list of arguments.
		First the string pattern is parsed into an Term. Then the holes in
		the pattern are filled with arguments taken from the supplied list of
		arguments.'''

		_pattern = self.parse(pattern)
		i = 0
		_args = []
		for i in range(len(args)):
			_args.append(self.coerce(args[i], str(i)))
			i += 1

		_kargs = {}
		for name, value in kargs.iteritems():
			_kargs[name] = self.coerce(value, "'" + name + "'")

		return _pattern.make(*_args, **_kargs)

<commit_msg>Cache nil list.<commit_after>'''Facilities for building terms.'''

from aterm import exceptions
from aterm import terms

class _Singleton(type):
	'''Metaclass for the Singleton design pattern. Based on
	http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/102187
	'''

	def __init__(mcs, name, bases, dic):
		super(_Singleton, mcs).__init__(name, bases, dic)
		mcs.__instance = None

	def __call__(mcs, *args, **kargs):
		if mcs.__instance is None:
			mcs.__instance = super(_Singleton, mcs).__call__(*args, **kargs)
		return mcs.__instance

class Factory(object):
	'''An Factory is responsible for make new Terms, either by parsing
	from string or stream, or via one the of the "make" methods.'''

	__metaclass__ = _Singleton

	# TODO: implement maximal sharing

	MAX_PARSE_CACHE_LEN = 512

	def __init__(self):
		self.parseCache = {}
		self.__nil = terms.Nil(self)

	def makeInt(self, value, annotations = None):
		'''Creates a new integer literal term'''
		return terms.Integer(self, value, annotations)

	def makeReal(self, value, annotations = None):
		'''Creates a new real literal term'''
		return terms.Real(self, value, annotations)

	def makeStr(self, value, annotations = None):
		'''Creates a new string literal term'''
		return terms.String(self, value, annotations)

	def makeNil(self, annotations = None):
		'''Creates a new empty list term'''
		if annotations is None or self.__nil:
			return self.__nil
		else:
			return terms.Nil(self, annotations)

	def makeCons(self, head, tail = None, annotations = None):
		'''Creates a new extended list term'''
		return terms.Cons(self, head, tail, annotations)

	def makeList(self, seq, annotations = None):
		'''Creates a new list from a sequence.'''
		accum = self.makeNil()
		for i in xrange(len(seq) - 1, -1, -1):
			accum = self.makeCons(seq[i], accum)
		if annotations is not None:
			accum = accum.setAnnotations(annotations)
		return accum

	# TODO: add a makeTuple method

	def makeAppl(self, name, args = None, annotations = None):
		'''Creates a new appplication term'''
		return terms.Application(self, name, args, annotations)

	def makeWildcard(self, annotations = None):
		'''Creates a new wildcard term'''
		return terms.Wildcard(self, annotations)

	def makeVar(self, name, pattern, annotations = None):
		'''Creates a new variable term'''
		return terms.Variable(self, name, pattern, annotations)

	def coerce(self, value, name = None):
		'''Coerce an object to a term. Value must be an int, a float, a string,
		a sequence of terms, or a term.'''

		if isinstance(value, terms.Term):
			return value
		elif isinstance(value, int):
			return self.makeInt(value)
		elif isinstance(value, float):
			return self.makeReal(value)
		elif isinstance(value, basestring):
			return self.makeStr(value)
		elif isinstance(value, list):
			return self.makeList(value)
		elif isinstance(value, tuple):
			return self.makeList(value)
		else:
			msg = "argument"
			if not name is None:
				msg += " " + name
			msg += " is neither a term, a literal, or a list: "
			msg += repr(value)
			raise TypeError(msg)

	def readFromTextFile(self, fp):
		'''Creates a new term by parsing from a text stream.'''

		from aterm.lexer import Lexer
		from aterm.parser import Parser
		from antlr import ANTLRException

		try:
			lexer = Lexer(fp)
			parser = Parser(lexer, factory = self)
			return parser.aterm()
		except ANTLRException, ex:
			raise exceptions.ParseException(str(ex))

	def parse(self, buf):
		'''Creates a new term by parsing a string.'''

		try:
			return self.parseCache[buf]
		except KeyError:
			try:
				from cStringIO import StringIO
			except ImportError:
				from StringIO import StringIO

			fp = StringIO(buf)
			result = self.readFromTextFile(fp)

			if len(self.parseCache) > self.MAX_PARSE_CACHE_LEN:
				# TODO: use a LRU cache policy
				self.parseCache.clear()
			self.parseCache[buf] = result

			return result

	def match(self, pattern, other, args = None, kargs = None):
		'''Matches the term to a string pattern and a list of arguments.
		First the string pattern is parsed into an Term. .'''

		return self.parse(pattern).match(other, args, kargs)

	def make(self, pattern, *args, **kargs):
		'''Creates a new term from a string pattern and a list of arguments.
		First the string pattern is parsed into an Term. Then the holes in
		the pattern are filled with arguments taken from the supplied list of
		arguments.'''

		_pattern = self.parse(pattern)
		i = 0
		_args = []
		for i in range(len(args)):
			_args.append(self.coerce(args[i], str(i)))
			i += 1

		_kargs = {}
		for name, value in kargs.iteritems():
			_kargs[name] = self.coerce(value, "'" + name + "'")

		return _pattern.make(*_args, **_kargs)

<|endoftext|>


<commit_before>import json
import time
import asyncio

import aiohttp
import tornado.web
from raven.contrib.tornado import SentryMixin

from waterbutler.core import utils
from waterbutler.core import signing
from waterbutler.core import exceptions
from waterbutler.server import settings
from waterbutler.server.identity import get_identity

CORS_ACCEPT_HEADERS = [
    'Content-Type',
    'Cache-Control',
    'X-Requested-With',
]

def list_or_value(value):
    assert isinstance(value, list)
    if len(value) == 0:
        return None
    if len(value) == 1:
        # Remove leading slashes as they break things
        return value[0].decode('utf-8')
    return [item.decode('utf-8') for item in value]

signer = signing.Signer(settings.HMAC_SECRET, settings.HMAC_ALGORITHM)

class BaseHandler(tornado.web.RequestHandler, SentryMixin):

    ACTION_MAP = {}

    def set_default_headers(self):
        self.set_header('Access-Control-Allow-Origin', '*')

    def initialize(self):
        method = self.get_query_argument('method', None)
        if method:
            self.request.method = method.upper()

    @asyncio.coroutine
    def prepare(self):
        self.arguments = {
            key: list_or_value(value)
            for key, value in self.request.query_arguments.items()
        }

        try:
            self.arguments['action'] = self.ACTION_MAP[self.request.method]
        except KeyError:
            return

        self.payload = yield from get_identity(settings.IDENTITY_METHOD, **self.arguments)

        self.provider = utils.make_provider(
            self.arguments['provider'],
            self.payload['auth'],
            self.payload['credentials'],
            self.payload['settings'],
        )

    def write_error(self, status_code, exc_info):
        etype, exc, _ = exc_info
        if issubclass(etype, exceptions.ProviderError):
            if exc.data:
                self.set_status(exc.code)
                self.finish(exc.data)
                return

        self.finish({
            "code": status_code,
            "message": self._reason,
        })

    def options(self):
        self.set_status(204)
        self.set_header('Access-Control-Allow-Methods', 'PUT, DELETE'),
        self.set_header('Access-Control-Allow-Headers', ', '.join(CORS_ACCEPT_HEADERS))

    @utils.async_retry(retries=5, backoff=5)
    def _send_hook(self, action, metadata):
        payload = {
            'action': action,
            'provider': self.arguments['provider'],
            'metadata': metadata,
            'auth': self.payload['auth'],
            'time': time.time() + 60
        }
        message, signature = signer.sign_payload(payload)
        resp = aiohttp.request(
            'PUT',
            self.payload['callback_url'],
            data=json.dumps({
                'payload': message.decode(),
                'signature': signature,
            }),
            headers={'Content-Type': 'application/json'},
        )
        return resp
<commit_msg>Log all errors to sentry<commit_after>import json
import time
import asyncio

import aiohttp
import tornado.web
from raven.contrib.tornado import SentryMixin

from waterbutler.core import utils
from waterbutler.core import signing
from waterbutler.core import exceptions
from waterbutler.server import settings
from waterbutler.server.identity import get_identity

CORS_ACCEPT_HEADERS = [
    'Content-Type',
    'Cache-Control',
    'X-Requested-With',
]

def list_or_value(value):
    assert isinstance(value, list)
    if len(value) == 0:
        return None
    if len(value) == 1:
        # Remove leading slashes as they break things
        return value[0].decode('utf-8')
    return [item.decode('utf-8') for item in value]

signer = signing.Signer(settings.HMAC_SECRET, settings.HMAC_ALGORITHM)

class BaseHandler(tornado.web.RequestHandler, SentryMixin):

    ACTION_MAP = {}

    def set_default_headers(self):
        self.set_header('Access-Control-Allow-Origin', '*')

    def initialize(self):
        method = self.get_query_argument('method', None)
        if method:
            self.request.method = method.upper()

    @asyncio.coroutine
    def prepare(self):
        self.arguments = {
            key: list_or_value(value)
            for key, value in self.request.query_arguments.items()
        }

        try:
            self.arguments['action'] = self.ACTION_MAP[self.request.method]
        except KeyError:
            return

        self.payload = yield from get_identity(settings.IDENTITY_METHOD, **self.arguments)

        self.provider = utils.make_provider(
            self.arguments['provider'],
            self.payload['auth'],
            self.payload['credentials'],
            self.payload['settings'],
        )

    def write_error(self, status_code, exc_info):
        self.captureException(exc_info)
        etype, exc, _ = exc_info
        if issubclass(etype, exceptions.ProviderError):
            if exc.data:
                self.set_status(exc.code)
                self.finish(exc.data)
                return

        self.finish({
            "code": status_code,
            "message": self._reason,
        })

    def options(self):
        self.set_status(204)
        self.set_header('Access-Control-Allow-Methods', 'PUT, DELETE'),
        self.set_header('Access-Control-Allow-Headers', ', '.join(CORS_ACCEPT_HEADERS))

    @utils.async_retry(retries=5, backoff=5)
    def _send_hook(self, action, metadata):
        payload = {
            'action': action,
            'provider': self.arguments['provider'],
            'metadata': metadata,
            'auth': self.payload['auth'],
            'time': time.time() + 60
        }
        message, signature = signer.sign_payload(payload)
        resp = aiohttp.request(
            'PUT',
            self.payload['callback_url'],
            data=json.dumps({
                'payload': message.decode(),
                'signature': signature,
            }),
            headers={'Content-Type': 'application/json'},
        )
        return resp
<|endoftext|>


<commit_before>#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""Script to commit the doc build outputs into the github-pages repo.

Use:

  gh-pages.py [tag]

If no tag is given, the current output of 'git describe' is used.  If given,
that is how the resulting directory will be named.

In practice, you should use either actual clean tags from a current build or
something like 'current' as a stable URL for the most current version of the """
from __future__ import print_function, division, absolute_import

#-----------------------------------------------------------------------------
# Imports
#-----------------------------------------------------------------------------
import os
import re
import shutil
import sys
from os import chdir as cd
from os.path import join as pjoin

from subprocess import Popen, PIPE, CalledProcessError, check_call

#-----------------------------------------------------------------------------
# Globals
#-----------------------------------------------------------------------------

pages_dir = 'gh-pages'
html_dir = '_build/html'
pdf_dir = '_build/latex'
pages_repo = 'git@github.com:numba/numba-doc.git'

#-----------------------------------------------------------------------------
# Functions
#-----------------------------------------------------------------------------
def sh(cmd):
    """Execute command in a subshell, return status code."""
    return check_call(cmd, shell=True)

def sh2(cmd):
    """Execute command in a subshell, return stdout.

    Stderr is unbuffered from the subshell.x"""
    p = Popen(cmd, stdout=PIPE, shell=True)
    out = p.communicate()[0]
    retcode = p.returncode
    if retcode:
        raise CalledProcessError(retcode, cmd)
    else:
        return out.rstrip()

def sh3(cmd):
    """Execute command in a subshell, return stdout, stderr

    If anything appears in stderr, print it out to sys.stderr"""
    p = Popen(cmd, stdout=PIPE, stderr=PIPE, shell=True)
    out, err = p.communicate()
    retcode = p.returncode
    if retcode:
        raise CalledProcessError(retcode, cmd)
    else:
        return out.rstrip(), err.rstrip()

def init_repo(path):
    """clone the gh-pages repo if we haven't already."""
    sh("git clone %s %s"%(pages_repo, path))
    here = os.getcwdu()
    cd(path)
    sh('git checkout gh-pages')
    cd(here)

#-----------------------------------------------------------------------------
# Script starts
#-----------------------------------------------------------------------------
if __name__ == '__main__':
    # The tag can be given as a positional argument
    try:
        tag = sys.argv[1]
    except IndexError:
        try:
            tag = sh2('git describe --exact-match')
        except CalledProcessError:
            tag = "dev"   # Fallback
            print("Using dev")

    startdir = os.getcwdu()
    if not os.path.exists(pages_dir):
        # init the repo
        init_repo(pages_dir)
    else:
        # ensure up-to-date before operating
        cd(pages_dir)
        sh('git checkout gh-pages')
        sh('git pull')
        cd(startdir)

    dest = pjoin(pages_dir, tag)

    # don't `make html` here, because gh-pages already depends on html in Makefile
    # sh('make html')
    if tag != 'dev':
        # only build pdf for non-dev targets
        #sh2('make pdf')
        pass

    # This is pretty unforgiving: we unconditionally nuke the destination
    # directory, and then copy the html tree in there
    shutil.rmtree(dest, ignore_errors=True)
    shutil.copytree(html_dir, dest)
    if tag != 'dev':
        #shutil.copy(pjoin(pdf_dir, 'ipython.pdf'), pjoin(dest, 'ipython.pdf'))
        pass

    try:
        cd(pages_dir)
        status = sh2('git status | head -1')
        branch = re.match('\# On branch (.*)$', status).group(1)
        if branch != 'gh-pages':
            e = 'On %r, git branch is %r, MUST be "gh-pages"' % (pages_dir,
                                                                 branch)
            raise RuntimeError(e)

        sh('git add -A %s' % tag)
        sh('git commit -m"Updated doc release: %s"' % tag)
        print()
        print('Most recent 3 commits:')
        sys.stdout.flush()
        sh('git --no-pager log --oneline HEAD~3..')
    finally:
        cd(startdir)

    print()
    print('Now verify the build in: %r' % dest)
    print("If everything looks good, 'git push'")
<commit_msg>Fix gh-pages.py regular expression to match current git command output format.<commit_after>#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""Script to commit the doc build outputs into the github-pages repo.

Use:

  gh-pages.py [tag]

If no tag is given, the current output of 'git describe' is used.  If given,
that is how the resulting directory will be named.

In practice, you should use either actual clean tags from a current build or
something like 'current' as a stable URL for the most current version of the """
from __future__ import print_function, division, absolute_import

#-----------------------------------------------------------------------------
# Imports
#-----------------------------------------------------------------------------
import os
import re
import shutil
import sys
from os import chdir as cd
from os.path import join as pjoin

from subprocess import Popen, PIPE, CalledProcessError, check_call

#-----------------------------------------------------------------------------
# Globals
#-----------------------------------------------------------------------------

pages_dir = 'gh-pages'
html_dir = '_build/html'
pdf_dir = '_build/latex'
pages_repo = 'git@github.com:numba/numba-doc.git'

#-----------------------------------------------------------------------------
# Functions
#-----------------------------------------------------------------------------
def sh(cmd):
    """Execute command in a subshell, return status code."""
    return check_call(cmd, shell=True)

def sh2(cmd):
    """Execute command in a subshell, return stdout.

    Stderr is unbuffered from the subshell.x"""
    p = Popen(cmd, stdout=PIPE, shell=True)
    out = p.communicate()[0]
    retcode = p.returncode
    if retcode:
        raise CalledProcessError(retcode, cmd)
    else:
        return out.rstrip()

def sh3(cmd):
    """Execute command in a subshell, return stdout, stderr

    If anything appears in stderr, print it out to sys.stderr"""
    p = Popen(cmd, stdout=PIPE, stderr=PIPE, shell=True)
    out, err = p.communicate()
    retcode = p.returncode
    if retcode:
        raise CalledProcessError(retcode, cmd)
    else:
        return out.rstrip(), err.rstrip()

def init_repo(path):
    """clone the gh-pages repo if we haven't already."""
    sh("git clone %s %s"%(pages_repo, path))
    here = os.getcwdu()
    cd(path)
    sh('git checkout gh-pages')
    cd(here)

#-----------------------------------------------------------------------------
# Script starts
#-----------------------------------------------------------------------------
if __name__ == '__main__':
    # The tag can be given as a positional argument
    try:
        tag = sys.argv[1]
    except IndexError:
        try:
            tag = sh2('git describe --exact-match')
        except CalledProcessError:
            tag = "dev"   # Fallback
            print("Using dev")

    startdir = os.getcwdu()
    if not os.path.exists(pages_dir):
        # init the repo
        init_repo(pages_dir)
    else:
        # ensure up-to-date before operating
        cd(pages_dir)
        sh('git checkout gh-pages')
        sh('git pull')
        cd(startdir)

    dest = pjoin(pages_dir, tag)

    # don't `make html` here, because gh-pages already depends on html in Makefile
    # sh('make html')
    if tag != 'dev':
        # only build pdf for non-dev targets
        #sh2('make pdf')
        pass

    # This is pretty unforgiving: we unconditionally nuke the destination
    # directory, and then copy the html tree in there
    shutil.rmtree(dest, ignore_errors=True)
    shutil.copytree(html_dir, dest)
    if tag != 'dev':
        #shutil.copy(pjoin(pdf_dir, 'ipython.pdf'), pjoin(dest, 'ipython.pdf'))
        pass

    try:
        cd(pages_dir)
        status = sh2('git status | head -1')
        branch = re.match('On branch (.*)$', status).group(1)
        if branch != 'gh-pages':
            e = 'On %r, git branch is %r, MUST be "gh-pages"' % (pages_dir,
                                                                 branch)
            raise RuntimeError(e)

        sh('git add -A %s' % tag)
        sh('git commit -m"Updated doc release: %s"' % tag)
        print()
        print('Most recent 3 commits:')
        sys.stdout.flush()
        sh('git --no-pager log --oneline HEAD~3..')
    finally:
        cd(startdir)

    print()
    print('Now verify the build in: %r' % dest)
    print("If everything looks good, 'git push'")
<|endoftext|>


<commit_before>from jamjar.base.views import BaseView, authenticate
from jamjar.artists.models import Artist
from jamjar.artists.serializers import ArtistSerializer

class ArtistSearchView(BaseView):
    serializer_class = ArtistSerializer

    """
    Description:
        Given a search string for an artist, search spotify and return the results
        (To be used for Text Field autocompletion)

    Request:
        GET /artists/search/:search_string/

    Response:
        A list of all Artists matching that string
    """
    @authenticate
    def get(self, request, search_string):
        artists = Artist.search_artist(search_string)
        return self.success_response(artists)

class ArtistListView(BaseView):
    serializer_class = ArtistSerializer

    """
    Description:
        Given a list of artist spotify_ids, get or create the artist in the db

    Request:
        POST /artists/
          {
            "spotify_ids": [
              "0cmWgDlu9CwTgxPhf403hb"
            ]
          }

    Response:
        The retrieved or created artist, with the genres and images serialized
        [
          {
            "id": 1,
            "name": "Bonobo",
            "spotify_id": "0cmWgDlu9CwTgxPhf403hb",
            "genres": [
              "chill-out",
              "downtempo",
              "ninja",
              "nu jazz",
              "trip hop"
            ],
            "images": [
              {
                "url": "https://i.scdn.co/image/10e789fe4259875a0bb7f5a41f13a2c5815b4635",
                "height": 667,
                "width": 1000
              },
              {
                "url": "https://i.scdn.co/image/47ca8ff0c123abac4e424fa203c9bdd14685c69e",
                "height": 427,
                "width": 640
              },
              {
                "url": "https://i.scdn.co/image/1478b2e2861c22dcfa152e67581b41659ea02b47",
                "height": 133,
                "width": 200
              },
              {
                "url": "https://i.scdn.co/image/165e00daafa1ae302a549c01a7a50d59e3583fb1",
                "height": 43,
                "width": 64
              }
            ],
            "unofficial": false
          },

        ]
    """
    @authenticate
    def post(self, request):
        # Validate the request
        spotify_ids = request.data.get('spotify_ids')
        if spotify_ids == None:
            return self.error_response("spotify_ids required", 400)

        artists = []

        for spotify_id in spotify_ids:
          artist = Artist.get_or_create_artist(spotify_id)

          if not artist:
            return self.error_response("Unable to get or create an artist with this spotify_id: {}".format(spotify_id), 400)
          else:
            artists.append(artist)

        self.serializer = self.get_serializer(artists,many=True)

        return self.success_response(self.serializer.data)
<commit_msg>Updated endpoint documentation.<commit_after>from jamjar.base.views import BaseView, authenticate
from jamjar.artists.models import Artist
from jamjar.artists.serializers import ArtistSerializer

class ArtistSearchView(BaseView):
    serializer_class = ArtistSerializer

    """
    Description:
        Given a search string for an artist, search spotify and return the results
        (To be used for Text Field autocompletion)

    Request:
        GET /artists/search/:search_string/

    Response:
        A list of all Artists matching that string
    """
    @authenticate
    def get(self, request, search_string):
        artists = Artist.search_artist(search_string)
        return self.success_response(artists)

class ArtistListView(BaseView):
    serializer_class = ArtistSerializer

    """
    Description:
        Given a list of artist spotify_ids, get or create the artist in the db

    Request:
        POST /artists/
          {
            "spotify_ids": [
              "0cmWgDlu9CwTgxPhf403hb"
            ]
          }

    Response:
        The retrieved or created artist, with the genres and images serialized
        [
          {
            "id": 1,
            "name": "Bonobo",
            "spotify_id": "0cmWgDlu9CwTgxPhf403hb",
            "genres": [
              "chill-out",
              "downtempo",
              "ninja",
              "nu jazz",
              "trip hop"
            ],
            "images": [
              {
                "url": "https://i.scdn.co/image/10e789fe4259875a0bb7f5a41f13a2c5815b4635",
                "height": 667,
                "width": 1000
              },
              {
                "url": "https://i.scdn.co/image/47ca8ff0c123abac4e424fa203c9bdd14685c69e",
                "height": 427,
                "width": 640
              },
              {
                "url": "https://i.scdn.co/image/1478b2e2861c22dcfa152e67581b41659ea02b47",
                "height": 133,
                "width": 200
              },
              {
                "url": "https://i.scdn.co/image/165e00daafa1ae302a549c01a7a50d59e3583fb1",
                "height": 43,
                "width": 64
              }
            ],
            "popularity": 70,
            "followers": 419757,
            "unofficial": false
          },

        ]
    """
    @authenticate
    def post(self, request):
        # Validate the request
        spotify_ids = request.data.get('spotify_ids')
        if spotify_ids == None:
            return self.error_response("spotify_ids required", 400)

        artists = []

        for spotify_id in spotify_ids:
          artist = Artist.get_or_create_artist(spotify_id)

          if not artist:
            return self.error_response("Unable to get or create an artist with this spotify_id: {}".format(spotify_id), 400)
          else:
            artists.append(artist)

        self.serializer = self.get_serializer(artists,many=True)

        return self.success_response(self.serializer.data)
<|endoftext|>