<commit_before>### $Id$
### $URL$

import sys
import pprint
import os
import httplib
from xml.dom import minidom
from types import StringTypes, ListType

class Rspec:

    def __init__(self, xml = None, xsd = None, NSURL = None):
        '''
        Class to manipulate RSpecs.  Reads and parses rspec xml into python dicts
        and reads python dicts and writes rspec xml

        self.xsd = # Schema.  Can be local or remote file.
        self.NSURL = # If schema is remote, Name Space URL to query (full path minus filename)
        self.rootNode = # root of the DOM
        self.dict = # dict of the RSpec.
        self.schemaDict = {} # dict of the Schema
        '''

        self.xsd = xsd
        self.rootNode = None
        self.dict = {}
        self.schemaDict = {}
        self.NSURL = NSURL
        if xml:
            if type(xml) == file:
                self.parseFile(xml)
            if type(xml) == str:
                self.parseString(xml)
            self.dict = self.toDict()
        if xsd:
            self._parseXSD(self.NSURL + self.xsd)

    def _getText(self, nodelist):
        rc = ""
        for node in nodelist:
            if node.nodeType == node.TEXT_NODE:
                rc = rc + node.data
        return rc

    # The rspec is comprised of 2 parts, and 1 reference:
    # attributes/elements describe individual resources
    # complexTypes are used to describe a set of attributes/elements
    # complexTypes can include a reference to other complexTypes.

    def _getName(self, node):
        '''Gets name of node. If tag has no name, then return tag's localName'''
        name = None
        if not node.nodeName.startswith("#"):
            if node.localName:
                name = node.localName
            elif node.attributes.has_key("name"):
                name = node.attributes.get("name").value
        return name

    # Attribute.  {name : nameofattribute, {items: values})
    def _attributeDict(self, attributeDom):
        '''Traverse single attribute node.  Create a dict {attributename : {name: value,}]}'''
        node = {} # parsed dict
        for attr in attributeDom.attributes.keys():
            node[attr] = attributeDom.attributes.get(attr).value
        return node

    def appendToDictOrCreate(self, dict, key, value):
        if (dict.has_key(key)):
            dict[key].append(value)
        else:
            dict[key]=[value]
        return dict

    def toGenDict(self, nodeDom=None, parentdict={}, siblingdict={}, parent=None):
        """
        convert an XML to a nested dict:
          * Non-terminal nodes (elements with string children and attributes) are simple dictionaries
          * Terminal nodes (the rest) are nested dictionaries
        """

        if (not nodeDom):
            nodeDom=self.rootNode

        curNodeName = nodeDom.localName

        if (nodeDom.nodeValue):
            siblingdict = self.appendToDictOrCreate(siblingdict, parent, nodeDom.nodeValue)
        elif (nodeDom.hasChildNodes()):
            for child in nodeDom.childNodes:
                 siblingdict = self.toGenDict(child, None, siblingdict,curNodeName)

            for attribute in nodeDom.attributes.keys():
                parentdict = self.appendToDictOrCreate(parentdict, curNodeName, nodeDom.getAttribute(attribute))

        if (parentdict is not None):
            parentdict = self.appendToDictOrCreate(parentdict, curNodeName, siblingdict)
            return parentdict
        else:
            return siblingdict

    def toDict(self, nodeDom = None):
        """
        convert this rspec to a dict and return it.
        """
        node = {}
        if not nodeDom:
             nodeDom = self.rootNode

        elementName = nodeDom.nodeName
        if elementName and not elementName.startswith("#"):
            # attributes have tags and values.  get {tag: value}, else {type: value}
            node[elementName] = self._attributeDict(nodeDom)
            # resolve the child nodes.
            if nodeDom.hasChildNodes():
                for child in nodeDom.childNodes:
                    childName = self._getName(child)
                    # skip null children
                    if not childName:
                        continue
                    # initialize the possible array of children
                    if not node[elementName].has_key(childName):
                        node[elementName][childName] = []
                    # if child node has text child nodes
                    # append the children to the array as strings
                    if child.hasChildNodes() and isinstance(child.childNodes[0], minidom.Text):
                        for nextchild in child.childNodes:
                            node[elementName][childName].append(nextchild.data)
                    # convert element child node to dict
                    else:
                        childdict = self.toDict(child)
                        for value in childdict.values():
                            node[elementName][childName].append(value)
                    #node[childName].append(self.toDict(child))
        return node

    def toxml(self):
        """
        convert this rspec to an xml string and return it.
        """
        return self.rootNode.toxml()

    def toprettyxml(self):
        """
        print this rspec in xml in a pretty format.
        """
        return self.rootNode.toprettyxml()

    def parseFile(self, filename):
        """
        read a local xml file and store it as a dom object.
        """
        dom = minidom.parse(filename)
        self.rootNode = dom.childNodes[0]

    def parseString(self, xml):
        """
        read an xml string and store it as a dom object.
        """
        xml = xml.replace('\n', '').replace('\t', '').replace(' ', '').strip()
        dom = minidom.parseString(xml)
        self.rootNode = dom.childNodes[0]

    def _httpGetXSD(self, xsdURI):
        # split the URI into relevant parts
        host = xsdURI.split("/")[2]
        if xsdURI.startswith("https"):
            conn = httplib.HTTPSConnection(host,
                httplib.HTTPSConnection.default_port)
        elif xsdURI.startswith("http"):
            conn = httplib.HTTPConnection(host,
                httplib.HTTPConnection.default_port)
        conn.request("GET", xsdURI)
        # If we can't download the schema, raise an exception
        r1 = conn.getresponse()
        if r1.status != 200:
            raise Exception
        return r1.read().replace('\n', '').replace('\t', '').strip()

    def _parseXSD(self, xsdURI):
        """
        Download XSD from URL, or if file, read local xsd file and set schemaDict
        """
        # Since the schema definiton is a global namespace shared by and agreed upon by
        # others, this should probably be a URL.  Check for URL, download xsd, parse, or
        # if local file, use local file.
        schemaDom = None
        if xsdURI.startswith("http"):
            try:
                schemaDom = minidom.parseString(self._httpGetXSD(xsdURI))
            except Exception, e:
                # logging.debug("%s: web file not found" % xsdURI)
                # logging.debug("Using local file %s" % self.xsd")
                print e
                print "Can't find %s on the web. Continuing." % xsdURI
        if not schemaDom:
            if os.path.exists(xsdURI):
                # logging.debug("using local copy.")
                print "Using local %s" % xsdURI
                schemaDom = minidom.parse(xsdURI)
            else:
                raise Exception("Can't find xsd locally")
        self.schemaDict = self.toDict(schemaDom.childNodes[0])

    def dict2dom(self, rdict, include_doc = False):
        """
        convert a dict object into a dom object.
        """

        def elementNode(tagname, rd):
            element = minidom.Element(tagname)
            for key in rd.keys():
                if isinstance(rd[key], StringTypes) or isinstance(rd[key], int):
                    element.setAttribute(key, str(rd[key]))
                elif isinstance(rd[key], dict):
                    child = elementNode(key, rd[key])
                    element.appendChild(child)
                elif isinstance(rd[key], list):
                    for item in rd[key]:
                        if isinstance(item, dict):
                            child = elementNode(key, item)
                            element.appendChild(child)
                        elif isinstance(item, StringTypes) or isinstance(item, int):
                            child = minidom.Element(key)
                            text = minidom.Text()
                            text.data = item
                            child.appendChild(text)
                            element.appendChild(child)
            return element

        # Minidom does not allow documents to have more then one
        # child, but elements may have many children. Because of
        # this, the document's root node will be the first key/value
        # pair in the dictionary.
        node = elementNode(rdict.keys()[0], rdict.values()[0])
        if include_doc:
            rootNode = minidom.Document()
            rootNode.appendChild(node)
        else:
            rootNode = node
        return rootNode

    def parseDict(self, rdict, include_doc = True):
        """
        Convert a dictionary into a dom object and store it.
        """
        self.rootNode = self.dict2dom(rdict, include_doc)

    def getDictsByTagName(self, tagname, dom = None):
        """
        Search the dom for all elements with the specified tagname
        and return them as a list of dicts
        """
        if not dom:
            dom = self.rootNode
        dicts = []
        doms = dom.getElementsByTagName(tagname)
        dictlist = [self.toDict(d) for d in doms]
        for item in dictlist:
            for value in item.values():
                dicts.append(value)
        return dicts

    def getDictByTagNameValue(self, tagname, value, dom = None):
        """
        Search the dom for the first element with the specified tagname
        and value and return it as a dict.
        """
        tempdict = {}
        if not dom:
            dom = self.rootNode
        dicts = self.getDictsByTagName(tagname, dom)

        for rdict in dicts:
            if rdict.has_key('name') and rdict['name'] in [value]:
                return rdict

        return tempdict

    def filter(self, tagname, attribute, blacklist = [], whitelist = [], dom = None):
        """
        Removes all elements where:
        1. tagname matches the element tag
        2. attribute matches the element attribte
        3. attribute value is in valuelist
        """

        tempdict = {}
        if not dom:
            dom = self.rootNode

        if dom.localName in [tagname] and dom.attributes.has_key(attribute):
            if whitelist and dom.attributes.get(attribute).value not in whitelist:
                dom.parentNode.removeChild(dom)
            if blacklist and dom.attributes.get(attribute).value in blacklist:
                dom.parentNode.removeChild(dom)

        if dom.hasChildNodes():
            for child in dom.childNodes:
                self.filter(tagname, attribute, blacklist, whitelist, child)

    def validateDicts(self):
        types = {
            'EInt' : int,
            'EString' : str,
            'EByteArray' : list,
            'EBoolean' : bool,
            'EFloat' : float,
            'EDate' : date}

    def pprint(self, r = None, depth = 0):
        """
        Pretty print the dict
        """
        line = ""
        if r == None: r = self.dict
        # Set the dept
        for tab in range(0,depth): line += "    "
        # check if it's nested
        if type(r) == dict:
            for i in r.keys():
                print line + "%s:" % i
                self.pprint(r[i], depth + 1)
        elif type(r) in (tuple, list):
            for j in r: self.pprint(j, depth + 1)
        # not nested so just print.
        else:
            print line + "%s" %  r

class RecordSpec(Rspec):

    root_tag = 'record'
    def parseDict(self, rdict, include_doc = False):
        """
        Convert a dictionary into a dom object and store it.
        """
        self.rootNode = self.dict2dom(rdict, include_doc)

    def dict2dom(self, rdict, include_doc = False):
        record_dict = rdict
        if not len(rdict.keys()) == 1:
            record_dict = {self.root_tag : rdict}
        return Rspec.dict2dom(self, record_dict, include_doc)

# vim:ts=4:expandtab

<commit_msg>Bad. Need to get rid of the tab as well.<commit_after>### $Id$
### $URL$

import sys
import pprint
import os
import httplib
from xml.dom import minidom
from types import StringTypes, ListType

class Rspec:

    def __init__(self, xml = None, xsd = None, NSURL = None):
        '''
        Class to manipulate RSpecs.  Reads and parses rspec xml into python dicts
        and reads python dicts and writes rspec xml

        self.xsd = # Schema.  Can be local or remote file.
        self.NSURL = # If schema is remote, Name Space URL to query (full path minus filename)
        self.rootNode = # root of the DOM
        self.dict = # dict of the RSpec.
        self.schemaDict = {} # dict of the Schema
        '''

        self.xsd = xsd
        self.rootNode = None
        self.dict = {}
        self.schemaDict = {}
        self.NSURL = NSURL
        if xml:
            if type(xml) == file:
                self.parseFile(xml)
            if type(xml) == str:
                self.parseString(xml)
            self.dict = self.toDict()
        if xsd:
            self._parseXSD(self.NSURL + self.xsd)

    def _getText(self, nodelist):
        rc = ""
        for node in nodelist:
            if node.nodeType == node.TEXT_NODE:
                rc = rc + node.data
        return rc

    # The rspec is comprised of 2 parts, and 1 reference:
    # attributes/elements describe individual resources
    # complexTypes are used to describe a set of attributes/elements
    # complexTypes can include a reference to other complexTypes.

    def _getName(self, node):
        '''Gets name of node. If tag has no name, then return tag's localName'''
        name = None
        if not node.nodeName.startswith("#"):
            if node.localName:
                name = node.localName
            elif node.attributes.has_key("name"):
                name = node.attributes.get("name").value
        return name

    # Attribute.  {name : nameofattribute, {items: values})
    def _attributeDict(self, attributeDom):
        '''Traverse single attribute node.  Create a dict {attributename : {name: value,}]}'''
        node = {} # parsed dict
        for attr in attributeDom.attributes.keys():
            node[attr] = attributeDom.attributes.get(attr).value
        return node

    def appendToDictOrCreate(self, dict, key, value):
        if (dict.has_key(key)):
            dict[key].append(value)
        else:
            dict[key]=[value]
        return dict

    def toGenDict(self, nodeDom=None, parentdict={}, siblingdict={}, parent=None):
        """
        convert an XML to a nested dict:
          * Non-terminal nodes (elements with string children and attributes) are simple dictionaries
          * Terminal nodes (the rest) are nested dictionaries
        """

        if (not nodeDom):
            nodeDom=self.rootNode

        curNodeName = nodeDom.localName

        if (nodeDom.nodeValue):
            siblingdict = self.appendToDictOrCreate(siblingdict, parent, nodeDom.nodeValue)
        elif (nodeDom.hasChildNodes()):
            for child in nodeDom.childNodes:
                 siblingdict = self.toGenDict(child, None, siblingdict,curNodeName)

            for attribute in nodeDom.attributes.keys():
                parentdict = self.appendToDictOrCreate(parentdict, curNodeName, nodeDom.getAttribute(attribute))

        if (parentdict is not None):
            parentdict = self.appendToDictOrCreate(parentdict, curNodeName, siblingdict)
            return parentdict
        else:
            return siblingdict

    def toDict(self, nodeDom = None):
        """
        convert this rspec to a dict and return it.
        """
        node = {}
        if not nodeDom:
             nodeDom = self.rootNode

        elementName = nodeDom.nodeName
        if elementName and not elementName.startswith("#"):
            # attributes have tags and values.  get {tag: value}, else {type: value}
            node[elementName] = self._attributeDict(nodeDom)
            # resolve the child nodes.
            if nodeDom.hasChildNodes():
                for child in nodeDom.childNodes:
                    childName = self._getName(child)
                    # skip null children
                    if not childName:
                        continue
                    # initialize the possible array of children
                    if not node[elementName].has_key(childName):
                        node[elementName][childName] = []
                    # if child node has text child nodes
                    # append the children to the array as strings
                    if child.hasChildNodes() and isinstance(child.childNodes[0], minidom.Text):
                        for nextchild in child.childNodes:
                            node[elementName][childName].append(nextchild.data)
                    # convert element child node to dict
                    else:
                        childdict = self.toDict(child)
                        for value in childdict.values():
                            node[elementName][childName].append(value)
                    #node[childName].append(self.toDict(child))
        return node

    def toxml(self):
        """
        convert this rspec to an xml string and return it.
        """
        return self.rootNode.toxml()

    def toprettyxml(self):
        """
        print this rspec in xml in a pretty format.
        """
        return self.rootNode.toprettyxml()

    def parseFile(self, filename):
        """
        read a local xml file and store it as a dom object.
        """
        dom = minidom.parse(filename)
        self.rootNode = dom.childNodes[0]

    def parseString(self, xml):
        """
        read an xml string and store it as a dom object.
        """
        xml = xml.replace('\n', '').replace('\t', '').strip()
        dom = minidom.parseString(xml)
        self.rootNode = dom.childNodes[0]

    def _httpGetXSD(self, xsdURI):
        # split the URI into relevant parts
        host = xsdURI.split("/")[2]
        if xsdURI.startswith("https"):
            conn = httplib.HTTPSConnection(host,
                httplib.HTTPSConnection.default_port)
        elif xsdURI.startswith("http"):
            conn = httplib.HTTPConnection(host,
                httplib.HTTPConnection.default_port)
        conn.request("GET", xsdURI)
        # If we can't download the schema, raise an exception
        r1 = conn.getresponse()
        if r1.status != 200:
            raise Exception
        return r1.read().replace('\n', '').replace('\t', '').strip()

    def _parseXSD(self, xsdURI):
        """
        Download XSD from URL, or if file, read local xsd file and set schemaDict
        """
        # Since the schema definiton is a global namespace shared by and agreed upon by
        # others, this should probably be a URL.  Check for URL, download xsd, parse, or
        # if local file, use local file.
        schemaDom = None
        if xsdURI.startswith("http"):
            try:
                schemaDom = minidom.parseString(self._httpGetXSD(xsdURI))
            except Exception, e:
                # logging.debug("%s: web file not found" % xsdURI)
                # logging.debug("Using local file %s" % self.xsd")
                print e
                print "Can't find %s on the web. Continuing." % xsdURI
        if not schemaDom:
            if os.path.exists(xsdURI):
                # logging.debug("using local copy.")
                print "Using local %s" % xsdURI
                schemaDom = minidom.parse(xsdURI)
            else:
                raise Exception("Can't find xsd locally")
        self.schemaDict = self.toDict(schemaDom.childNodes[0])

    def dict2dom(self, rdict, include_doc = False):
        """
        convert a dict object into a dom object.
        """

        def elementNode(tagname, rd):
            element = minidom.Element(tagname)
            for key in rd.keys():
                if isinstance(rd[key], StringTypes) or isinstance(rd[key], int):
                    element.setAttribute(key, str(rd[key]))
                elif isinstance(rd[key], dict):
                    child = elementNode(key, rd[key])
                    element.appendChild(child)
                elif isinstance(rd[key], list):
                    for item in rd[key]:
                        if isinstance(item, dict):
                            child = elementNode(key, item)
                            element.appendChild(child)
                        elif isinstance(item, StringTypes) or isinstance(item, int):
                            child = minidom.Element(key)
                            text = minidom.Text()
                            text.data = item
                            child.appendChild(text)
                            element.appendChild(child)
            return element

        # Minidom does not allow documents to have more then one
        # child, but elements may have many children. Because of
        # this, the document's root node will be the first key/value
        # pair in the dictionary.
        node = elementNode(rdict.keys()[0], rdict.values()[0])
        if include_doc:
            rootNode = minidom.Document()
            rootNode.appendChild(node)
        else:
            rootNode = node
        return rootNode

    def parseDict(self, rdict, include_doc = True):
        """
        Convert a dictionary into a dom object and store it.
        """
        self.rootNode = self.dict2dom(rdict, include_doc)

    def getDictsByTagName(self, tagname, dom = None):
        """
        Search the dom for all elements with the specified tagname
        and return them as a list of dicts
        """
        if not dom:
            dom = self.rootNode
        dicts = []
        doms = dom.getElementsByTagName(tagname)
        dictlist = [self.toDict(d) for d in doms]
        for item in dictlist:
            for value in item.values():
                dicts.append(value)
        return dicts

    def getDictByTagNameValue(self, tagname, value, dom = None):
        """
        Search the dom for the first element with the specified tagname
        and value and return it as a dict.
        """
        tempdict = {}
        if not dom:
            dom = self.rootNode
        dicts = self.getDictsByTagName(tagname, dom)

        for rdict in dicts:
            if rdict.has_key('name') and rdict['name'] in [value]:
                return rdict

        return tempdict

    def filter(self, tagname, attribute, blacklist = [], whitelist = [], dom = None):
        """
        Removes all elements where:
        1. tagname matches the element tag
        2. attribute matches the element attribte
        3. attribute value is in valuelist
        """

        tempdict = {}
        if not dom:
            dom = self.rootNode

        if dom.localName in [tagname] and dom.attributes.has_key(attribute):
            if whitelist and dom.attributes.get(attribute).value not in whitelist:
                dom.parentNode.removeChild(dom)
            if blacklist and dom.attributes.get(attribute).value in blacklist:
                dom.parentNode.removeChild(dom)

        if dom.hasChildNodes():
            for child in dom.childNodes:
                self.filter(tagname, attribute, blacklist, whitelist, child)

    def validateDicts(self):
        types = {
            'EInt' : int,
            'EString' : str,
            'EByteArray' : list,
            'EBoolean' : bool,
            'EFloat' : float,
            'EDate' : date}

    def pprint(self, r = None, depth = 0):
        """
        Pretty print the dict
        """
        line = ""
        if r == None: r = self.dict
        # Set the dept
        for tab in range(0,depth): line += "    "
        # check if it's nested
        if type(r) == dict:
            for i in r.keys():
                print line + "%s:" % i
                self.pprint(r[i], depth + 1)
        elif type(r) in (tuple, list):
            for j in r: self.pprint(j, depth + 1)
        # not nested so just print.
        else:
            print line + "%s" %  r

class RecordSpec(Rspec):

    root_tag = 'record'
    def parseDict(self, rdict, include_doc = False):
        """
        Convert a dictionary into a dom object and store it.
        """
        self.rootNode = self.dict2dom(rdict, include_doc)

    def dict2dom(self, rdict, include_doc = False):
        record_dict = rdict
        if not len(rdict.keys()) == 1:
            record_dict = {self.root_tag : rdict}
        return Rspec.dict2dom(self, record_dict, include_doc)

# vim:ts=4:expandtab

<|endoftext|>


<commit_before>from .base import BaseEstimator

class Pipeline(BaseEstimator):
    """
    Pipeline of transformers with a final predictor
    Sequentialy apply a list of transformers and a final predictor
    A transformer implements fit & transform methods
    A predictor implements fit & predict methods

    Example
    =======

    >>> from scikits.learn import svm, datasets
    >>> from scikits.learn.datasets import samples_generator
    >>> from scikits.learn.feature_selection import SelectKBest, f_regression
    >>> from scikits.learn.pipeline import Pipeline

    >>> # generate some data to play with
    >>> X, y = samples_generator.test_dataset_classif(k=5)

    >>> # ANOVA SVM-C
    >>> anova_filter = SelectKBest(f_regression, k=5)
    >>> clf = svm.SVC(kernel='linear')

    >>> anova_svm = Pipeline([anova_filter], clf)
    >>> _ = anova_svm.fit(X,y)

    >>> prediction = anova_svm.predict(X)
    >>> score = anova_svm.score(X)
    """
    def __init__(self, transformers=[], estimator=None):
        """
        methods: list of UnivRanking objects,
        ie.: with fit/reduce/getSelectedFeatures methods
        """
        for t in  transformers:
            assert hasattr(t, "fit") and hasattr(t, "transform"), ValueError(
                "All transformers should implement fit and transform",
                "'%s' (type %s) )" % (t, type(t))
        )
        assert hasattr(estimator, "fit") and hasattr(estimator, "predict"), \
            ValueError("Predictor should implement fit and predict",
                "'%s' (type %s) )" % (t, type(t))
        )
        self.transformers = transformers
        self.estimator = estimator

    def fit(self, X, y=None):
        Xt = X
        for transformer in self.transformers:
            Xt = transformer.fit(Xt, y).transform(Xt)
        self.estimator.fit(Xt, y)
        return self

    def predict(self, X):
        Xt = X
        for transformer in self.transformers:
            Xt = transformer.transform(Xt)
        return self.estimator.predict(Xt)

    def score(self, X, y=None):
        Xt = X
        for transformer in self.transformers:
            Xt = transformer.transform(Xt)
        return self.estimator.score(Xt, y)

<commit_msg>Cosmit<commit_after>"""
Pipeline: chain transforms and estimators to build a composite estimator.
"""
# Author: Edouard Duchesnay
#         Gael Varoquaux
#         Virgile Fritsch
# Licence: BSD

from .base import BaseEstimator

class Pipeline(BaseEstimator):
    """
    Pipeline of transformers with a final estimator
    Sequentialy apply a list of transformers and a final estimator
    A transform implements fit & transform methods
    A estimator implements fit & predict methods

    Example
    =======

    >>> from scikits.learn import svm, datasets
    >>> from scikits.learn.datasets import samples_generator
    >>> from scikits.learn.feature_selection import SelectKBest, f_regression
    >>> from scikits.learn.pipeline import Pipeline

    >>> # generate some data to play with
    >>> X, y = samples_generator.test_dataset_classif(k=5)

    >>> # ANOVA SVM-C
    >>> anova_filter = SelectKBest(f_regression, k=5)
    >>> clf = svm.SVC(kernel='linear')

    >>> anova_svm = Pipeline([anova_filter], clf)
    >>> _ = anova_svm.fit(X,y)

    >>> prediction = anova_svm.predict(X)
    >>> score = anova_svm.score(X)
    """
    def __init__(self, transformers=[], estimator=None):
        """
        methods: list of UnivRanking objects,
        ie.: with fit/reduce/getSelectedFeatures methods
        """
        for t in  transformers:
            assert hasattr(t, "fit") and hasattr(t, "transform"), ValueError(
                "All transformers should implement fit and transform",
                "'%s' (type %s) )" % (t, type(t))
        )
        assert hasattr(estimator, "fit") and hasattr(estimator, "predict"), \
            ValueError("Predictor should implement fit and predict",
                "'%s' (type %s) )" % (t, type(t))
        )
        self.transformers = transformers
        self.estimator = estimator

    def fit(self, X, y=None):
        Xt = X
        for transformer in self.transformers:
            Xt = transformer.fit(Xt, y).transform(Xt)
        self.estimator.fit(Xt, y)
        return self

    def predict(self, X):
        Xt = X
        for transformer in self.transformers:
            Xt = transformer.transform(Xt)
        return self.estimator.predict(Xt)

    def score(self, X, y=None):
        Xt = X
        for transformer in self.transformers:
            Xt = transformer.transform(Xt)
        return self.estimator.score(Xt, y)

<|endoftext|>


<commit_before>from singer import utils
from singer.utils import (
    chunk,
    load_json,
    parse_args,
    ratelimit,
    strftime,
    strptime,
    update_state,
)

from singer.logger import get_logger

from singer.metrics import (
    Counter,
    Timer,
    http_request_timer,
    job_timer,
    record_counter,
)

from singer.messages import (
    ActivateVersionMessage,
    Message,
    RecordMessage,
    SchemaMessage,
    StateMessage,
    format_message,
    parse_message,
    write_record,
    write_records,
    write_schema,
    write_state,
)

from singer.transform import (
    NO_INTEGER_DATETIME_PARSING,
    UNIX_SECONDS_INTEGER_DATETIME_PARSING,
    UNIX_MILLISECONDS_INTEGER_DATETIME_PARSING,
    Transformer,
    transform,
    _transform_datetime,
)

from singer.catalog import Catalog
from singer.schema import Schema

from singer.bookmarks import (
    write_bookmark,
    get_bookmark,
    set_offset,
    clear_offset,
    get_offset,
    set_currently_syncing,
    get_currently_syncing,
)

if __name__ == "__main__":
    import doctest
    doctest.testmod()
<commit_msg>import write_message from messages<commit_after>from singer import utils
from singer.utils import (
    chunk,
    load_json,
    parse_args,
    ratelimit,
    strftime,
    strptime,
    update_state,
)

from singer.logger import get_logger

from singer.metrics import (
    Counter,
    Timer,
    http_request_timer,
    job_timer,
    record_counter,
)

from singer.messages import (
    ActivateVersionMessage,
    Message,
    RecordMessage,
    SchemaMessage,
    StateMessage,
    format_message,
    parse_message,
    write_message,
    write_record,
    write_records,
    write_schema,
    write_state,
)

from singer.transform import (
    NO_INTEGER_DATETIME_PARSING,
    UNIX_SECONDS_INTEGER_DATETIME_PARSING,
    UNIX_MILLISECONDS_INTEGER_DATETIME_PARSING,
    Transformer,
    transform,
    _transform_datetime,
)

from singer.catalog import Catalog
from singer.schema import Schema

from singer.bookmarks import (
    write_bookmark,
    get_bookmark,
    set_offset,
    clear_offset,
    get_offset,
    set_currently_syncing,
    get_currently_syncing,
)

if __name__ == "__main__":
    import doctest
    doctest.testmod()
<|endoftext|>


<commit_before>from pymongo import MongoClient
from datetime import timedelta
from flask import Flask,make_response, request, current_app
from functools import update_wrapper
import requests

def crossdomain(origin=None, methods=None, headers=None,
                max_age=21600, attach_to_all=True,
                automatic_options=True):
    if methods is not None:
        methods = ', '.join(sorted(x.upper() for x in methods))
    if headers is not None and not isinstance(headers, basestring):
        headers = ', '.join(x.upper() for x in headers)
    if not isinstance(origin, basestring):
        origin = ', '.join(origin)
    if isinstance(max_age, timedelta):
        max_age = max_age.total_seconds()

    def get_methods():
        if methods is not None:
            return methods

        options_resp = current_app.make_default_options_response()
        return options_resp.headers['allow']

    def decorator(f):
        def wrapped_function(*args, **kwargs):
            if automatic_options and request.method == 'OPTIONS':
                resp = current_app.make_default_options_response()
            else:
                resp = make_response(f(*args, **kwargs))
            if not attach_to_all and request.method != 'OPTIONS':
                return resp

            h = resp.headers

            h['Access-Control-Allow-Origin'] = origin
            h['Access-Control-Allow-Methods'] = get_methods()
            h['Access-Control-Max-Age'] = str(max_age)
            if headers is not None:
                h['Access-Control-Allow-Headers'] = headers
            return resp

        f.provide_automatic_options = False
        return update_wrapper(wrapped_function, f)
    return decorator
app = Flask(__name__)

db = MongoClient('localhost', 27017).data
users = db.users

motion = db.motion

@app.route('/getuser=<name>')
@crossdomain(origin='*')
def getMoves(access_token):
    for user in users:
    	if user['name'] == name:
    		return user['name']
    return "Not found."

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=8081, debug=True)

<commit_msg>Fixing.<commit_after>from pymongo import MongoClient
from datetime import timedelta
from flask import Flask,make_response, request, current_app
from functools import update_wrapper
import requests

def crossdomain(origin=None, methods=None, headers=None,
                max_age=21600, attach_to_all=True,
                automatic_options=True):
    if methods is not None:
        methods = ', '.join(sorted(x.upper() for x in methods))
    if headers is not None and not isinstance(headers, basestring):
        headers = ', '.join(x.upper() for x in headers)
    if not isinstance(origin, basestring):
        origin = ', '.join(origin)
    if isinstance(max_age, timedelta):
        max_age = max_age.total_seconds()

    def get_methods():
        if methods is not None:
            return methods

        options_resp = current_app.make_default_options_response()
        return options_resp.headers['allow']

    def decorator(f):
        def wrapped_function(*args, **kwargs):
            if automatic_options and request.method == 'OPTIONS':
                resp = current_app.make_default_options_response()
            else:
                resp = make_response(f(*args, **kwargs))
            if not attach_to_all and request.method != 'OPTIONS':
                return resp

            h = resp.headers

            h['Access-Control-Allow-Origin'] = origin
            h['Access-Control-Allow-Methods'] = get_methods()
            h['Access-Control-Max-Age'] = str(max_age)
            if headers is not None:
                h['Access-Control-Allow-Headers'] = headers
            return resp

        f.provide_automatic_options = False
        return update_wrapper(wrapped_function, f)
    return decorator
app = Flask(__name__)

db = MongoClient('localhost', 27017).data
users = db.users

motion = db.motion

@app.route('/getuser=<username>')
@crossdomain(origin='*')
def getMoves(username):
    for user in users:
    	if user['name'] == username:
    		return user['name']
    return "Not found."

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=8081, debug=True)

<|endoftext|>


<commit_before>#!/usr/bin/env python
import sqlite3
import os
import argparse
from datetime import datetime
from tabulate import tabulate

from macshared import DATABASE_NAME

def create_database():
	print("Creating MAC Monitor Sqlite3 Database")

	conn = sqlite3.connect(DATABASE_NAME)
	c = conn.cursor()
	c.execute('PRAGMA foreign_keys = ON')
	c.execute('''
		CREATE TABLE devices
			(devid INTEGER PRIMARY KEY,
			 mac TEXT,
			 description TEXT DEFAULT NULL)
		''')
	c.execute('''
		CREATE TABLE connections
			(connid INTEGER PRIMARY KEY,
			 device INTEGER,
			 start_date INTEGER,
			 latest_date INTEGER,
			 ip TEXT,
			 open INTEGER DEFAULT 1,
			 FOREIGN KEY(device) REFERENCES devices(devid))
		''')
	conn.commit()
	conn.close()

def delete_database():
	print("Deleting MAC Monitor Sqlite3 Database")
	os.remove(DATABASE_NAME)

def dump_database():
	print("MAC Monitor Database Dump:")
	print("Inner join on device ID")
	conn = sqlite3.connect(DATABASE_NAME)
	c = conn.cursor()
	c.execute('''
		SELECT mac, start_date, latest_date, ip, open, description
		FROM devices, connections
		WHERE devices.devid = connections.device
		ORDER BY connections.latest_date DESC
		''')
	data = c.fetchall()
	print(tabulate(data, ["MAC", "Start Date", "Latest Date", "IP", "Open", "Description"], tablefmt="psql"))
	conn.close()

def open_connections():
	print("Open Connections:")
	conn = sqlite3.connect(DATABASE_NAME)
	c = conn.cursor()
	data = []
	for row in c.execute('''
		SELECT d.mac, c.ip, c.start_date, d.description
		FROM devices d, connections c
		WHERE c.device = d.devid
		AND c.open = 1
		ORDER BY c.ip
		'''):
		timedelta = datetime.now() - datetime.fromtimestamp(row[2])
		data.append([row[0], row[1], timedelta, row[3]])
	print(tabulate(data, ["MAC", "IP", "Connection Time", "Description"], tablefmt="psql"))
	conn.close()

def edit_description():
	print("Choose a device to edit description:")
	conn = sqlite3.connect(DATABASE_NAME)
	c = conn.cursor()
	c.execute('''
		SELECT devid, mac, description FROM devices
		''')
	macs = c.fetchall()
	print(tabulate(macs, ["ID", "MAC", "Description"], tablefmt="psql"))
	devid = input("Enter ID or press 'q' to quit: ")
	if devid is 'q':
		return
	else:
		desc = input("Enter description for ID %d: " % int(devid))
		c.execute('''
			UPDATE devices
			SET description = ?
			WHERE devid = ?
			''', (desc, int(devid),))
	conn.commit()
	conn.close()

if __name__ == "__main__":
	print("Running MAC Manage\n")

	parser = argparse.ArgumentParser()
	parser.add_argument('-c', '--create-db', action='store_true',
		help="Create a blank MAC Monitor database")
	parser.add_argument('-d', '--dump', action='store_true',
		help="Dump the contents of the MAC Monitor database")
	parser.add_argument('-o', '--open-conns', action='store_true',
		help="List currently open connections")
	parser.add_argument('-e', '--edit-desc', action='store_true',
		help="Edit the description of a device")
	args = parser.parse_args()

	if args.create_db:
		delete_database()
		create_database()

	if args.dump:
		dump_database()

	if args.open_conns:
		open_connections()

	if args.edit_desc:
		edit_description()

	if not (args.create_db or args.dump or args.open_conns or args.edit_desc):
		parser.parse_args('-h'.split())

	# provide options to
	#   - Print statistics
<commit_msg>Replace or series with any()<commit_after>#!/usr/bin/env python
import sqlite3
import os
import argparse
from datetime import datetime
from tabulate import tabulate

from macshared import DATABASE_NAME

def create_database():
	print("Creating MAC Monitor Sqlite3 Database")

	conn = sqlite3.connect(DATABASE_NAME)
	c = conn.cursor()
	c.execute('PRAGMA foreign_keys = ON')
	c.execute('''
		CREATE TABLE devices
			(devid INTEGER PRIMARY KEY,
			 mac TEXT,
			 description TEXT DEFAULT NULL)
		''')
	c.execute('''
		CREATE TABLE connections
			(connid INTEGER PRIMARY KEY,
			 device INTEGER,
			 start_date INTEGER,
			 latest_date INTEGER,
			 ip TEXT,
			 open INTEGER DEFAULT 1,
			 FOREIGN KEY(device) REFERENCES devices(devid))
		''')
	conn.commit()
	conn.close()

def delete_database():
	print("Deleting MAC Monitor Sqlite3 Database")
	os.remove(DATABASE_NAME)

def dump_database():
	print("MAC Monitor Database Dump:")
	print("Inner join on device ID")
	conn = sqlite3.connect(DATABASE_NAME)
	c = conn.cursor()
	c.execute('''
		SELECT mac, start_date, latest_date, ip, open, description
		FROM devices, connections
		WHERE devices.devid = connections.device
		ORDER BY connections.latest_date DESC
		''')
	data = c.fetchall()
	print(tabulate(data, ["MAC", "Start Date", "Latest Date", "IP", "Open", "Description"], tablefmt="psql"))
	conn.close()

def open_connections():
	print("Open Connections:")
	conn = sqlite3.connect(DATABASE_NAME)
	c = conn.cursor()
	data = []
	for row in c.execute('''
		SELECT d.mac, c.ip, c.start_date, d.description
		FROM devices d, connections c
		WHERE c.device = d.devid
		AND c.open = 1
		ORDER BY c.ip
		'''):
		timedelta = datetime.now() - datetime.fromtimestamp(row[2])
		data.append([row[0], row[1], timedelta, row[3]])
	print(tabulate(data, ["MAC", "IP", "Connection Time", "Description"], tablefmt="psql"))
	conn.close()

def edit_description():
	print("Choose a device to edit description:")
	conn = sqlite3.connect(DATABASE_NAME)
	c = conn.cursor()
	c.execute('''
		SELECT devid, mac, description FROM devices
		''')
	macs = c.fetchall()
	print(tabulate(macs, ["ID", "MAC", "Description"], tablefmt="psql"))
	devid = input("Enter ID or press 'q' to quit: ")
	if devid is 'q':
		return
	else:
		desc = input("Enter description for ID %d: " % int(devid))
		c.execute('''
			UPDATE devices
			SET description = ?
			WHERE devid = ?
			''', (desc, int(devid),))
	conn.commit()
	conn.close()

if __name__ == "__main__":
	print("Running MAC Manage\n")

	parser = argparse.ArgumentParser()
	parser.add_argument('-c', '--create-db', action='store_true',
		help="Create a blank MAC Monitor database")
	parser.add_argument('-d', '--dump', action='store_true',
		help="Dump the contents of the MAC Monitor database")
	parser.add_argument('-o', '--open-conns', action='store_true',
		help="List currently open connections")
	parser.add_argument('-e', '--edit-desc', action='store_true',
		help="Edit the description of a device")
	args = parser.parse_args()

	if args.create_db:
		delete_database()
		create_database()

	if args.dump:
		dump_database()

	if args.open_conns:
		open_connections()

	if args.edit_desc:
		edit_description()

	if not any(vars(args).values()): # No arguments passed
		parser.parse_args('-h'.split())

	# provide options to
	#   - Print statistics
<|endoftext|>


<commit_before>import time
import os
import atexit

import numpy as nm

from sfepy.base.base import sfepy_config_dir, ordered_iteritems
from sfepy.base.base import output, get_default, set_defaults, Output, Struct
from sfepy.base.tasks import Process, Pipe
from sfepy.linalg import cycle

try:
    import gobject
except ImportError:
    pass

try:
    import matplotlib as mpl
    from matplotlib.ticker import LogLocator, AutoLocator
except:
    mpl = None

if (mpl is not None) and mpl.rcParams['backend'] == 'GTKAgg':
    can_live_plot = True
else:
    can_live_plot = False

_msg_no_live = """warning: log plot is disabled, install matplotlib
         (use GTKAgg backend) and multiprocessing"""

def get_logging_conf(conf):
    """
    Check for a logging configuration ('log' attribute) in conf. Supply default
    values if necessary.

    Returns
    -------
    log : dict
        The dictionary {'plot' : <figure_file>, 'text' : <text_log_file>}. One
        or both values can be None.
    """
    get = conf.get_default_attr

    log = get('log', None)

    default_log = {'text' : None, 'plot' : None}

    if log is None:
        log = default_log

    else:
        set_defaults(log, default_log)

    return log

class ProcessPlotter( Struct ):
    output = Output('plotter:')
    output = staticmethod( output )

    def __init__( self, aggregate = 100 ):
        Struct.__init__( self, aggregate = aggregate )

    def process_command( self, command ):
        self.output( command[0] )

        if command[0] == 'ig':
            self.ig = command[1]

        elif command[0] == 'plot':
            xdata, ydata = command[1:]

            ig = self.ig
            ax = self.ax[ig]
            ax.set_yscale(self.yscales[ig])
            ax.yaxis.grid(True)
            ax.plot(xdata, ydata)

            if self.yscales[ig] == 'log':
                ymajor_formatter = ax.yaxis.get_major_formatter()
                ymajor_formatter.label_minor(True)
                yminor_locator = LogLocator()
            else:
                yminor_locator = AutoLocator()
                self.ax[ig].yaxis.set_minor_locator(yminor_locator)

        elif command[0] == 'vline':
            x, kwargs = command[1:]

            self.vlines[self.ig].append((x, kwargs))

        elif command[0] == 'clear':
            self.ax[self.ig].cla()

        elif command[0] == 'legends':
            for ig, ax in enumerate(self.ax):
                try:
                    ax.legend(self.data_names[ig])
                except:
                    pass

                if self.xlabels[ig]:
                    ax.set_xlabel(self.xlabels[ig])
                if self.ylabels[ig]:
                    ax.set_ylabel(self.ylabels[ig])

                for x, kwargs in self.vlines[ig]:
                    ax.axvline(x, **kwargs)

        elif command[0] == 'add_axis':
            ig, names, yscale, xlabel, ylabel = command[1:]
            self.data_names[ig] = names
            self.yscales[ig] = yscale
            self.xlabels[ig] = xlabel
            self.ylabels[ig] = ylabel
            self.n_gr = len(self.data_names)
            self.make_axes()

        elif command[0] == 'save':
            self.fig.savefig(command[1])
            self.pipe.send(True) # Acknowledge save.

    def terminate( self ):
        if self.ii:
            self.output( 'processed %d commands' % self.ii )
        self.output( 'ended.' )
        self.plt.close( 'all' )

    def poll_draw( self ):

        def call_back():
            self.ii = 0

            while 1:
                if not self.pipe.poll():
                    break

                command = self.pipe.recv()
                can_break = False

                if command is None:
                    self.terminate()
                    return False
                elif command[0] == 'continue':
                    can_break = True
                else:
                    self.process_command( command )

                if (self.ii >= self.aggregate) and can_break:
                    break

                self.ii += 1

            if self.ii:
                self.fig.canvas.draw()
                self.output( 'processed %d commands' % self.ii )

            return True

        return call_back

    def make_axes(self):
        self.fig.clf()
        self.ax = []

        n_col = min(5.0, nm.fix(nm.sqrt(self.n_gr)))
        if int(n_col) == 0:
            n_row = 0
        else:
            n_row = int(nm.ceil(self.n_gr / n_col))
            n_col = int(n_col)

        for ii, (ir, ic) in enumerate(cycle((n_col, n_row))):
            if ii == self.n_gr: break
            self.ax.append(self.fig.add_subplot(n_row, n_col, ii+1))
            self.vlines.setdefault(ii, [])

    def __call__(self, pipe, log_file, data_names, yscales, xlabels, ylabels):
        """Sets-up the plotting window, sets GTK event loop timer callback to
        callback() returned by self.poll_draw(). The callback does the actual
        plotting, taking commands out of `pipe`, and is called every second.

        Note that pyplot _must_ be imported here and not in this module so that
        the import occurs _after_ the plotting process is started in that
        process.
        """
        import matplotlib.pyplot as plt
        self.plt = plt

        self.output.set_output(filename=log_file)
        self.output( 'starting plotter...' )

        self.pipe = pipe
        self.data_names = data_names
        self.yscales = yscales
        self.xlabels = xlabels
        self.ylabels = ylabels
        self.n_gr = len(data_names)
        self.vlines = {}

        self.fig = self.plt.figure()
        self.make_axes()
        self.gid = gobject.timeout_add( 1000, self.poll_draw() )

        self.output( '...done' )
        self.plt.show()

def name_to_key( name, ii ):
    return name + (':%d' % ii)

class Log( Struct ):
    """Log data and (optionally) plot them in the second process via
    ProcessPlotter."""
    count = -1

    def from_conf( conf, data_names ):
        """`data_names` ... tuple of names grouped by subplots:
                            ([name1, name2, ...], [name3, name4, ...], ...)
        where name<n> are strings to display in (sub)plot legends."""
        if not isinstance( data_names, tuple ):
            data_names = (data_names,)

        obj = Log(data_names, **conf)

        return obj
    from_conf = staticmethod( from_conf )

    def __init__(self, data_names=None, yscales=None,
                 xlabels=None, ylabels=None, is_plot=True, aggregate=200,
                 formats=None, log_filename=None):
        """`data_names` ... tuple of names grouped by subplots:
                            ([name1, name2, ...], [name3, name4, ...], ...)
        where name<n> are strings to display in (sub)plot legends."""
        Struct.__init__(self, data_names = {},
                        n_arg = 0, n_gr = 0,
                        data = {}, x_values = {}, n_calls = 0,
                        yscales = {}, xlabels = {}, ylabels = {},
                        plot_pipe = None, formats = {}, output = None)

        if data_names is not None:
            n_gr = len(data_names)
        else:
            n_gr = 0
            data_names = []

        yscales = get_default(yscales, ['linear'] * n_gr)
        xlabels = get_default(xlabels, ['iteration'] * n_gr)
        ylabels = get_default(ylabels, [''] * n_gr )

        if formats is None:
            formats = [None] * n_gr

        for ig, names in enumerate(data_names):
            self.add_group(names, yscales[ig], xlabels[ig], ylabels[ig],
                           formats[ig])

        self.is_plot = get_default( is_plot, True )
        self.aggregate = get_default( aggregate, 100 )

        self.can_plot = (can_live_plot and (mpl is not None)
                         and (Process is not None))

        if log_filename is not None:
            self.output = Output('', filename=log_filename)
            self.output('# started: %s' % time.asctime())

        if self.is_plot and (not self.can_plot):
            output(_msg_no_live)

    def add_group(self, names, yscale=None, xlabel=None, ylabel=None,
                  formats=None):
        """Add a new data group. Notify the plotting process if it is
        already running."""
        ig = self.n_gr
        self.n_gr += 1

        self.x_values[ig] = []

        self.data_names[ig] = names
        self.yscales[ig] = yscale
        self.xlabels[ig] = xlabel
        self.ylabels[ig] = ylabel

        ii = self.n_arg
        for iseq, name in enumerate(names):
            key = name_to_key(name, ii)
            self.data[key] = []
            ii += 1

            if formats is not None:
                self.formats[key] = formats[iseq]
            else:
                self.formats[key] = '%.3e'

        self.n_arg = ii

        if self.plot_pipe is not None:
            send = self.plot_pipe.send
            send(['add_axis', ig, names, yscale, xlabel, ylabel])

    def iter_names(self, igs=None):
        if igs is None:
            igs = nm.arange(self.n_gr)

        ii = iseq = 0
        for ig, names in ordered_iteritems(self.data_names):
            for name in names:
                if ig in igs:
                    yield ig, ii, iseq, name
                    iseq += 1
                ii += 1

    def get_log_name(self):
        return os.path.join(sfepy_config_dir,
                            'plotter_%03d.log' % self.__class__.count)

    def __call__( self, *args, **kwargs ):
        """Log the data passed via *args, and send them to the plotting
        process, if available."""
        finished = False
        save_figure = ''
        x_values = None
        igs = nm.arange(self.n_gr)
        full = True
        if kwargs:
            if 'finished' in kwargs:
                finished = kwargs['finished']
            if 'save_figure' in kwargs:
                save_figure = kwargs['save_figure']
            if 'x' in kwargs:
                x_values = kwargs['x']

            if 'igs' in kwargs:
                igs = nm.array(kwargs['igs'])
                full = False

        if save_figure and (self.plot_pipe is not None):
            self.plot_pipe.send( ['save', save_figure] )
            ok = self.plot_pipe.recv()

        if finished:
            self.terminate()
            return

        ls = len( args ), self.n_arg
        if full and (ls[0] != ls[1]):
            if kwargs:
                return
            else:
                msg = 'log called with wrong number of arguments! (%d == %d)' \
                      % ls
                raise IndexError( msg )

        for ig in igs:
            if (x_values is not None) and (x_values[ig] is not None):
                self.x_values[ig].append(x_values[ig])
            else:
                if len(self.x_values[ig]):
                    ii = self.x_values[ig][-1] + 1
                else:
                    ii = 0
                self.x_values[ig].append(ii)

        for ig, ii, iseq, name in self.iter_names(igs):
            aux = args[iseq]
            if isinstance( aux, nm.ndarray ):
                aux = nm.array( aux, ndmin = 1 )
                if len( aux ) == 1:
                    aux = aux[0]
                else:
                    raise ValueError, 'can log only scalars (%s)' % aux
            key = name_to_key( name, ii )
            self.data[key].append( aux )

            if self.output:
                self.output(('%%s: %%s: %s' % self.formats[key])
                            % (name, self.x_values[ig][-1], aux))

        if self.is_plot and self.can_plot:
            if self.n_calls == 0:
                atexit.register( self.terminate )

                self.__class__.count += 1

                self.plot_pipe, plotter_pipe = Pipe()
                self.plotter = ProcessPlotter( self.aggregate )
                self.plot_process = Process( target = self.plotter,
                                             args = (plotter_pipe,
                                                     self.get_log_name(),
                                                     self.data_names,
                                                     self.yscales,
                                                     self.xlabels,
                                                     self.ylabels) )
                self.plot_process.daemon = True
                self.plot_process.start()

            self.plot_data(igs)

        self.n_calls += 1

    def terminate(self):
        if self.output is not None:
            self.output('# ended: %s' % time.asctime())
            self.output = None

        if self.is_plot and self.can_plot:
            self.plot_pipe.send(None)
            self.plot_process.join()
            self.n_calls = 0
            output('terminated')

    def plot_data(self, igs):
        send = self.plot_pipe.send

        ii = 0
        for ig, names in ordered_iteritems(self.data_names):
            if ig in igs:
                send(['ig', ig])
                send(['clear'])
                for name in names:
                    key = name_to_key(name, ii)
                    try:
                        send(['plot',
                              nm.array(self.x_values[ig]),
                              nm.array(self.data[key])])
                    except:
                        msg = "send failed! (%s, %s, %s)!" \
                              % (ii, name, self.data[key])
                        raise IOError(msg)
                    ii += 1

            else:
                ii += len(names)

        send(['legends'])
        send(['continue'])

    def plot_vlines(self, igs=None, **kwargs):
        """Plot vertical lines in axes given by igs at current x locations
        to mark some events."""
        if self.plot_pipe is not None:
            send = self.plot_pipe.send

            if igs is None:
                igs = range(self.n_gr)

            for ig in igs:
                x = self.x_values[ig]
                if len(x):
                    send(['ig', ig])
                    send(['vline', x[-1], kwargs])

            send(['continue'])
<commit_msg>update Log.plot_vlines() to add line also to text log file<commit_after>import time
import os
import atexit

import numpy as nm

from sfepy.base.base import sfepy_config_dir, ordered_iteritems
from sfepy.base.base import output, get_default, set_defaults, Output, Struct
from sfepy.base.tasks import Process, Pipe
from sfepy.linalg import cycle

try:
    import gobject
except ImportError:
    pass

try:
    import matplotlib as mpl
    from matplotlib.ticker import LogLocator, AutoLocator
except:
    mpl = None

if (mpl is not None) and mpl.rcParams['backend'] == 'GTKAgg':
    can_live_plot = True
else:
    can_live_plot = False

_msg_no_live = """warning: log plot is disabled, install matplotlib
         (use GTKAgg backend) and multiprocessing"""

def get_logging_conf(conf):
    """
    Check for a logging configuration ('log' attribute) in conf. Supply default
    values if necessary.

    Returns
    -------
    log : dict
        The dictionary {'plot' : <figure_file>, 'text' : <text_log_file>}. One
        or both values can be None.
    """
    get = conf.get_default_attr

    log = get('log', None)

    default_log = {'text' : None, 'plot' : None}

    if log is None:
        log = default_log

    else:
        set_defaults(log, default_log)

    return log

class ProcessPlotter( Struct ):
    output = Output('plotter:')
    output = staticmethod( output )

    def __init__( self, aggregate = 100 ):
        Struct.__init__( self, aggregate = aggregate )

    def process_command( self, command ):
        self.output( command[0] )

        if command[0] == 'ig':
            self.ig = command[1]

        elif command[0] == 'plot':
            xdata, ydata = command[1:]

            ig = self.ig
            ax = self.ax[ig]
            ax.set_yscale(self.yscales[ig])
            ax.yaxis.grid(True)
            ax.plot(xdata, ydata)

            if self.yscales[ig] == 'log':
                ymajor_formatter = ax.yaxis.get_major_formatter()
                ymajor_formatter.label_minor(True)
                yminor_locator = LogLocator()
            else:
                yminor_locator = AutoLocator()
                self.ax[ig].yaxis.set_minor_locator(yminor_locator)

        elif command[0] == 'vline':
            x, kwargs = command[1:]

            self.vlines[self.ig].append((x, kwargs))

        elif command[0] == 'clear':
            self.ax[self.ig].cla()

        elif command[0] == 'legends':
            for ig, ax in enumerate(self.ax):
                try:
                    ax.legend(self.data_names[ig])
                except:
                    pass

                if self.xlabels[ig]:
                    ax.set_xlabel(self.xlabels[ig])
                if self.ylabels[ig]:
                    ax.set_ylabel(self.ylabels[ig])

                for x, kwargs in self.vlines[ig]:
                    ax.axvline(x, **kwargs)

        elif command[0] == 'add_axis':
            ig, names, yscale, xlabel, ylabel = command[1:]
            self.data_names[ig] = names
            self.yscales[ig] = yscale
            self.xlabels[ig] = xlabel
            self.ylabels[ig] = ylabel
            self.n_gr = len(self.data_names)
            self.make_axes()

        elif command[0] == 'save':
            self.fig.savefig(command[1])
            self.pipe.send(True) # Acknowledge save.

    def terminate( self ):
        if self.ii:
            self.output( 'processed %d commands' % self.ii )
        self.output( 'ended.' )
        self.plt.close( 'all' )

    def poll_draw( self ):

        def call_back():
            self.ii = 0

            while 1:
                if not self.pipe.poll():
                    break

                command = self.pipe.recv()
                can_break = False

                if command is None:
                    self.terminate()
                    return False
                elif command[0] == 'continue':
                    can_break = True
                else:
                    self.process_command( command )

                if (self.ii >= self.aggregate) and can_break:
                    break

                self.ii += 1

            if self.ii:
                self.fig.canvas.draw()
                self.output( 'processed %d commands' % self.ii )

            return True

        return call_back

    def make_axes(self):
        self.fig.clf()
        self.ax = []

        n_col = min(5.0, nm.fix(nm.sqrt(self.n_gr)))
        if int(n_col) == 0:
            n_row = 0
        else:
            n_row = int(nm.ceil(self.n_gr / n_col))
            n_col = int(n_col)

        for ii, (ir, ic) in enumerate(cycle((n_col, n_row))):
            if ii == self.n_gr: break
            self.ax.append(self.fig.add_subplot(n_row, n_col, ii+1))
            self.vlines.setdefault(ii, [])

    def __call__(self, pipe, log_file, data_names, yscales, xlabels, ylabels):
        """Sets-up the plotting window, sets GTK event loop timer callback to
        callback() returned by self.poll_draw(). The callback does the actual
        plotting, taking commands out of `pipe`, and is called every second.

        Note that pyplot _must_ be imported here and not in this module so that
        the import occurs _after_ the plotting process is started in that
        process.
        """
        import matplotlib.pyplot as plt
        self.plt = plt

        self.output.set_output(filename=log_file)
        self.output( 'starting plotter...' )

        self.pipe = pipe
        self.data_names = data_names
        self.yscales = yscales
        self.xlabels = xlabels
        self.ylabels = ylabels
        self.n_gr = len(data_names)
        self.vlines = {}

        self.fig = self.plt.figure()
        self.make_axes()
        self.gid = gobject.timeout_add( 1000, self.poll_draw() )

        self.output( '...done' )
        self.plt.show()

def name_to_key( name, ii ):
    return name + (':%d' % ii)

class Log( Struct ):
    """Log data and (optionally) plot them in the second process via
    ProcessPlotter."""
    count = -1

    def from_conf( conf, data_names ):
        """`data_names` ... tuple of names grouped by subplots:
                            ([name1, name2, ...], [name3, name4, ...], ...)
        where name<n> are strings to display in (sub)plot legends."""
        if not isinstance( data_names, tuple ):
            data_names = (data_names,)

        obj = Log(data_names, **conf)

        return obj
    from_conf = staticmethod( from_conf )

    def __init__(self, data_names=None, yscales=None,
                 xlabels=None, ylabels=None, is_plot=True, aggregate=200,
                 formats=None, log_filename=None):
        """`data_names` ... tuple of names grouped by subplots:
                            ([name1, name2, ...], [name3, name4, ...], ...)
        where name<n> are strings to display in (sub)plot legends."""
        Struct.__init__(self, data_names = {},
                        n_arg = 0, n_gr = 0,
                        data = {}, x_values = {}, n_calls = 0,
                        yscales = {}, xlabels = {}, ylabels = {},
                        plot_pipe = None, formats = {}, output = None)

        if data_names is not None:
            n_gr = len(data_names)
        else:
            n_gr = 0
            data_names = []

        yscales = get_default(yscales, ['linear'] * n_gr)
        xlabels = get_default(xlabels, ['iteration'] * n_gr)
        ylabels = get_default(ylabels, [''] * n_gr )

        if formats is None:
            formats = [None] * n_gr

        for ig, names in enumerate(data_names):
            self.add_group(names, yscales[ig], xlabels[ig], ylabels[ig],
                           formats[ig])

        self.is_plot = get_default( is_plot, True )
        self.aggregate = get_default( aggregate, 100 )

        self.can_plot = (can_live_plot and (mpl is not None)
                         and (Process is not None))

        if log_filename is not None:
            self.output = Output('', filename=log_filename)
            self.output('# started: %s' % time.asctime())

        if self.is_plot and (not self.can_plot):
            output(_msg_no_live)

    def add_group(self, names, yscale=None, xlabel=None, ylabel=None,
                  formats=None):
        """Add a new data group. Notify the plotting process if it is
        already running."""
        ig = self.n_gr
        self.n_gr += 1

        self.x_values[ig] = []

        self.data_names[ig] = names
        self.yscales[ig] = yscale
        self.xlabels[ig] = xlabel
        self.ylabels[ig] = ylabel

        ii = self.n_arg
        for iseq, name in enumerate(names):
            key = name_to_key(name, ii)
            self.data[key] = []
            ii += 1

            if formats is not None:
                self.formats[key] = formats[iseq]
            else:
                self.formats[key] = '%.3e'

        self.n_arg = ii

        if self.plot_pipe is not None:
            send = self.plot_pipe.send
            send(['add_axis', ig, names, yscale, xlabel, ylabel])

    def iter_names(self, igs=None):
        if igs is None:
            igs = nm.arange(self.n_gr)

        ii = iseq = 0
        for ig, names in ordered_iteritems(self.data_names):
            for name in names:
                if ig in igs:
                    yield ig, ii, iseq, name
                    iseq += 1
                ii += 1

    def get_log_name(self):
        return os.path.join(sfepy_config_dir,
                            'plotter_%03d.log' % self.__class__.count)

    def __call__( self, *args, **kwargs ):
        """Log the data passed via *args, and send them to the plotting
        process, if available."""
        finished = False
        save_figure = ''
        x_values = None
        igs = nm.arange(self.n_gr)
        full = True
        if kwargs:
            if 'finished' in kwargs:
                finished = kwargs['finished']
            if 'save_figure' in kwargs:
                save_figure = kwargs['save_figure']
            if 'x' in kwargs:
                x_values = kwargs['x']

            if 'igs' in kwargs:
                igs = nm.array(kwargs['igs'])
                full = False

        if save_figure and (self.plot_pipe is not None):
            self.plot_pipe.send( ['save', save_figure] )
            ok = self.plot_pipe.recv()

        if finished:
            self.terminate()
            return

        ls = len( args ), self.n_arg
        if full and (ls[0] != ls[1]):
            if kwargs:
                return
            else:
                msg = 'log called with wrong number of arguments! (%d == %d)' \
                      % ls
                raise IndexError( msg )

        for ig in igs:
            if (x_values is not None) and (x_values[ig] is not None):
                self.x_values[ig].append(x_values[ig])
            else:
                if len(self.x_values[ig]):
                    ii = self.x_values[ig][-1] + 1
                else:
                    ii = 0
                self.x_values[ig].append(ii)

        for ig, ii, iseq, name in self.iter_names(igs):
            aux = args[iseq]
            if isinstance( aux, nm.ndarray ):
                aux = nm.array( aux, ndmin = 1 )
                if len( aux ) == 1:
                    aux = aux[0]
                else:
                    raise ValueError, 'can log only scalars (%s)' % aux
            key = name_to_key( name, ii )
            self.data[key].append( aux )

            if self.output:
                self.output(('%%s: %%s: %s' % self.formats[key])
                            % (name, self.x_values[ig][-1], aux))

        if self.is_plot and self.can_plot:
            if self.n_calls == 0:
                atexit.register( self.terminate )

                self.__class__.count += 1

                self.plot_pipe, plotter_pipe = Pipe()
                self.plotter = ProcessPlotter( self.aggregate )
                self.plot_process = Process( target = self.plotter,
                                             args = (plotter_pipe,
                                                     self.get_log_name(),
                                                     self.data_names,
                                                     self.yscales,
                                                     self.xlabels,
                                                     self.ylabels) )
                self.plot_process.daemon = True
                self.plot_process.start()

            self.plot_data(igs)

        self.n_calls += 1

    def terminate(self):
        if self.output is not None:
            self.output('# ended: %s' % time.asctime())
            self.output = None

        if self.is_plot and self.can_plot:
            self.plot_pipe.send(None)
            self.plot_process.join()
            self.n_calls = 0
            output('terminated')

    def plot_data(self, igs):
        send = self.plot_pipe.send

        ii = 0
        for ig, names in ordered_iteritems(self.data_names):
            if ig in igs:
                send(['ig', ig])
                send(['clear'])
                for name in names:
                    key = name_to_key(name, ii)
                    try:
                        send(['plot',
                              nm.array(self.x_values[ig]),
                              nm.array(self.data[key])])
                    except:
                        msg = "send failed! (%s, %s, %s)!" \
                              % (ii, name, self.data[key])
                        raise IOError(msg)
                    ii += 1

            else:
                ii += len(names)

        send(['legends'])
        send(['continue'])

    def plot_vlines(self, igs=None, **kwargs):
        """Plot vertical lines in axes given by igs at current x locations
        to mark some events."""
        if self.plot_pipe is not None:
            send = self.plot_pipe.send

            if igs is None:
                igs = range(self.n_gr)

            for ig in igs:
                x = self.x_values[ig]
                if len(x):
                    send(['ig', ig])
                    send(['vline', x[-1], kwargs])

            send(['continue'])

        if self.output:
            self.output('-----')
<|endoftext|>


<commit_before>#!/bin/python

import signal, sys, ssl, logging
from SimpleWebSocketServer import WebSocket, SimpleWebSocketServer, SimpleSSLWebSocketServer
from optparse import OptionParser
from sabertooth import Sabertooth
import Adafruit_BBIO.GPIO as GPIO
import Adafruit_BBIO.PWM as PWM
from Adafruit_HMC5883L import Adafruit_HMC5883L as MAG
import threading
from datetime import datetime
from time import sleep
import json

logging.basicConfig(format='%(asctime)s %(message)s', level=logging.INFO)

class RobotControl(WebSocket):
    saber = None
    UART = "UART1"
    TTY  ="ttyO1"
    STOP_GPIO = "P9_13"
    STOP_BUTTON = "P9_15"

    PROXIMITY_GPIO = {"P9_11": {"name": "right"},
                      "P9_12": {"name": "left"}
                     }

    LEDS_GPIO = { "RED_pin": "P8_10",
                  "GREEN_pin": "P8_11" }
    SPEAKER_PWM = "P8_13"
    SERVO_PWM = "P8_34"

    ECHO_RETURN = "P8_15"
    ECHO_TRIGGER = "P9_14"

    SPEED = 10
    CMD = None
    OBSTACLE = False
    SPEAKER = False
    SCAN = False
    angle = 0.0
    distance = (0.0, 0.0)
    COUNTING = False
    startTime = datetime.now()
    endTime = datetime.now()
    delta = endTime-startTime

    # cmd values that can be sent for a JSON "drive" event
    # maps command to corresponding function to control motors
    commands = {"fwd":   "do_forward",
                "rev":   "do_reverse",
                "left":  "turn_left",
                "right": "turn_right",
                "stop":  "do_stop",
                "speed": "set_speed"
               }

    def __init__(self, server, sock, address):
        super(RobotControl, self).__init__(server, sock, address)

        # setup GPIO pins for proximity sensors
        for PIN in self.PROXIMITY_GPIO:
            GPIO.setup(PIN, GPIO.IN)

        # try to add event detection for proximity GPIO pins
        for PIN, val in self.PROXIMITY_GPIO.items():
            # wait until the GPIO is configured as an input
            while GPIO.gpio_function(PIN) != GPIO.IN:
                GPIO.setup(PIN, GPIO.IN)
            GPIO.add_event_detect(PIN, GPIO.FALLING, self.__proximityDetect, 10)

        for LED in self.LEDS_GPIO.itervalues():
            GPIO.setup(LED, GPIO.OUT)
            GPIO.output(LED, GPIO.LOW)

        # Connected to Sabertooth S2 as "emergency stop" button
        GPIO.setup(self.STOP_GPIO, GPIO.OUT)
        GPIO.output(self.STOP_GPIO, GPIO.HIGH)
        # Triggers when button pressed
        GPIO.setup(self.STOP_BUTTON, GPIO.IN)
        while GPIO.gpio_function(self.STOP_BUTTON) != GPIO.IN:
            GPIO.setup(self.STOP_BUTTON, GPIO.IN)
        GPIO.add_event_detect(self.STOP_BUTTON, GPIO.RISING, self.__stopButton, 10)

        # HMC5883L Magnetometer
        self.mag = MAG(declination=(11,35))

        # HC-SR04 pin setup
        # ECHO_TRIGGER initiates ultrasonic pulse
        GPIO.setup(self.ECHO_TRIGGER, GPIO.OUT)

        # ECHO_RETURN - needs to be level shifted from 5.0V to 3.3V
        # time of +ve pulse is the distance
        GPIO.setup(self.ECHO_RETURN, GPIO.IN)
        while GPIO.gpio_function(self.ECHO_RETURN) != GPIO.IN:
            GPIO.setup(self.ECHO_RETURN, GPIO.IN)
        GPIO.add_event_detect(self.ECHO_RETURN, GPIO.BOTH, self.__measureEcho, 1)
        GPIO.output(self.ECHO_TRIGGER, GPIO.LOW)

        # Start servo scanning movement thread
        self.SCAN = True
        threading.Thread(target=self.__servoScan).start()
        # Start HC-SR04 timing/measurement thread
        threading.Thread(target=self.__HCSR04).start()

        self.do_beep(0.25)
        GPIO.output(self.LEDS_GPIO["RED_pin"], GPIO.HIGH)

        self.saber = Sabertooth(self.UART, self.TTY)
        self.saber.setRamp(15)

    def __speaker(self):
        if self.SPEAKER:
            return
        self.SPEAKER = True
        PWM.start(self.SPEAKER_PWM, 50, 3000)
        for dir in [-1,2]:
            for x in range(3,20):
                PWM.set_frequency(self.SPEAKER_PWM, 3000 + (dir * x * 100))
                sleep(0.05)
        PWM.stop(self.SPEAKER_PWM)
        self.SPEAKER = False
        return

    def __proximityDetect(self, channel):
        if self.OBSTACLE or (self.CMD in ["stop", None]):
            return # already handling a problem or not moving
        threading.Thread(target=self.__speaker).start()
        self.OBSTACLE = True
        self.sendJSON("obstacle", {"sensor": "%s" % (channel),
                                   "name": "%s" % (self.PROXIMITY_GPIO[channel]["name"])})
        self.saber.driveMotor("both", "rev", int(float(self.SPEED)*1.5))
        delay = 1 - (float(self.SPEED)/200)
        sleep(delay)
        self.do_stop(self.SPEED)
        self.OBSTACLE = False
        return

    def __stopButton(self, channel):
        self.SCAN = False
        GPIO.output(self.STOP_GPIO, GPIO.HIGH)
        self.do_stop(self.SPEED)
        return

    def __servoScan(self):
        PWM.start(self.SERVO_PWM, 3, 50)
        while self.SCAN:
            for a in xrange(0,180,1):
                self.angle = a
                duty = 3.7 + (a/180.0)*9.5
                if self.SCAN:
                    PWM.set_duty_cycle(self.SERVO_PWM, duty)
                else:
                    break
                sleep(0.01)
            for a in xrange(181,1,-1):
                self.angle = a
                duty = 3.7 + (a/180.0)*9.5
                if self.SCAN:
                    PWM.set_duty_cycle(self.SERVO_PWM, duty)
                else:
                    break
                sleep(0.01)
        return

    def __measureEcho(self, channel):
        # Get time when Echo line goes high (ie: RISING edge)
        if GPIO.input(self.ECHO_RETURN) == GPIO.HIGH and not self.COUNTING:
            self.startTime = datetime.now()
            self.COUNTING = True
        # Get time when Echo line goes low (ie: FALLING edge)
        elif GPIO.input(self.ECHO_RETURN) == GPIO.LOW and self.COUNTING:
            self.endTime = datetime.now()
            # delta is the period of the echo (roughly)
            self.delta = self.endTime - self.startTime
            self.COUNTING = False
        return

    def __HCSR04(self):
        measures = []
        while self.SCAN:
            # Set Trigger to HIGH
            GPIO.output("P9_14", GPIO.HIGH)
            # Wait a tiny amount (should be 10us). This is not deterministic
            # when running stock Linux. To get better use a RTOS or the PRUSS
            sleep(0.001)
            # Set Trigger to LOW
            # This will cause the HC-SR04 to output an ultrasonic pulse and start
            # listening for the return
            GPIO.output("P9_14", GPIO.LOW)
            # Sleep for a bit so that we don't send out another pulse before the
            # previous one has finished
            sleep(0.05)
            # 58.77 is the magic number for cm per microsecond
            d = min(200.0, max(self.delta.microseconds/58.77,17.0))
            # only include value if it is reasonable/valid
            if d > 17 and d < 200:
                measures.insert(0, d)
                if len(measures) > 3:
                    measures.pop()
            # take an average of the last few measures as the distance
            if len(measures) > 0:
                self.distance = sum(measures)/len(measures)
            else:
                self.distance = 20.0
            if self.distance < 20 and not self.OBSTACLE:
                self.OBSTACLE = True
                if self.angle < 90:
                    self.sendJSON("obstacle", {"sensor": "P9_12", "name": "left"})
                else:
                    self.sendJSON("obstacle", {"sensor": "P9_11", "name": "right"})
                self.OBSTACLE = False
        return

    def do_beep(self, duration):
        PWM.start(self.SPEAKER_PWM, 50, 3000)
        sleep(duration)
        PWM.stop(self.SPEAKER_PWM)

    def do_forward(self, set_speed):
        if set_speed != None:
            self.SPEED = set_speed
        self.saber.driveMotor("both", "fwd", self.SPEED)

    def do_reverse(self, set_speed):
        if set_speed != None:
            self.SPEED = set_speed
        self.saber.driveMotor("both", "rev", self.SPEED)

    def do_stop(self, set_speed):
        GPIO.output(self.LEDS_GPIO["RED_pin"], GPIO.HIGH)
        GPIO.output(self.LEDS_GPIO["GREEN_pin"], GPIO.LOW)
        self.saber.stop()

    def turn_left(self, set_speed):
        if set_speed != None:
            self.SPEED = set_speed
        self.saber.driveMotor("left", "fwd", self.SPEED)
        self.saber.driveMotor("right", "rev", self.SPEED)
        delay = 1 - (float(self.SPEED)/100)
        sleep(delay)
        if self.CMD in ["fwd", "rev"]:
            getattr(self, self.commands[self.CMD])(int(self.SPEED))
        else:
            self.do_stop(self.SPEED)

    def turn_right(self, set_speed):
        if set_speed != None:
            self.SPEED = set_speed
        self.saber.driveMotor("right", "fwd", self.SPEED)
        self.saber.driveMotor("left", "rev", self.SPEED)
        delay = 1 - (float(self.SPEED)/100)
        sleep(delay)
        if self.CMD in ["fwd", "rev"]:
            getattr(self, self.commands[self.CMD])(int(self.SPEED))
        else:
            self.do_stop(self.SPEED)

    def set_speed(self, new_speed):
        self.SPEED = new_speed
        if (self.CMD != "speed") and (self.CMD != None):
            getattr(self, self.commands[self.CMD])(int(self.SPEED))

    def sendJSON(self, event, data):
        try:
            self.sendMessage(json.dumps({"event": event, "data": data}))
        except Exception as n:
            print "sendJSON: ", n

    def handleMessage(self):
        if self.data is None:
            self.data = ''

        msg = json.loads(str(self.data))

        if msg['event'] == 'drive' and msg['data']['cmd'] in self.commands:
            if msg['data']['speed'] == None:
                msg['data']['speed'] = self.SPEED

            GPIO.output(self.LEDS_GPIO["RED_pin"], GPIO.LOW)
            GPIO.output(self.LEDS_GPIO["GREEN_pin"], GPIO.HIGH)

            getattr(self, self.commands[msg['data']['cmd']])(int(msg['data']['speed']))
            if msg['data']['cmd']  in ["fwd", "rev", "stop"]:
                self.CMD = msg['data']['cmd']
                self.SPEED = int(msg['data']['speed'])
            self.sendJSON("ack", {"cmd": "%s %d" % (self.commands[msg['data']['cmd']], self.SPEED)})
        elif (msg["event"] == 'fetch'):
            if msg['data']['cmd'] == 'angle':
                self.sendJSON("angle", {"angle": "%2.2f" % (self.angle)})
            elif msg['data']['cmd'] == 'heading':
                self.sendJSON("heading", {"angle": "%2.2f" % (self.mag.getHeading()[0])})

    def handleConnected(self):
        print self.address, 'connected'

    def handleClose(self):
        self.do_beep(0.25)
        for PIN in self.PROXIMITY_GPIO:
            GPIO.remove_event_detect(PIN)
        GPIO.remove_event_detect(self.STOP_BUTTON)
        GPIO.remove_event_detect(self.ECHO_RETURN)
        self.SCAN = False
        sleep(1)
        PWM.stop(self.SERVO_PWM)
        PWM.stop(self.SPEAKER_PWM)
        self.saber.stop()
        print self.address, 'closed'

if __name__ == "__main__":

    def close_sig_handler(signal, frame):
        GPIO.cleanup()
        PWM.cleanup()
        server.close()
        sys.exit()

    parser = OptionParser(usage="usage: %prog [options]", version="%prog 1.0")
    parser.add_option("--host", default='', type='string', action="store", dest="host", help="hostname (localhost)")
    parser.add_option("--port", default=8000, type='int', action="store", dest="port", help="port (8000)")
    parser.add_option("--ssl", default=0, type='int', action="store", dest="ssl", help="ssl (1: on, 0: off (default))")
    parser.add_option("--cert", default='./cert.pem', type='string', action="store", dest="cert", help="cert (./cert.pem)")
    parser.add_option("--ver", default=ssl.PROTOCOL_TLSv1, type=int, action="store", dest="ver", help="ssl version")

    (options, args) = parser.parse_args()

    cls = RobotControl

    if options.ssl == 1:
        server = SimpleSSLWebSocketServer(options.host, options.port, cls, options.cert, options.cert, version=options.ver)
    else:
        server = SimpleWebSocketServer(options.host, options.port, cls)

    signal.signal(signal.SIGINT, close_sig_handler)

    print "Starting robot control server.  Listening on ws://%s:%d" % (options.host, options.port)
    server.serveforever()<commit_msg>Updates to support moving sensors and other parts into modules<commit_after>#!/bin/python

import signal, sys, ssl, logging
from SimpleWebSocketServer import *
from optparse import OptionParser
import Sabertooth.Sabertooth as Sabertooth
import Adafruit_BBIO.GPIO as GPIO
import Adafruit_BBIO.PWM as PWM
import Sensors.Adafruit_HMC5883L as MAG
import Sensors.Adafruit_SharpIR as IR
import Sensors.Adafruit_ADXL345 as COMPASS
import threading
from datetime import datetime
from time import sleep
import json

logging.basicConfig(format='%(asctime)s %(message)s', level=logging.DEBUG)

class RobotControl(SimpleWebSocketServer.WebSocket):
    saber = None
    UART = "UART1"
    TTY  ="ttyO1"
    STOP_GPIO = "P9_13"
    STOP_BUTTON = "P9_15"

    PROXIMITY_GPIO = {"P9_11": {"name": "right"},
                      "P9_12": {"name": "left"}
                     }

    LEDS_GPIO = { "RED_pin": "P8_10",
                  "GREEN_pin": "P8_11" }
    SPEAKER_PWM = "P8_13"
    SERVO_PWM = "P8_34"

    ECHO_RETURN = "P8_15"
    ECHO_TRIGGER = "P9_14"

    SPEED = 10
    CMD = None
    OBSTACLE = False
    SPEAKER = False
    SCAN = False
    angle = 0.0
    distance = (0.0, 0.0)
    COUNTING = False
    startTime = datetime.now()
    endTime = datetime.now()
    delta = endTime-startTime

    # cmd values that can be sent for a JSON "drive" event
    # maps command to corresponding function to control motors
    commands = {"fwd":   "do_forward",
                "rev":   "do_reverse",
                "left":  "turn_left",
                "right": "turn_right",
                "stop":  "do_stop",
                "speed": "set_speed"
               }

    def __init__(self, server, sock, address):
        super(RobotControl, self).__init__(server, sock, address)

        # setup GPIO pins for proximity sensors
        for PIN in self.PROXIMITY_GPIO:
            GPIO.setup(PIN, GPIO.IN)

        # try to add event detection for proximity GPIO pins
        for PIN, val in self.PROXIMITY_GPIO.items():
            # wait until the GPIO is configured as an input
            while GPIO.gpio_function(PIN) != GPIO.IN:
                GPIO.setup(PIN, GPIO.IN)
            GPIO.add_event_detect(PIN, GPIO.FALLING, self.__proximityDetect, 10)

        for LED in self.LEDS_GPIO.itervalues():
            GPIO.setup(LED, GPIO.OUT)
            GPIO.output(LED, GPIO.LOW)

        # Connected to Sabertooth S2 as "emergency stop" button
        GPIO.setup(self.STOP_GPIO, GPIO.OUT)
        GPIO.output(self.STOP_GPIO, GPIO.HIGH)
        # Triggers when button pressed
        GPIO.setup(self.STOP_BUTTON, GPIO.IN)
        while GPIO.gpio_function(self.STOP_BUTTON) != GPIO.IN:
            GPIO.setup(self.STOP_BUTTON, GPIO.IN)
        GPIO.add_event_detect(self.STOP_BUTTON, GPIO.RISING, self.__stopButton, 10)

        # HMC5883L Magnetometer
        self.mag = MAG.Adafruit_HMC5883L(declination=(11,35))

        # HC-SR04 pin setup
        # ECHO_TRIGGER initiates ultrasonic pulse
        GPIO.setup(self.ECHO_TRIGGER, GPIO.OUT)

        # ECHO_RETURN - needs to be level shifted from 5.0V to 3.3V
        # time of +ve pulse is the distance
        GPIO.setup(self.ECHO_RETURN, GPIO.IN)
        while GPIO.gpio_function(self.ECHO_RETURN) != GPIO.IN:
            GPIO.setup(self.ECHO_RETURN, GPIO.IN)
        GPIO.add_event_detect(self.ECHO_RETURN, GPIO.BOTH, self.__measureEcho, 1)
        GPIO.output(self.ECHO_TRIGGER, GPIO.LOW)

        # Start servo scanning movement thread
        self.SCAN = True
        threading.Thread(target=self.__servoScan).start()
        # Start HC-SR04 timing/measurement thread
        threading.Thread(target=self.__HCSR04).start()

        self.do_beep(0.25)
        GPIO.output(self.LEDS_GPIO["RED_pin"], GPIO.HIGH)

        self.saber = Sabertooth.Sabertooth(self.UART, self.TTY)
        self.saber.setRamp(15)

    def __speaker(self):
        if self.SPEAKER:
            return
        self.SPEAKER = True
        PWM.start(self.SPEAKER_PWM, 50, 3000)
        for dir in [-1,2]:
            for x in range(3,20):
                PWM.set_frequency(self.SPEAKER_PWM, 3000 + (dir * x * 100))
                sleep(0.05)
        PWM.stop(self.SPEAKER_PWM)
        self.SPEAKER = False
        return

    def __proximityDetect(self, channel):
        if self.OBSTACLE or (self.CMD in ["stop", None]):
            return # already handling a problem or not moving
        threading.Thread(target=self.__speaker).start()
        self.OBSTACLE = True
        self.sendJSON("obstacle", {"sensor": "%s" % (channel),
                                   "name": "%s" % (self.PROXIMITY_GPIO[channel]["name"])})
        self.saber.driveMotor("both", "rev", int(float(self.SPEED)*1.5))
        delay = 1 - (float(self.SPEED)/200)
        sleep(delay)
        self.do_stop(self.SPEED)
        self.OBSTACLE = False
        return

    def __stopButton(self, channel):
        self.SCAN = False
        GPIO.output(self.STOP_GPIO, GPIO.HIGH)
        self.do_stop(self.SPEED)
        return

    def __servoScan(self):
        PWM.start(self.SERVO_PWM, 3, 50)
        while self.SCAN:
            for a in xrange(0,180,1):
                self.angle = a
                duty = 3.7 + (a/180.0)*9.5
                if self.SCAN:
                    PWM.set_duty_cycle(self.SERVO_PWM, duty)
                else:
                    break
                sleep(0.01)
            for a in xrange(181,1,-1):
                self.angle = a
                duty = 3.7 + (a/180.0)*9.5
                if self.SCAN:
                    PWM.set_duty_cycle(self.SERVO_PWM, duty)
                else:
                    break
                sleep(0.01)
        return

    def __measureEcho(self, channel):
        # Get time when Echo line goes high (ie: RISING edge)
        if GPIO.input(self.ECHO_RETURN) == GPIO.HIGH and not self.COUNTING:
            self.startTime = datetime.now()
            self.COUNTING = True
        # Get time when Echo line goes low (ie: FALLING edge)
        elif GPIO.input(self.ECHO_RETURN) == GPIO.LOW and self.COUNTING:
            self.endTime = datetime.now()
            # delta is the period of the echo (roughly)
            self.delta = self.endTime - self.startTime
            self.COUNTING = False
        return

    def __HCSR04(self):
        measures = []
        while self.SCAN:
            # Set Trigger to HIGH
            GPIO.output("P9_14", GPIO.HIGH)
            # Wait a tiny amount (should be 10us). This is not deterministic
            # when running stock Linux. To get better use a RTOS or the PRUSS
            sleep(0.001)
            # Set Trigger to LOW
            # This will cause the HC-SR04 to output an ultrasonic pulse and start
            # listening for the return
            GPIO.output("P9_14", GPIO.LOW)
            # Sleep for a bit so that we don't send out another pulse before the
            # previous one has finished
            sleep(0.05)
            # 58.77 is the magic number for cm per microsecond
            d = min(200.0, max(self.delta.microseconds/58.77,17.0))
            # only include value if it is reasonable/valid
            if d > 17 and d < 200:
                measures.insert(0, d)
                if len(measures) > 3:
                    measures.pop()
            # take an average of the last few measures as the distance
            if len(measures) > 0:
                self.distance = sum(measures)/len(measures)
            else:
                self.distance = 20.0
            if self.distance < 20 and not self.OBSTACLE:
                self.OBSTACLE = True
                if self.angle < 90:
                    self.sendJSON("obstacle", {"sensor": "P9_12", "name": "left"})
                else:
                    self.sendJSON("obstacle", {"sensor": "P9_11", "name": "right"})
                self.OBSTACLE = False
        return

    def do_beep(self, duration):
        PWM.start(self.SPEAKER_PWM, 50, 3000)
        sleep(duration)
        PWM.stop(self.SPEAKER_PWM)

    def do_forward(self, set_speed):
        if set_speed != None:
            self.SPEED = set_speed
        self.saber.driveMotor("both", "fwd", self.SPEED)

    def do_reverse(self, set_speed):
        if set_speed != None:
            self.SPEED = set_speed
        self.saber.driveMotor("both", "rev", self.SPEED)

    def do_stop(self, set_speed):
        GPIO.output(self.LEDS_GPIO["RED_pin"], GPIO.HIGH)
        GPIO.output(self.LEDS_GPIO["GREEN_pin"], GPIO.LOW)
        self.saber.stop()

    def turn_left(self, set_speed):
        if set_speed != None:
            self.SPEED = set_speed
        self.saber.driveMotor("left", "fwd", self.SPEED)
        self.saber.driveMotor("right", "rev", self.SPEED)
        delay = 1 - (float(self.SPEED)/100)
        sleep(delay)
        if self.CMD in ["fwd", "rev"]:
            getattr(self, self.commands[self.CMD])(int(self.SPEED))
        else:
            self.do_stop(self.SPEED)

    def turn_right(self, set_speed):
        if set_speed != None:
            self.SPEED = set_speed
        self.saber.driveMotor("right", "fwd", self.SPEED)
        self.saber.driveMotor("left", "rev", self.SPEED)
        delay = 1 - (float(self.SPEED)/100)
        sleep(delay)
        if self.CMD in ["fwd", "rev"]:
            getattr(self, self.commands[self.CMD])(int(self.SPEED))
        else:
            self.do_stop(self.SPEED)

    def set_speed(self, new_speed):
        self.SPEED = new_speed
        if (self.CMD != "speed") and (self.CMD != None):
            getattr(self, self.commands[self.CMD])(int(self.SPEED))

    def sendJSON(self, event, data):
        try:
            self.sendMessage(json.dumps({"event": event, "data": data}))
        except Exception as n:
            print "sendJSON: ", n

    def handleMessage(self):
        if self.data is None:
            self.data = ''

        msg = json.loads(str(self.data))

        if msg['event'] == 'drive' and msg['data']['cmd'] in self.commands:
            if msg['data']['speed'] == None:
                msg['data']['speed'] = self.SPEED

            GPIO.output(self.LEDS_GPIO["RED_pin"], GPIO.LOW)
            GPIO.output(self.LEDS_GPIO["GREEN_pin"], GPIO.HIGH)

            getattr(self, self.commands[msg['data']['cmd']])(int(msg['data']['speed']))
            if msg['data']['cmd']  in ["fwd", "rev", "stop"]:
                self.CMD = msg['data']['cmd']
                self.SPEED = int(msg['data']['speed'])
            self.sendJSON("ack", {"cmd": "%s %d" % (self.commands[msg['data']['cmd']], self.SPEED)})
        elif (msg["event"] == 'fetch'):
            if msg['data']['cmd'] == 'angle':
                self.sendJSON("angle", {"angle": "%2.2f" % (self.angle)})
            elif msg['data']['cmd'] == 'heading':
                self.sendJSON("heading", {"angle": "%2.2f" % (self.mag.getHeading())})

    def handleConnected(self):
        print self.address, 'connected'

    def handleClose(self):
        self.do_beep(0.25)
        for PIN in self.PROXIMITY_GPIO:
            GPIO.remove_event_detect(PIN)
        GPIO.remove_event_detect(self.STOP_BUTTON)
        GPIO.remove_event_detect(self.ECHO_RETURN)
        self.SCAN = False
        sleep(1)
        PWM.stop(self.SERVO_PWM)
        PWM.stop(self.SPEAKER_PWM)
        self.saber.stop()
        print self.address, 'closed'

if __name__ == "__main__":

    def close_sig_handler(signal, frame):
        GPIO.cleanup()
        PWM.cleanup()
        server.close()
        sys.exit()

    parser = OptionParser(usage="usage: %prog [options]", version="%prog 1.0")
    parser.add_option("--host", default='', type='string', action="store", dest="host", help="hostname (localhost)")
    parser.add_option("--port", default=8000, type='int', action="store", dest="port", help="port (8000)")
    parser.add_option("--ssl", default=0, type='int', action="store", dest="ssl", help="ssl (1: on, 0: off (default))")
    parser.add_option("--cert", default='./cert.pem', type='string', action="store", dest="cert", help="cert (./cert.pem)")
    parser.add_option("--ver", default=ssl.PROTOCOL_TLSv1, type=int, action="store", dest="ver", help="ssl version")

    (options, args) = parser.parse_args()

    cls = RobotControl

    if options.ssl == 1:
        server = SimpleWebSocketServer.SimpleSSLWebSocketServer(options.host, options.port, cls, options.cert, options.cert, version=options.ver)
    else:
        server = SimpleWebSocketServer.SimpleWebSocketServer(options.host, options.port, cls)

    signal.signal(signal.SIGINT, close_sig_handler)

    print "Starting robot control server.  Listening on ws://%s:%d" % (options.host, options.port)
    server.serveforever()<|endoftext|>