<commit_before>from django.test import TestCase
from mdot.mdot_rest_client.client import MDOT
import json

class MdotClientRequestTest(TestCase):

    def setUp(self):
        pass

    def test_get_all_resources(self):
        """
        Tests getting JSON from the uwresources API and converting it into a
        class object for use in our templates.
        """
        with self.settings(
            RESTCLIENTS_MDOT_DAO_CLASS='Mock'
        ):
            resources = MDOT().get_resources()
            # Make sure what we get back is a list
            self.assertEqual(type(resources), type([]))
            # Make sure that the first object in the list is of object
            # type ClientResource

            # -> Make sure that we get back the bare minimum fields
            # that we need to make mdot work

            # title: Make sure that the title is unicode
            self.assertEqual(type(resources[0].title), type(u'unicode string'))

            # feature_desc: Make sure that the description is unicode
            self.assertEqual(type(resources[0].feature_desc), type(u'unicode'))

            # image: Make sure that the url is unicode
            self.assertEqual(type(resources[0].image_url), type(u'unicode'))

            # resource_links: Make sure that the resource links are in a dict
            self.assertEqual(type(resources[0].resource_links), type({}))
            self.assertEqual(len(resources), 3)

    def test_get_resources_by_featured(self):
        """
        Tests retrieval of resources by filtering on attributes.
        """
        with self.settings(
            RESTCLIENTS_MDOT_DAO_CLASS='Mock'
        ):
            resources = MDOT().get_resources(featured=True)
            # make a request separately to ?featured=true
            response = MDOT().getURL('/api/v1/uwresources/?featured=True',
                                     {'Accept': 'application/json'})
            # assert a 200 status
            self.assertEqual(response.status, 200)
            comparison_data = json.loads(response.data)

            # assert that the two retrieved resources have the same id as the
            # ones in the response
            id_list = []
            for item in comparison_data:
                id_list.append(item['id'])
            for resource in resources:
                self.assertTrue(resource.resource_id in id_list)

            # assert the same number of items are returned (and no extras)
            self.assertEqual(comparison_data.__len__(), resources.__len__())

    def test_get_resources_by_multiple_attrs(self):
        """
        WILL TEST retrieval of resources filtered by more than one attribute.
        """
        with self.settings(
            RESTCLIENTS_MDOT_DAO_CLASS='Mock'
        ):
            resources = MDOT().get_resources(featured=True, audience='alumni')
            # make a request separately to ?featured=true&audience=alumni
            url = '/api/v1/uwresources/?featured=True&audience=alumni'
            response = MDOT().getURL(url,
                                     {'Accept': 'application/json'})
            # assert a 200 status
            self.assertEqual(response.status, 200)
            comparison_data = json.loads(response.data)

            # assert that the two retrieved resources have the same id as the
            # ones in the response
            id_list = []
            for item in comparison_data:
                id_list.append(item['id'])
            for resource in resources:
                self.assertTrue(resource.resource_id in id_list)

            # assert the same number of items are returned (and no extras)
            self.assertEqual(comparison_data.__len__(), resources.__len__())
<commit_msg>cleaned up test suite code<commit_after>from django.test import TestCase, override_settings
from mdot.mdot_rest_client.client import MDOT
import json

DAO = 'Mock'

@override_settings(RESTCLIENTS_MDOT_DAO_CLASS=DAO)
class MdotClientRequestTest(TestCase):

    def setUp(self):
        pass

    def test_get_all_resources(self):
        """
        Tests getting JSON from the uwresources API and converting it into a
        class object for use in our templates.
        """
        resources = MDOT().get_resources()
        # Make sure what we get back is a list
        self.assertEqual(type(resources), type([]))
        # Make sure that the first object in the list is of object
        # type ClientResource

        # -> Make sure that we get back the bare minimum fields
        # that we need to make mdot work

        # title: Make sure that the title is unicode
        self.assertEqual(type(resources[0].title), type(u'unicode string'))

        # feature_desc: Make sure that the description is unicode
        self.assertEqual(type(resources[0].feature_desc), type(u'unicode'))

        # image: Make sure that the url is unicode
        self.assertEqual(type(resources[0].image_url), type(u'unicode'))

        # resource_links: Make sure that the resource links are in a dict
        self.assertEqual(type(resources[0].resource_links), type({}))
        self.assertEqual(len(resources), 3)

    def test_get_resources_by_featured(self):
        """
        Tests retrieval of resources by filtering on attributes.
        """
        resources = MDOT().get_resources(featured=True)
        # make a request separately to ?featured=true
        response = MDOT().getURL('/api/v1/uwresources/?featured=True',
                                    {'Accept': 'application/json'})
        # assert a 200 status
        self.assertEqual(response.status, 200)
        comparison_data = json.loads(response.data)

        # assert that the two retrieved resources have the same id as the
        # ones in the response
        id_list = []
        for item in comparison_data:
            id_list.append(item['id'])
        for resource in resources:
            self.assertTrue(resource.resource_id in id_list)

        # assert the same number of items are returned (and no extras)
        self.assertEqual(comparison_data.__len__(), resources.__len__())

    def test_get_resources_by_multiple_attrs(self):
        """
        WILL TEST retrieval of resources filtered by more than one attribute.
        """
        resources = MDOT().get_resources(featured=True, audience='alumni')
        # make a request separately to ?featured=true&audience=alumni
        url = '/api/v1/uwresources/?featured=True&audience=alumni'
        response = MDOT().getURL(url,
                                    {'Accept': 'application/json'})
        # assert a 200 status
        self.assertEqual(response.status, 200)
        comparison_data = json.loads(response.data)

        # assert that the two retrieved resources have the same id as the
        # ones in the response
        id_list = []
        for item in comparison_data:
            id_list.append(item['id'])
        for resource in resources:
            self.assertTrue(resource.resource_id in id_list)

        # assert the same number of items are returned (and no extras)
        self.assertEqual(comparison_data.__len__(), resources.__len__())
<|endoftext|>


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

import wx
import controlled_vocabularies as vocab

# this module will provide all the functionality for the drop-down controlled vocabulary menus
# ideally, these classes should take in a grid item and then provide the functionality

class Menus():

    def __init__(self, data_type, check, grid, belongs_to, headers=['site_class', 'site_lithology', 'site_type', 'site_definition']):
        """take: data_type (string), check (top level class object for ErMagic steps 1-6), grid (grid object), belongs_to (options for data object to belong to, i.e. locations for the site Menus)"""
        self.data_type = data_type
        self.check = check # check is top level class object for entire ErMagic steps 1-6
        self.grid = grid
        self.window = grid.Parent # parent window in which grid resides
        self.belongs_to = belongs_to
        self.headers = headers
        self.selected_col = None
        self.InitUI()

    def InitUI(self):
        belongs_to = self.belongs_to
        if self.data_type == 'specimen':
            choices = {2: (belongs_to, False)}
        if self.data_type == 'sample' or self.data_type == 'site':
            choices = {2: (belongs_to, False), 3: (vocab.site_class, False), 4: (vocab.site_lithology, True), 5: (vocab.site_type, False)}
        if self.data_type == 'site':
            choices[6] = (vocab.site_definition, False)
        if self.data_type == 'location':
            choices = {1: (vocab.location_type, False)}
        if self.data_type == 'age':
            choices = {3: (vocab.geochronology_method_codes, False), 5: (vocab.age_units, False)}
        self.window.Bind(wx.grid.EVT_GRID_SELECT_CELL, lambda event: self.on_left_click(event, self.grid, choices), self.grid)
        self.window.Bind(wx.grid.EVT_GRID_LABEL_LEFT_CLICK, self.on_label_click, self.grid)

    def on_label_click(self, event):
        col = event.GetCol()
        if col == -1:
            return 0
        if col == 2 and self.data_type == 'age':
            return 0
        if (col not in (-1, 0, 1)) or (col == 1 and self.data_type == 'location'):
        # if a new column was chosen without de-selecting the previous column, deselect the old selected_col
            if self.selected_col != None and self.selected_col != col:
                col_label_value = self.grid.GetColLabelValue(self.selected_col)
                self.grid.SetColLabelValue(self.selected_col, col_label_value[:-10])
                for row in range(self.grid.GetNumberRows()):
                    self.grid.SetCellBackgroundColour(row, self.selected_col, 'white')
                self.grid.ForceRefresh()
            # deselect col if user is clicking on it a second time
            if col == self.selected_col:
                col_label_value = self.grid.GetColLabelValue(col)
                self.grid.SetColLabelValue(col, col_label_value[:-10])
                for row in range(self.grid.GetNumberRows()):
                    self.grid.SetCellBackgroundColour(row, col, 'white')
                self.grid.ForceRefresh()
                self.selected_col = None
            else:
                self.selected_col = col
                col_label_value = self.grid.GetColLabelValue(col)
                self.grid.SetColLabelValue(col, col_label_value + " \nEDIT ALL")
                for row in range(self.grid.GetNumberRows()):
                    self.grid.SetCellBackgroundColour(row, col, 'light blue')
                self.grid.ForceRefresh()
        has_dropdown = ((col == 2 and self.data_type is 'specimen') or (col in range(2, 6) and self.data_type in ['site', 'sample']) or (col in (3, 5) and self.data_type == 'age') or (col == 6 and self.data_type == 'site') or (col == 1 and self.data_type == 'location'))

        # if the column has no drop-down list, allow user to edit all cells in the column through text entry
        if not has_dropdown and col not in (0, 1):
            if self.selected_col == col:
                self.check.changes = True
                default_value = self.grid.GetCellValue(0, col)
                #data = wx.GetTextFromUser("Enter value for all cells in the column\nNote: this will overwrite any existing cell values", "Edit All", default_value)

                data = None
                dialog = wx.TextEntryDialog(None, "Enter value for all cells in the column\nNote: this will overwrite any existing cell values", "Edit All", default_value, style=wx.OK|wx.CANCEL)
                if dialog.ShowModal() == wx.ID_OK:
                    data = dialog.GetValue()
                    for row in range(self.grid.GetNumberRows()):
                        self.grid.SetCellValue(row, col, str(data))
                dialog.Destroy()
                # then deselect column
                col_label_value = self.grid.GetColLabelValue(col)
                self.grid.SetColLabelValue(col, col_label_value[:-10])
                for row in range(self.grid.GetNumberRows()):
                    self.grid.SetCellBackgroundColour(row, col, 'white')
                self.grid.ForceRefresh()
                self.selected_col = None

    def clean_up(self, grid):
        if self.selected_col:
            col_label_value = self.grid.GetColLabelValue(self.selected_col)
            self.grid.SetColLabelValue(self.selected_col, col_label_value[:-10])
            for row in range(self.grid.GetNumberRows()):
                self.grid.SetCellBackgroundColour(row, self.selected_col, 'white')
        self.grid.ForceRefresh()

    def on_left_click(self, event, grid, choices):
        """creates popup menu when user clicks on the column
        if that column is in the list of choices that get a drop-down menu.
        allows user to edit the column, but only from available values"""
        col = event.GetCol()
        if col in choices.keys(): # column should have a pop-up menu
            row = event.GetRow()
            menu = wx.Menu()
            two_tiered = choices[col][1]
            choices = choices[col][0]
            if not two_tiered: # menu is one tiered
                # insert CLEAR option as first choice
                if 'CLEAR cell of all values' not in choices:
                    choices.insert(0, 'CLEAR cell of all values')
                for choice in choices:
                    if not choice: choice = " " # prevents error if choice is an empty string
                    menuitem = menu.Append(wx.ID_ANY, choice)
                    self.window.Bind(wx.EVT_MENU, lambda event: self.on_select_menuitem(event, grid, row, col), menuitem)
                self.window.PopupMenu(menu)
                menu.Destroy()
            else: # menu is two_tiered
                # insert CLEAR option as first menuitem
                clear = menu.Append(-1, 'CLEAR cell of all values')
                self.window.Bind(wx.EVT_MENU, lambda event: self.on_select_menuitem(event, grid, row, col), clear)
                for choice in sorted(choices.items()):
                    submenu = wx.Menu()
                    for item in choice[1]:
                        menuitem = submenu.Append(-1, item)
                        self.window.Bind(wx.EVT_MENU, lambda event: self.on_select_menuitem(event, grid, row, col), menuitem)
                    menu.AppendMenu(-1, choice[0], submenu)
                self.window.PopupMenu(menu)
                menu.Destroy()

    def update_drop_down_menu(self, grid, choices):
        self.window.Bind(wx.grid.EVT_GRID_SELECT_CELL, lambda event: self.on_left_click(event, grid, choices), grid)

    def on_select_menuitem(self, event, grid, row, col):
        """
        sets value of selected cell to value selected from menu
        """
        self.check.changes = True # if user selects a menuitem, that is an edit
        item_id =  event.GetId()
        item = event.EventObject.FindItemById(item_id)
        label = item.Label
        cell_value = grid.GetCellValue(row, col)
        if str(label) == "CLEAR cell of all values":
            label = ""
        elif (col in range(3, 6) and self.data_type in ['site', 'sample']) or (col == 3 and self.data_type == 'age'):
        #if True:
            if not label.lower() in cell_value.lower():
                label += (":" + cell_value).rstrip(':')
            else:
                label = cell_value
        if self.selected_col and self.selected_col == col:
            for row in range(self.grid.GetNumberRows()):
                grid.SetCellValue(row, col, label)
                #self.selected_col = None
        else:
            grid.SetCellValue(row, col, label)

<commit_msg>QuickMagic step 3: fix some more column settings problems in drop-down-menus<commit_after>#!/usr/bin/env python

import wx
import controlled_vocabularies as vocab

# this module will provide all the functionality for the drop-down controlled vocabulary menus
# ideally, these classes should take in a grid item and then provide the functionality

class Menus():

    def __init__(self, data_type, check, grid, belongs_to, headers=['site_class', 'site_lithology', 'site_type', 'site_definition']):
        """take: data_type (string), check (top level class object for ErMagic steps 1-6), grid (grid object), belongs_to (options for data object to belong to, i.e. locations for the site Menus)"""
        self.data_type = data_type
        self.check = check # check is top level class object for entire ErMagic steps 1-6
        self.grid = grid
        self.window = grid.Parent # parent window in which grid resides
        self.belongs_to = belongs_to
        self.headers = headers
        self.selected_col = None
        self.InitUI()

    def InitUI(self):
        belongs_to = self.belongs_to
        if self.data_type == 'specimen':
            choices = {2: (belongs_to, False)}
        if self.data_type == 'sample' or self.data_type == 'site':
            choices = {2: (belongs_to, False), 3: (vocab.site_class, False), 4: (vocab.site_lithology, True), 5: (vocab.site_type, False)}
        if self.data_type == 'site':
            choices[6] = (vocab.site_definition, False)
        if self.data_type == 'location':
            choices = {1: (vocab.location_type, False)}
        if self.data_type == 'age':
            choices = {3: (vocab.geochronology_method_codes, False), 5: (vocab.age_units, False)}
        self.window.Bind(wx.grid.EVT_GRID_SELECT_CELL, lambda event: self.on_left_click(event, self.grid, choices), self.grid)
        self.window.Bind(wx.grid.EVT_GRID_LABEL_LEFT_CLICK, self.on_label_click, self.grid)

    def on_label_click(self, event):
        col = event.GetCol()
        if col == -1:
            return 0
        if col == 2 and self.data_type == 'age':
            return 0
        if (col not in (-1, 0, 1)) or (col == 1 and self.data_type in ['location', 'age']):
        # if a new column was chosen without de-selecting the previous column, deselect the old selected_col
            if self.selected_col != None and self.selected_col != col:
                col_label_value = self.grid.GetColLabelValue(self.selected_col)
                self.grid.SetColLabelValue(self.selected_col, col_label_value[:-10])
                for row in range(self.grid.GetNumberRows()):
                    self.grid.SetCellBackgroundColour(row, self.selected_col, 'white')
                self.grid.ForceRefresh()
            # deselect col if user is clicking on it a second time
            if col == self.selected_col:
                col_label_value = self.grid.GetColLabelValue(col)
                self.grid.SetColLabelValue(col, col_label_value[:-10])
                for row in range(self.grid.GetNumberRows()):
                    self.grid.SetCellBackgroundColour(row, col, 'white')
                self.grid.ForceRefresh()
                self.selected_col = None
            else:
                self.selected_col = col
                col_label_value = self.grid.GetColLabelValue(col)
                self.grid.SetColLabelValue(col, col_label_value + " \nEDIT ALL")
                for row in range(self.grid.GetNumberRows()):
                    self.grid.SetCellBackgroundColour(row, col, 'light blue')
                self.grid.ForceRefresh()
        has_dropdown = ((col == 2 and self.data_type is 'specimen') or (col in range(2, 6) and self.data_type in ['site', 'sample']) or (col in (3, 5) and self.data_type == 'age') or (col == 6 and self.data_type == 'site') or (col == 1 and self.data_type in ['location']))

        # if the column has no drop-down list, allow user to edit all cells in the column through text entry
        if (not has_dropdown and col not in (0, 1)) or (col == 1 and self.data_type in ['age']):
            if self.selected_col == col:
                self.check.changes = True
                default_value = self.grid.GetCellValue(0, col)
                #data = wx.GetTextFromUser("Enter value for all cells in the column\nNote: this will overwrite any existing cell values", "Edit All", default_value)
                data = None
                dialog = wx.TextEntryDialog(None, "Enter value for all cells in the column\nNote: this will overwrite any existing cell values", "Edit All", default_value, style=wx.OK|wx.CANCEL)
                dialog.Centre()
                if dialog.ShowModal() == wx.ID_OK:
                    data = dialog.GetValue()
                    for row in range(self.grid.GetNumberRows()):
                        self.grid.SetCellValue(row, col, str(data))
                dialog.Destroy()
                # then deselect column
                col_label_value = self.grid.GetColLabelValue(col)
                self.grid.SetColLabelValue(col, col_label_value[:-10])
                for row in range(self.grid.GetNumberRows()):
                    self.grid.SetCellBackgroundColour(row, col, 'white')
                self.grid.ForceRefresh()
                self.selected_col = None

    def clean_up(self, grid):
        if self.selected_col:
            col_label_value = self.grid.GetColLabelValue(self.selected_col)
            self.grid.SetColLabelValue(self.selected_col, col_label_value[:-10])
            for row in range(self.grid.GetNumberRows()):
                self.grid.SetCellBackgroundColour(row, self.selected_col, 'white')
        self.grid.ForceRefresh()

    def on_left_click(self, event, grid, choices):
        """creates popup menu when user clicks on the column
        if that column is in the list of choices that get a drop-down menu.
        allows user to edit the column, but only from available values"""
        #print dir(event)
        #print "event.WasProcessed()", event.WasProcessed()
        #print "event.Position", event.Position
        #print "event.ResumePropagation", event.ResumePropagation() # requires level argument, or something
        #event.Skip() # doesn't seem to do anything useful
        #event.Veto() # prevents border from being drawn
        col = event.GetCol()
        row = event.GetRow()

        #print "row", row
        #print "col", col
        #self.grid.SetGridCursor(row, col) # causes infinite recursion error
        if col in choices.keys(): # column should have a pop-up menu
            menu = wx.Menu()
            two_tiered = choices[col][1]
            choices = choices[col][0]
            if not two_tiered: # menu is one tiered
                if 'CLEAR cell of all values' not in choices:
                    choices.insert(0, 'CLEAR cell of all values')
                for choice in choices:
                    if not choice: choice = " " # prevents error if choice is an empty string
                    menuitem = menu.Append(wx.ID_ANY, choice)
                    self.window.Bind(wx.EVT_MENU, lambda event: self.on_select_menuitem(event, grid, row, col), menuitem)
                self.window.PopupMenu(menu)
                menu.Destroy()
            else: # menu is two_tiered
                clear = menu.Append(-1, 'CLEAR cell of all values')
                self.window.Bind(wx.EVT_MENU, lambda event: self.on_select_menuitem(event, grid, row, col), clear)
                for choice in sorted(choices.items()):
                    submenu = wx.Menu()
                    for item in choice[1]:
                        menuitem = submenu.Append(-1, item)
                        self.window.Bind(wx.EVT_MENU, lambda event: self.on_select_menuitem(event, grid, row, col), menuitem)
                    menu.AppendMenu(-1, choice[0], submenu)
                self.window.PopupMenu(menu)
                menu.Destroy()

    def update_drop_down_menu(self, grid, choices):
        self.window.Bind(wx.grid.EVT_GRID_SELECT_CELL, lambda event: self.on_left_click(event, grid, choices), grid)

    def on_select_menuitem(self, event, grid, row, col):
        """
        sets value of selected cell to value selected from menu
        """
        self.check.changes = True # if user selects a menuitem, that is an edit
        item_id =  event.GetId()
        item = event.EventObject.FindItemById(item_id)
        label = item.Label
        cell_value = grid.GetCellValue(row, col)
        if str(label) == "CLEAR cell of all values":
            label = ""
        elif (col in range(3, 6) and self.data_type in ['site', 'sample']) or (col == 3 and self.data_type == 'age'):
        #if True:
            if not label.lower() in cell_value.lower():
                label += (":" + cell_value).rstrip(':')
            else:
                label = cell_value
        if self.selected_col and self.selected_col == col:
            for row in range(self.grid.GetNumberRows()):
                grid.SetCellValue(row, col, label)
                #self.selected_col = None
        else:
            grid.SetCellValue(row, col, label)

<|endoftext|>


<commit_before>#!/usr/bin/env python2
from __future__ import division
import sys

import cv2
import sys
import numpy as np
from networktables import NetworkTables
import logging
BLUR_SIZE = (11, 11)
BLUR_FACTOR = 90
GREEN_LOWER_LIMIT = 230
MEDIAN_BLUR_SIZE = 5
logging.basicConfig(level=logging.DEBUG)

ip = "10.29.28.2"

def ntInit(table):
    NetworkTables.initialize(ip)
    return NetworkTables.getTable(table)

# From http://stackoverflow.com/questions/4961017/clojure-style-function-threading-in-python
def T(*args):
    return reduce(lambda l, r: r(l), args)

def toGrayscale(src):
    return cv2.cvtColor(src, cv2.COLOR_BGR2GRAY)

def toGreenscale(src):
    return cv2.extractChannel(src, 1)

def brightPass(src):
    return cv2.inRange(src, GREEN_LOWER_LIMIT, 255)

def blur(src):
    return cv2.GaussianBlur(src, BLUR_SIZE, BLUR_FACTOR)

def medianBlur(src):
    return cv2.medianBlur(src, MEDIAN_BLUR_SIZE)
def blobbify(src):
    data = src.flat
    dims = src.shape
    print dims
    for i in range(0, len(data)):
        if data[i] > 1:
            cv2.ellipse(src, (i % dims[0], i / dims[0]), (15, 6), 90, 0, 360, 0xFF, -1)
    return src

def outline(src):
    dst = np.zeros(src.shape, np.uint8)
    im2, contours, hierarchy  = cv2.findContours(src, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
    cv2.drawContours(dst, contours, -1, (255), 1)
    return dst, contours

def quads(contours):
    heightWidthRatio = 5/2
    tolerance = 0.75
    output = []
    boxes = []
    polys = [cv2.approxPolyDP(c, 5, True) for c in contours]
    polys = filter(lambda c: len(c) == 4, polys)
    for p in polys:
        _, _, w, h = cv2.boundingRect(p)
        boxes.append(abs(h/w - heightWidthRatio) <= tolerance)
    for i in range(len(boxes)):
        if boxes[i]:
            output.append(polys[i])
    return output

def pairs(contours):
    areas = [cv2.contourArea(c) for c in contours]
    outputMask = [False] * len(areas)
    output = []
    # Awful imperative code TODO: write something better
    for i in range(len(areas)):
        for j in range(len(areas)):
            if i == j or outputMask[i] or outputMask[j]:
                continue
            if abs(max(areas[i], areas[j])/min(areas[i], areas[j])) - 1 <= 2.0:
                outputMask[i] = True
                outputMask[j] = True
    for i in range(len(areas)):
        if outputMask[i]:
            output.append(contours[i])
    return output

def distanceToCenter(contours, frameWidth):
    moments = [cv2.moments(c) for c in contours][:2]
    normalized = []
    for m in moments:
        cx = int(m['m10'] / m['m00'])
        print cx
        normalized.append(2*cx/frameWidth - 1)
    if len(normalized) > 0:
        return apply(lambda a, b: a + b, normalized) / len(normalized)
    return -2

def main(camera = 0):
    vc = ntInit('VisionControl')
    cap = cv2.VideoCapture(camera)
    #cv2.namedWindow("Output")
    ret, frame = cap.read()
    print frame.shape[0]
    while ret:
        distanceSent = False
        ret, frame = cap.read()
        frame, contours = outline(T(frame, toGreenscale, brightPass, medianBlur))
        contours = pairs(quads(contours))
        distance = distanceToCenter(contours, frame.shape[1])
        if abs(distance) <= 1:
            vc.putValue("detectedValue", distance)
            distanceSent = True
        vc.putBoolean("targetLocked", distanceSent)
        cv2.drawContours(frame, contours, -1, (127), 3)
        #cv2.imshow("Output", frame)
        if(cv2.waitKey(30) & 0xFF == ord('q')):
            break
    cap.release()

if __name__ == "__main__":
    main(0 if len(sys.argv) < 2 else int(sys.argv[1]))
<commit_msg>Small changes made from robot<commit_after>#!/usr/bin/env python2
from __future__ import division
import sys

import cv2
import sys
import numpy as np
from networktables import NetworkTables
import logging
BLUR_SIZE = (11, 11)
BLUR_FACTOR = 90
GREEN_LOWER_LIMIT = 230
MEDIAN_BLUR_SIZE = 5
logging.basicConfig(level=logging.DEBUG)

ip = "10.29.28.56"

def ntInit(table):
    NetworkTables.initialize(ip)
    return NetworkTables.getTable(table)

# From http://stackoverflow.com/questions/4961017/clojure-style-function-threading-in-python
def T(*args):
    return reduce(lambda l, r: r(l), args)

def toGrayscale(src):
    return cv2.cvtColor(src, cv2.COLOR_BGR2GRAY)

def toGreenscale(src):
    return cv2.extractChannel(src, 1)

def brightPass(src):
    return cv2.inRange(src, GREEN_LOWER_LIMIT, 255)

def blur(src):
    return cv2.GaussianBlur(src, BLUR_SIZE, BLUR_FACTOR)

def medianBlur(src):
    return cv2.medianBlur(src, MEDIAN_BLUR_SIZE)
def blobbify(src):
    data = src.flat
    dims = src.shape
    print dims
    for i in range(0, len(data)):
        if data[i] > 1:
            cv2.ellipse(src, (i % dims[0], i / dims[0]), (15, 6), 90, 0, 360, 0xFF, -1)
    return src

def outline(src):
    dst = np.zeros(src.shape, np.uint8)
    im2, contours, hierarchy  = cv2.findContours(src, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
    cv2.drawContours(dst, contours, -1, (255), 1)
    return dst, contours

def quads(contours):
    heightWidthRatio = 5/2
    tolerance = 0.75
    output = []
    boxes = []
    polys = [cv2.approxPolyDP(c, 5, True) for c in contours]
    polys = filter(lambda c: len(c) == 4, polys)
    for p in polys:
        _, _, w, h = cv2.boundingRect(p)
        boxes.append(abs(h/w - heightWidthRatio) <= tolerance)
    for i in range(len(boxes)):
        if boxes[i]:
            output.append(polys[i])
    return output

def pairs(contours):
    areas = [cv2.contourArea(c) for c in contours]
    outputMask = [False] * len(areas)
    output = []
    # Awful imperative code TODO: write something better
    for i in range(len(areas)):
        for j in range(len(areas)):
            if i == j or outputMask[i] or outputMask[j]:
                continue
            if abs(max(areas[i], areas[j])/min(areas[i], areas[j])) - 1 <= 2.0:
                outputMask[i] = True
                outputMask[j] = True
    for i in range(len(areas)):
        if outputMask[i]:
            output.append(contours[i])
    return output

def distanceToCenter(contours, frameWidth):
    moments = [cv2.moments(c) for c in contours][:2]
    normalized = []
    for m in moments:
        cx = int(m['m10'] / m['m00'])
        normalized.append(2*cx/frameWidth - 1)
    if len(normalized) > 0:
        return apply(lambda a, b: a + b, normalized) / len(normalized)
    return -2

def main(camera = 0):
    vc = ntInit('VisionControl')
    cap = cv2.VideoCapture(camera)
    #cv2.namedWindow("Output")
    ret, frame = cap.read()
    print frame.shape[0]
    while ret:
        distanceSent = False
        ret, frame = cap.read()
        frame, contours = outline(T(frame, toGreenscale, brightPass, medianBlur))
        contours = pairs(quads(contours))
        distance = distanceToCenter(contours, frame.shape[1])
        if abs(distance) <= 1:
            vc.putValue("detectedValue", distance)
            distanceSent = True
        logging.info(str((distance, distanceSent)))
        vc.putBoolean("targetLocked", distanceSent)
        cv2.drawContours(frame, contours, -1, (127), 3)
        #cv2.imshow("Output", frame)
        if(cv2.waitKey(30) & 0xFF == ord('q')):
            break
    cap.release()

if __name__ == "__main__":
    main(0 if len(sys.argv) < 2 else int(sys.argv[1]))
<|endoftext|>


<commit_before># Define here the models for your scraped items
#
# See documentation in:
# http://doc.scrapy.org/topics/items.html

import re
from scrapy.item import Item, Field
from scrapy.selector import HtmlXPathSelector
from scrapy.selector.list import XPathSelectorList

class ManagedItem(Item):
    name = Field()
    type = Field()
    info = Field()
    description = Field()
    methods = Field()
    properties = Field()

class DataItem(Item):
    name = Field()
    type = Field()
    info = Field()
    description = Field()
    properties = Field()

class EnumItem(Item):
    # define the fields for your item here like:
    name = Field()
    type = Field()
    description = Field()
    constants = Field()

def _clean(selector):
    if isinstance(selector, list):
        rv = []
        for row in selector:
            row = _clean(row)
            if row:
                rv.append(row)
        if len(rv) == 1:
            return rv[0]
        if len(rv) == 0:
            return ''
        return rv
    elif isinstance(selector, unicode) or isinstance(selector, str):
        return selector.strip().replace('
', '').replace('
', '').replace('
', '').replace('
', '').strip()
    else:
        return _clean(selector.extract())

class IteratorObject(object):
    def __init__(self):
        self.data = []

    def __len__(self):
        return len(self.data)

    def __iter__(self):
        for value in self.data:
            yield value

    def __str__(self):
        return str(self.data)

class Fault(object):
    """ A fault that can be raised from a method """
    def __init__(self, type, description=""):
        self.type = type
        self.description = description

    def __str__(self):
        return self.type

class Faults(IteratorObject):
    """ Faults that can be raised from a method """
    def __init__(self):
        super(Faults, self).__init__()

    def parse(self, table):
        for row in table.select('.//tr')[1:]:
            cols = row.select('./td')
            if len(cols) > 1:
                _type = _clean(cols[0].select('./text()'))
                desc = _clean(cols[1].select('./text()'))
                if isinstance(desc, list):
                    desc = ' '.join(desc)

                self.data.append( Fault(_type, desc) )
        return self.data

class ReturnValue(object):
    """return value from a method """
    def __init__(self):
        self.type = None
        self.description = ""

    def parse(self, table):
        rv = []
        for row in table.select('.//tr')[1:]:
            cols = row.select('./td')

            if len(cols) > 1:
                self.type = _clean(cols[0].select('./text()'))
                if self.type and isinstance(self.type, list):
                    self.type = ' '.join(self.type)
                else:
                    self.type = ""
                self.description = _clean(cols[1].select('./text()'))
                if self.description and isinstance(self.description, list):
                    self.description = ' '.join(self.description)
                else:
                    self.description = ""
        return self

    def __str__(self):
        return str(self.type if not None else self.description)

class Argument(object):
    """ An argument to a method """
    def __init__(self, name, type, description="", optional=False):
        self.name = name
        self.type = type
        self.description = description
        self.optional = optional

    def __str__(self):
        return self.name

class Arguments(IteratorObject):
    """ the arguments of a method """
    def __init__(self):
        super(Arguments, self).__init__()

    def parse(self, table):
        for row in table.select('.//tr')[1:]:
            optional=False
            if row.re(r"""(title="Need not be set")"""):
                optional = True
            cols = []
            for col in row.select('./td/text()'):
                col = _clean(col)
                if col:
                    cols.append(col)
            if len(cols) < 3:
                continue

            desc = ""
            if len(cols) > 3:
                for x in _clean(cols[2:]):
                    desc += x
            else:
                desc = _clean(cols[2])

            name        = _clean(cols[0])
            if name == u'_this':
                continue

            self.data.append( Argument(name, _clean(cols[1]), desc, optional) )
        return self.data

class Method(object):
    """ The method of a class """
    def __init__(self, name, description="", arguments=[], return_value=None, faults=[]):
        self.name = name
        self.description = description
        self.arguments = arguments
        self.return_value = return_value
        self.faults = faults

    def __str__(self):
        return self.name

class Methods(IteratorObject):
    """ the methods of a class """
    def __init__(self):
        super(Methods, self).__init__()

    def parse(self, hxs):
        method_selectors = hxs.select("//h1")

        if isinstance(method_selectors, XPathSelectorList):
            # gather up all method descriptions
            for s in method_selectors:
                name = _clean(s)
                if ' ' in name:
                    continue
                desc = ""
                index = 0
                nodes = s.select('following::*')
                for node in nodes:
                    print node
                    print type(node)
                    try:
                        ntype = _clean(node.select('name()')[0])
                    except:
                        break
                    if not ntype in ['text', 'p']:
                        break
                    else:
                        if ntype == 'p':
                            x = _clean(nodes[index])
                            if isinstance(x, list):
                                x = ' '.join(x)
                            desc += x
                        else:
                            x = _clean(nodes[index].select('./text()'))
                            if isinstance(x, list):
                                x = ' '.join(x)
                            desc += x

                # the next three tables are for args, return and faults
                args_table, return_table, faults_table = self._findParameters(s)

                args    = Arguments().parse(args_table)
                rv      = ReturnValue().parse(return_table)
                faults  = Faults().parse(faults_table)

                self.data.append( Method(name, desc, args, rv, faults) )
        return self.data

    def _findParameters(self, selector):
        args_table = rv_table = faults_table = None
        paras = selector.select('following::p')
        for para in paras:
            if para.re('Parameters'):
                args_table = para.select('following::table[1]')[0]
            if 'Return Value' in _clean(para.select('./text()')):
                rv_table = para.select('following::table[1]')[0]
            if 'Faults' in _clean(para.select('./text()')):
                faults_table = para.select('following::table[1]')[0]
            if args_table and rv_table and faults_table:
                break
        return args_table, rv_table, faults_table

class Property(object):
    """ The property of a class, i.e. obj.name """
    def __init__(self, name, type="", optional=False, description=""):
        self.name = name
        self.type = type
        self.optional = optional
        self.description = description

class Properties(IteratorObject):
    """ The properties of a class """
    def __init__(self):
        super(Properties, self).__init__()

    def parse(self, hxs):
        rows = self._findProperties(hxs).select(".//tr")[1:]
        for row in rows:
            self._parse_row(row)
        return self.data

    def _parse_row(self, row):
        if len(row.select('./td')) > 2:
            optional = False
            if row.re(r"""(title="Need not be set")"""):
                optional = True
            name = _clean(row.select("./td[1]/text()"))
            if isinstance(name, list):
                name = " ".join(name)
            _type = _clean(row.select("./td[2]/text()"))
            if isinstance(_type, list):
                _type = " ".join(name)
            desc = _clean(row.select("./td[3]/text()"))
            if isinstance(desc, list):
                try:
                    desc = desc[0]
                except:
                    desc = ""
            self.data.append( Property(name, _type, optional, desc) )

    def _findProperties(self, selector):
        props_table = None
        paras = selector.select('//p')
        for para in paras:
            if 'Properties' in para.extract():
                props_table = para.select('following::table[1]')[0]
                break
        return props_table

class Klass(object):
    def __init__(self):
        self.referer = None
        self.name = ""
        self.description = ""
        self.hxs = None
        self.referer = None

    def parse(self, response):
        print "="*80
        print response
        print "="*80
        self.hxs = HtmlXPathSelector(response)
        self.referer = response.request.headers['Referer']

        text = _clean(self.hxs.select('/html/body/h1[1]/text()')).strip()
        print "*" *80
        print text
        print "*" *80
        name_obj = re.search(r""".*\b.*?(?P<name>\w+)$""", text)
        print "name_obj: %s" % name_obj
        self.name = name_obj.group('name')

        self.description = self._findDescription(self.hxs)

    def _gatherInfo(self):
        info = {}
        dts = self.hxs.select("/html/body/dl[1]/dt")
        dds = self.hxs.select("/html/body/dl[1]/dd")
        for dt, dd in zip(dts, dds):
            name = _clean(dt.select('./text()'))
            value = _clean(dd.select('./text()'))
            info[name] = value
        return info

    def _findDescription(self, selector):
        h2s = selector.select('//h2')
        for h2 in h2s:
            if " Description" in h2.extract():
                break

        # now we have our h2...
        paras = h2.select('following::p')
        desc = ''
        for para in paras:
            text = _clean(para.select('./text()'))
            if isinstance(text, list):
                text = " ".join([x.strip() for x in text])

            if 'Properties' == text:
                break
            elif 'Enum Constants' == text:
                break

            desc += text
        return desc

class ManagedObject(Klass):
    def __init__(self):
        super(ManagedObject, self).__init__()
        self.type = 'mo'
        self.item = None

    def parse(self, response):
        Klass.parse(self, response)

        if self.name == 'PropertyFilter':
            pass

        self.item = ManagedItem()
        self.item['name'] = self.name
        self.item['type'] = self.type
        self.item['info'] = self._gatherInfo()
        self.item['description'] = self.description
        self.item['methods'] = Methods().parse(self.hxs)
        self.item['properties'] = Properties().parse(self.hxs)
        return self.item

class DataObject(Klass):
    def __init__(self):
        super(DataObject, self).__init__()
        self.type = 'do'
        self.item = None

    def parse(self, response):
        Klass.parse(self, response)

        self.item = DataItem()
        self.item['name'] = self.name
        self.item['type'] = self.type
        self.item['info'] = self._gatherInfo()
        self.item['description'] = self.description
        self.item['properties'] = Properties().parse(self.hxs)
        return self.item

class EnumObject(Klass):
    def __init__(self):
        super(EnumObject, self).__init__()
        self.type = 'enum'
        self.item = None

    def parse(self, response):
        Klass.parse(self, response)

        self.item = EnumItem()
        self.item['name'] = self.name
        self.item['type'] = self.type
        self.item['description'] = self.description
        self.item['constants'] = Enums().parse(self.hxs)
        return self.item

class Enum(object):
    """ The enumeration """
    def __init__(self, name, description=""):
        self.name = name
        self.description = description

class Enums(IteratorObject):
    """ The enumerations """
    def __init__(self):
        super(Enums, self).__init__()

    def parse(self, selector):
        table = self._findEnumContants(selector)
        rows = table.select(".//tr")[1:]
        for row in rows:
            name = _clean(row.select("./td[1]/text()"))
            if isinstance(name, list):
                name = " ".join(name)

            desc = _clean(row.select("./td[2]/text()"))
            if isinstance(desc, list):
                desc = " ".join(desc)

            self.data.append( Enum(name, desc) )
        return self.data

    def _findEnumContants(self, selector):
        enum_table = None
        paras = selector.select('//p')
        for para in paras:
            if para.re('Enum Constants'):
                enum_table = para.select('following::table[1]')[0]
                break
        return enum_table

<commit_msg>Proper handling on method parameters without documentation<commit_after># Define here the models for your scraped items
#
# See documentation in:
# http://doc.scrapy.org/topics/items.html

import re
from scrapy.item import Item, Field
from scrapy.selector import HtmlXPathSelector
from scrapy.selector.list import XPathSelectorList

class ManagedItem(Item):
    name = Field()
    type = Field()
    info = Field()
    description = Field()
    methods = Field()
    properties = Field()

class DataItem(Item):
    name = Field()
    type = Field()
    info = Field()
    description = Field()
    properties = Field()

class EnumItem(Item):
    # define the fields for your item here like:
    name = Field()
    type = Field()
    description = Field()
    constants = Field()

def _clean(selector):
    if isinstance(selector, list):
        rv = []
        for row in selector:
            row = _clean(row)
            if row:
                rv.append(row)
        if len(rv) == 1:
            return rv[0]
        if len(rv) == 0:
            return ''
        return rv
    elif isinstance(selector, unicode) or isinstance(selector, str):
        return selector.strip().replace('
', '').replace('
', '').replace('
', '').replace('
', '').strip()
    else:
        return _clean(selector.extract())

class IteratorObject(object):
    def __init__(self):
        self.data = []

    def __len__(self):
        return len(self.data)

    def __iter__(self):
        for value in self.data:
            yield value

    def __str__(self):
        return str(self.data)

class Fault(object):
    """ A fault that can be raised from a method """
    def __init__(self, type, description=""):
        self.type = type
        self.description = description

    def __str__(self):
        return self.type

class Faults(IteratorObject):
    """ Faults that can be raised from a method """
    def __init__(self):
        super(Faults, self).__init__()

    def parse(self, table):
        for row in table.select('.//tr')[1:]:
            cols = row.select('./td')
            if len(cols) > 1:
                _type = _clean(cols[0].select('./text()'))
                desc = _clean(cols[1].select('./text()'))
                if isinstance(desc, list):
                    desc = ' '.join(desc)

                self.data.append( Fault(_type, desc) )
        return self.data

class ReturnValue(object):
    """return value from a method """
    def __init__(self):
        self.type = None
        self.description = ""

    def parse(self, table):
        rv = []
        for row in table.select('.//tr')[1:]:
            cols = row.select('./td')

            if len(cols) > 1:
                self.type = _clean(cols[0].select('./text()'))
                if self.type and isinstance(self.type, list):
                    self.type = ' '.join(self.type)
                else:
                    self.type = ""
                self.description = _clean(cols[1].select('./text()'))
                if self.description and isinstance(self.description, list):
                    self.description = ' '.join(self.description)
                else:
                    self.description = ""
        return self

    def __str__(self):
        return str(self.type if not None else self.description)

class Argument(object):
    """ An argument to a method """
    def __init__(self, name, type, description="", optional=False):
        self.name = name
        self.type = type
        self.description = description
        self.optional = optional

    def __str__(self):
        return self.name

class Arguments(IteratorObject):
    """ the arguments of a method """
    def __init__(self):
        super(Arguments, self).__init__()

    def parse(self, table):
        for row in table.select('.//tr')[1:]:
            optional=False
            if row.re(r"""(title="Need not be set")"""):
                optional = True
            cols = []
            for col in row.select('./td/text()'):
                col = _clean(col)
                if col:
                    cols.append(col)
            if len(cols) < 3:
                cols.append(' ')

            desc = ""
            if len(cols) > 3:
                for x in _clean(cols[2:]):
                    desc += x
            else:
                desc = _clean(cols[2])

            name        = _clean(cols[0])
            if name == u'_this':
                continue

            self.data.append( Argument(name, _clean(cols[1]), desc, optional) )
        return self.data

class Method(object):
    """ The method of a class """
    def __init__(self, name, description="", arguments=[], return_value=None, faults=[]):
        self.name = name
        self.description = description
        self.arguments = arguments
        self.return_value = return_value
        self.faults = faults

    def __str__(self):
        return self.name

class Methods(IteratorObject):
    """ the methods of a class """
    def __init__(self):
        super(Methods, self).__init__()

    def parse(self, hxs):
        method_selectors = hxs.select("//h1")

        if isinstance(method_selectors, XPathSelectorList):
            # gather up all method descriptions
            for s in method_selectors:
                name = _clean(s)
                if ' ' in name:
                    continue
                desc = ""
                index = 0
                nodes = s.select('following::*')
                for node in nodes:
                    print node
                    print type(node)
                    try:
                        ntype = _clean(node.select('name()')[0])
                    except:
                        break
                    if not ntype in ['text', 'p']:
                        break
                    else:
                        if ntype == 'p':
                            x = _clean(nodes[index])
                            if isinstance(x, list):
                                x = ' '.join(x)
                            desc += x
                        else:
                            x = _clean(nodes[index].select('./text()'))
                            if isinstance(x, list):
                                x = ' '.join(x)
                            desc += x

                # the next three tables are for args, return and faults
                args_table, return_table, faults_table = self._findParameters(s)

                args    = Arguments().parse(args_table)
                rv      = ReturnValue().parse(return_table)
                faults  = Faults().parse(faults_table)

                self.data.append( Method(name, desc, args, rv, faults) )
        return self.data

    def _findParameters(self, selector):
        args_table = rv_table = faults_table = None
        paras = selector.select('following::p')
        for para in paras:
            if para.re('Parameters'):
                args_table = para.select('following::table[1]')[0]
            if 'Return Value' in _clean(para.select('./text()')):
                rv_table = para.select('following::table[1]')[0]
            if 'Faults' in _clean(para.select('./text()')):
                faults_table = para.select('following::table[1]')[0]
            if args_table and rv_table and faults_table:
                break
        return args_table, rv_table, faults_table

class Property(object):
    """ The property of a class, i.e. obj.name """
    def __init__(self, name, type="", optional=False, description=""):
        self.name = name
        self.type = type
        self.optional = optional
        self.description = description

class Properties(IteratorObject):
    """ The properties of a class """
    def __init__(self):
        super(Properties, self).__init__()

    def parse(self, hxs):
        rows = self._findProperties(hxs).select(".//tr")[1:]
        for row in rows:
            self._parse_row(row)
        return self.data

    def _parse_row(self, row):
        if len(row.select('./td')) > 2:
            optional = False
            if row.re(r"""(title="Need not be set")"""):
                optional = True
            name = _clean(row.select("./td[1]/text()"))
            if isinstance(name, list):
                name = " ".join(name)
            _type = _clean(row.select("./td[2]/text()"))
            if isinstance(_type, list):
                _type = " ".join(name)
            desc = _clean(row.select("./td[3]/text()"))
            if isinstance(desc, list):
                try:
                    desc = desc[0]
                except:
                    desc = ""
            self.data.append( Property(name, _type, optional, desc) )

    def _findProperties(self, selector):
        props_table = None
        paras = selector.select('//p')
        for para in paras:
            if 'Properties' in para.extract():
                props_table = para.select('following::table[1]')[0]
                break
        return props_table

class Klass(object):
    def __init__(self):
        self.referer = None
        self.name = ""
        self.description = ""
        self.hxs = None
        self.referer = None

    def parse(self, response):
        print "="*80
        print response
        print "="*80
        self.hxs = HtmlXPathSelector(response)
        self.referer = response.request.headers['Referer']

        text = _clean(self.hxs.select('/html/body/h1[1]/text()')).strip()
        print "*" *80
        print text
        print "*" *80
        name_obj = re.search(r""".*\b.*?(?P<name>\w+)$""", text)
        print "name_obj: %s" % name_obj
        self.name = name_obj.group('name')

        self.description = self._findDescription(self.hxs)

    def _gatherInfo(self):
        info = {}
        dts = self.hxs.select("/html/body/dl[1]/dt")
        dds = self.hxs.select("/html/body/dl[1]/dd")
        for dt, dd in zip(dts, dds):
            name = _clean(dt.select('./text()'))
            value = _clean(dd.select('./text()'))
            info[name] = value
        return info

    def _findDescription(self, selector):
        h2s = selector.select('//h2')
        for h2 in h2s:
            if " Description" in h2.extract():
                break

        # now we have our h2...
        paras = h2.select('following::p')
        desc = ''
        for para in paras:
            text = _clean(para.select('./text()'))
            if isinstance(text, list):
                text = " ".join([x.strip() for x in text])

            if 'Properties' == text:
                break
            elif 'Enum Constants' == text:
                break

            desc += text
        return desc

class ManagedObject(Klass):
    def __init__(self):
        super(ManagedObject, self).__init__()
        self.type = 'mo'
        self.item = None

    def parse(self, response):
        Klass.parse(self, response)

        if self.name == 'PropertyFilter':
            pass

        self.item = ManagedItem()
        self.item['name'] = self.name
        self.item['type'] = self.type
        self.item['info'] = self._gatherInfo()
        self.item['description'] = self.description
        self.item['methods'] = Methods().parse(self.hxs)
        self.item['properties'] = Properties().parse(self.hxs)
        return self.item

class DataObject(Klass):
    def __init__(self):
        super(DataObject, self).__init__()
        self.type = 'do'
        self.item = None

    def parse(self, response):
        Klass.parse(self, response)

        self.item = DataItem()
        self.item['name'] = self.name
        self.item['type'] = self.type
        self.item['info'] = self._gatherInfo()
        self.item['description'] = self.description
        self.item['properties'] = Properties().parse(self.hxs)
        return self.item

class EnumObject(Klass):
    def __init__(self):
        super(EnumObject, self).__init__()
        self.type = 'enum'
        self.item = None

    def parse(self, response):
        Klass.parse(self, response)

        self.item = EnumItem()
        self.item['name'] = self.name
        self.item['type'] = self.type
        self.item['description'] = self.description
        self.item['constants'] = Enums().parse(self.hxs)
        return self.item

class Enum(object):
    """ The enumeration """
    def __init__(self, name, description=""):
        self.name = name
        self.description = description

class Enums(IteratorObject):
    """ The enumerations """
    def __init__(self):
        super(Enums, self).__init__()

    def parse(self, selector):
        table = self._findEnumContants(selector)
        rows = table.select(".//tr")[1:]
        for row in rows:
            name = _clean(row.select("./td[1]/text()"))
            if isinstance(name, list):
                name = " ".join(name)

            desc = _clean(row.select("./td[2]/text()"))
            if isinstance(desc, list):
                desc = " ".join(desc)

            self.data.append( Enum(name, desc) )
        return self.data

    def _findEnumContants(self, selector):
        enum_table = None
        paras = selector.select('//p')
        for para in paras:
            if para.re('Enum Constants'):
                enum_table = para.select('following::table[1]')[0]
                break
        return enum_table

<|endoftext|>


<commit_before>"""
Aggregate functions which handle plotting
"""

import numpy as np
import networkx as nx

import matplotlib as mpl
import matplotlib.pylab as plt

from reconstruction import compute_error

def plot_graph(A, B, ax, bundle=None):
    """
    Plot graph on given axis.

    Arguments
        A
            Adjacency matrix of graph to plot
        B
            Vector of coupling to external force
        ax
            Axis to plot on
        bundle (optional)
            If given, label edges with reconstruction error
    """
    graph = nx.from_numpy_matrix(A)

    # add external force
    graph.add_node('F', color='red')

    for i, b in enumerate(B):
        if abs(b) > 1e-1:
            graph.add_edge('F', i, weight=b, style='dashed')

    # generate some node/edge properties
    node_labels = {}
    for n in graph.nodes():
        node_labels[n] = n

    node_colors = []
    for n, data in graph.nodes(data=True):
        node_colors.append(data.get('color', 'lightskyblue'))

    if not bundle is None:
        err_A, err_B = compute_error(bundle)

    edge_labels = {}
    for source, sink, data in graph.edges(data=True):
        if bundle is None:
            edge_labels[(source, sink)] = round(data['weight'], 2)
        else:
            if sink == 'F':
                edge_labels[(source, sink)] = round(err_B[source], 2)
            else:
                edge_labels[(source, sink)] = round(np.mean([
                    err_A[source, sink],
                    err_A[sink, source]
                ]), 2)

    edge_style = []
    for source, sink, data in graph.edges(data=True):
        edge_style.append(data.get('style', 'solid'))

    # compute layout
    pos = nx.nx_pydot.graphviz_layout(graph, prog='neato')

    # draw graph
    plt.axis('off')

    nx.draw_networkx_nodes(
        graph, pos,
        node_color=node_colors, node_size=800,
        font_size=20,
        ax=ax)
    nx.draw_networkx_labels(
        graph, pos,
        node_labels,
        ax=ax)
    nx.draw_networkx_edges(
        graph, pos,
        style=edge_style,
        ax=ax)
    nx.draw_networkx_edge_labels(
        graph, pos,
        edge_labels,
        ax=ax)

def show_reconstruction_overview(syst, bundle):
    """
    Plot representation of reconstruction results.

    Arguments
        syst
            Exemplary system used for reconstruction
        orig_A
            Original matrix A
        orig_B
            Original vector B
        rec_A
            Reconstructed matrix A
        rec_B
            Reconstructed vector B
    """
    fig = plt.figure(figsize=(32, 8))
    gs = mpl.gridspec.GridSpec(1, 2)

    err_A, err_B = compute_error(bundle)
    plt.suptitle(r'$A_{{err}} = {:.2}, B_{{err}} = {:.2}$'.format(np.mean(err_A), np.mean(err_B)))

    # original graph
    orig_ax = plt.subplot(gs[0])
    orig_ax.set_title('Original graph')
    orig_ax.set_aspect('equal')

    plot_graph(bundle.orig_A, bundle.orig_B, orig_ax)

    # reconstructed graph
    rec_ax = plt.subplot(gs[1])
    rec_ax.set_title('Reconstructed graph')
    rec_ax.set_aspect('equal')

    tmp = bundle.rec_A
    tmp[abs(tmp) < 1e-1] = 0
    plot_graph(tmp, bundle.rec_B, rec_ax, bundle=bundle)

    # save plot
    plt.tight_layout()
    plt.savefig('images/reconstruction_overview.pdf')
<commit_msg>Improve comparison-plot<commit_after>"""
Aggregate functions which handle plotting
"""

import numpy as np
import networkx as nx

import matplotlib as mpl
import matplotlib.pylab as plt

from reconstruction import compute_error

def plot_graph(A, B, ax, bundle=None, verbose=True):
    """
    Plot graph on given axis.

    Arguments
        A
            Adjacency matrix of graph to plot
        B
            Vector of coupling to external force
        ax
            Axis to plot on
        bundle (optional)
            If given, label edges with reconstruction error
    """
    graph = nx.from_numpy_matrix(A)

    # add external force
    if verbose:
        graph.add_node('F', color='red')

        for i, b in enumerate(B):
            if abs(b) > 1e-1:
                graph.add_edge('F', i, weight=b, style='dashed')

    # generate some node/edge properties
    node_labels = {}
    for n in graph.nodes():
        node_labels[n] = n

    node_colors = []
    for n, data in graph.nodes(data=True):
        node_colors.append(data.get('color', 'lightskyblue'))

    if not bundle is None:
        err_A, err_B = compute_error(bundle)

    edge_labels = {}
    for source, sink, data in graph.edges(data=True):
        if bundle is None:
            edge_labels[(source, sink)] = round(data['weight'], 2)
        else:
            if sink == 'F':
                edge_labels[(source, sink)] = round(err_B[source], 2)
            else:
                edge_labels[(source, sink)] = round(np.mean([
                    err_A[source, sink],
                    err_A[sink, source]
                ]), 2)

    edge_style = []
    for source, sink, data in graph.edges(data=True):
        edge_style.append(data.get('style', 'solid'))

    # compute layout
    pos = nx.nx_pydot.graphviz_layout(graph, prog='neato')

    # draw graph
    plt.axis('off')

    nx.draw_networkx_nodes(
        graph, pos,
        node_color=node_colors, node_size=800 if verbose else 400,
        font_size=20,
        ax=ax)
    if verbose:
        nx.draw_networkx_labels(
            graph, pos,
            node_labels,
            ax=ax)
    nx.draw_networkx_edges(
        graph, pos,
        style=edge_style,
        ax=ax)
    if verbose:
        nx.draw_networkx_edge_labels(
            graph, pos,
            edge_labels,
            ax=ax)

def show_reconstruction_overview(syst, bundle):
    """
    Plot representation of reconstruction results.

    Arguments
        syst
            Exemplary system used for reconstruction
        orig_A
            Original matrix A
        orig_B
            Original vector B
        rec_A
            Reconstructed matrix A
        rec_B
            Reconstructed vector B
    """
    fig = plt.figure(figsize=(20, 8))
    gs = mpl.gridspec.GridSpec(1, 2)

    err_A, err_B = compute_error(bundle)
    plt.suptitle(
        r'$A_{{err}} = {:.2}, B_{{err}} = {:.2}$'.format(
            np.mean(err_A), np.mean(err_B)))

    # original graph
    orig_ax = plt.subplot(gs[0])
    orig_ax.set_title('Original graph')
    orig_ax.set_aspect('equal')

    plot_graph(bundle.orig_A, bundle.orig_B, orig_ax)

    # reconstructed graph
    rec_ax = plt.subplot(gs[1])
    rec_ax.set_title('Reconstructed graph')
    rec_ax.set_aspect('equal')

    tmp = bundle.rec_A
    tmp[abs(tmp) < 1e-1] = 0
    plot_graph(tmp, bundle.rec_B, rec_ax, bundle=bundle)

    # save plot
    plt.tight_layout()
    plt.savefig('images/reconstruction_overview.pdf', bbox_inches='tight')

    return err_A, err_B
<|endoftext|>


<commit_before>#!/usr/bin/env python3
"""
Convert a Verilog simulation model to a VPR `model.xml`

The following Verilog attributes are considered on ports:
    - `(* CLOCK *)` : force a given port to be a clock

    - `(* ASSOC_CLOCK="RDCLK" *)` : force a port's associated clock to a given value

The following Verilog attributes are considered on modules:
    - `(* MODEL_NAME="model" *)` : override the name used for <model> and for
    ".subckt name" in the BLIF model. Mostly intended for use with w.py, when several
    different pb_types implement the same model.

    - `(* CLASS="lut|routing|mux|flipflop|mem" *)` : specify the class of an given
    instance. A model will not be generated for the `lut`, `routing` or `flipflop`
    class.
"""
import argparse, re
import os, sys

import lxml.etree as ET

import yosys.run
from yosys.json import YosysJSON
import xmlinc

parser = argparse.ArgumentParser(description=__doc__.strip())
parser.add_argument(
    'infiles',
    metavar='input.v',
    type=str,
    nargs='+',
    help="""\
One or more Verilog input files, that will be passed to Yosys internally.
They should be enough to generate a flattened representation of the model,
so that paths through the model can be determined.
"""
)
parser.add_argument(
    '--top',
    help="""\
Top level module, will usually be automatically determined from the file name
%.sim.v
"""
)
parser.add_argument(
    '--includes',
    help="""\
Command seperate list of include directories.
""",
    default=""
)
parser.add_argument('-o', help="""\
Output filename, default 'model.xml'
""")

args = parser.parse_args()
iname = os.path.basename(args.infiles[0])

outfile = "model.xml"
if "o" in args and args.o is not None:
    outfile = args.o

if args.includes:
    for include in args.includes.split(','):
        yosys.run.add_include(include)

aig_json = yosys.run.vlog_to_json(args.infiles, flatten=True, aig=True)

if args.top is not None:
    yj = YosysJSON(aig_json, args.top)
    top = yj.top
else:
    wm = re.match(r"([A-Za-z0-9_]+)\.sim\.v", iname)
    if wm:
        top = wm.group(1).upper()
    else:
        print(
            "ERROR file name not of format %.sim.v ({}), cannot detect top level. Manually specify the top level module using --top"
        ).format(iname)
        sys.exit(1)
    yj = YosysJSON(aig_json, top)

if top is None:
    print(
        "ERROR: more than one module in design, cannot detect top level. Manually specify the top level module using --top"
    )
    sys.exit(1)

tmod = yj.top_module
models_xml = ET.Element("models", nsmap={'xi': xmlinc.xi_url})

inc_re = re.compile(r'^\s*`include\s+"([^"]+)"')

deps_files = set()
# XML dependencies need to correspond 1:1 with Verilog includes, so we have
# to do this manually rather than using Yosys
with open(args.infiles[0], 'r') as f:
    for line in f:
        im = inc_re.match(line)
        if not im:
            continue
        deps_files.add(im.group(1))

if len(deps_files) > 0:
    # Has dependencies, not a leaf model
    for df in sorted(deps_files):
        abs_base = os.path.dirname(os.path.abspath(args.infiles[0]))
        abs_dep = os.path.normpath(os.path.join(abs_base, df))
        module_path = os.path.dirname(abs_dep)
        module_basename = os.path.basename(abs_dep)
        wm = re.match(r"([A-Za-z0-9_]+)\.sim\.v", module_basename)
        if wm:
            model_path = "{}/{}.model.xml".format(
                module_path,
                wm.group(1).lower()
            )
        else:
            assert False, "included Verilog file name {} does not follow pattern %%.sim.v".format(
                module_basename
            )
        xmlinc.include_xml(
            parent=models_xml,
            href=model_path,
            outfile=outfile,
            xptr="xpointer(models/child::node())"
        )
else:
    # Is a leaf model
    topname = tmod.attr("MODEL_NAME", top)
    modclass = tmod.attr("CLASS", "")
    if modclass not in ("lut", "routing", "flipflop"):
        model_xml = ET.SubElement(models_xml, "model", {'name': topname})
        ports = tmod.ports

        inports_xml = ET.SubElement(model_xml, "input_ports")
        outports_xml = ET.SubElement(model_xml, "output_ports")

        clocks = yosys.run.list_clocks(args.infiles, top)
        clk_sigs = dict()
        for clk in clocks:
            clk_sigs[clk] = yosys.run.get_clock_assoc_signals(
                args.infiles, top, clk
            )

        for name, width, iodir in ports:
            attrs = dict(name=name)
            sinks = yosys.run.get_combinational_sinks(args.infiles, top, name)
            if len(sinks) > 0 and iodir == "input":
                attrs["combinational_sink_ports"] = " ".join(sinks)
            if name in clocks:
                attrs["is_clock"] = "1"
            for clk in clocks:
                if name in clk_sigs[clk]:
                    attrs["clock"] = clk
            if iodir == "input":
                ET.SubElement(inports_xml, "port", attrs)
            elif iodir == "output":
                ET.SubElement(outports_xml, "port", attrs)
            else:
                assert False, "bidirectional ports not permitted in VPR models"

if len(models_xml) == 0:
    models_xml.insert(0, ET.Comment("this file is intentionally left blank"))

f = open(outfile, 'w')
f.write(ET.tostring(models_xml, pretty_print=True).decode('utf-8'))
f.close()
print("Generated {} from {}".format(outfile, iname))
<commit_msg>utils/vlog: Don't output clock and combinational_sink_ports on clocks.<commit_after>#!/usr/bin/env python3
"""
Convert a Verilog simulation model to a VPR `model.xml`

The following Verilog attributes are considered on ports:
    - `(* CLOCK *)` : force a given port to be a clock

    - `(* ASSOC_CLOCK="RDCLK" *)` : force a port's associated clock to a given value

The following Verilog attributes are considered on modules:
    - `(* MODEL_NAME="model" *)` : override the name used for <model> and for
    ".subckt name" in the BLIF model. Mostly intended for use with w.py, when several
    different pb_types implement the same model.

    - `(* CLASS="lut|routing|mux|flipflop|mem" *)` : specify the class of an given
    instance. A model will not be generated for the `lut`, `routing` or `flipflop`
    class.
"""
import argparse, re
import os, sys

import lxml.etree as ET

import yosys.run
from yosys.json import YosysJSON
import xmlinc

parser = argparse.ArgumentParser(description=__doc__.strip())
parser.add_argument(
    'infiles',
    metavar='input.v',
    type=str,
    nargs='+',
    help="""\
One or more Verilog input files, that will be passed to Yosys internally.
They should be enough to generate a flattened representation of the model,
so that paths through the model can be determined.
"""
)
parser.add_argument(
    '--top',
    help="""\
Top level module, will usually be automatically determined from the file name
%.sim.v
"""
)
parser.add_argument(
    '--includes',
    help="""\
Command seperate list of include directories.
""",
    default=""
)
parser.add_argument('-o', help="""\
Output filename, default 'model.xml'
""")

args = parser.parse_args()
iname = os.path.basename(args.infiles[0])

outfile = "model.xml"
if "o" in args and args.o is not None:
    outfile = args.o

if args.includes:
    for include in args.includes.split(','):
        yosys.run.add_include(include)

aig_json = yosys.run.vlog_to_json(args.infiles, flatten=True, aig=True)

if args.top is not None:
    yj = YosysJSON(aig_json, args.top)
    top = yj.top
else:
    wm = re.match(r"([A-Za-z0-9_]+)\.sim\.v", iname)
    if wm:
        top = wm.group(1).upper()
    else:
        print(
            "ERROR file name not of format %.sim.v ({}), cannot detect top level. Manually specify the top level module using --top"
        ).format(iname)
        sys.exit(1)
    yj = YosysJSON(aig_json, top)

if top is None:
    print(
        "ERROR: more than one module in design, cannot detect top level. Manually specify the top level module using --top"
    )
    sys.exit(1)

tmod = yj.top_module
models_xml = ET.Element("models", nsmap={'xi': xmlinc.xi_url})

inc_re = re.compile(r'^\s*`include\s+"([^"]+)"')

deps_files = set()
# XML dependencies need to correspond 1:1 with Verilog includes, so we have
# to do this manually rather than using Yosys
with open(args.infiles[0], 'r') as f:
    for line in f:
        im = inc_re.match(line)
        if not im:
            continue
        deps_files.add(im.group(1))

if True:
    # Has dependencies, not a leaf model
    for df in sorted(deps_files):
        abs_base = os.path.dirname(os.path.abspath(args.infiles[0]))
        abs_dep = os.path.normpath(os.path.join(abs_base, df))
        module_path = os.path.dirname(abs_dep)
        module_basename = os.path.basename(abs_dep)
        wm = re.match(r"([A-Za-z0-9_]+)\.sim\.v", module_basename)
        if wm:
            model_path = "{}/{}.model.xml".format(
                module_path,
                wm.group(1).lower()
            )
        else:
            assert False, "included Verilog file name {} does not follow pattern %%.sim.v".format(
                module_basename
            )
        xmlinc.include_xml(
            parent=models_xml,
            href=model_path,
            outfile=outfile,
            xptr="xpointer(models/child::node())"
        )
if True:
    # Is a leaf model
    topname = tmod.attr("MODEL_NAME", top)
    modclass = tmod.attr("CLASS", "")
    if modclass not in ("lut", "routing", "flipflop"):
        model_xml = ET.SubElement(models_xml, "model", {'name': topname})
        ports = tmod.ports

        inports_xml = ET.SubElement(model_xml, "input_ports")
        outports_xml = ET.SubElement(model_xml, "output_ports")

        clocks = yosys.run.list_clocks(args.infiles, top)
        clk_sigs = dict()
        for clk in clocks:
            clk_sigs[clk] = yosys.run.get_clock_assoc_signals(
                args.infiles, top, clk
            )

        for name, width, iodir in ports:
            attrs = dict(name=name)
            sinks = yosys.run.get_combinational_sinks(args.infiles, top, name)
            # FIXME: Check if ignoring clock for "combination_sink_ports" is a
            # valid thing to do.
            if name in clocks:
                attrs["is_clock"] = "1"
            else:
                if len(sinks) > 0 and iodir == "input" and name not in clocks:
                    attrs["combinational_sink_ports"] = " ".join(sinks)
                for clk in clocks:
                    if name in clk_sigs[clk]:
                        attrs["clock"] = clk
            if iodir == "input":
                ET.SubElement(inports_xml, "port", attrs)
            elif iodir == "output":
                ET.SubElement(outports_xml, "port", attrs)
            else:
                assert False, "bidirectional ports not permitted in VPR models"

if len(models_xml) == 0:
    models_xml.insert(0, ET.Comment("this file is intentionally left blank"))

f = open(outfile, 'w')
f.write(ET.tostring(models_xml, pretty_print=True).decode('utf-8'))
f.close()
print("Generated {} from {}".format(outfile, iname))
<|endoftext|>


<commit_before>"""Definitions and behavior for vCard 3.0"""

import behavior
import itertools

from base import VObjectError, NativeError, ValidateError, ParseError, \
                    VBase, Component, ContentLine, logger, defaultSerialize, \
                    registerBehavior, backslashEscape, ascii
from icalendar import stringToTextValues

#------------------------ vCard structs ----------------------------------------

class Name(object):
    def __init__(self, family = '', given = '', additional = '', prefix = '',
                 suffix = ''):
        """Each name attribute can be a string or a list of strings."""
        self.family     = family
        self.given      = given
        self.additional = additional
        self.prefix     = prefix
        self.suffix     = suffix

    @staticmethod
    def toString(val):
        """Turn a string or array value into a string."""
        if type(val) in (list, tuple):
            return ' '.join(val)
        return val

    def __str__(self):
        eng_order = ('prefix', 'given', 'additional', 'family', 'suffix')
        out = ' '.join(self.toString(getattr(self, val)) for val in eng_order)
        return ascii(out)

    def __repr__(self):
        return "<Name: %s>" % self.__str__()

    def __eq__(self, other):
        try:
            return (self.family == other.family and
                    self.given == other.given and
                    self.additional == other.additional and
                    self.prefix == other.prefix and
                    self.suffix == other.suffix)
        except:
            return False

class Address(object):
    def __init__(self, street = '', city = '', region = '', code = '',
                 country = '', box = '', extended = ''):
        """Each name attribute can be a string or a list of strings."""
        self.box      = box
        self.extended = extended
        self.street   = street
        self.city     = city
        self.region   = region
        self.code     = code
        self.country  = country

    @staticmethod
    def toString(val, join_char='\n'):
        """Turn a string or array value into a string."""
        if type(val) in (list, tuple):
            return join_char.join(val)
        return val

    lines = ('box', 'extended', 'street')
    one_line = ('city', 'region', 'code')

    def __str__(self):
        lines = '\n'.join(self.toString(getattr(self, val)) for val in self.lines if getattr(self, val))
        one_line = tuple(self.toString(getattr(self, val), ' ') for val in self.one_line)
        lines += "\n%s, %s %s" % one_line
        if self.country:
            lines += '\n' + self.toString(self.country)
        return ascii(lines)

    def __repr__(self):
        return "<Address: %s>" % repr(str(self))[1:-1]

    def __eq__(self, other):
        try:
            return (self.box == other.box and
                    self.extended == other.extended and
                    self.street == other.street and
                    self.city == other.city and
                    self.region == other.region and
                    self.code == other.code and
                    self.country == other.country)
        except:
            False

#------------------------ Registered Behavior subclasses -----------------------

class VCardTextBehavior(behavior.Behavior):
    """Provide backslash escape encoding/decoding for single valued properties.

    TextBehavior also deals with base64 encoding if the ENCODING parameter is
    explicitly set to BASE64.

    """
    allowGroup = True
    base64string = 'B'

    @classmethod
    def decode(cls, line):
        """Remove backslash escaping from line.valueDecode line, either to remove
        backslash espacing, or to decode base64 encoding. The content line should
        contain a ENCODING=b for base64 encoding, but Apple Addressbook seems to
        export a singleton parameter of 'BASE64', which does not match the 3.0
        vCard spec. If we encouter that, then we transform the parameter to
        ENCODING=b"""
        if line.encoded:
            if 'BASE64' in line.singletonparams:
                line.singletonparams.remove('BASE64')
                line.encoding_param = cls.base64string
            encoding = getattr(line, 'encoding_param', None)
            if encoding:
                line.value = line.value.decode('base64')
            else:
                line.value = stringToTextValues(line.value)[0]
            line.encoded=False

    @classmethod
    def encode(cls, line):
        """Backslash escape line.value."""
        if not line.encoded:
            encoding = getattr(line, 'encoding_param', None)
            if encoding and encoding.upper() == cls.base64string:
                line.value = line.value.encode('base64').replace('\n', '')
            else:
                line.value = backslashEscape(line.value)
            line.encoded=True

class VCardBehavior(behavior.Behavior):
    allowGroup = True
    defaultBehavior = VCardTextBehavior

class VCard3_0(VCardBehavior):
    """vCard 3.0 behavior."""
    name = 'VCARD'
    description = 'vCard 3.0, defined in rfc2426'
    versionString = '3.0'
    isComponent = True
    sortFirst = ('version', 'prodid', 'uid')
    knownChildren = {'N':         (1, 1, None),#min, max, behaviorRegistry id
                     'FN':        (1, 1, None),
                     'VERSION':   (1, 1, None),#required, auto-generated
                     'PRODID':    (0, 1, None),
                     'LABEL':     (0, None, None),
                     'UID':       (0, None, None),
                     'ADR':       (0, None, None),
                     'ORG':       (0, None, None),
                     'PHOTO':     (0, None, None),
                     'CATEGORIES':(0, None, None)
                    }

    @classmethod
    def generateImplicitParameters(cls, obj):
        """Create PRODID, VERSION, and VTIMEZONEs if needed.

        VTIMEZONEs will need to exist whenever TZID parameters exist or when
        datetimes with tzinfo exist.

        """
        if not hasattr(obj, 'version'):
            obj.add(ContentLine('VERSION', [], cls.versionString))
registerBehavior(VCard3_0, default=True)

class FN(VCardTextBehavior):
    name = "FN"
    description = 'Formatted name'
registerBehavior(FN)

class Label(VCardTextBehavior):
    name = "Label"
    description = 'Formatted address'
registerBehavior(FN)

class Photo(VCardTextBehavior):
    name = "Photo"
    description = 'Photograph'
    @classmethod
    def valueRepr( cls, line ):
        return " (BINARY PHOTO DATA at 0x%s) " % id( line.value )

registerBehavior(Photo)

def toListOrString(string):
    stringList = stringToTextValues(string)
    if len(stringList) == 1:
        return stringList[0]
    else:
        return stringList

def splitFields(string):
    """Return a list of strings or lists from a Name or Address."""
    return [toListOrString(i) for i in
            stringToTextValues(string, listSeparator=';', charList=';')]

def toList(stringOrList):
    if isinstance(stringOrList, basestring):
        return [stringOrList]
    return stringOrList

def serializeFields(obj, order=None):
    """Turn an object's fields into a ';' and ',' seperated string.

    If order is None, obj should be a list, backslash escape each field and
    return a ';' separated string.
    """
    fields = []
    if order is None:
        fields = [backslashEscape(val) for val in obj]
    else:
        for field in order:
            escapedValueList = [backslashEscape(val) for val in
                                toList(getattr(obj, field))]
            fields.append(','.join(escapedValueList))
    return ';'.join(fields)

NAME_ORDER = ('family', 'given', 'additional', 'prefix', 'suffix')

class NameBehavior(VCardBehavior):
    """A structured name."""
    hasNative = True

    @staticmethod
    def transformToNative(obj):
        """Turn obj.value into a Name."""
        if obj.isNative: return obj
        obj.isNative = True
        obj.value = Name(**dict(zip(NAME_ORDER, splitFields(obj.value))))
        return obj

    @staticmethod
    def transformFromNative(obj):
        """Replace the Name in obj.value with a string."""
        obj.isNative = False
        obj.value = serializeFields(obj.value, NAME_ORDER)
        return obj
registerBehavior(NameBehavior, 'N')

ADDRESS_ORDER = ('box', 'extended', 'street', 'city', 'region', 'code',
                 'country')

class AddressBehavior(VCardBehavior):
    """A structured address."""
    hasNative = True

    @staticmethod
    def transformToNative(obj):
        """Turn obj.value into an Address."""
        if obj.isNative: return obj
        obj.isNative = True
        obj.value = Address(**dict(zip(ADDRESS_ORDER, splitFields(obj.value))))
        return obj

    @staticmethod
    def transformFromNative(obj):
        """Replace the Address in obj.value with a string."""
        obj.isNative = False
        obj.value = serializeFields(obj.value, ADDRESS_ORDER)
        return obj
registerBehavior(AddressBehavior, 'ADR')

class OrgBehavior(VCardBehavior):
    """A list of organization values and sub-organization values."""
    hasNative = True

    @staticmethod
    def transformToNative(obj):
        """Turn obj.value into a list."""
        if obj.isNative: return obj
        obj.isNative = True
        obj.value = splitFields(obj.value)
        return obj

    @staticmethod
    def transformFromNative(obj):
        """Replace the list in obj.value with a string."""
        if not obj.isNative: return obj
        obj.isNative = False
        obj.value = serializeFields(obj.value)
        return obj
registerBehavior(OrgBehavior, 'ORG')

<commit_msg>Fix to properly register Label behavior.<commit_after>"""Definitions and behavior for vCard 3.0"""

import behavior
import itertools

from base import VObjectError, NativeError, ValidateError, ParseError, \
                    VBase, Component, ContentLine, logger, defaultSerialize, \
                    registerBehavior, backslashEscape, ascii
from icalendar import stringToTextValues

#------------------------ vCard structs ----------------------------------------

class Name(object):
    def __init__(self, family = '', given = '', additional = '', prefix = '',
                 suffix = ''):
        """Each name attribute can be a string or a list of strings."""
        self.family     = family
        self.given      = given
        self.additional = additional
        self.prefix     = prefix
        self.suffix     = suffix

    @staticmethod
    def toString(val):
        """Turn a string or array value into a string."""
        if type(val) in (list, tuple):
            return ' '.join(val)
        return val

    def __str__(self):
        eng_order = ('prefix', 'given', 'additional', 'family', 'suffix')
        out = ' '.join(self.toString(getattr(self, val)) for val in eng_order)
        return ascii(out)

    def __repr__(self):
        return "<Name: %s>" % self.__str__()

    def __eq__(self, other):
        try:
            return (self.family == other.family and
                    self.given == other.given and
                    self.additional == other.additional and
                    self.prefix == other.prefix and
                    self.suffix == other.suffix)
        except:
            return False

class Address(object):
    def __init__(self, street = '', city = '', region = '', code = '',
                 country = '', box = '', extended = ''):
        """Each name attribute can be a string or a list of strings."""
        self.box      = box
        self.extended = extended
        self.street   = street
        self.city     = city
        self.region   = region
        self.code     = code
        self.country  = country

    @staticmethod
    def toString(val, join_char='\n'):
        """Turn a string or array value into a string."""
        if type(val) in (list, tuple):
            return join_char.join(val)
        return val

    lines = ('box', 'extended', 'street')
    one_line = ('city', 'region', 'code')

    def __str__(self):
        lines = '\n'.join(self.toString(getattr(self, val)) for val in self.lines if getattr(self, val))
        one_line = tuple(self.toString(getattr(self, val), ' ') for val in self.one_line)
        lines += "\n%s, %s %s" % one_line
        if self.country:
            lines += '\n' + self.toString(self.country)
        return ascii(lines)

    def __repr__(self):
        return "<Address: %s>" % repr(str(self))[1:-1]

    def __eq__(self, other):
        try:
            return (self.box == other.box and
                    self.extended == other.extended and
                    self.street == other.street and
                    self.city == other.city and
                    self.region == other.region and
                    self.code == other.code and
                    self.country == other.country)
        except:
            False

#------------------------ Registered Behavior subclasses -----------------------

class VCardTextBehavior(behavior.Behavior):
    """Provide backslash escape encoding/decoding for single valued properties.

    TextBehavior also deals with base64 encoding if the ENCODING parameter is
    explicitly set to BASE64.

    """
    allowGroup = True
    base64string = 'B'

    @classmethod
    def decode(cls, line):
        """Remove backslash escaping from line.valueDecode line, either to remove
        backslash espacing, or to decode base64 encoding. The content line should
        contain a ENCODING=b for base64 encoding, but Apple Addressbook seems to
        export a singleton parameter of 'BASE64', which does not match the 3.0
        vCard spec. If we encouter that, then we transform the parameter to
        ENCODING=b"""
        if line.encoded:
            if 'BASE64' in line.singletonparams:
                line.singletonparams.remove('BASE64')
                line.encoding_param = cls.base64string
            encoding = getattr(line, 'encoding_param', None)
            if encoding:
                line.value = line.value.decode('base64')
            else:
                line.value = stringToTextValues(line.value)[0]
            line.encoded=False

    @classmethod
    def encode(cls, line):
        """Backslash escape line.value."""
        if not line.encoded:
            encoding = getattr(line, 'encoding_param', None)
            if encoding and encoding.upper() == cls.base64string:
                line.value = line.value.encode('base64').replace('\n', '')
            else:
                line.value = backslashEscape(line.value)
            line.encoded=True

class VCardBehavior(behavior.Behavior):
    allowGroup = True
    defaultBehavior = VCardTextBehavior

class VCard3_0(VCardBehavior):
    """vCard 3.0 behavior."""
    name = 'VCARD'
    description = 'vCard 3.0, defined in rfc2426'
    versionString = '3.0'
    isComponent = True
    sortFirst = ('version', 'prodid', 'uid')
    knownChildren = {'N':         (1, 1, None),#min, max, behaviorRegistry id
                     'FN':        (1, 1, None),
                     'VERSION':   (1, 1, None),#required, auto-generated
                     'PRODID':    (0, 1, None),
                     'LABEL':     (0, None, None),
                     'UID':       (0, None, None),
                     'ADR':       (0, None, None),
                     'ORG':       (0, None, None),
                     'PHOTO':     (0, None, None),
                     'CATEGORIES':(0, None, None)
                    }

    @classmethod
    def generateImplicitParameters(cls, obj):
        """Create PRODID, VERSION, and VTIMEZONEs if needed.

        VTIMEZONEs will need to exist whenever TZID parameters exist or when
        datetimes with tzinfo exist.

        """
        if not hasattr(obj, 'version'):
            obj.add(ContentLine('VERSION', [], cls.versionString))
registerBehavior(VCard3_0, default=True)

class FN(VCardTextBehavior):
    name = "FN"
    description = 'Formatted name'
registerBehavior(FN)

class Label(VCardTextBehavior):
    name = "Label"
    description = 'Formatted address'
registerBehavior(Label)

class Photo(VCardTextBehavior):
    name = "Photo"
    description = 'Photograph'
    @classmethod
    def valueRepr( cls, line ):
        return " (BINARY PHOTO DATA at 0x%s) " % id( line.value )

registerBehavior(Photo)

def toListOrString(string):
    stringList = stringToTextValues(string)
    if len(stringList) == 1:
        return stringList[0]
    else:
        return stringList

def splitFields(string):
    """Return a list of strings or lists from a Name or Address."""
    return [toListOrString(i) for i in
            stringToTextValues(string, listSeparator=';', charList=';')]

def toList(stringOrList):
    if isinstance(stringOrList, basestring):
        return [stringOrList]
    return stringOrList

def serializeFields(obj, order=None):
    """Turn an object's fields into a ';' and ',' seperated string.

    If order is None, obj should be a list, backslash escape each field and
    return a ';' separated string.
    """
    fields = []
    if order is None:
        fields = [backslashEscape(val) for val in obj]
    else:
        for field in order:
            escapedValueList = [backslashEscape(val) for val in
                                toList(getattr(obj, field))]
            fields.append(','.join(escapedValueList))
    return ';'.join(fields)

NAME_ORDER = ('family', 'given', 'additional', 'prefix', 'suffix')

class NameBehavior(VCardBehavior):
    """A structured name."""
    hasNative = True

    @staticmethod
    def transformToNative(obj):
        """Turn obj.value into a Name."""
        if obj.isNative: return obj
        obj.isNative = True
        obj.value = Name(**dict(zip(NAME_ORDER, splitFields(obj.value))))
        return obj

    @staticmethod
    def transformFromNative(obj):
        """Replace the Name in obj.value with a string."""
        obj.isNative = False
        obj.value = serializeFields(obj.value, NAME_ORDER)
        return obj
registerBehavior(NameBehavior, 'N')

ADDRESS_ORDER = ('box', 'extended', 'street', 'city', 'region', 'code',
                 'country')

class AddressBehavior(VCardBehavior):
    """A structured address."""
    hasNative = True

    @staticmethod
    def transformToNative(obj):
        """Turn obj.value into an Address."""
        if obj.isNative: return obj
        obj.isNative = True
        obj.value = Address(**dict(zip(ADDRESS_ORDER, splitFields(obj.value))))
        return obj

    @staticmethod
    def transformFromNative(obj):
        """Replace the Address in obj.value with a string."""
        obj.isNative = False
        obj.value = serializeFields(obj.value, ADDRESS_ORDER)
        return obj
registerBehavior(AddressBehavior, 'ADR')

class OrgBehavior(VCardBehavior):
    """A list of organization values and sub-organization values."""
    hasNative = True

    @staticmethod
    def transformToNative(obj):
        """Turn obj.value into a list."""
        if obj.isNative: return obj
        obj.isNative = True
        obj.value = splitFields(obj.value)
        return obj

    @staticmethod
    def transformFromNative(obj):
        """Replace the list in obj.value with a string."""
        if not obj.isNative: return obj
        obj.isNative = False
        obj.value = serializeFields(obj.value)
        return obj
registerBehavior(OrgBehavior, 'ORG')

<|endoftext|>