<commit_before># -*- coding: utf-8 -*-
from __future__ import absolute_import, unicode_literals
import base64
import hashlib
import io
from logging import getLogger
import os
from psd_tools.user_api.psd_image import PSDImage
from psd_tools.user_api.layers import _RawLayer
from psd2svg.storage import get_storage
import xml.dom.minidom as minidom

logger = getLogger(__name__)

class PSDReader(object):

    def _load(self, input_data):
        if hasattr(input_data, "read"):
            self._load_stream(input_data)
            self._input_layer = None
        elif isinstance(input_data, PSDImage):
            self._load_psd(input_data)
            self._input_layer = None
        elif isinstance(input_data, _RawLayer):
            self._load_psd(input_data._psd)
            self._input_layer = input_data
        else:
            self._load_storage(input_data)
            self._input_layer = None

    def _load_storage(self, url):
        storage = get_storage(os.path.dirname(url))
        filename = os.path.basename(url)
        logger.info('Opening {}'.format(url))
        with storage.open(filename) as f:
            self._load_stream(f)
        self._input = url

    def _load_stream(self, stream):
        self._input = None
        self._psd = PSDImage.from_stream(stream)

    def _load_psd(self, psd):
        self._input = None
        self._psd = psd

class SVGWriter(object):

    def _set_output(self, output_data):
        # IO object.
        if not output_data:
            self._output = None
            self._resource = get_storage(self.resource_prefix)
            self._output_file = None
            return
        if hasattr(output_data, 'write'):
            self._output = output_data
            self._resource = get_storage(self.resource_prefix)
            self._output_file = None
            return

        # Else save to a file.
        if not output_data.endswith('/') and os.path.isdir(output_data):
            output_data += '/'
        self._output = get_storage(os.path.dirname(output_data))
        self._resource = get_storage(
            self._output.url(self.resource_prefix))
        self._output_file = os.path.basename(output_data)
        if not self._output_file:
            if self._input:
                basename = os.path.splitext(os.path.basename(self._input))[0]
                self._output_file = basename + '.svg'
            else:
                raise ValueError('Invalid output: {}'.format(output_data))

    def _save_svg(self):
        # Write to the output.
        pretty_string = self._get_svg()
        if self._output_file:
            url = self._output.url(self._output_file)
            logger.info('Saving {}'.format(url))
            self._output.put(self._output_file, pretty_string.encode('utf-8'))
            return url
        elif self._output:
            self._output.write(pretty_string)
            return self._output
        else:
            return pretty_string

    def _get_svg(self):
        with io.StringIO() as f:
            # svgwrite's pretty option is not compatible with Python 2.7
            # unicode. Here we manually encode utf-8.
            self._dwg.write(f, pretty=False)
            xml_string = f.getvalue().encode('utf-8')

        xml_tree = minidom.parseString(xml_string)
        return xml_tree.toprettyxml(indent='  ')

    def _get_image_href(self, image, fmt='png', icc_profile=None):
        output = io.BytesIO()
        image.save(output, format=fmt, icc_profile=icc_profile)
        encoded_image = output.getvalue()
        output.close()
        checksum = hashlib.md5(encoded_image).hexdigest()
        if self.export_resource:
            filename = checksum + '.' + fmt
            if self.overwrite or not self._resource.exists(filename):
                logger.info('Saving {}'.format(
                    self._resource.url(filename)))
                self._resource.put(filename, encoded_image)
            href = os.path.join(self.resource_prefix, filename)
        else:
            href = ('data:image/{};base64,'.format(fmt) +
                    base64.b64encode(encoded_image).decode('utf-8'))
        return href
<commit_msg>Skip digest when not needed<commit_after># -*- coding: utf-8 -*-
from __future__ import absolute_import, unicode_literals
import base64
import hashlib
import io
from logging import getLogger
import os
from psd_tools.user_api.psd_image import PSDImage
from psd_tools.user_api.layers import _RawLayer
from psd2svg.storage import get_storage
import xml.dom.minidom as minidom

logger = getLogger(__name__)

class PSDReader(object):

    def _load(self, input_data):
        if hasattr(input_data, "read"):
            self._load_stream(input_data)
            self._input_layer = None
        elif isinstance(input_data, PSDImage):
            self._load_psd(input_data)
            self._input_layer = None
        elif isinstance(input_data, _RawLayer):
            self._load_psd(input_data._psd)
            self._input_layer = input_data
        else:
            self._load_storage(input_data)
            self._input_layer = None

    def _load_storage(self, url):
        storage = get_storage(os.path.dirname(url))
        filename = os.path.basename(url)
        logger.info('Opening {}'.format(url))
        with storage.open(filename) as f:
            self._load_stream(f)
        self._input = url

    def _load_stream(self, stream):
        self._input = None
        self._psd = PSDImage.from_stream(stream)

    def _load_psd(self, psd):
        self._input = None
        self._psd = psd

class SVGWriter(object):

    def _set_output(self, output_data):
        # IO object.
        if not output_data:
            self._output = None
            self._resource = get_storage(self.resource_prefix)
            self._output_file = None
            return
        if hasattr(output_data, 'write'):
            self._output = output_data
            self._resource = get_storage(self.resource_prefix)
            self._output_file = None
            return

        # Else save to a file.
        if not output_data.endswith('/') and os.path.isdir(output_data):
            output_data += '/'
        self._output = get_storage(os.path.dirname(output_data))
        self._resource = get_storage(
            self._output.url(self.resource_prefix))
        self._output_file = os.path.basename(output_data)
        if not self._output_file:
            if self._input:
                basename = os.path.splitext(os.path.basename(self._input))[0]
                self._output_file = basename + '.svg'
            else:
                raise ValueError('Invalid output: {}'.format(output_data))

    def _save_svg(self):
        # Write to the output.
        pretty_string = self._get_svg()
        if self._output_file:
            url = self._output.url(self._output_file)
            logger.info('Saving {}'.format(url))
            self._output.put(self._output_file, pretty_string.encode('utf-8'))
            return url
        elif self._output:
            self._output.write(pretty_string)
            return self._output
        else:
            return pretty_string

    def _get_svg(self):
        with io.StringIO() as f:
            # svgwrite's pretty option is not compatible with Python 2.7
            # unicode. Here we manually encode utf-8.
            self._dwg.write(f, pretty=False)
            xml_string = f.getvalue().encode('utf-8')

        xml_tree = minidom.parseString(xml_string)
        return xml_tree.toprettyxml(indent='  ')

    def _get_image_href(self, image, fmt='png', icc_profile=None):
        output = io.BytesIO()
        image.save(output, format=fmt, icc_profile=icc_profile)
        encoded_image = output.getvalue()
        output.close()
        if self.export_resource:
            checksum = hashlib.md5(encoded_image).hexdigest()
            filename = checksum + '.' + fmt
            if self.overwrite or not self._resource.exists(filename):
                logger.info('Saving {}'.format(
                    self._resource.url(filename)))
                self._resource.put(filename, encoded_image)
            href = os.path.join(self.resource_prefix, filename)
        else:
            href = ('data:image/{};base64,'.format(fmt) +
                    base64.b64encode(encoded_image).decode('utf-8'))
        return href
<|endoftext|>


<commit_before>"""
File header structure.
"""
from __future__ import absolute_import, unicode_literals
import attr
import logging
from psd_tools.validators import in_, range_
from psd_tools.psd.base import BaseElement
from psd_tools.constants import ColorMode
from psd_tools.utils import read_fmt, write_fmt

logger = logging.getLogger(__name__)

@attr.s(repr=False, slots=True)
class FileHeader(BaseElement):
    """
    Header section of the PSD file.

    Example::

        from psd_tools.psd.header import FileHeader
        from psd_tools.constants import ColorMode

        header = FileHeader(channels=2, height=359, width=400, depth=8,
                            color_mode=ColorMode.GRAYSCALE)

    .. py:attribute:: signature

        Signature: always equal to ``b'8BPS'``.

    .. py:attribute:: version

        Version number. PSD is 1, and PSB is 2.

    .. py:attribute:: channels

        The number of channels in the image, including any user-defined alpha
        channel.

    .. py:attribute:: height

        The height of the image in pixels.

    .. py:attribute:: width

        The width of the image in pixels.

    .. py:attribute:: depth

        The number of bits per channel.

    .. py:attribute:: color_mode

        The color mode of the file. See
        :py:class:`~psd_tools.constants.ColorMode`
    """
    _FORMAT = '4sH6xHIIHH'

    signature = attr.ib(default=b'8BPS', type=bytes, repr=False)
    version = attr.ib(default=1, type=int, validator=in_((1, 2)))
    channels = attr.ib(default=4, type=int, validator=range_(1, 57))
    height = attr.ib(default=64, type=int, validator=range_(1, 300001))
    width = attr.ib(default=64, type=int, validator=range_(1, 300001))
    depth = attr.ib(default=8, type=int, validator=in_((1, 8, 16, 32)))
    color_mode = attr.ib(
        default=ColorMode.RGB, converter=ColorMode, validator=in_(ColorMode)
    )

    @signature.validator
    def _validate_signature(self, attribute, value):
        if value != b'8BPS':
            raise ValueError('This is not a PSD or PSB file')

    @classmethod
    def read(cls, fp):
        return cls(*read_fmt(cls._FORMAT, fp))

    def write(self, fp):
        return write_fmt(fp, self._FORMAT, *attr.astuple(self))
<commit_msg>Add repr=True to file header<commit_after>"""
File header structure.
"""
from __future__ import absolute_import, unicode_literals
import attr
import logging
from psd_tools.validators import in_, range_
from psd_tools.psd.base import BaseElement
from psd_tools.constants import ColorMode
from psd_tools.utils import read_fmt, write_fmt

logger = logging.getLogger(__name__)

@attr.s(repr=True, slots=True)
class FileHeader(BaseElement):
    """
    Header section of the PSD file.

    Example::

        from psd_tools.psd.header import FileHeader
        from psd_tools.constants import ColorMode

        header = FileHeader(channels=2, height=359, width=400, depth=8,
                            color_mode=ColorMode.GRAYSCALE)

    .. py:attribute:: signature

        Signature: always equal to ``b'8BPS'``.

    .. py:attribute:: version

        Version number. PSD is 1, and PSB is 2.

    .. py:attribute:: channels

        The number of channels in the image, including any user-defined alpha
        channel.

    .. py:attribute:: height

        The height of the image in pixels.

    .. py:attribute:: width

        The width of the image in pixels.

    .. py:attribute:: depth

        The number of bits per channel.

    .. py:attribute:: color_mode

        The color mode of the file. See
        :py:class:`~psd_tools.constants.ColorMode`
    """
    _FORMAT = '4sH6xHIIHH'

    signature = attr.ib(default=b'8BPS', type=bytes, repr=False)
    version = attr.ib(default=1, type=int, validator=in_((1, 2)))
    channels = attr.ib(default=4, type=int, validator=range_(1, 57))
    height = attr.ib(default=64, type=int, validator=range_(1, 300001))
    width = attr.ib(default=64, type=int, validator=range_(1, 300001))
    depth = attr.ib(default=8, type=int, validator=in_((1, 8, 16, 32)))
    color_mode = attr.ib(
        default=ColorMode.RGB, converter=ColorMode, validator=in_(ColorMode)
    )

    @signature.validator
    def _validate_signature(self, attribute, value):
        if value != b'8BPS':
            raise ValueError('This is not a PSD or PSB file')

    @classmethod
    def read(cls, fp):
        return cls(*read_fmt(cls._FORMAT, fp))

    def write(self, fp):
        return write_fmt(fp, self._FORMAT, *attr.astuple(self))
<|endoftext|>


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

import json
import bson
from bson.json_util import loads

def generate_insert_queries(table, psql_schema_name, initial_indexes = {}):
    """ get insert queries as
    tuple: (format string, [(list,of,values,as,tuples)])
    @param table object schema_engine.SqlTable
    @param initial_indexes dict of indexes from db tables"""
    queries = []
    if len(psql_schema_name):
        psql_schema_name += '.'
    fmt_string = "INSERT INTO %s%s (%s) VALUES(%s);" \
        % (psql_schema_name, \
               table.table_name, \
               ', '.join(table.sql_column_names), \
               ', '.join(['%s' for i in table.sql_column_names]))
    firstcolname = table.sql_column_names[0]
    reccount = len(table.sql_columns[firstcolname].values)
    for val_i in xrange(reccount):
        values = []
        for column_name in table.sql_column_names:
            col = table.sql_columns[column_name]
            index_key = col.index_key()
            if index_key and index_key in initial_indexes:
                values.append(initial_indexes[index_key] + col.values[val_i])
            else:
                values.append(col.values[val_i])
        queries.append( tuple(values) )
    return (fmt_string, queries)

def opinsert_oplog_handler_callback(ns, schema, objdata):
    return schema_engine.create_schema_engine(collection_name, schema_path)
    pass

if __name__ == "__main__":
    from test_opinsert import test_insert1
    test_insert1()
<commit_msg>added doublequotes into insert query<commit_after>#!/usr/bin/env python

import json
import bson
from bson.json_util import loads

def generate_insert_queries(table, psql_schema_name, initial_indexes = {}):
    """ get insert queries as
    tuple: (format string, [(list,of,values,as,tuples)])
    @param table object schema_engine.SqlTable
    @param initial_indexes dict of indexes from db tables"""
    queries = []
    if len(psql_schema_name):
        psql_schema_name += '.'
    fmt_string = "INSERT INTO %s%s (%s) VALUES(%s);" \
        % (psql_schema_name, \
               table.table_name, \
               ', '.join(['"'+i+'"' for i in table.sql_column_names]), \
               ', '.join(['%s' for i in table.sql_column_names]))
    firstcolname = table.sql_column_names[0]
    reccount = len(table.sql_columns[firstcolname].values)
    for val_i in xrange(reccount):
        values = []
        for column_name in table.sql_column_names:
            col = table.sql_columns[column_name]
            index_key = col.index_key()
            if index_key and index_key in initial_indexes:
                values.append(initial_indexes[index_key] + col.values[val_i])
            else:
                values.append(col.values[val_i])
        queries.append( tuple(values) )
    return (fmt_string, queries)

def opinsert_oplog_handler_callback(ns, schema, objdata):
    return schema_engine.create_schema_engine(collection_name, schema_path)
    pass

if __name__ == "__main__":
    from test_opinsert import test_insert1
    test_insert1()
<|endoftext|>


<commit_before>
import logging

try:
    from http.client import HTTPConnection
except ImportError:
    # pylint: disable=import-error
    from httplib import HTTPConnection

try:
    from urllib.parse import urlparse
except ImportError:
    # pylint: disable=import-error
    from urlparse import urlparse

from .constants import (
    UNLIMITED_REDIRECTS,
)

from .cursors import Cursor
from .extensions import PARSE_DECLTYPES, PARSE_COLNAMES

class Connection(object):

    def __init__(self, host=None, port=None, connect_timeout=None,
                 detect_types=0, max_redirects=UNLIMITED_REDIRECTS):

        self.messages = []
        self.host = host
        self.port = port
        self.connect_timeout = connect_timeout
        self.max_redirects = max_redirects
        self.detect_types = detect_types
        self.parse_decltypes = detect_types & PARSE_DECLTYPES
        self.parse_colnames = detect_types & PARSE_COLNAMES
        self._connection = self._init_connection()

    def _init_connection(self):
        return HTTPConnection(self.host, port=self.port,
                              timeout=None if self.connect_timeout is None else float(self.connect_timeout))

    def _fetch_response(self, method, uri, body=None, headers={}):
        """
        Fetch a response, handling redirection.
        """
        self._connection.request(method, uri, body=body, headers=headers)
        response = self._connection.getresponse()
        redirects = 0

        while response.status == 301 and \
                response.getheader('Location') is not None and \
                (self.max_redirects == UNLIMITED_REDIRECTS or redirects < self.max_redirects):
            redirects += 1
            uri = response.getheader('Location')
            location = urlparse(uri)

            logging.debug("status: %s reason: '%s' location: '%s'",
                          response.status, response.reason, uri)

            if self.host != location.hostname or self.port != location.port:
                self._connection.close()
                self.host = location.hostname
                self.port = location.port
                self._connection = self._init_connection()

            self._connection.request(method, uri, body=body, headers=headers)
            response = self._connection.getresponse()

        return response

    def close(self):
        """Close the connection now (rather than whenever .__del__() is
        called).

        The connection will be unusable from this point forward; an
        Error (or subclass) exception will be raised if any operation
        is attempted with the connection. The same applies to all
        cursor objects trying to use the connection. Note that closing
        a connection without committing the changes first will cause an
        implicit rollback to be performed."""
        self._connection.close()

    def commit(self):
        """Database modules that do not support transactions should
        implement this method with void functionality."""
        pass

    def rollback(self):
        """This method is optional since not all databases provide
        transaction support. """
        pass

    def cursor(self):
        """Return a new Cursor Object using the connection."""
        return Cursor(self)
<commit_msg>Implicit cursor on Connection.execute<commit_after>
import logging

try:
    from http.client import HTTPConnection
except ImportError:
    # pylint: disable=import-error
    from httplib import HTTPConnection

try:
    from urllib.parse import urlparse
except ImportError:
    # pylint: disable=import-error
    from urlparse import urlparse

from .constants import (
    UNLIMITED_REDIRECTS,
)

from .cursors import Cursor
from .extensions import PARSE_DECLTYPES, PARSE_COLNAMES

class Connection(object):

    def __init__(self, host=None, port=None, connect_timeout=None,
                 detect_types=0, max_redirects=UNLIMITED_REDIRECTS):

        self.messages = []
        self.host = host
        self.port = port
        self.connect_timeout = connect_timeout
        self.max_redirects = max_redirects
        self.detect_types = detect_types
        self.parse_decltypes = detect_types & PARSE_DECLTYPES
        self.parse_colnames = detect_types & PARSE_COLNAMES
        self._connection = self._init_connection()

    def _init_connection(self):
        return HTTPConnection(self.host, port=self.port,
                              timeout=None if self.connect_timeout is None else float(self.connect_timeout))

    def _fetch_response(self, method, uri, body=None, headers={}):
        """
        Fetch a response, handling redirection.
        """
        self._connection.request(method, uri, body=body, headers=headers)
        response = self._connection.getresponse()
        redirects = 0

        while response.status == 301 and \
                response.getheader('Location') is not None and \
                (self.max_redirects == UNLIMITED_REDIRECTS or redirects < self.max_redirects):
            redirects += 1
            uri = response.getheader('Location')
            location = urlparse(uri)

            logging.debug("status: %s reason: '%s' location: '%s'",
                          response.status, response.reason, uri)

            if self.host != location.hostname or self.port != location.port:
                self._connection.close()
                self.host = location.hostname
                self.port = location.port
                self._connection = self._init_connection()

            self._connection.request(method, uri, body=body, headers=headers)
            response = self._connection.getresponse()

        return response

    def close(self):
        """Close the connection now (rather than whenever .__del__() is
        called).

        The connection will be unusable from this point forward; an
        Error (or subclass) exception will be raised if any operation
        is attempted with the connection. The same applies to all
        cursor objects trying to use the connection. Note that closing
        a connection without committing the changes first will cause an
        implicit rollback to be performed."""
        self._connection.close()

    def commit(self):
        """Database modules that do not support transactions should
        implement this method with void functionality."""
        pass

    def rollback(self):
        """This method is optional since not all databases provide
        transaction support. """
        pass

    def cursor(self):
        """Return a new Cursor Object using the connection."""
        return Cursor(self)

    def execute(self, *args, **kwargs):
        with self.cursor() as cursor:
            return cursor.execute(*args, **kwargs)

<|endoftext|>


<commit_before>import os
import sys
import math
import time
import types
import numpy as np
import vtkAll as vtk
from ddapp.timercallback import TimerCallback

from ddapp import transformUtils
from ddapp import lcmUtils
from ddapp import objectmodel as om
from ddapp import visualization as vis

import drc as lcmdrc

class Gamepad(object):
    def __init__(self, teleopPanel, teleopJointController, ikPlanner, view):
        print 'gamepad init'
        lcmUtils.addSubscriber('GAMEPAD_CHANNEL', lcmdrc.gamepad_cmd_t, self.onGamepadCommand)
        self.speedMultiplier = 1.0
        self.maxSpeedMultiplier = 3.0
        self.minSpeedMultiplier = 0.2
        self.travel = 1
        self.angularTravel = 180
        self.baseFrame = None
        self.resetDeltas()
        self.timer = TimerCallback()
        self.timer.callback = self.tick
        self.teleopPanel = teleopPanel
        self.teleopJointController = teleopJointController
        self.ikPlanner = ikPlanner
        self.view = view
        self.camera = view.camera()
        self.cameraTarget = np.asarray(self.camera.GetFocalPoint())
        self.endEffectorFrames = []
        self.endEffectorIndex = 0
        self.teleopOn = False
        self.keyFramePoses = list()
        self.cameraMode = False
        self.timerStarted = False

    def findEndEffectors(self):
        planning = om.getOrCreateContainer('planning')
        if planning is not None:
            teleopFolder = planning.findChild('teleop plan')
            if teleopFolder is not None:
                framesFolder = teleopFolder.findChild('constraint frames')
                if framesFolder is not None:
                    self.endEffectorFrames = framesFolder.children()

    def cycleEndEffector(self):
        if len(self.endEffectorFrames) is not 0:
            self.clearKeyframePoses()
            self.endEffectorFrames[self.endEffectorIndex].setProperty('Edit', False)
            self.endEffectorIndex = (self.endEffectorIndex + 1) % len(self.endEffectorFrames)
            self.endEffectorFrames[self.endEffectorIndex].setProperty('Edit', True)
            om.setActiveObject(self.endEffectorFrames[self.endEffectorIndex])
            self.baseFrame = self.endEffectorFrames[self.endEffectorIndex]
            self.baseTransform = transformUtils.copyFrame(self.baseFrame.transform)
            self.resetDeltas()
            self.addKeyframePose()

    def clearKeyframePoses(self):
        self.keyFramePoses = list()

    def addKeyframePose(self):
        self.keyFramePoses.append(self.teleopJointController.q.copy())

    def finalizeTrajectory(self):
        self.ikPlanner.computeMultiPostureGoal(self.keyFramePoses)

    def tick(self):
        self.updateFrame()

    def resetDeltas(self):
        self.theta = 0.0
        self.phi = 0.0
        self.yaw = 0.0
        self.X = 0.0
        self.Y = 0.0
        self.Z = 0.0

        self.thetadot = 0.0
        self.phidot = 0.0
        self.yawdot = 0.0
        self.Xdot = 0.0
        self.Ydot = 0.0
        self.Zdot = 0.0

    def toggleTeleop(self):
        self.teleopOn = not self.teleopOn

        if self.teleopOn:
            self.teleopPanel.endEffectorTeleop.activate()
            self.teleopPanel.endEffectorTeleop.setLHandConstraint('ee fixed')
            self.teleopPanel.endEffectorTeleop.setRHandConstraint('ee fixed')
        else:
            self.teleopPanel.endEffectorTeleop.deactivate()

    def increaseTeleopSpeed(self):
        self.speedMultiplier = self.clampTeleopSpeed(self.speedMultiplier + 0.2)
        print 'teleop speed: ' + str(self.speedMultiplier)

    def decreaseTeleopSpeed(self):
        self.speedMultiplier = self.clampTeleopSpeed(self.speedMultiplier - 0.2)
        print 'teleop speed: ' + str(self.speedMultiplier)

    def clampTeleopSpeed(self, speed):
        return np.clip(speed, self.minSpeedMultiplier, self.maxSpeedMultiplier)

    def enableCameraMode(self):
        print 'Gamepad camera mode on'
        self.cameraMode = True

    def disableCameraMode(self):
        print 'Gamepad camera mode off'
        self.cameraMode = False

    def setCameraTarget(self):
        if self.baseFrame is not None:
            self.cameraTarget = np.asarray(self.baseFrame.transform.GetPosition())

    def onGamepadCommand(self, msg):
        if self.timerStarted is not True:
            self.timer.start()
            self.timerStarted = True

        if msg.button == msg.GAMEPAD_BUTTON_A and msg.button_a == 1:
            self.finalizeTrajectory()

        if msg.button == msg.GAMEPAD_DPAD_X and msg.button_dpad_x < 0:
            self.enableCameraMode()
            self.setCameraTarget()

        if msg.button == msg.GAMEPAD_DPAD_X and msg.button_dpad_x > 0:
            self.disableCameraMode()

        if msg.button == msg.GAMEPAD_BUTTON_Y and msg.button_y == 1:
            self.findEndEffectors()
            self.cycleEndEffector()
            self.setCameraTarget()

        if msg.button == msg.GAMEPAD_DPAD_Y and msg.button_dpad_y > 0:
            self.increaseTeleopSpeed()

        if msg.button == msg.GAMEPAD_DPAD_Y and msg.button_dpad_y < 0:
            self.decreaseTeleopSpeed()

        if msg.button == msg.GAMEPAD_BUTTON_START and msg.button_start == 1:
            self.toggleTeleop()

        if msg.button == msg.GAMEPAD_BUTTON_X and msg.button_x == 1:
            self.addKeyframePose()

        if msg.button == msg.GAMEPAD_BUTTON_LB:
            self.yawdot = -self.angularTravel * msg.button_lb

        if msg.button == msg.GAMEPAD_BUTTON_RB:
            self.yawdot = self.angularTravel * msg.button_rb

        if msg.button == msg.GAMEPAD_LEFT_X or msg.button == msg.GAMEPAD_LEFT_Y:
            self.thetadot = msg.thumbpad_left_x * self.angularTravel
            self.phidot = msg.thumbpad_left_y * self.angularTravel

        if msg.button == msg.GAMEPAD_RIGHT_X or msg.button == msg.GAMEPAD_RIGHT_Y:
            self.Xdot = self.travel * msg.thumbpad_right_x
            self.Zdot = self.travel * msg.thumbpad_right_y

        if msg.button == msg.GAMEPAD_TRIGGER_L:
            self.Ydot = -self.travel * msg.trigger_left

        if msg.button == msg.GAMEPAD_TRIGGER_R:
            self.Ydot = self.travel * msg.trigger_right

    def updateFrame(self):
        norm = np.linalg.norm(np.array([self.thetadot, self.phidot, self.yawdot, self.Xdot, self.Ydot, self.Zdot]))
        dt = 0.01 #self.timer.elapsed

        if self.baseFrame is not None:
            cameraFocus = np.asarray(self.camera.GetFocalPoint())
            cameraInterp = cameraFocus + (self.cameraTarget - cameraFocus)*0.02
            self.camera.SetFocalPoint(cameraInterp)

        if self.cameraMode is not True:
            if self.baseFrame is not None and norm > 0.1:
                t = vtk.vtkTransform()
                t.Concatenate(self.baseFrame.transform)
                t.RotateZ(-self.thetadot * dt * self.speedMultiplier)
                t.RotateX(self.phidot * dt * self.speedMultiplier)
                t.RotateY(self.yawdot * dt * self.speedMultiplier)
                t.Translate(self.Xdot * dt * self.speedMultiplier, self.Ydot * dt * self.speedMultiplier, self.Zdot * dt * self.speedMultiplier)
                self.baseFrame.copyFrame(t)
        else:

            self.camera.Elevation(self.Zdot * self.speedMultiplier)
            self.camera.Azimuth(self.Xdot * self.speedMultiplier)
            self.camera.Zoom(1.0 + self.phidot/1000.0)

        self.view.render()

<commit_msg>removed print from init function<commit_after>import os
import sys
import math
import time
import types
import numpy as np
import vtkAll as vtk
from ddapp.timercallback import TimerCallback

from ddapp import transformUtils
from ddapp import lcmUtils
from ddapp import objectmodel as om
from ddapp import visualization as vis

import drc as lcmdrc

class Gamepad(object):
    def __init__(self, teleopPanel, teleopJointController, ikPlanner, view):
        lcmUtils.addSubscriber('GAMEPAD_CHANNEL', lcmdrc.gamepad_cmd_t, self.onGamepadCommand)
        self.speedMultiplier = 1.0
        self.maxSpeedMultiplier = 3.0
        self.minSpeedMultiplier = 0.2
        self.travel = 1
        self.angularTravel = 180
        self.baseFrame = None
        self.resetDeltas()
        self.timer = TimerCallback()
        self.timer.callback = self.tick
        self.teleopPanel = teleopPanel
        self.teleopJointController = teleopJointController
        self.ikPlanner = ikPlanner
        self.view = view
        self.camera = view.camera()
        self.cameraTarget = np.asarray(self.camera.GetFocalPoint())
        self.endEffectorFrames = []
        self.endEffectorIndex = 0
        self.teleopOn = False
        self.keyFramePoses = list()
        self.cameraMode = False
        self.timerStarted = False

    def findEndEffectors(self):
        planning = om.getOrCreateContainer('planning')
        if planning is not None:
            teleopFolder = planning.findChild('teleop plan')
            if teleopFolder is not None:
                framesFolder = teleopFolder.findChild('constraint frames')
                if framesFolder is not None:
                    self.endEffectorFrames = framesFolder.children()

    def cycleEndEffector(self):
        if len(self.endEffectorFrames) is not 0:
            self.clearKeyframePoses()
            self.endEffectorFrames[self.endEffectorIndex].setProperty('Edit', False)
            self.endEffectorIndex = (self.endEffectorIndex + 1) % len(self.endEffectorFrames)
            self.endEffectorFrames[self.endEffectorIndex].setProperty('Edit', True)
            om.setActiveObject(self.endEffectorFrames[self.endEffectorIndex])
            self.baseFrame = self.endEffectorFrames[self.endEffectorIndex]
            self.baseTransform = transformUtils.copyFrame(self.baseFrame.transform)
            self.resetDeltas()
            self.addKeyframePose()

    def clearKeyframePoses(self):
        self.keyFramePoses = list()

    def addKeyframePose(self):
        self.keyFramePoses.append(self.teleopJointController.q.copy())

    def finalizeTrajectory(self):
        self.ikPlanner.computeMultiPostureGoal(self.keyFramePoses)

    def tick(self):
        self.updateFrame()

    def resetDeltas(self):
        self.theta = 0.0
        self.phi = 0.0
        self.yaw = 0.0
        self.X = 0.0
        self.Y = 0.0
        self.Z = 0.0

        self.thetadot = 0.0
        self.phidot = 0.0
        self.yawdot = 0.0
        self.Xdot = 0.0
        self.Ydot = 0.0
        self.Zdot = 0.0

    def toggleTeleop(self):
        self.teleopOn = not self.teleopOn

        if self.teleopOn:
            self.teleopPanel.endEffectorTeleop.activate()
            self.teleopPanel.endEffectorTeleop.setLHandConstraint('ee fixed')
            self.teleopPanel.endEffectorTeleop.setRHandConstraint('ee fixed')
        else:
            self.teleopPanel.endEffectorTeleop.deactivate()

    def increaseTeleopSpeed(self):
        self.speedMultiplier = self.clampTeleopSpeed(self.speedMultiplier + 0.2)
        print 'teleop speed: ' + str(self.speedMultiplier)

    def decreaseTeleopSpeed(self):
        self.speedMultiplier = self.clampTeleopSpeed(self.speedMultiplier - 0.2)
        print 'teleop speed: ' + str(self.speedMultiplier)

    def clampTeleopSpeed(self, speed):
        return np.clip(speed, self.minSpeedMultiplier, self.maxSpeedMultiplier)

    def enableCameraMode(self):
        print 'Gamepad camera mode on'
        self.cameraMode = True

    def disableCameraMode(self):
        print 'Gamepad camera mode off'
        self.cameraMode = False

    def setCameraTarget(self):
        if self.baseFrame is not None:
            self.cameraTarget = np.asarray(self.baseFrame.transform.GetPosition())

    def onGamepadCommand(self, msg):
        if self.timerStarted is not True:
            self.timer.start()
            self.timerStarted = True

        if msg.button == msg.GAMEPAD_BUTTON_A and msg.button_a == 1:
            self.finalizeTrajectory()

        if msg.button == msg.GAMEPAD_DPAD_X and msg.button_dpad_x < 0:
            self.enableCameraMode()
            self.setCameraTarget()

        if msg.button == msg.GAMEPAD_DPAD_X and msg.button_dpad_x > 0:
            self.disableCameraMode()

        if msg.button == msg.GAMEPAD_BUTTON_Y and msg.button_y == 1:
            self.findEndEffectors()
            self.cycleEndEffector()
            self.setCameraTarget()

        if msg.button == msg.GAMEPAD_DPAD_Y and msg.button_dpad_y > 0:
            self.increaseTeleopSpeed()

        if msg.button == msg.GAMEPAD_DPAD_Y and msg.button_dpad_y < 0:
            self.decreaseTeleopSpeed()

        if msg.button == msg.GAMEPAD_BUTTON_START and msg.button_start == 1:
            self.toggleTeleop()

        if msg.button == msg.GAMEPAD_BUTTON_X and msg.button_x == 1:
            self.addKeyframePose()

        if msg.button == msg.GAMEPAD_BUTTON_LB:
            self.yawdot = -self.angularTravel * msg.button_lb

        if msg.button == msg.GAMEPAD_BUTTON_RB:
            self.yawdot = self.angularTravel * msg.button_rb

        if msg.button == msg.GAMEPAD_LEFT_X or msg.button == msg.GAMEPAD_LEFT_Y:
            self.thetadot = msg.thumbpad_left_x * self.angularTravel
            self.phidot = msg.thumbpad_left_y * self.angularTravel

        if msg.button == msg.GAMEPAD_RIGHT_X or msg.button == msg.GAMEPAD_RIGHT_Y:
            self.Xdot = self.travel * msg.thumbpad_right_x
            self.Zdot = self.travel * msg.thumbpad_right_y

        if msg.button == msg.GAMEPAD_TRIGGER_L:
            self.Ydot = -self.travel * msg.trigger_left

        if msg.button == msg.GAMEPAD_TRIGGER_R:
            self.Ydot = self.travel * msg.trigger_right

    def updateFrame(self):
        norm = np.linalg.norm(np.array([self.thetadot, self.phidot, self.yawdot, self.Xdot, self.Ydot, self.Zdot]))
        dt = 0.01 #self.timer.elapsed

        if self.baseFrame is not None:
            cameraFocus = np.asarray(self.camera.GetFocalPoint())
            cameraInterp = cameraFocus + (self.cameraTarget - cameraFocus)*0.02
            self.camera.SetFocalPoint(cameraInterp)

        if self.cameraMode is not True:
            if self.baseFrame is not None and norm > 0.1:
                t = vtk.vtkTransform()
                t.Concatenate(self.baseFrame.transform)
                t.RotateZ(-self.thetadot * dt * self.speedMultiplier)
                t.RotateX(self.phidot * dt * self.speedMultiplier)
                t.RotateY(self.yawdot * dt * self.speedMultiplier)
                t.Translate(self.Xdot * dt * self.speedMultiplier, self.Ydot * dt * self.speedMultiplier, self.Zdot * dt * self.speedMultiplier)
                self.baseFrame.copyFrame(t)
        else:

            self.camera.Elevation(self.Zdot * self.speedMultiplier)
            self.camera.Azimuth(self.Xdot * self.speedMultiplier)
            self.camera.Zoom(1.0 + self.phidot/1000.0)

        self.view.render()

<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
import sys

import mock
import pytest
from cumulusci.cli.ui import CHECKMARK, CliTable

@pytest.fixture
def sample_data():
    return {
        "service_list": [
            ["Name", "Description", "Configured"],
            ["saucelabs", "Configure connection for saucelabs tasks.", False],
            ["sentry", "Configure connection to sentry.io for error tracking", False],
        ],
        "org_list": [
            ["Org", "Default", "Scratch", "Days", "Expired", "Config", "Username"],
            ["beta", None, True, 1, None, "beta", ""],
            ["dev", True, True, "1/7", False, "dev", "test-h8znvutwnctb@example.com"],
            ["feature", None, True, 1, None, "feature", ""],
        ],
        "task_list_util": [
            ["Task", "Description"],
            ["command", "Run an arbitrary command"],
            ["log", "Log a line at the info level."],
            ["util_sleep", "Sleeps for N seconds"],
        ],
    }

@pytest.fixture
def pretty_output():
    return {
        "service_list": "\x1b(0lqqqqqqqqqqqwqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqwqqqqqqqqqqqqk\x1b(B\n\x1b(0x\x1b(B Name      \x1b(0x\x1b(B Description                                          \x1b(0x\x1b(B Configured \x1b(0x\x1b(B\n\x1b(0tqqqqqqqqqqqnqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqnqqqqqqqqqqqqu\x1b(B\n\x1b(0x\x1b(B saucelabs \x1b(0x\x1b(B Configure connection for saucelabs tasks.            \x1b(0x\x1b(B False      \x1b(0x\x1b(B\n\x1b(0x\x1b(B sentry    \x1b(0x\x1b(B Configure connection to sentry.io for error tracking \x1b(0x\x1b(B False      \x1b(0x\x1b(B\n\x1b(0mqqqqqqqqqqqvqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqvqqqqqqqqqqqqj\x1b(B",
        "org_list": "\x1b(0lqqqqqqqqqwqqqqqqqqqwqqqqqqqqqwqqqqqqwqqqqqqqqqwqqqqqqqqqwqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqk\x1b(B\n\x1b(0x\x1b(B Org     \x1b(0x\x1b(B Default \x1b(0x\x1b(B Scratch \x1b(0x\x1b(B Days \x1b(0x\x1b(B Expired \x1b(0x\x1b(B Config  \x1b(0x\x1b(B Username                      \x1b(0x\x1b(B\n\x1b(0tqqqqqqqqqnqqqqqqqqqnqqqqqqqqqnqqqqqqnqqqqqqqqqnqqqqqqqqqnqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqu\x1b(B\n\x1b(0x\x1b(B beta    \x1b(0x\x1b(B None    \x1b(0x\x1b(B True    \x1b(0x\x1b(B 1    \x1b(0x\x1b(B None    \x1b(0x\x1b(B beta    \x1b(0x\x1b(B                               \x1b(0x\x1b(B\n\x1b(0x\x1b(B dev     \x1b(0x\x1b(B True    \x1b(0x\x1b(B True    \x1b(0x\x1b(B 1/7  \x1b(0x\x1b(B False   \x1b(0x\x1b(B dev     \x1b(0x\x1b(B test-h8znvutwnctb@example.com \x1b(0x\x1b(B\n\x1b(0x\x1b(B feature \x1b(0x\x1b(B None    \x1b(0x\x1b(B True    \x1b(0x\x1b(B 1    \x1b(0x\x1b(B None    \x1b(0x\x1b(B feature \x1b(0x\x1b(B                               \x1b(0x\x1b(B\n\x1b(0mqqqqqqqqqvqqqqqqqqqvqqqqqqqqqvqqqqqqvqqqqqqqqqvqqqqqqqqqvqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqj\x1b(B",
        "task_list_util": "\x1b(0lqqqqqqqqqqqqwqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqk\x1b(B\n\x1b(0x\x1b(B Task       \x1b(0x\x1b(B Description                   \x1b(0x\x1b(B\n\x1b(0tqqqqqqqqqqqqnqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqu\x1b(B\n\x1b(0x\x1b(B command    \x1b(0x\x1b(B Run an arbitrary command      \x1b(0x\x1b(B\n\x1b(0x\x1b(B log        \x1b(0x\x1b(B Log a line at the info level. \x1b(0x\x1b(B\n\x1b(0x\x1b(B util_sleep \x1b(0x\x1b(B Sleeps for N seconds          \x1b(0x\x1b(B\n\x1b(0mqqqqqqqqqqqqvqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqj\x1b(B",
    }

@pytest.fixture
def pretty_output_win():
    return {
        "service_list": """
┌───────────┬──────────────────────────────────────────────────────┬────────────┐
│ Name      │ Description                                          │ Configured │
├───────────┼──────────────────────────────────────────────────────┼────────────┤
│ saucelabs │ Configure connection for saucelabs tasks.            │ False      │
│ sentry    │ Configure connection to sentry.io for error tracking │ False      │
└───────────┴──────────────────────────────────────────────────────┴────────────┘
""",
        "org_list": """
┌─────────┬─────────┬─────────┬──────┬─────────┬─────────┬───────────────────────────────┐
│ Org     │ Default │ Scratch │ Days │ Expired │ Config  │ Username                      │
├─────────┼─────────┼─────────┼──────┼─────────┼─────────┼───────────────────────────────┤
│ beta    │ None    │ True    │ 1    │ None    │ beta    │                               │
│ dev     │ True    │ True    │ 1/7  │ False   │ dev     │ test-h8znvutwnctb@example.com │
│ feature │ None    │ True    │ 1    │ None    │ feature │                               │
└─────────┴─────────┴─────────┴──────┴─────────┴─────────┴───────────────────────────────┘
""",
        "task_list_util": """
┌────────────┬───────────────────────────────┐
│ Task       │ Description                   │
├────────────┼───────────────────────────────┤
│ command    │ Run an arbitrary command      │
│ log        │ Log a line at the info level. │
│ util_sleep │ Sleeps for N seconds          │
└────────────┴───────────────────────────────┘
""",
    }

@pytest.fixture
def plain_output():
    return {
        "service_list": """+-----------------------------------------------------------------------------+
| Name       Description                                           Configured |
+-----------------------------------------------------------------------------+
| saucelabs  Configure connection for saucelabs tasks.             False      |
| sentry     Configure connection to sentry.io for error tracking  False      |
+-----------------------------------------------------------------------------+
""",
        "org_list": """+----------------------------------------------------------------------------------+
| Org      Default  Scratch  Days  Expired  Config   Username                      |
+----------------------------------------------------------------------------------+
| beta     None     True     1     None     beta                                   |
| dev      True     True     1/7   False    dev      test-h8znvutwnctb@example.com |
| feature  None     True     1     None     feature                                |
+----------------------------------------------------------------------------------+
""",
        "task_list_util": """+-------------------------------------------+
| Task        Description                   |
+-------------------------------------------+
| command     Run an arbitrary command      |
| log         Log a line at the info level. |
| util_sleep  Sleeps for N seconds          |
+-------------------------------------------+
""",
    }

@pytest.mark.skipif(
    sys.platform.startswith("win"),
    reason="Windows uses unicode chars instead of ASCII box chars.",
)
@pytest.mark.parametrize("fixture_key", ["service_list", "org_list", "task_list_util"])
def test_table_pretty_output(sample_data, pretty_output, fixture_key):
    instance = CliTable(sample_data[fixture_key])
    assert pretty_output[fixture_key] == instance.table.table

@pytest.mark.skipif(
    not sys.platform.startswith("win"),
    reason="Windows uses unicode chars instead of ASCII box chars.",
)
@pytest.mark.parametrize("fixture_key", ["service_list"])
def test_table_pretty_output_windows(sample_data, pretty_output_win, fixture_key):
    instance = CliTable(sample_data[fixture_key])
    assert pretty_output_win[fixture_key].strip() == instance.table.table

@pytest.mark.parametrize("fixture_key", ["service_list", "org_list", "task_list_util"])
def test_table_plain_output(sample_data, plain_output, fixture_key, capsys):
    instance = CliTable(sample_data[fixture_key])
    instance.ascii_table()
    captured = capsys.readouterr()
    expected = plain_output[fixture_key] + "\n\n"
    assert expected == captured.out

@pytest.mark.parametrize("fixture_key", ["service_list", "org_list", "task_list_util"])
def test_table_plain_echo(sample_data, plain_output, fixture_key, capsys):
    instance = CliTable(sample_data[fixture_key])
    instance.echo(plain=True)
    captured = capsys.readouterr()
    expected = plain_output[fixture_key] + "\n\n"
    assert expected == captured.out

def test_table_plain_fallback(sample_data, plain_output, capsys):
    with mock.patch("cumulusci.cli.ui.CliTable.pretty_table") as pretty_table:
        pretty_table.side_effect = UnicodeEncodeError(
            "cp1542", u"", 42, 43, "Fake exception"
        )
        instance = CliTable(sample_data["service_list"])
        instance.echo(plain=False)
        captured = capsys.readouterr()
        # append newlines because echo adds them to account for task tables
        assert plain_output["service_list"] + "\n\n" == captured.out

def test_table_stringify_booleans(sample_data):
    data = sample_data["service_list"]
    data[1][2] = True
    instance = CliTable(data)
    instance.stringify_boolean_col(col_name="Configured")
    assert CHECKMARK in instance.table.table_data[1]
    assert CliTable.PICTOGRAM_FALSE in instance.table.table_data[2]
<commit_msg>Use unicode for windows py2 tests<commit_after># -*- coding: utf-8 -*-
import sys

import mock
import pytest
from cumulusci.cli.ui import CHECKMARK, CliTable

@pytest.fixture
def sample_data():
    return {
        "service_list": [
            ["Name", "Description", "Configured"],
            ["saucelabs", "Configure connection for saucelabs tasks.", False],
            ["sentry", "Configure connection to sentry.io for error tracking", False],
        ],
        "org_list": [
            ["Org", "Default", "Scratch", "Days", "Expired", "Config", "Username"],
            ["beta", None, True, 1, None, "beta", ""],
            ["dev", True, True, "1/7", False, "dev", "test-h8znvutwnctb@example.com"],
            ["feature", None, True, 1, None, "feature", ""],
        ],
        "task_list_util": [
            ["Task", "Description"],
            ["command", "Run an arbitrary command"],
            ["log", "Log a line at the info level."],
            ["util_sleep", "Sleeps for N seconds"],
        ],
    }

@pytest.fixture
def pretty_output():
    return {
        "service_list": "\x1b(0lqqqqqqqqqqqwqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqwqqqqqqqqqqqqk\x1b(B\n\x1b(0x\x1b(B Name      \x1b(0x\x1b(B Description                                          \x1b(0x\x1b(B Configured \x1b(0x\x1b(B\n\x1b(0tqqqqqqqqqqqnqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqnqqqqqqqqqqqqu\x1b(B\n\x1b(0x\x1b(B saucelabs \x1b(0x\x1b(B Configure connection for saucelabs tasks.            \x1b(0x\x1b(B False      \x1b(0x\x1b(B\n\x1b(0x\x1b(B sentry    \x1b(0x\x1b(B Configure connection to sentry.io for error tracking \x1b(0x\x1b(B False      \x1b(0x\x1b(B\n\x1b(0mqqqqqqqqqqqvqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqvqqqqqqqqqqqqj\x1b(B",
        "org_list": "\x1b(0lqqqqqqqqqwqqqqqqqqqwqqqqqqqqqwqqqqqqwqqqqqqqqqwqqqqqqqqqwqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqk\x1b(B\n\x1b(0x\x1b(B Org     \x1b(0x\x1b(B Default \x1b(0x\x1b(B Scratch \x1b(0x\x1b(B Days \x1b(0x\x1b(B Expired \x1b(0x\x1b(B Config  \x1b(0x\x1b(B Username                      \x1b(0x\x1b(B\n\x1b(0tqqqqqqqqqnqqqqqqqqqnqqqqqqqqqnqqqqqqnqqqqqqqqqnqqqqqqqqqnqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqu\x1b(B\n\x1b(0x\x1b(B beta    \x1b(0x\x1b(B None    \x1b(0x\x1b(B True    \x1b(0x\x1b(B 1    \x1b(0x\x1b(B None    \x1b(0x\x1b(B beta    \x1b(0x\x1b(B                               \x1b(0x\x1b(B\n\x1b(0x\x1b(B dev     \x1b(0x\x1b(B True    \x1b(0x\x1b(B True    \x1b(0x\x1b(B 1/7  \x1b(0x\x1b(B False   \x1b(0x\x1b(B dev     \x1b(0x\x1b(B test-h8znvutwnctb@example.com \x1b(0x\x1b(B\n\x1b(0x\x1b(B feature \x1b(0x\x1b(B None    \x1b(0x\x1b(B True    \x1b(0x\x1b(B 1    \x1b(0x\x1b(B None    \x1b(0x\x1b(B feature \x1b(0x\x1b(B                               \x1b(0x\x1b(B\n\x1b(0mqqqqqqqqqvqqqqqqqqqvqqqqqqqqqvqqqqqqvqqqqqqqqqvqqqqqqqqqvqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqj\x1b(B",
        "task_list_util": "\x1b(0lqqqqqqqqqqqqwqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqk\x1b(B\n\x1b(0x\x1b(B Task       \x1b(0x\x1b(B Description                   \x1b(0x\x1b(B\n\x1b(0tqqqqqqqqqqqqnqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqu\x1b(B\n\x1b(0x\x1b(B command    \x1b(0x\x1b(B Run an arbitrary command      \x1b(0x\x1b(B\n\x1b(0x\x1b(B log        \x1b(0x\x1b(B Log a line at the info level. \x1b(0x\x1b(B\n\x1b(0x\x1b(B util_sleep \x1b(0x\x1b(B Sleeps for N seconds          \x1b(0x\x1b(B\n\x1b(0mqqqqqqqqqqqqvqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqj\x1b(B",
    }

@pytest.fixture
def pretty_output_win():
    return {
        "service_list": u"""
┌───────────┬──────────────────────────────────────────────────────┬────────────┐
│ Name      │ Description                                          │ Configured │
├───────────┼──────────────────────────────────────────────────────┼────────────┤
│ saucelabs │ Configure connection for saucelabs tasks.            │ False      │
│ sentry    │ Configure connection to sentry.io for error tracking │ False      │
└───────────┴──────────────────────────────────────────────────────┴────────────┘
""",
        "org_list": u"""
┌─────────┬─────────┬─────────┬──────┬─────────┬─────────┬───────────────────────────────┐
│ Org     │ Default │ Scratch │ Days │ Expired │ Config  │ Username                      │
├─────────┼─────────┼─────────┼──────┼─────────┼─────────┼───────────────────────────────┤
│ beta    │ None    │ True    │ 1    │ None    │ beta    │                               │
│ dev     │ True    │ True    │ 1/7  │ False   │ dev     │ test-h8znvutwnctb@example.com │
│ feature │ None    │ True    │ 1    │ None    │ feature │                               │
└─────────┴─────────┴─────────┴──────┴─────────┴─────────┴───────────────────────────────┘
""",
        "task_list_util": u"""
┌────────────┬───────────────────────────────┐
│ Task       │ Description                   │
├────────────┼───────────────────────────────┤
│ command    │ Run an arbitrary command      │
│ log        │ Log a line at the info level. │
│ util_sleep │ Sleeps for N seconds          │
└────────────┴───────────────────────────────┘
""",
    }

@pytest.fixture
def plain_output():
    return {
        "service_list": """+-----------------------------------------------------------------------------+
| Name       Description                                           Configured |
+-----------------------------------------------------------------------------+
| saucelabs  Configure connection for saucelabs tasks.             False      |
| sentry     Configure connection to sentry.io for error tracking  False      |
+-----------------------------------------------------------------------------+
""",
        "org_list": """+----------------------------------------------------------------------------------+
| Org      Default  Scratch  Days  Expired  Config   Username                      |
+----------------------------------------------------------------------------------+
| beta     None     True     1     None     beta                                   |
| dev      True     True     1/7   False    dev      test-h8znvutwnctb@example.com |
| feature  None     True     1     None     feature                                |
+----------------------------------------------------------------------------------+
""",
        "task_list_util": """+-------------------------------------------+
| Task        Description                   |
+-------------------------------------------+
| command     Run an arbitrary command      |
| log         Log a line at the info level. |
| util_sleep  Sleeps for N seconds          |
+-------------------------------------------+
""",
    }

@pytest.mark.skipif(
    sys.platform.startswith("win"),
    reason="Windows uses unicode chars instead of ASCII box chars.",
)
@pytest.mark.parametrize("fixture_key", ["service_list", "org_list", "task_list_util"])
def test_table_pretty_output(sample_data, pretty_output, fixture_key):
    instance = CliTable(sample_data[fixture_key])
    assert pretty_output[fixture_key] == instance.table.table

@pytest.mark.skipif(
    not sys.platform.startswith("win"),
    reason="Windows uses unicode chars instead of ASCII box chars.",
)
@pytest.mark.parametrize("fixture_key", ["service_list"])
def test_table_pretty_output_windows(sample_data, pretty_output_win, fixture_key):
    instance = CliTable(sample_data[fixture_key])
    assert pretty_output_win[fixture_key].strip() == instance.table.table

@pytest.mark.parametrize("fixture_key", ["service_list", "org_list", "task_list_util"])
def test_table_plain_output(sample_data, plain_output, fixture_key, capsys):
    instance = CliTable(sample_data[fixture_key])
    instance.ascii_table()
    captured = capsys.readouterr()
    expected = plain_output[fixture_key] + "\n\n"
    assert expected == captured.out

@pytest.mark.parametrize("fixture_key", ["service_list", "org_list", "task_list_util"])
def test_table_plain_echo(sample_data, plain_output, fixture_key, capsys):
    instance = CliTable(sample_data[fixture_key])
    instance.echo(plain=True)
    captured = capsys.readouterr()
    expected = plain_output[fixture_key] + "\n\n"
    assert expected == captured.out

def test_table_plain_fallback(sample_data, plain_output, capsys):
    with mock.patch("cumulusci.cli.ui.CliTable.pretty_table") as pretty_table:
        pretty_table.side_effect = UnicodeEncodeError(
            "cp1542", u"", 42, 43, "Fake exception"
        )
        instance = CliTable(sample_data["service_list"])
        instance.echo(plain=False)
        captured = capsys.readouterr()
        # append newlines because echo adds them to account for task tables
        assert plain_output["service_list"] + "\n\n" == captured.out

def test_table_stringify_booleans(sample_data):
    data = sample_data["service_list"]
    data[1][2] = True
    instance = CliTable(data)
    instance.stringify_boolean_col(col_name="Configured")
    assert CHECKMARK in instance.table.table_data[1]
    assert CliTable.PICTOGRAM_FALSE in instance.table.table_data[2]
<|endoftext|>


<commit_before># Copyright 2016 by Raytheon BBN Technologies Corp.  All Rights Reserved.

import ast
import os
import sys

from copy import deepcopy

from pyqgl2.ast_util import ast2str, NodeError
from pyqgl2.concur_unroll import is_concur, is_seq, find_all_channels
from pyqgl2.importer import collapse_name
from pyqgl2.lang import QGL2
from pyqgl2.substitute import getChanLabel

class SingleSequence(object):
    """
    Create a sequence list for a single QBIT

    Note: this assumes that the AST is for one function
    definition that has already been inlined, successfully
    flattened, grouped, and sequenced already.
    """

    def __init__(self, importer):

        self.importer = importer

        self.qbits = set()
        self.qbit_creates = list()
        self.sequence = list()

        # the imports we need to make in order to satisfy the stubs
        #
        # the key is the name of the module (i.e. something like
        # 'QGL.PulsePrimitives') and the values are sets of import
        # clauses (i.e. 'foo' or 'foo as bar')
        #
        self.stub_imports = dict()

    def is_qbit_create(self, node):
        """
        If the node does not represent a qbit creation and assignment,
        return False.  Otherwise, return a triple (sym_name, use_name,
        node) where sym_name is the symbolic name, use_name is the
        name used by the preprocessor to substitute for this qbit
        reference, and node is the node parameter (i.e. the root
        of the ast for the assignment.

        There are several sloppy assumptions here.
        """

        if not isinstance(node, ast.Assign):
            return False

        # Only handles simple assignments; not tuples
        # TODO: handle tuples
        if len(node.targets) != 1:
            return False

        if not isinstance(node.value, ast.Call):
            return False

        if not isinstance(node.value.func, ast.Name):
            return False

        # This is the old name, and needs to be updated
        # TODO: update to new name/signature
        if node.value.func.id != QGL2.QBIT_ALLOC and \
           node.value.func.id != QGL2.QBIT_ALLOC2:
            return False

        chanLabel = getChanLabel(node)
        if not chanLabel:
            NodeError.warning_msg(node, 'failed to find chanLabel')

        # HACK FIXME: assumes old-style Qbit allocation
        sym_name = node.targets[0].id
        use_name = 'QBIT_%s' % chanLabel
        return (sym_name, use_name, node)

    def find_imports(self, node):

        default_namespace = node.qgl_fname

        for subnode in ast.walk(node):
            if (isinstance(subnode, ast.Call) and
                    isinstance(subnode.func, ast.Name)):
                funcname = subnode.func.id

                # If we created a node without an qgl_fname,
                # then use the default namespace instead.
                # FIXME: This is a hack, but it will work for now.
                #
                if not hasattr(subnode, 'qgl_fname'):
                    namespace = default_namespace
                else:
                    namespace = subnode.qgl_fname

                fdef = self.importer.resolve_sym(namespace, funcname)
                if not fdef:
                    NodeError.error_msg(subnode,
                            'cannot find import info for [%s]' % funcname)
                elif not fdef.qgl_stub_import:
                    NodeError.error_msg(subnode,
                            'not a stub: [%s]' % funcname)
                else:
                    # print('FI AST %s' % ast.dump(fdef))
                    (sym_name, module_name, orig_name) = fdef.qgl_stub_import

                    if orig_name:
                        import_str = '%s as %s' % (orig_name, sym_name)
                    else:
                        import_str = sym_name

                    if module_name not in self.stub_imports:
                        self.stub_imports[module_name] = set()

                    self.stub_imports[module_name].add(import_str)

        return True

    def create_imports_list(self):

        import_list = list()

        for module_name in sorted(self.stub_imports.keys()):
            for sym_name in sorted(self.stub_imports[module_name]):
                import_list.append(
                        'from %s import %s' % (module_name, sym_name))

        return import_list

    def find_sequence(self, node):

        if not isinstance(node, ast.FunctionDef):
            NodeError.fatal_msg(node, 'not a function definition')
            return False

        self.qbits = find_all_channels(node)

        if len(self.qbits) == 0:
            NodeError.error_msg(node, 'no channels found')
            return False
        elif len(self.qbits) > 1:
            NodeError.error_msg(node, 'more than one channel found')
            return False

        for stmnt in node.body:
            assignment = self.is_qbit_create(stmnt)
            if assignment:
                self.qbit_creates.append(assignment)
                continue
            elif is_concur(stmnt):
                if is_seq(stmnt.body[0]):
                    self.sequence += stmnt.body[0].body
                else:
                    NodeError.diag_msg(stmnt.body[0], 'expected seq?')
            elif isinstance(stmnt, ast.Expr):
                self.sequence.append(stmnt)
            else:
                NodeError.error_msg(stmnt,
                        'orphan statement %s' % ast.dump(stmnt))

        return True

    def emit_function(self, func_name='qgl1_main'):
        """
        Create a function that, when run, creates the context
        in which the sequence is evaluated, and evaluate it.

        func_name is the name for the function, if provided.
        I'm not certain that the name has any significance
        or whether this function will be, for all practical
        purposes, a lambda.
        """

        # assumes a standard 4-space indent; if the surrounding
        # context uses some other indentation scheme, the interpreter
        # may gripe, and pep8 certainly will
        #
        indent = '    '

        # FIXME: Ugliness
        # In the proper namespace we need to import all the QGL1 functions
        # that this method is using / might use
        # Here we include the imports matching stuff in qgl2.qgl1.py
        # Can we perhaps annotate all the stubs with the proper
        # import statement and use that to figure out what to include here?
        base_imports = """    from QGL.Compiler import compile_to_hardware
    from QGL.PulseSequencePlotter import plot_pulse_files
"""

        found_imports = ('\n' + indent).join(self.create_imports_list())

        # allow QBIT parameters to be overridden
        #
        preamble = 'def %s(**kwargs):\n' % func_name
        preamble += base_imports
        preamble += indent + found_imports
        preamble += '\n\n'

        for (sym_name, _use_name, node) in self.qbit_creates:
            preamble += indent + 'if \'' + sym_name + '\' in kwargs:\n'
            preamble += (2 * indent) + sym_name
            preamble += ' = kwargs[\'%s\']\n' % sym_name
            preamble += indent + 'else:\n'
            preamble += (2 * indent) + ast2str(node).strip() + '\n'

        for (sym_name, use_name, _node) in self.qbit_creates:
            preamble += indent + '%s = %s\n' % (use_name, sym_name)

        sequence = [ast2str(item).strip() for item in self.sequence]

        # TODO: check that this is always OK.
        #
        # HACK ALERT: this might not always be the right thing to do
        # but right now extraneous calls to Sync at the start of
        # program appear to cause a problem, and they don't serve
        # any known purpose, so skip them.
        #
        while sequence[0] == 'Sync()':
            sequence = sequence[1:]

        # TODO there must be a more elegant way to indent this properly
        seq_str = indent + 'seq = [\n' + 2 * indent
        seq_str += (',\n' + 2 * indent).join(sequence)
        seq_str += '\n' + indent + ']\n'

        # That was a single sequence. We want a list of sequences
        # FIXME: Really, we want a new sequence every time the source code used Init()
        seqs_str = indent + 'seqs = [seq]\n'

        postamble = indent + 'return seqs\n'

        res =  preamble + seq_str + seqs_str + postamble
        return res

def single_sequence(node, func_name, importer):
    """
    Create a function that encapsulates the QGL code (for a single
    sequence) from the given AST node, which is presumed to already
    be fully pre-processed.

    TODO: we don't test that the node is fully pre-processed.
    TODO: each step of the preprocessor should mark the nodes
    so that we know whether or not they've been processed.
    """

    builder = SingleSequence(importer)

    if builder.find_sequence(node) and builder.find_imports(node):
        code = builder.emit_function(func_name)

        NodeError.diag_msg(
                node, 'generated code:\n#start\n%s\n#end code' % code)

        # TODO: we might want to pass in elements of the local scope
        scratch_scope = dict()
        eval(compile(code, '<none>', mode='exec'), globals(), scratch_scope)

        return scratch_scope[func_name]
    else:
        NodeError.fatal_msg(
                node, 'find_sequence failed: not a single sequence')
        return None

<commit_msg>hacked up single.py that treats every 'with seq' as starting a new sequence. Almost certainly fails for every other case.<commit_after># Copyright 2016 by Raytheon BBN Technologies Corp.  All Rights Reserved.

import ast
import os
import sys

from copy import deepcopy

from pyqgl2.ast_util import ast2str, NodeError
from pyqgl2.concur_unroll import is_concur, is_seq, find_all_channels
from pyqgl2.importer import collapse_name
from pyqgl2.lang import QGL2
from pyqgl2.substitute import getChanLabel

class SingleSequence(object):
    """
    Create a sequence list for a single QBIT

    Note: this assumes that the AST is for one function
    definition that has already been inlined, successfully
    flattened, grouped, and sequenced already.
    """

    def __init__(self, importer):

        self.importer = importer

        self.qbits = set()
        self.qbit_creates = list()
        self.sequences = list()

        # the imports we need to make in order to satisfy the stubs
        #
        # the key is the name of the module (i.e. something like
        # 'QGL.PulsePrimitives') and the values are sets of import
        # clauses (i.e. 'foo' or 'foo as bar')
        #
        self.stub_imports = dict()

    def is_qbit_create(self, node):
        """
        If the node does not represent a qbit creation and assignment,
        return False.  Otherwise, return a triple (sym_name, use_name,
        node) where sym_name is the symbolic name, use_name is the
        name used by the preprocessor to substitute for this qbit
        reference, and node is the node parameter (i.e. the root
        of the ast for the assignment.

        There are several sloppy assumptions here.
        """

        if not isinstance(node, ast.Assign):
            return False

        # Only handles simple assignments; not tuples
        # TODO: handle tuples
        if len(node.targets) != 1:
            return False

        if not isinstance(node.value, ast.Call):
            return False

        if not isinstance(node.value.func, ast.Name):
            return False

        # This is the old name, and needs to be updated
        # TODO: update to new name/signature
        if node.value.func.id != QGL2.QBIT_ALLOC and \
           node.value.func.id != QGL2.QBIT_ALLOC2:
            return False

        chanLabel = getChanLabel(node)
        if not chanLabel:
            NodeError.warning_msg(node, 'failed to find chanLabel')

        # HACK FIXME: assumes old-style Qbit allocation
        sym_name = node.targets[0].id
        use_name = 'QBIT_%s' % chanLabel
        return (sym_name, use_name, node)

    def find_imports(self, node):

        default_namespace = node.qgl_fname

        for subnode in ast.walk(node):
            if (isinstance(subnode, ast.Call) and
                    isinstance(subnode.func, ast.Name)):
                funcname = subnode.func.id

                # If we created a node without an qgl_fname,
                # then use the default namespace instead.
                # FIXME: This is a hack, but it will work for now.
                #
                if not hasattr(subnode, 'qgl_fname'):
                    namespace = default_namespace
                else:
                    namespace = subnode.qgl_fname

                fdef = self.importer.resolve_sym(namespace, funcname)
                if not fdef:
                    NodeError.error_msg(subnode,
                            'cannot find import info for [%s]' % funcname)
                elif not fdef.qgl_stub_import:
                    NodeError.error_msg(subnode,
                            'not a stub: [%s]' % funcname)
                else:
                    # print('FI AST %s' % ast.dump(fdef))
                    (sym_name, module_name, orig_name) = fdef.qgl_stub_import

                    if orig_name:
                        import_str = '%s as %s' % (orig_name, sym_name)
                    else:
                        import_str = sym_name

                    if module_name not in self.stub_imports:
                        self.stub_imports[module_name] = set()

                    self.stub_imports[module_name].add(import_str)

        return True

    def create_imports_list(self):

        import_list = list()

        for module_name in sorted(self.stub_imports.keys()):
            for sym_name in sorted(self.stub_imports[module_name]):
                import_list.append(
                        'from %s import %s' % (module_name, sym_name))

        return import_list

    def find_sequence(self, node):

        if not isinstance(node, ast.FunctionDef):
            NodeError.fatal_msg(node, 'not a function definition')
            return False

        self.qbits = find_all_channels(node)

        if len(self.qbits) == 0:
            NodeError.error_msg(node, 'no channels found')
            return False
#        elif len(self.qbits) > 1:
#            NodeError.error_msg(node, 'more than one channel found')
#            return False

        lineNo = -1
        while lineNo+1 < len(node.body):
            lineNo += 1
            print("Line %d of %d" % (lineNo+1, len(node.body)))
            stmnt = node.body[lineNo]
            print("Looking at stmnt %s" % stmnt)
            assignment = self.is_qbit_create(stmnt)
            if assignment:
                self.qbit_creates.append(assignment)
                continue
            elif is_concur(stmnt):
                print("Found concur at line %d: %s" % (lineNo+1,stmnt))
                for s in stmnt.body:
                    lineNo += 1
                    if is_seq(s):
                        print("With seq next at line %d: %s" % (lineNo+1,s))
                        self.sequences.append(list())
                        print("Append body %s" % s.body)
                        for s2 in s.body:
                            print(ast2str(s2))
                        self.sequences[-1] += s.body
                        lineNo += len(s.body)
                    else:
                        print("Not seq next at line %d: %s" % (lineNo+1,s))
                        self.sequences[-1] += s
                  #else:
                  #  NodeError.diag_msg(stmnt.body[0], 'expected seq?')
            elif isinstance(stmnt, ast.Expr):
                print("Append expr %s" % stmnt)
                self.sequences[-1].append(stmnt)
            else:
                NodeError.error_msg(stmnt,
                        'orphan statement %s' % ast.dump(stmnt))
        print("Seqs: %s" % self.sequences)
        return True

    def emit_function(self, func_name='qgl1_main'):
        """
        Create a function that, when run, creates the context
        in which the sequence is evaluated, and evaluate it.

        func_name is the name for the function, if provided.
        I'm not certain that the name has any significance
        or whether this function will be, for all practical
        purposes, a lambda.
        """

        # assumes a standard 4-space indent; if the surrounding
        # context uses some other indentation scheme, the interpreter
        # may gripe, and pep8 certainly will
        #
        indent = '    '

        # FIXME: Ugliness
        # In the proper namespace we need to import all the QGL1 functions
        # that this method is using / might use
        # Here we include the imports matching stuff in qgl2.qgl1.py
        # Can we perhaps annotate all the stubs with the proper
        # import statement and use that to figure out what to include here?
        base_imports = """    from QGL.Compiler import compile_to_hardware
    from QGL.PulseSequencePlotter import plot_pulse_files
"""

        found_imports = ('\n' + indent).join(self.create_imports_list())

        # allow QBIT parameters to be overridden
        #
        preamble = 'def %s(**kwargs):\n' % func_name
        preamble += base_imports
        preamble += indent + found_imports
        preamble += '\n\n'

        for (sym_name, _use_name, node) in self.qbit_creates:
            preamble += indent + 'if \'' + sym_name + '\' in kwargs:\n'
            preamble += (2 * indent) + sym_name
            preamble += ' = kwargs[\'%s\']\n' % sym_name
            preamble += indent + 'else:\n'
            preamble += (2 * indent) + ast2str(node).strip() + '\n'

        for (sym_name, use_name, _node) in self.qbit_creates:
            preamble += indent + '%s = %s\n' % (use_name, sym_name)

        seqs_def = indent + 'seqs = list()\n'
        seqs_str = ''
        seq_strs = list()

        for seq in self.sequences:
            print("Looking at seq %s" % seq)
            sequence = [ast2str(item).strip() for item in seq]
            print ("It is %s" % sequence)
            # TODO: check that this is always OK.
            #
            # HACK ALERT: this might not always be the right thing to do
            # but right now extraneous calls to Sync at the start of
            # program appear to cause a problem, and they don't serve
            # any known purpose, so skip them.
            #
            while sequence[0] == 'Sync()':
                sequence = sequence[1:]

            # TODO there must be a more elegant way to indent this properly
            seq_str = indent + 'seq = [\n' + 2 * indent
            seq_str += (',\n' + 2 * indent).join(sequence)
            seq_str += '\n' + indent + ']\n'
            seq_strs.append(seq_str)

        for seq_str in seq_strs:
            seqs_str += seq_str

            # That was a single sequence. We want a list of sequences
            # FIXME: Really, we want a new sequence every time the source code used Init()
            seqs_str += indent + 'seqs += [seq]\n'

        postamble = indent + 'return seqs\n'

        res =  preamble + seqs_def + seqs_str + postamble
        return res

def single_sequence(node, func_name, importer):
    """
    Create a function that encapsulates the QGL code (for a single
    sequence) from the given AST node, which is presumed to already
    be fully pre-processed.

    TODO: we don't test that the node is fully pre-processed.
    TODO: each step of the preprocessor should mark the nodes
    so that we know whether or not they've been processed.
    """

    builder = SingleSequence(importer)

    if builder.find_sequence(node) and builder.find_imports(node):
        code = builder.emit_function(func_name)

        NodeError.diag_msg(
                node, 'generated code:\n#start\n%s\n#end code' % code)

        # TODO: we might want to pass in elements of the local scope
        scratch_scope = dict()
        eval(compile(code, '<none>', mode='exec'), globals(), scratch_scope)

        return scratch_scope[func_name]
    else:
        NodeError.fatal_msg(
                node, 'find_sequence failed: not a single sequence')
        return None

<|endoftext|>


<commit_before>from UM.Application import Application
from UM.Qt.ListModel import ListModel

from PyQt5.QtCore import pyqtProperty, Qt, pyqtSignal, pyqtSlot, QUrl

from UM.Settings.ContainerRegistry import ContainerRegistry
from UM.Settings.InstanceContainer import InstanceContainer

class ContainerSettingsModel(ListModel):
    LabelRole = Qt.UserRole + 1
    CategoryRole = Qt.UserRole + 2
    UnitRole = Qt.UserRole + 3
    ValuesRole = Qt.UserRole + 4

    def __init__(self, parent = None):
        super().__init__(parent)
        self.addRoleName(self.LabelRole, "label")
        self.addRoleName(self.CategoryRole, "category")
        self.addRoleName(self.UnitRole, "unit")
        self.addRoleName(self.ValuesRole, "values")

        self._container_ids = []
        self._containers = []

    def _onPropertyChanged(self, key, property_name):
        if property_name == "value":
            self._update()

    def _update(self):
        self.clear()

        if len(self._container_ids) == 0:
            return

        keys = []
        for container in self._containers:
            keys = keys + list(container.getAllKeys())

        keys = list(set(keys)) # remove duplicate keys
        keys.sort()

        for key in keys:
            definition = None
            category = None
            values = []
            for container in self._containers:
                instance = container.getInstance(key)
                if instance:
                    definition = instance.definition

                    # Traverse up to find the category
                    category = definition
                    while category.type != "category":
                        category = category.parent

                    values.append(container.getProperty(key, "value"))
                else:
                    values.append("")

            self.appendItem({
                "key": key,
                "values": values,
                "label": definition.label,
                "unit": definition.unit,
                "category": category.label
            })

    ##  Set the ids of the containers which have the settings this model should list.
    #   Also makes sure the model updates when the containers have property changes
    def setContainers(self, container_ids):
        for container in self._containers:
            container.propertyChanged.disconnect(self._onPropertyChanged)

        self._container_ids = container_ids
        self._containers = []

        for container_id in self._container_ids:
            containers = ContainerRegistry.getInstance().findContainers(id = container_id)
            if containers:
                containers[0].propertyChanged.connect(self._onPropertyChanged)
                self._containers.append(containers[0])

        self._update()

    containersChanged = pyqtSignal()
    @pyqtProperty("QVariantList", fset = setContainers, notify = containersChanged)
    def containers(self):
        return self.container_ids<commit_msg>Show that a value is being calculated instead of showing "QVariant..."<commit_after>from UM.Application import Application
from UM.Qt.ListModel import ListModel

from PyQt5.QtCore import pyqtProperty, Qt, pyqtSignal, pyqtSlot, QUrl

from UM.Settings.ContainerRegistry import ContainerRegistry
from UM.Settings.InstanceContainer import InstanceContainer
from UM.Settings.SettingFunction import SettingFunction

class ContainerSettingsModel(ListModel):
    LabelRole = Qt.UserRole + 1
    CategoryRole = Qt.UserRole + 2
    UnitRole = Qt.UserRole + 3
    ValuesRole = Qt.UserRole + 4

    def __init__(self, parent = None):
        super().__init__(parent)
        self.addRoleName(self.LabelRole, "label")
        self.addRoleName(self.CategoryRole, "category")
        self.addRoleName(self.UnitRole, "unit")
        self.addRoleName(self.ValuesRole, "values")

        self._container_ids = []
        self._containers = []

    def _onPropertyChanged(self, key, property_name):
        if property_name == "value":
            self._update()

    def _update(self):
        self.clear()

        if len(self._container_ids) == 0:
            return

        keys = []
        for container in self._containers:
            keys = keys + list(container.getAllKeys())

        keys = list(set(keys)) # remove duplicate keys
        keys.sort()

        for key in keys:
            definition = None
            category = None
            values = []
            for container in self._containers:
                instance = container.getInstance(key)
                if instance:
                    definition = instance.definition

                    # Traverse up to find the category
                    category = definition
                    while category.type != "category":
                        category = category.parent

                    value = container.getProperty(key, "value")
                    if type(value) == SettingFunction:
                        values.append("=\u0192")
                    else:
                        values.append(container.getProperty(key, "value"))
                else:
                    values.append("")

            self.appendItem({
                "key": key,
                "values": values,
                "label": definition.label,
                "unit": definition.unit,
                "category": category.label
            })

    ##  Set the ids of the containers which have the settings this model should list.
    #   Also makes sure the model updates when the containers have property changes
    def setContainers(self, container_ids):
        for container in self._containers:
            container.propertyChanged.disconnect(self._onPropertyChanged)

        self._container_ids = container_ids
        self._containers = []

        for container_id in self._container_ids:
            containers = ContainerRegistry.getInstance().findContainers(id = container_id)
            if containers:
                containers[0].propertyChanged.connect(self._onPropertyChanged)
                self._containers.append(containers[0])

        self._update()

    containersChanged = pyqtSignal()
    @pyqtProperty("QVariantList", fset = setContainers, notify = containersChanged)
    def containers(self):
        return self.container_ids<|endoftext|>