<commit_before>#!/usr/bin/env python
import time
import threading
import os
import pyuarm
import rospy
import ThreadSafePriorityQueue as tspq
from uarm_decorators import *

from std_msgs.msg import String, Bool
from std_msgs.msg import Float32MultiArray as Array

class UarmMetal():

    def __init__(self):
        self.uarm = None
        self.connected = False
        self.ready = False
        self.alive = True

        self.ros_rate = None
        self.ros_hz = 0
        self.read_pos = None
        self.read_ja = None
        self.read_AI = None

        self.settings = []

        self.parameter_monitor_thread = None

        self.uarm_read_thread = None
        self.string_read_pub = None
        self.rq = tspq.ThreadSafePriorityQueue("read_queue")

        self.uarm_interface_thread = None
        self.iq = tspq.ThreadSafePriorityQueue("interface_queue")

        self.pos_pub = None
        self.ja_pub = None
        self.ai_pub = None

        self.playback_thread = None
        self.playback_active = False
        self.playback_data = []
        self.loading = False

        self.ja = []

#INIT Initialisation
# Initialisation
#endINIT

    def get_setting(self, name, string_val=False, list_type=False):
        for line in self.settings:
            if line[0] == name:
                if string_val:
                    return line[1]
                else:
                    if list_type:
                        try:
                            return map(float, line[1:-1])
                        except Exception as e:
                            print e
                    else:
                        return float(line[1])

    def connect(self):
        try:
            self.uarm = pyuarm.get_uarm()
            self.connected = True
            self.load_parameters()
            self.connect_to_ROS()
            self.start_threads()
            rospy.loginfo("Connected")
            self.ready = True
        except Exception as e:
            self.connected = False
            err = str(e.message)
            rospy.logerr("Connection error: " + err)
            rospy.signal_shutdown("Connection error")

    def shutdown(self):
        rospy.loginfo("Shutdown function call")
        rospy.signal_shutdown("Shutdown function call")
        start_shutdown = time.time()
        while self.uarm_interface_thread.is_alive() or self.uarm_read_thread.is_alive():
            self.iq.send_to_queue("SHUTDOWN", priority=1)
            self.rq.send_to_queue("SHUTDOWN", priority=1)
            time.sleep(0.5)
            if time.time()-start_shutdown > 5:
                break
        self.alive = False
        self.uarm.disconnect()

    def load_parameters(self):
        rospy.loginfo("Loading parameters")

        dir_path = os.path.dirname(os.path.realpath(__file__))
        f = open(dir_path + "/settings.txt")
        self.settings = []
        for line in f:
            self.settings.append(line.split(','))
        f.close()

        self.ros_hz = self.get_setting("ros_hz")
        self.read_pos = self.get_setting("read_pos")
        self.read_ja = self.get_setting("read_ja")
        self.read_AI = self.get_setting("read_AI", list_type=True)

        rospy.set_param('uarm_metal/read_position', self.read_pos)
        rospy.set_param('uarm_metal/read_joint_angles', self.read_ja)
        rospy.set_param('uarm_metal/read_AI', self.read_AI)

    def connect_to_ROS(self):
        self.string_read_pub = rospy.Publisher('uarm_metal/string_read', String, queue_size=10)
        self.pos_pub = rospy.Publisher('uarm_metal/position_read', Array, queue_size=10)
        self.ja_pub = rospy.Publisher('uarm_metal/joint_angles_read', Array, queue_size=10)
        self.ai_pub = rospy.Publisher('uarm_metal/analog_inputs_read', String, queue_size=10)

        rospy.Subscriber("uarm_metal/string_write", String, self.string_write_callback, queue_size= 1000)
        rospy.Subscriber("uarm_metal/position_write", Array, self.position_write_callback, queue_size=1000)
        rospy.Subscriber("uarm_metal/joint_angles_write", Array, self.ja_write_callback, queue_size=1000)
        rospy.Subscriber("uarm_metal/pump", Bool, self.pump_write_callback, queue_size=1000)
        rospy.init_node('uarm_node', anonymous=True)
        self.ros_rate = rospy.Rate(self.ros_hz)

        rospy.loginfo("Done loading parameters.")

    def parameter_monitor(self):
        rospy.loginfo("Parameter monitor running.")
        while True and (rospy.is_shutdown() is False):
            self.read_pos = int(rospy.get_param('uarm_metal/read_position'))
            self.read_ja = int(rospy.get_param('uarm_metal/read_joint_angles'))
            self.read_AI = map(int, rospy.get_param('uarm_metal/read_AI'))
            time.sleep(0.5)

        rospy.loginfo("Parameter monitor shutdown")

    def start_threads(self):
        rospy.loginfo("Starting threads")
        if self.connected is True:
            self.uarm_read_thread = threading.Thread(target=self.uarm_read)
            self.uarm_interface_thread = threading.Thread(target=self.uarm_interface)
            self.parameter_monitor_thread = threading.Thread(target=self.parameter_monitor)

            self.uarm_read_thread.daemon = True
            self.uarm_read_thread.start()

            self.uarm_interface_thread.daemon = True
            self.uarm_interface_thread.start()

            self.parameter_monitor_thread.daemon = True
            self.parameter_monitor_thread.start()

            #self.request_detach()

        else:
            rospy.logerr("Startup error")
            rospy.signal_shutdown("Startup error")

#MAIN Main Threads
# Main threads/functions
#endMAIN

    def get_read_data(self):
        msg = []
        if self.read_pos > 0:
            msg.append(self.read_position())
        if self.read_ja > 0:
            msg.append(self.read_joint_angles())
        if self.read_AI[0] > 0:
            reading = []
            for i in self.read_AI[1:]:
                reading.append(self.read_analog(i))
            msg.append(reading[:])
        return msg

    def uarm_interface(self):
        rospy.loginfo("uarm_interface running")
        while True and (rospy.is_shutdown() is False):
            request = self.iq.get_from_queue()

            if request == "READ":
                curr_vals = self.get_read_data()
                try:
                    self.rq.send_to_queue(curr_vals)
                except Exception as e:
                    print "Error: ", e
                    rospy.logerr("Error writing to queue. Queue probably shutdown.")
                    break

                if self.playback_active is False and self.loading is False:
                    self.iq.send_to_queue("READ")

            elif request == "SHUTDOWN":
                break
            else:
                self.process_command(request)
                if self.playback_active is False and self.loading is False:
                    self.iq.send_to_queue("READ")

        rospy.loginfo("uarm_interface shutdown")
        self.shutdown()

    def uarm_read(self):
        rospy.loginfo("uarm_read running")
        while True and (rospy.is_shutdown() is False):
            robot_values = self.rq.get_from_queue(blocking=False)
            if robot_values:
                if robot_values == "SHUTDOWN":
                    rospy.logwarn("sending shutdown signal")
                    rospy.signal_shutdown("Normal Shutdown Procedure")
                    break
                else:
                    msg = str(robot_values)
                    msg = msg.translate(None, '[]')

                    if str(msg)[0:5] == "False":
                        rospy.logerr("uArm read error")
                        rospy.signal_shutdown("uArm read error")
                        self.uarm.disconnect()
                        break
                    try:
                        self.string_read_pub.publish(msg)
                        if self.read_pos > 0:
                            pos_msg = map(float,str(robot_values[0]).translate(None,'[]').split(','))
                            self.pos_pub.publish(len(pos_msg),pos_msg)
                        if self.read_ja > 0:
                            ja_data = robot_values[self.read_pos]
                            print ja_data
                            ja_msg = map(float,str(ja_data).translate(None, '[]'))
                            self.ja_pub.publish(len(ja_msg),ja_msg)
                        if self.read_AI[0] > 0:
                            self.ai_pub.publish(str(robot_values[self.read_pos +
                                                                 self.read_ja]).translate(None, '[]'))

                    except Exception as e:
                        err_msg = "Failed to publish data: ", e.message
                        rospy.logerr(err_msg)
                        rospy.signal_shutdown("Error Shutdown Procedure")
                        break
        time.sleep(1.0/self.ros_hz)
        rospy.loginfo("uarm_read shutdown")

    def string_write_callback(self, data):
        if data.data == "CLEAR":
                self.iq.get_from_queue(all_msgs=True)
                self.rq.get_from_queue(all_msgs=True)

        elif data.data[0] == "!":
                msg = data.data[1:]
                self.iq.send_to_queue(msg, priority=1)
        else:
                self.iq.send_to_queue(data.data)

    def position_write_callback(self, data):
        print data.data
        # if data.data[0]:
        #     msg = data.data[1:]
        #     self.iq.send_to_queue(msg)

    def ja_write_callback(self, data):
        print data.data

    def pump_write_callback(self, data):
        print data.data
        # if data.data[0]:
        #     msg = data.data[1:]
        #     self.iq.send_to_queue(msg)

#ACTIONS Action request for uArm
# Actions
#endACTIONS

    def request_detach(self):
        rospy.loginfo("uArm detach")
        self.iq.send_to_queue("DET")

    def request_attach(self):
        rospy.loginfo("uArm attach")
        self.iq.send_to_queue("ATT")

    def pump_on(self):
        rospy.loginfo("uArm Pump On")
        self.iq.send_to_queue("PUMP_ON")

    def pump_off(self):
        rospy.loginfo("uArm Pump Off")
        self.iq.send_to_queue("PUMP_OFF")

    @ros_try_catch
    def read_analog(self, pin_num):
        return round(self.uarm.get_analog(pin_num), 3)

    @ros_try_catch
    def get_joint_angles(self):
        return self.uarm.get_servo_angle()

    @ros_try_catch
    def read_position(self):
        position = []
        position = self.uarm.get_position()
        return position

    @ros_try_catch
    def read_joint_angles(self):
        angles = []
        angles = self.get_joint_angles()
        return angles

    @ros_try_catch
    def process_command(self, command):
        if command == "PUMP_ON":
            self.uarm.set_pump(1)

        if command == "PUMP_OFF":
            self.uarm.set_pump(0)

        if command == "ATT":
            self.uarm.set_servo_attach()

        if command == "DET":
            self.uarm.set_servo_detach()

        if command[0:3] == "POS":  # and self.playback_active:
            position = map(float, command[3:].split(','))
            self.uarm.set_position(position[0], position[1], position[2])

        if command[0:2] == "WR":
            angle = float(command[2:])
            self.uarm.set_servo_angle(3,angle)

        if command[0:3] == "REL":
            adjust = float(command[3:])
            self.uarm.set_position(x=0, y=0, z=adjust, speed=0, relative=True)

        if command[0:2] == "JA":  # and self.playback_active:
            angle = map(float, command[2:].split(','))
            for i in range(0, len(angle)):
                self.uarm.set_servo_angle(i, angle[i])

        if command == "BEEP":
            self.uarm.set_buzzer(10000, 0.1)
            self.playback_active = False

        if command == "STOP":
            self.iq.filter_queue(msg_filter="READ")
            time.sleep(0.5)
            self.iq.filter_queue(msg_filter="JA")

            # if command[0:4] == "LOAD":
            #     self.load_playback_data(command[4:])

            # if command == "PLAY":
            #     if self.playback_data:
            #         self.playback_active = True
            #         self.playback_thread = threading.Thread(target=self.playback)
            #         self.playback_thread.daemon = True

            # self.playback_thread.start()
<commit_msg>ROSifying<commit_after>#!/usr/bin/env python
import time
import threading
import os
import pyuarm
import rospy
import ThreadSafePriorityQueue as tspq
from uarm_decorators import *

from std_msgs.msg import String, Bool
from std_msgs.msg import Float32MultiArray as Array

class UarmMetal():

    def __init__(self):
        self.uarm = None
        self.connected = False
        self.ready = False
        self.alive = True

        self.ros_rate = None
        self.ros_hz = 0
        self.read_pos = None
        self.read_ja = None
        self.read_AI = None

        self.settings = []

        self.parameter_monitor_thread = None

        self.uarm_read_thread = None
        self.string_read_pub = None
        self.rq = tspq.ThreadSafePriorityQueue("read_queue")

        self.uarm_interface_thread = None
        self.iq = tspq.ThreadSafePriorityQueue("interface_queue")

        self.pos_pub = None
        self.ja_pub = None
        self.ai_pub = None

        self.playback_thread = None
        self.playback_active = False
        self.playback_data = []
        self.loading = False

        self.ja = []

#INIT Initialisation
# Initialisation
#endINIT

    def get_setting(self, name, string_val=False, list_type=False):
        for line in self.settings:
            if line[0] == name:
                if string_val:
                    return line[1]
                else:
                    if list_type:
                        try:
                            return map(float, line[1:-1])
                        except Exception as e:
                            print e
                    else:
                        return float(line[1])

    def connect(self):
        try:
            self.uarm = pyuarm.get_uarm()
            self.connected = True
            self.load_parameters()
            self.connect_to_ROS()
            self.start_threads()
            rospy.loginfo("Connected")
            self.ready = True
        except Exception as e:
            self.connected = False
            err = str(e.message)
            rospy.logerr("Connection error: " + err)
            rospy.signal_shutdown("Connection error")

    def shutdown(self):
        rospy.loginfo("Shutdown function call")
        rospy.signal_shutdown("Shutdown function call")
        start_shutdown = time.time()
        while self.uarm_interface_thread.is_alive() or self.uarm_read_thread.is_alive():
            self.iq.send_to_queue("SHUTDOWN", priority=1)
            self.rq.send_to_queue("SHUTDOWN", priority=1)
            time.sleep(0.5)
            if time.time()-start_shutdown > 5:
                break
        self.alive = False
        self.uarm.disconnect()

    def load_parameters(self):
        rospy.loginfo("Loading parameters")

        dir_path = os.path.dirname(os.path.realpath(__file__))
        f = open(dir_path + "/settings.txt")
        self.settings = []
        for line in f:
            self.settings.append(line.split(','))
        f.close()

        self.ros_hz = self.get_setting("ros_hz")
        self.read_pos = self.get_setting("read_pos")
        self.read_ja = self.get_setting("read_ja")
        self.read_AI = self.get_setting("read_AI", list_type=True)

        rospy.set_param('uarm_metal/read_position', self.read_pos)
        rospy.set_param('uarm_metal/read_joint_angles', self.read_ja)
        rospy.set_param('uarm_metal/read_AI', self.read_AI)

    def connect_to_ROS(self):
        self.string_read_pub = rospy.Publisher('uarm_metal/string_read', String, queue_size=10)
        self.pos_pub = rospy.Publisher('uarm_metal/position_read', Array, queue_size=10)
        self.ja_pub = rospy.Publisher('uarm_metal/joint_angles_read', Array, queue_size=10)
        self.ai_pub = rospy.Publisher('uarm_metal/analog_inputs_read', String, queue_size=10)

        rospy.Subscriber("uarm_metal/string_write", String, self.string_write_callback, queue_size= 1000)
        rospy.Subscriber("uarm_metal/position_write", Array, self.position_write_callback, queue_size=1000)
        rospy.Subscriber("uarm_metal/joint_angles_write", Array, self.ja_write_callback, queue_size=1000)
        rospy.Subscriber("uarm_metal/pump", Bool, self.pump_write_callback, queue_size=1000)
        rospy.init_node('uarm_node', anonymous=True)
        self.ros_rate = rospy.Rate(self.ros_hz)

        rospy.loginfo("Done loading parameters.")

    def parameter_monitor(self):
        rospy.loginfo("Parameter monitor running.")
        while True and (rospy.is_shutdown() is False):
            self.read_pos = int(rospy.get_param('uarm_metal/read_position'))
            self.read_ja = int(rospy.get_param('uarm_metal/read_joint_angles'))
            self.read_AI = map(int, rospy.get_param('uarm_metal/read_AI'))
            time.sleep(0.5)

        rospy.loginfo("Parameter monitor shutdown")

    def start_threads(self):
        rospy.loginfo("Starting threads")
        if self.connected is True:
            self.uarm_read_thread = threading.Thread(target=self.uarm_read)
            self.uarm_interface_thread = threading.Thread(target=self.uarm_interface)
            self.parameter_monitor_thread = threading.Thread(target=self.parameter_monitor)

            self.uarm_read_thread.daemon = True
            self.uarm_read_thread.start()

            self.uarm_interface_thread.daemon = True
            self.uarm_interface_thread.start()

            self.parameter_monitor_thread.daemon = True
            self.parameter_monitor_thread.start()

            #self.request_detach()

        else:
            rospy.logerr("Startup error")
            rospy.signal_shutdown("Startup error")

#MAIN Main Threads
# Main threads/functions
#endMAIN

    def get_read_data(self):
        msg = []
        if self.read_pos > 0:
            msg.append(self.read_position())
        if self.read_ja > 0:
            msg.append(self.read_joint_angles())
        if self.read_AI[0] > 0:
            reading = []
            for i in self.read_AI[1:]:
                reading.append(self.read_analog(i))
            msg.append(reading[:])
        return msg

    def uarm_interface(self):
        rospy.loginfo("uarm_interface running")
        while True and (rospy.is_shutdown() is False):
            request = self.iq.get_from_queue()

            if request == "READ":
                curr_vals = self.get_read_data()
                try:
                    self.rq.send_to_queue(curr_vals)
                except Exception as e:
                    print "Error: ", e
                    rospy.logerr("Error writing to queue. Queue probably shutdown.")
                    break

                if self.playback_active is False and self.loading is False:
                    self.iq.send_to_queue("READ")

            elif request == "SHUTDOWN":
                break
            else:
                self.process_command(request)
                if self.playback_active is False and self.loading is False:
                    self.iq.send_to_queue("READ")

        rospy.loginfo("uarm_interface shutdown")
        self.shutdown()

    def uarm_read(self):
        rospy.loginfo("uarm_read running")
        while True and (rospy.is_shutdown() is False):
            robot_values = self.rq.get_from_queue(blocking=False)
            if robot_values:
                if robot_values == "SHUTDOWN":
                    rospy.logwarn("sending shutdown signal")
                    rospy.signal_shutdown("Normal Shutdown Procedure")
                    break
                else:
                    msg = str(robot_values)
                    msg = msg.translate(None, '[]')

                    if str(msg)[0:5] == "False":
                        rospy.logerr("uArm read error")
                        rospy.signal_shutdown("uArm read error")
                        self.uarm.disconnect()
                        break
                    try:
                        self.string_read_pub.publish(msg)
                        if self.read_pos > 0:
                            pos_data = robot_values[0]
                            #pos_msg = map(float,str(robot_values[0]).translate(None,'[]').split(','))
                            self.pos_pub.publish(len(pos_data),pos_data)
                        if self.read_ja > 0:
                            ja_data = robot_values[self.read_pos]
                            #print ja_data
                            #ja_msg = map(float,str(ja_data).translate(None, '[]'))
                            self.ja_pub.publish(len(ja_data),ja_data)
                        if self.read_AI[0] > 0:
                            self.ai_pub.publish(str(robot_values[self.read_pos +
                                                                 self.read_ja]).translate(None, '[]'))

                    except Exception as e:
                        err_msg = "Failed to publish data: ", e.message
                        rospy.logerr(err_msg)
                        rospy.signal_shutdown("Error Shutdown Procedure")
                        break
        time.sleep(1.0/self.ros_hz)
        rospy.loginfo("uarm_read shutdown")

    def string_write_callback(self, data):
        if data.data == "CLEAR":
                self.iq.get_from_queue(all_msgs=True)
                self.rq.get_from_queue(all_msgs=True)

        elif data.data[0] == "!":
                msg = data.data[1:]
                self.iq.send_to_queue(msg, priority=1)
        else:
                self.iq.send_to_queue(data.data)

    def position_write_callback(self, data):
        print data.data
        # if data.data[0]:
        #     msg = data.data[1:]
        #     self.iq.send_to_queue(msg)

    def ja_write_callback(self, data):
        print data.data

    def pump_write_callback(self, data):
        print data.data
        # if data.data[0]:
        #     msg = data.data[1:]
        #     self.iq.send_to_queue(msg)

#ACTIONS Action request for uArm
# Actions
#endACTIONS

    def request_detach(self):
        rospy.loginfo("uArm detach")
        self.iq.send_to_queue("DET")

    def request_attach(self):
        rospy.loginfo("uArm attach")
        self.iq.send_to_queue("ATT")

    def pump_on(self):
        rospy.loginfo("uArm Pump On")
        self.iq.send_to_queue("PUMP_ON")

    def pump_off(self):
        rospy.loginfo("uArm Pump Off")
        self.iq.send_to_queue("PUMP_OFF")

    @ros_try_catch
    def read_analog(self, pin_num):
        return round(self.uarm.get_analog(pin_num), 3)

    @ros_try_catch
    def get_joint_angles(self):
        return self.uarm.get_servo_angle()

    @ros_try_catch
    def read_position(self):
        position = []
        position = self.uarm.get_position()
        return position

    @ros_try_catch
    def read_joint_angles(self):
        angles = []
        angles = self.get_joint_angles()
        return angles

    @ros_try_catch
    def process_command(self, command):
        if command == "PUMP_ON":
            self.uarm.set_pump(1)

        if command == "PUMP_OFF":
            self.uarm.set_pump(0)

        if command == "ATT":
            self.uarm.set_servo_attach()

        if command == "DET":
            self.uarm.set_servo_detach()

        if command[0:3] == "POS":  # and self.playback_active:
            position = map(float, command[3:].split(','))
            self.uarm.set_position(position[0], position[1], position[2])

        if command[0:2] == "WR":
            angle = float(command[2:])
            self.uarm.set_servo_angle(3,angle)

        if command[0:3] == "REL":
            adjust = float(command[3:])
            self.uarm.set_position(x=0, y=0, z=adjust, speed=0, relative=True)

        if command[0:2] == "JA":  # and self.playback_active:
            angle = map(float, command[2:].split(','))
            for i in range(0, len(angle)):
                self.uarm.set_servo_angle(i, angle[i])

        if command == "BEEP":
            self.uarm.set_buzzer(10000, 0.1)
            self.playback_active = False

        if command == "STOP":
            self.iq.filter_queue(msg_filter="READ")
            time.sleep(0.5)
            self.iq.filter_queue(msg_filter="JA")

            # if command[0:4] == "LOAD":
            #     self.load_playback_data(command[4:])

            # if command == "PLAY":
            #     if self.playback_data:
            #         self.playback_active = True
            #         self.playback_thread = threading.Thread(target=self.playback)
            #         self.playback_thread.daemon = True

            # self.playback_thread.start()
<|endoftext|>


<commit_before>##
# Copyright (c) 2008-2010 Sprymix Inc.
# All rights reserved.
#
# See LICENSE for details.
##

from semantix.ast import dump
import copy

class ASTError(Exception):
    pass

class MetaAST(type):
    counter = 0

    def __init__(cls, name, bases, dct):
        super().__init__(name, bases, dct)

        MetaAST.counter += 1

        fields = list()
        for i in range(0, len(cls.__mro__) - 1):
            lst = getattr(cls, '_' + cls.__mro__[i].__name__ + '__fields', [])
            for item in lst:
                if item not in fields:
                    fields.append(item)

        code = 'def _init_fields(self):\n'
        code += '\tself._id = %d\n' % MetaAST.counter

        _fields = []
        if fields:
            for field in fields:
                if field.startswith('*'):
                    field = field[1:]
                    code += '\tself.%s = list()\n' % field

                elif field.startswith('#'):
                    field = field[1:]
                    code += '\tself.%s = dict()\n' % field

                elif field.startswith('!'):
                    field = field[1:]
                    code += '\tself.%s = set()\n' % field

                else:
                    code += '\tself.%s = None\n' % field

                _fields.append(field)

        context = {}
        exec(code, context)
        func = context['_init_fields']

        setattr(cls, '_fields', _fields)
        setattr(cls, '_init_fields', func)

class AST(object, metaclass=MetaAST):
    __fields = []

    def __init__(self, **kwargs):
        self.parent = None
        self._init_fields()

        for arg, value in kwargs.items():
            if hasattr(self, arg):
                if isinstance(value, AST):
                    value.parent = self
                elif isinstance(value, list):
                    for v in value:
                        if isinstance(v, AST):
                            v.parent = self

                setattr(self, arg, value)
            else:
                raise ASTError('cannot set attribute "%s" in ast class "%s"' %
                               (arg, self.__class__.__name__))

        if 'parent' in kwargs:
            self.parent = kwargs['parent']

    def dump(self, *args, **kwargs):
        if 'pretty' in kwargs and kwargs['pretty']:
            del kwargs['pretty']
            return dump.pretty_dump(self, *args, **kwargs)
        else:
            return dump.dump(self, *args, **kwargs)

class ASTBlockNode(AST):
    __fields = ['*body']

    def append_node(self, node):
        if isinstance(node, list):
            for n in node:
                self.append_node(n)
        else:
            node.parent = self
            self.body.append(node)

def fix_parent_links(node):
    for field, value in iter_fields(node):
        if isinstance(value, list):
            for n in value:
                if isinstance(n, AST):
                    n.parent = node
                    fix_parent_links(n)

        elif isinstance(value, AST):
            value.parent = node
            fix_parent_links(value)

    return node

def iter_fields(node):
    for f in node._fields:
        try:
            yield f, getattr(node, f)
        except AttributeError:
            pass
<commit_msg>ast.base: Add support for weakref.WeakSet field type<commit_after>##
# Copyright (c) 2008-2010 Sprymix Inc.
# All rights reserved.
#
# See LICENSE for details.
##

from semantix.ast import dump
import weakref

class ASTError(Exception):
    pass

class MetaAST(type):
    counter = 0

    def __init__(cls, name, bases, dct):
        super().__init__(name, bases, dct)

        MetaAST.counter += 1

        fields = list()
        for i in range(0, len(cls.__mro__) - 1):
            lst = getattr(cls, '_' + cls.__mro__[i].__name__ + '__fields', [])
            for item in lst:
                if item not in fields:
                    fields.append(item)

        code = 'def _init_fields(self):\n'
        code += '\tself._id = %d\n' % MetaAST.counter

        _fields = []
        if fields:
            for field in fields:
                if field.startswith('*'):
                    field = field[1:]
                    code += '\tself.%s = list()\n' % field

                elif field.startswith('#'):
                    field = field[1:]
                    code += '\tself.%s = dict()\n' % field

                elif field.startswith('!!'):
                    field = field[2:]
                    code += '\tself.%s = weakref.WeakSet()\n' % field

                elif field.startswith('!'):
                    field = field[1:]
                    code += '\tself.%s = set()\n' % field

                else:
                    code += '\tself.%s = None\n' % field

                _fields.append(field)

        context = {'weakref': weakref}
        exec(code, context)
        func = context['_init_fields']

        setattr(cls, '_fields', _fields)
        setattr(cls, '_init_fields', func)

class AST(object, metaclass=MetaAST):
    __fields = []

    def __init__(self, **kwargs):
        self.parent = None
        self._init_fields()

        for arg, value in kwargs.items():
            if hasattr(self, arg):
                if isinstance(value, AST):
                    value.parent = self
                elif isinstance(value, list):
                    for v in value:
                        if isinstance(v, AST):
                            v.parent = self

                setattr(self, arg, value)
            else:
                raise ASTError('cannot set attribute "%s" in ast class "%s"' %
                               (arg, self.__class__.__name__))

        if 'parent' in kwargs:
            self.parent = kwargs['parent']

    def dump(self, *args, **kwargs):
        if 'pretty' in kwargs and kwargs['pretty']:
            del kwargs['pretty']
            return dump.pretty_dump(self, *args, **kwargs)
        else:
            return dump.dump(self, *args, **kwargs)

class ASTBlockNode(AST):
    __fields = ['*body']

    def append_node(self, node):
        if isinstance(node, list):
            for n in node:
                self.append_node(n)
        else:
            node.parent = self
            self.body.append(node)

def fix_parent_links(node):
    for field, value in iter_fields(node):
        if isinstance(value, list):
            for n in value:
                if isinstance(n, AST):
                    n.parent = node
                    fix_parent_links(n)

        elif isinstance(value, AST):
            value.parent = node
            fix_parent_links(value)

    return node

def iter_fields(node):
    for f in node._fields:
        try:
            yield f, getattr(node, f)
        except AttributeError:
            pass
<|endoftext|>


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

import io
import os
from os.path import abspath, dirname, exists, getmtime, join, realpath
os.environ['SECUREDROP_ENV'] = 'test'  # noqa
import i18n_tool
from mock import patch
import pytest
import shutil
import signal
import time

from sh import sed, msginit, pybabel, git, touch

class TestI18NTool(object):

    def setup(self):
        self.dir = abspath(dirname(realpath(__file__)))

    def test_main(self, tmpdir, caplog):
        with pytest.raises(SystemExit):
            i18n_tool.I18NTool().main(['--help'])

        tool = i18n_tool.I18NTool()
        with patch.object(tool,
                          'setup_verbosity',
                          side_effect=KeyboardInterrupt):
            assert tool.main([
                'translate-messages',
                '--translations-dir', str(tmpdir)
            ]) == signal.SIGINT

    def test_translate_desktop_l10n(self, tmpdir):
        in_files = {}
        for what in ('source', 'journalist'):
            in_files[what] = join(str(tmpdir), what + '.desktop.in')
            shutil.copy(join(self.dir, 'i18n/' + what + '.desktop.in'),
                        in_files[what])
        i18n_tool.I18NTool().main([
            '--verbose',
            'translate-desktop',
            '--translations-dir', str(tmpdir),
            '--sources', in_files['source'],
            '--extract-update',
        ])
        messages_file = join(str(tmpdir), 'desktop.pot')
        assert exists(messages_file)
        with io.open(messages_file) as fobj:
            pot = fobj.read()
            assert 'SecureDrop Source Interfaces' in pot
        # pretend this happened a few seconds ago
        few_seconds_ago = time.time() - 60
        os.utime(messages_file, (few_seconds_ago, few_seconds_ago))

        i18n_file = join(str(tmpdir), 'source.desktop')

        #
        # Extract+update but do not compile
        #
        old_messages_mtime = getmtime(messages_file)
        assert not exists(i18n_file)
        i18n_tool.I18NTool().main([
            '--verbose',
            'translate-desktop',
            '--translations-dir', str(tmpdir),
            '--sources', ",".join(in_files.values()),
            '--extract-update',
        ])
        assert not exists(i18n_file)
        current_messages_mtime = getmtime(messages_file)
        assert old_messages_mtime < current_messages_mtime

        locale = 'fr_FR'
        po_file = join(str(tmpdir), locale + ".po")
        msginit(
            '--no-translator',
            '--locale', locale,
            '--output', po_file,
            '--input', messages_file)
        source = 'SecureDrop Source Interfaces'
        sed('-i', '-e',
            '/{}/,+1s/msgstr ""/msgstr "SOURCE FR"/'.format(source),
            po_file)
        assert exists(po_file)

        #
        # Compile but do not extract+update
        #
        old_messages_mtime = current_messages_mtime
        i18n_tool.I18NTool().main([
            '--verbose',
            'translate-desktop',
            '--translations-dir', str(tmpdir),
            '--sources', ",".join(in_files.values() + ['BOOM']),
            '--compile',
        ])
        assert old_messages_mtime == getmtime(messages_file)
        with io.open(po_file) as fobj:
            po = fobj.read()
            assert 'SecureDrop Source Interfaces' in po
            assert 'SecureDrop Journalist Interfaces' not in po
        with io.open(i18n_file) as fobj:
            i18n = fobj.read()
            assert 'SOURCE FR' in i18n

    def test_translate_messages_l10n(self, tmpdir):
        source = [
            join(self.dir, 'i18n/code.py'),
            join(self.dir, 'i18n/template.html'),
        ]
        args = [
            '--verbose',
            'translate-messages',
            '--translations-dir', str(tmpdir),
            '--mapping', join(self.dir, 'i18n/babel.cfg'),
            '--sources', ",".join(source),
            '--extract-update',
            '--compile',
        ]
        i18n_tool.I18NTool().main(args)
        messages_file = join(str(tmpdir), 'messages.pot')
        assert exists(messages_file)
        with io.open(messages_file) as fobj:
            pot = fobj.read()
            assert 'code hello i18n' in pot
            assert 'template hello i18n' in pot

        locale = 'en_US'
        locale_dir = join(str(tmpdir), locale)
        pybabel('init', '-i', messages_file, '-d', str(tmpdir), '-l', locale)
        mo_file = join(locale_dir, 'LC_MESSAGES/messages.mo')
        assert not exists(mo_file)
        i18n_tool.I18NTool().main(args)
        assert exists(mo_file)
        with io.open(mo_file, mode='rb') as fobj:
            mo = fobj.read()
            assert 'code hello i18n' in mo
            assert 'template hello i18n' in mo

    def test_translate_messages_compile_arg(self, tmpdir):
        args = [
            '--verbose',
            'translate-messages',
            '--translations-dir', str(tmpdir),
            '--mapping', join(self.dir, 'i18n/babel.cfg'),
        ]
        i18n_tool.I18NTool().main(args + [
            '--sources', join(self.dir, 'i18n/code.py'),
            '--extract-update',
        ])
        messages_file = join(str(tmpdir), 'messages.pot')
        assert exists(messages_file)
        with io.open(messages_file) as fobj:
            pot = fobj.read()
            assert 'code hello i18n' in pot

        locale = 'en_US'
        locale_dir = join(str(tmpdir), locale)
        po_file = join(locale_dir, 'LC_MESSAGES/messages.po')
        pybabel(['init', '-i', messages_file, '-d', str(tmpdir), '-l', locale])
        assert exists(po_file)
        # pretend this happened a few seconds ago
        few_seconds_ago = time.time() - 60
        os.utime(po_file, (few_seconds_ago, few_seconds_ago))

        mo_file = join(locale_dir, 'LC_MESSAGES/messages.mo')

        #
        # Extract+update but do not compile
        #
        old_po_mtime = getmtime(po_file)
        assert not exists(mo_file)
        i18n_tool.I18NTool().main(args + [
            '--sources', join(self.dir, 'i18n/code.py'),
            '--extract-update',
        ])
        assert not exists(mo_file)
        current_po_mtime = getmtime(po_file)
        assert old_po_mtime < current_po_mtime

        #
        # Compile but do not extract+update
        #
        source = [
            join(self.dir, 'i18n/code.py'),
            join(self.dir, 'i18n/template.html'),
        ]
        old_po_mtime = current_po_mtime
        i18n_tool.I18NTool().main(args + [
            '--sources', ",".join(source),
            '--compile',
        ])
        assert old_po_mtime == getmtime(po_file)
        with io.open(mo_file, mode='rb') as fobj:
            mo = fobj.read()
            assert 'code hello i18n' in mo
            assert 'template hello i18n' not in mo

    def test_require_git_email_name(self, tmpdir):
        k = {'_cwd': str(tmpdir)}
        git('init', **k)
        with pytest.raises(Exception) as excinfo:
            i18n_tool.I18NTool.require_git_email_name(str(tmpdir))
        assert 'please set name' in excinfo.value.message

        git.config('user.email', "you@example.com", **k)
        git.config('user.name', "Your Name", **k)
        assert i18n_tool.I18NTool.require_git_email_name(str(tmpdir))

    def test_update_docs(self, tmpdir, caplog):
        k = {'_cwd': str(tmpdir)}
        git.init(**k)
        git.config('user.email', "you@example.com", **k)
        git.config('user.name', "Your Name", **k)
        os.mkdir(join(str(tmpdir), 'includes'))
        touch('includes/l10n.txt', **k)
        git.add('includes/l10n.txt', **k)
        git.commit('-m', 'init', **k)

        i18n_tool.I18NTool().main([
            '--verbose',
            'update-docs',
            '--documentation-dir', str(tmpdir)])
        assert 'l10n.txt updated' in caplog.text
        caplog.clear()
        i18n_tool.I18NTool().main([
            '--verbose',
            'update-docs',
            '--documentation-dir', str(tmpdir)])
        assert 'l10n.txt already up to date' in caplog.text

    def test_update_from_weblate(self, tmpdir, caplog):
        d = str(tmpdir)
        for repo in ('i18n', 'securedrop'):
            os.mkdir(join(d, repo))
            k = {'_cwd': join(d, repo)}
            git.init(**k)
            git.config('user.email', 'you@example.com', **k)
            git.config('user.name',  u'Loïc Nordhøy', **k)
            touch('README.md', **k)
            git.add('README.md', **k)
            git.commit('-m', 'README', 'README.md', **k)
        for o in os.listdir(join(self.dir, 'i18n')):
            f = join(self.dir, 'i18n', o)
            if os.path.isfile(f):
                shutil.copyfile(f, join(d, 'i18n', o))
            else:
                shutil.copytree(f, join(d, 'i18n', o))
        k = {'_cwd': join(d, 'i18n')}
        git.add('securedrop', 'install_files', **k)
        git.commit('-m', 'init', '-a', **k)
        git.checkout('-b', 'i18n', 'master', **k)

        def r():
            return "".join([str(l) for l in caplog.records])

        #
        # de_DE is not amount the supported languages, it is not taken
        # into account despite the fact that it exists in weblate.
        #
        caplog.clear()
        i18n_tool.I18NTool().main([
            '--verbose',
            'update-from-weblate',
            '--root', join(str(tmpdir), 'securedrop'),
            '--url', join(str(tmpdir), 'i18n'),
            '--supported-languages', 'nl',
        ])
        assert 'l10n: updated nl' in r()
        assert 'l10n: updated de_DE' not in r()

        #
        # de_DE is added but there is no change in the nl translation
        # therefore nothing is done for nl
        #
        caplog.clear()
        i18n_tool.I18NTool().main([
            '--verbose',
            'update-from-weblate',
            '--root', join(str(tmpdir), 'securedrop'),
            '--url', join(str(tmpdir), 'i18n'),
            '--supported-languages', 'nl,de_DE',
        ])
        assert 'l10n: updated nl' not in r()
        assert 'l10n: updated de_DE' in r()

        #
        # nothing new for nl or de_DE: nothing is done
        #
        caplog.clear()
        i18n_tool.I18NTool().main([
            '--verbose',
            'update-from-weblate',
            '--root', join(str(tmpdir), 'securedrop'),
            '--url', join(str(tmpdir), 'i18n'),
            '--supported-languages', 'nl,de_DE',
        ])
        assert 'l10n: updated nl' not in r()
        assert 'l10n: updated de_DE' not in r()
        message = unicode(git('--no-pager', '-C', 'securedrop', 'show',
                              _cwd=d, _encoding='utf-8'))
        assert u"Loïc" in message

        #
        # an update is done to nl in weblate
        #
        k = {'_cwd': join(d, 'i18n')}
        f = 'securedrop/translations/nl/LC_MESSAGES/messages.po'
        sed('-i', '-e', 's/inactiviteit/INACTIVITEIT/', f, **k)
        git.add(f, **k)
        git.config('user.email', 'somone@else.com', **k)
        git.config('user.name', 'Someone Else', **k)
        git.commit('-m', 'translation change', f, **k)

        k = {'_cwd': join(d, 'securedrop')}
        git.config('user.email', 'somone@else.com', **k)
        git.config('user.name', 'Someone Else', **k)

        #
        # the nl translation update from weblate is copied
        # over.
        #
        caplog.clear()
        i18n_tool.I18NTool().main([
            '--verbose',
            'update-from-weblate',
            '--root', join(str(tmpdir), 'securedrop'),
            '--url', join(str(tmpdir), 'i18n'),
            '--supported-languages', 'nl,de_DE',
        ])
        assert 'l10n: updated nl' in r()
        assert 'l10n: updated de_DE' not in r()
        message = unicode(git('--no-pager', '-C', 'securedrop', 'show',
                              _cwd=d))
        assert "Someone Else" in message
        assert u"Loïc" not in message
<commit_msg>test: regression test for #4192<commit_after># -*- coding: utf-8 -*-

import io
import os
from os.path import abspath, dirname, exists, getmtime, join, realpath
os.environ['SECUREDROP_ENV'] = 'test'  # noqa
import i18n_tool
from mock import patch
import pytest
import shutil
import signal
import time

from sh import sed, msginit, pybabel, git, touch

class TestI18NTool(object):

    def setup(self):
        self.dir = abspath(dirname(realpath(__file__)))

    def test_main(self, tmpdir, caplog):
        with pytest.raises(SystemExit):
            i18n_tool.I18NTool().main(['--help'])

        tool = i18n_tool.I18NTool()
        with patch.object(tool,
                          'setup_verbosity',
                          side_effect=KeyboardInterrupt):
            assert tool.main([
                'translate-messages',
                '--translations-dir', str(tmpdir)
            ]) == signal.SIGINT

    def test_translate_desktop_l10n(self, tmpdir):
        in_files = {}
        for what in ('source', 'journalist'):
            in_files[what] = join(str(tmpdir), what + '.desktop.in')
            shutil.copy(join(self.dir, 'i18n/' + what + '.desktop.in'),
                        in_files[what])
        i18n_tool.I18NTool().main([
            '--verbose',
            'translate-desktop',
            '--translations-dir', str(tmpdir),
            '--sources', in_files['source'],
            '--extract-update',
        ])
        messages_file = join(str(tmpdir), 'desktop.pot')
        assert exists(messages_file)
        with io.open(messages_file) as fobj:
            pot = fobj.read()
            assert 'SecureDrop Source Interfaces' in pot
        # pretend this happened a few seconds ago
        few_seconds_ago = time.time() - 60
        os.utime(messages_file, (few_seconds_ago, few_seconds_ago))

        i18n_file = join(str(tmpdir), 'source.desktop')

        #
        # Extract+update but do not compile
        #
        old_messages_mtime = getmtime(messages_file)
        assert not exists(i18n_file)
        i18n_tool.I18NTool().main([
            '--verbose',
            'translate-desktop',
            '--translations-dir', str(tmpdir),
            '--sources', ",".join(in_files.values()),
            '--extract-update',
        ])
        assert not exists(i18n_file)
        current_messages_mtime = getmtime(messages_file)
        assert old_messages_mtime < current_messages_mtime

        locale = 'fr_FR'
        po_file = join(str(tmpdir), locale + ".po")
        msginit(
            '--no-translator',
            '--locale', locale,
            '--output', po_file,
            '--input', messages_file)
        source = 'SecureDrop Source Interfaces'
        sed('-i', '-e',
            '/{}/,+1s/msgstr ""/msgstr "SOURCE FR"/'.format(source),
            po_file)
        assert exists(po_file)

        # Regression test to trigger bug introduced when adding
        # Romanian as an accepted language.
        locale = 'ro'
        po_file = join(str(tmpdir), locale + ".po")
        msginit(
            '--no-translator',
            '--locale', locale,
            '--output', po_file,
            '--input', messages_file)
        source = 'SecureDrop Source Interfaces'
        sed('-i', '-e',
            '/{}/,+1s/msgstr ""/msgstr "SOURCE RO"/'.format(source),
            po_file)
        assert exists(po_file)

        #
        # Compile but do not extract+update
        #
        old_messages_mtime = current_messages_mtime
        i18n_tool.I18NTool().main([
            '--verbose',
            'translate-desktop',
            '--translations-dir', str(tmpdir),
            '--sources', ",".join(in_files.values() + ['BOOM']),
            '--compile',
        ])
        assert old_messages_mtime == getmtime(messages_file)
        with io.open(po_file) as fobj:
            po = fobj.read()
            assert 'SecureDrop Source Interfaces' in po
            assert 'SecureDrop Journalist Interfaces' not in po
        with io.open(i18n_file) as fobj:
            i18n = fobj.read()
            assert 'SOURCE FR' in i18n

    def test_translate_messages_l10n(self, tmpdir):
        source = [
            join(self.dir, 'i18n/code.py'),
            join(self.dir, 'i18n/template.html'),
        ]
        args = [
            '--verbose',
            'translate-messages',
            '--translations-dir', str(tmpdir),
            '--mapping', join(self.dir, 'i18n/babel.cfg'),
            '--sources', ",".join(source),
            '--extract-update',
            '--compile',
        ]
        i18n_tool.I18NTool().main(args)
        messages_file = join(str(tmpdir), 'messages.pot')
        assert exists(messages_file)
        with io.open(messages_file) as fobj:
            pot = fobj.read()
            assert 'code hello i18n' in pot
            assert 'template hello i18n' in pot

        locale = 'en_US'
        locale_dir = join(str(tmpdir), locale)
        pybabel('init', '-i', messages_file, '-d', str(tmpdir), '-l', locale)
        mo_file = join(locale_dir, 'LC_MESSAGES/messages.mo')
        assert not exists(mo_file)
        i18n_tool.I18NTool().main(args)
        assert exists(mo_file)
        with io.open(mo_file, mode='rb') as fobj:
            mo = fobj.read()
            assert 'code hello i18n' in mo
            assert 'template hello i18n' in mo

    def test_translate_messages_compile_arg(self, tmpdir):
        args = [
            '--verbose',
            'translate-messages',
            '--translations-dir', str(tmpdir),
            '--mapping', join(self.dir, 'i18n/babel.cfg'),
        ]
        i18n_tool.I18NTool().main(args + [
            '--sources', join(self.dir, 'i18n/code.py'),
            '--extract-update',
        ])
        messages_file = join(str(tmpdir), 'messages.pot')
        assert exists(messages_file)
        with io.open(messages_file) as fobj:
            pot = fobj.read()
            assert 'code hello i18n' in pot

        locale = 'en_US'
        locale_dir = join(str(tmpdir), locale)
        po_file = join(locale_dir, 'LC_MESSAGES/messages.po')
        pybabel(['init', '-i', messages_file, '-d', str(tmpdir), '-l', locale])
        assert exists(po_file)
        # pretend this happened a few seconds ago
        few_seconds_ago = time.time() - 60
        os.utime(po_file, (few_seconds_ago, few_seconds_ago))

        mo_file = join(locale_dir, 'LC_MESSAGES/messages.mo')

        #
        # Extract+update but do not compile
        #
        old_po_mtime = getmtime(po_file)
        assert not exists(mo_file)
        i18n_tool.I18NTool().main(args + [
            '--sources', join(self.dir, 'i18n/code.py'),
            '--extract-update',
        ])
        assert not exists(mo_file)
        current_po_mtime = getmtime(po_file)
        assert old_po_mtime < current_po_mtime

        #
        # Compile but do not extract+update
        #
        source = [
            join(self.dir, 'i18n/code.py'),
            join(self.dir, 'i18n/template.html'),
        ]
        old_po_mtime = current_po_mtime
        i18n_tool.I18NTool().main(args + [
            '--sources', ",".join(source),
            '--compile',
        ])
        assert old_po_mtime == getmtime(po_file)
        with io.open(mo_file, mode='rb') as fobj:
            mo = fobj.read()
            assert 'code hello i18n' in mo
            assert 'template hello i18n' not in mo

    def test_require_git_email_name(self, tmpdir):
        k = {'_cwd': str(tmpdir)}
        git('init', **k)
        with pytest.raises(Exception) as excinfo:
            i18n_tool.I18NTool.require_git_email_name(str(tmpdir))
        assert 'please set name' in excinfo.value.message

        git.config('user.email', "you@example.com", **k)
        git.config('user.name', "Your Name", **k)
        assert i18n_tool.I18NTool.require_git_email_name(str(tmpdir))

    def test_update_docs(self, tmpdir, caplog):
        k = {'_cwd': str(tmpdir)}
        git.init(**k)
        git.config('user.email', "you@example.com", **k)
        git.config('user.name', "Your Name", **k)
        os.mkdir(join(str(tmpdir), 'includes'))
        touch('includes/l10n.txt', **k)
        git.add('includes/l10n.txt', **k)
        git.commit('-m', 'init', **k)

        i18n_tool.I18NTool().main([
            '--verbose',
            'update-docs',
            '--documentation-dir', str(tmpdir)])
        assert 'l10n.txt updated' in caplog.text
        caplog.clear()
        i18n_tool.I18NTool().main([
            '--verbose',
            'update-docs',
            '--documentation-dir', str(tmpdir)])
        assert 'l10n.txt already up to date' in caplog.text

    def test_update_from_weblate(self, tmpdir, caplog):
        d = str(tmpdir)
        for repo in ('i18n', 'securedrop'):
            os.mkdir(join(d, repo))
            k = {'_cwd': join(d, repo)}
            git.init(**k)
            git.config('user.email', 'you@example.com', **k)
            git.config('user.name',  u'Loïc Nordhøy', **k)
            touch('README.md', **k)
            git.add('README.md', **k)
            git.commit('-m', 'README', 'README.md', **k)
        for o in os.listdir(join(self.dir, 'i18n')):
            f = join(self.dir, 'i18n', o)
            if os.path.isfile(f):
                shutil.copyfile(f, join(d, 'i18n', o))
            else:
                shutil.copytree(f, join(d, 'i18n', o))
        k = {'_cwd': join(d, 'i18n')}
        git.add('securedrop', 'install_files', **k)
        git.commit('-m', 'init', '-a', **k)
        git.checkout('-b', 'i18n', 'master', **k)

        def r():
            return "".join([str(l) for l in caplog.records])

        #
        # de_DE is not amount the supported languages, it is not taken
        # into account despite the fact that it exists in weblate.
        #
        caplog.clear()
        i18n_tool.I18NTool().main([
            '--verbose',
            'update-from-weblate',
            '--root', join(str(tmpdir), 'securedrop'),
            '--url', join(str(tmpdir), 'i18n'),
            '--supported-languages', 'nl',
        ])
        assert 'l10n: updated nl' in r()
        assert 'l10n: updated de_DE' not in r()

        #
        # de_DE is added but there is no change in the nl translation
        # therefore nothing is done for nl
        #
        caplog.clear()
        i18n_tool.I18NTool().main([
            '--verbose',
            'update-from-weblate',
            '--root', join(str(tmpdir), 'securedrop'),
            '--url', join(str(tmpdir), 'i18n'),
            '--supported-languages', 'nl,de_DE',
        ])
        assert 'l10n: updated nl' not in r()
        assert 'l10n: updated de_DE' in r()

        #
        # nothing new for nl or de_DE: nothing is done
        #
        caplog.clear()
        i18n_tool.I18NTool().main([
            '--verbose',
            'update-from-weblate',
            '--root', join(str(tmpdir), 'securedrop'),
            '--url', join(str(tmpdir), 'i18n'),
            '--supported-languages', 'nl,de_DE',
        ])
        assert 'l10n: updated nl' not in r()
        assert 'l10n: updated de_DE' not in r()
        message = unicode(git('--no-pager', '-C', 'securedrop', 'show',
                              _cwd=d, _encoding='utf-8'))
        assert u"Loïc" in message

        #
        # an update is done to nl in weblate
        #
        k = {'_cwd': join(d, 'i18n')}
        f = 'securedrop/translations/nl/LC_MESSAGES/messages.po'
        sed('-i', '-e', 's/inactiviteit/INACTIVITEIT/', f, **k)
        git.add(f, **k)
        git.config('user.email', 'somone@else.com', **k)
        git.config('user.name', 'Someone Else', **k)
        git.commit('-m', 'translation change', f, **k)

        k = {'_cwd': join(d, 'securedrop')}
        git.config('user.email', 'somone@else.com', **k)
        git.config('user.name', 'Someone Else', **k)

        #
        # the nl translation update from weblate is copied
        # over.
        #
        caplog.clear()
        i18n_tool.I18NTool().main([
            '--verbose',
            'update-from-weblate',
            '--root', join(str(tmpdir), 'securedrop'),
            '--url', join(str(tmpdir), 'i18n'),
            '--supported-languages', 'nl,de_DE',
        ])
        assert 'l10n: updated nl' in r()
        assert 'l10n: updated de_DE' not in r()
        message = unicode(git('--no-pager', '-C', 'securedrop', 'show',
                              _cwd=d))
        assert "Someone Else" in message
        assert u"Loïc" not in message
<|endoftext|>


<commit_before>import json
import os
import os.path

class ConfigManager():
	_caches = {}
	def __init__(self, configPath = "configs/", overrideCache = False):
		if os.path.isdir(configPath):
			self.configPath = configPath
		else:
			raise IOError("Config Path does not eixst")

		if not overrideCache and configPath in ConfigManager._caches:
			self._cache = ConfigManager._caches['path']
		else:
			self._cache = {}

		self._configs = {}
		self._syncCache()
		self.getConfigs()

	def __getitem__(self, key):
		try:
			return self._configs[key]
		except KeyError:
			self.syncCache()
			return self._configs[key]

	#Recursive function to get all files. Sub is the relative path from the root config dir.
	def getConfigs(self, path = None, sub = "", overrideCache = False):
		if path == None:
			path = self.configPath
		files = os.listdir(path)
		for item in files:
			#Ignore hidden files.
			if item[0] == ".":
				continue

			#Remove the .json handle from the name
			name = item.replace(".json", "")
			finalName = os.path.join(sub, name)

			#If it's a directory, run this function again within that directory
			if os.path.isdir(os.path.join(path, item)):
				self.getConfigs(path = os.path.join(path, item), sub = os.path.join(sub, item))
			#If we already have something from the cache, or added in previously, skip it.
			elif overrideCache or finalName not in self._configs:
				#Read in the file
				f = open(os.path.join(path, item), "r")
				#Check if it's JSON. If it is, it will be parsed.
				parsed = self.parseConfig(f.read())
				f.close()
				if parsed != None:
					self.addConfig(finalName, parsed)
	#Returns parsed JSON if config is valid JSON, otherwise, return Noen
	def parseConfig(self, config):
		try:
			return json.loads(config)
		except ValueError:
			return None

	def addConfig(self, name, contents):
		self._configs[name] = contents
		self._cache[name] = contents

	def _syncCache(self):
		unmatchedKeys = [key for key in self._cache.keys() if key not in self._configs]
		for key in unmatchedKeys:
			self._configs[key] = self._cache[key]
<commit_msg>Change IOError to ValueError and add isfile check<commit_after>import json
import os
import os.path

class ConfigManager():
	_caches = {}
	def __init__(self, configPath = "configs/", overrideCache = False):
		if os.path.isdir(configPath):
			self.configPath = configPath
		else if os.path.isfile(configPath):
			raise ValueError("configPath is a file, expected directory.")
		else:
			raise ValueError("configPath does not eixst.")

		if not overrideCache and configPath in ConfigManager._caches:
			self._cache = ConfigManager._caches['path']
		else:
			self._cache = {}

		self._configs = {}
		self._syncCache()
		self.getConfigs()

	def __getitem__(self, key):
		try:
			return self._configs[key]
		except KeyError:
			self.syncCache()
			return self._configs[key]

	#Recursive function to get all files. Sub is the relative path from the root config dir.
	def getConfigs(self, path = None, sub = "", overrideCache = False):
		if path == None:
			path = self.configPath
		files = os.listdir(path)
		for item in files:
			#Ignore hidden files.
			if item[0] == ".":
				continue

			#Remove the .json handle from the name
			name = item.replace(".json", "")
			finalName = os.path.join(sub, name)

			#If it's a directory, run this function again within that directory
			if os.path.isdir(os.path.join(path, item)):
				self.getConfigs(path = os.path.join(path, item), sub = os.path.join(sub, item))
			#If we already have something from the cache, or added in previously, skip it.
			elif overrideCache or finalName not in self._configs:
				#Read in the file
				f = open(os.path.join(path, item), "r")
				#Check if it's JSON. If it is, it will be parsed.
				parsed = self.parseConfig(f.read())
				f.close()
				if parsed != None:
					self.addConfig(finalName, parsed)
	#Returns parsed JSON if config is valid JSON, otherwise, return Noen
	def parseConfig(self, config):
		try:
			return json.loads(config)
		except ValueError:
			return None

	def addConfig(self, name, contents):
		self._configs[name] = contents
		self._cache[name] = contents

	def _syncCache(self):
		unmatchedKeys = [key for key in self._cache.keys() if key not in self._configs]
		for key in unmatchedKeys:
			self._configs[key] = self._cache[key]
<|endoftext|>


<commit_before>#"!/usr/bin/python
# Pythonic abstraction layer for Nonolith Connect's RESTful API.
# Released under the terms of the BSD license
# (C) 2012 Nonolith Labs, LLC
# Authors:
#   Ian Daniher
#   Kevin Mehall

import httplib, atexit, urllib, json

class CEE:
	def __init__(self, devID = "com.nonolithlabs.cee*", start=True, server="localhost:9003"):
		""" Starts an HTTP connection, determines the target device ID, and optionally starts capture."""
		self.connection = httplib.HTTPConnection(server)

		deviceList = self.request("/rest/v1/devices/")

		for deviceEntry in deviceList.itervalues():
			if deviceEntry['model'] == 'com.nonolithlabs.cee':
				if deviceEntry['id'] == devID or devID == "com.nonolithlabs.cee*":
					break
		else:
			raise Exception('Device not found.')

		self.devID = deviceEntry['id']
		self.deviceResource = "/rest/v1/devices/{0}/".format(self.devID)

		self.getInfo()

		self.stopOnClose = False
		atexit.register(self._onClose)

		if start:
			self.start(True)

	def request(self, path, method='GET', encoding='url', jsonReply=True, **kwds):
		"""Send a request to the server.
			`path` is relative to the device resource if it does not begin with '/'.
			Keyword arguments are passed as POST parameters.
		"""
		if not path.startswith('/'): path = self.deviceResource + path

		#print method, path, kwds

		if method == 'GET':
			self.connection.request(method, path)
		elif method == 'POST' and encoding == 'url':
			headers = {"Content-Type": "application/x-www-form-urlencoded"}
			body = urllib.urlencode(kwds)
			self.connection.request(method, path, body, headers)
		else:
			raise ValueError('Unknown content encoding: '+encoding)

		r = self.connection.getresponse().read()
		if jsonReply:
			r = json.loads(r)
		return r

	def getInfo(self):
		"""Refresh the device metadata"""
		self.devInfo = self.request('')

	def start(self, stopOnClose=False):
		"""Start sampling. If stopOnClose is true, the CEE will stop automatically when python exits."""
		self.request('', 'POST', capture='on')
		self.stopOnClose = stopOnClose

	def pause(self):
		"""Stop sampling."""
		self.request('', 'POST', capture='off')

	def setSampleRate(self, sampleRate):
		"""Set the sample rate of the device"""
		if sampleRate < 1000:
			sampleRate *= 1000

		if sampleRate not in [1000, 5000, 10000, 20000, 40000, 80000, 100000]:
			raise ValueError("Invalid sample rate")

		sampleTime = 1.0 / sampleRate
		if sampleTime == self.devInfo['sampleTime']:
			return True

		if sampleTime < self.devInfo.get('minSampleTime', 1.0/40e3):
			raise ValueError("The device does not support this sample rate.")

		nsamples = int(self.devInfo['samples'] * self.devInfo['sampleTime'] / sampleTime)

		self.request('configuration', 'POST', sampleTime=sampleTime, samples=nsamples)
		self.getInfo()

		if self.stopOnClose:
			self.start(True)

	def _onClose(self):
		if self.stopOnClose:
			self.pause()
		self.connection.close()

	def getOutput(self, channel = "a"):
		""" Return a dictionary containing the output state of a given channel."""
		return self.request('{0}/output'.format(channel))

	def setOutputConstant(self, channel = "a", mode = "d", value = 0):
		""" Set the output state for a given channel.
			'mode' can be 'v' to set voltage, 'i' to set current, or 'd' for high impedance mode.
			'value' is a number either in volts or milliamps specifying the target value."""
		return self.request('{0}/output'.format(channel), 'POST', mode=mode, value=value)

	def setOutputWave(self, channel = "a", mode = "d", value = 0, wave="square", amplitude = 0, frequency = 0, relPhase = 1, phase = 0):
		""" Set the output state for a given channel.
			'mode' can be 'v' to set voltage, 'i' to set current, or 'd' for high impedance mode.
			'value' is a number either in volts or milliamps specifying the center value in AC mode.
			'wave' can be either triangle,' 'square,' or 'sine'.
			'amplitude' determines the maximum offset from center.
			'frequency' is the cycles per second.
			'relPhase' determines whether the starting value is based off of the previous output setting to provide seamless change in frequency.
			'phase' is the phase offset in seconds from the beginning of the stream (relPhase=0) or from the previous source (relPhase=1)."""

		if wave not in ["square", "triangle", "sine"]:
			raise ValueError('Invalid option for "wave"')

		return self.request('{0}/output'.format(channel), 'POST',
			mode = mode,
			wave = wave,
			value = value,
			amplitude = amplitude,
			frequency = frequency,
			relPhase = relPhase,
			phase = phase
		)

	# deprecated alias
	setOutputRepeating = setOutputWave

	def setOutputArbitrary(self, channel = "a", mode = "d", times = [], values = None, repeat=1, phase=-1):
		""" Set the output state for a given channel.
			'mode' can be 'v' to set voltage, 'i' to set current, or 'd' for high impedance mode.
			'times' is a list of times in seconds, or a list of (time, value) tuples if 'values' is None.
			'values' is a list of values, either in V or mA depending on mode, or None if the values are included in the 'times' list.
			'repeat' is the number of times to repeat the waveform. -1 for infinite
			'phase' is the offset of the start time in seconds. -1 means start at the time the source takes effect"""

		if values is not None:
			values = zip(times, values)
		else:
			# because times comes first, so it can be passed positionally
			values = times

		values.sort()

		if len(values) < 1:
			raise ValueError("Arb wave must have at least one point.")

		if values[0][0] != 0:
			raise ValueError("Arb wave first point must have t=0.")

		period = values[-1][0]
		if period == 0 and repeat != 1:
			raise ValueError("Arb wave with repeat must have nonzero period.")

		print values

		points = ','.join(
			"{0}:{1}".format(t,v) for t,v, in values
		)

		return self.request('{0}/output'.format(channel), 'POST',
			mode = mode,
			wave = 'arb',
			points = points,
			repeat = repeat,
			phase = phase
		)

	def setInput(self, channel = "a", vGain = 1, iGain = 1):
		""" Set the input gain for both streams of a given channel."""
		Gains = [0.5,1,2,4,8,16,32,64]
		if iGain == "0.5":
			iGain = float(iGain)
		elif iGain == 0.5:
			pass
		else:
			iGain = int(iGain)
		vGain = int(vGain)
		if vGain not in Gains[1::]:
			raise Exception("Invalid voltage gain.")
		if iGain not in Gains[0:-1]:
			raise Exception("Invalid current gain.")
		options = {"gain_v":vGain, "gain_i":iGain}
		return self.request('{0}/input'.format(channel), 'POST', **options)

	def getInput(self, channel = "a", resample = .01, count = 1, start = None):
		""" Returns a pair of lists indicating the measured state of the specified channel.
			The first list is measured voltage, the second list is measured current.
			Each list contains 'count' samples, averaged over 'resample' seconds, separated by 'resample' seconds.
			'start' is the sample index from which to start measuring."""
		options = {"resample":resample, "count":count, "header":0}
		if start != None:
			options['start'] = start

		response = self.request('{0}/input?{1}'.format(channel, urllib.urlencode(options)), jsonReply=False)

		values = [[float(item) for item in item.split(',')]
			for item in response.split('\n')
			if item != '']
		values = map(list, zip(*values))
		if count == 1:
			return [value[0] for value in values]
		else:
			return values
<commit_msg>fix awg's support for negative currents, all credit to @kevinmehall<commit_after>#"!/usr/bin/python
# Pythonic abstraction layer for Nonolith Connect's RESTful API.
# Released under the terms of the BSD license
# (C) 2012 Nonolith Labs, LLC
# Authors:
#   Ian Daniher
#   Kevin Mehall

import httplib, atexit, urllib, json

class CEE:
	def __init__(self, devID = "com.nonolithlabs.cee*", start=True, server="localhost:9003"):
		""" Starts an HTTP connection, determines the target device ID, and optionally starts capture."""
		self.connection = httplib.HTTPConnection(server)

		deviceList = self.request("/rest/v1/devices/")

		for deviceEntry in deviceList.itervalues():
			if deviceEntry['model'] == 'com.nonolithlabs.cee':
				if deviceEntry['id'] == devID or devID == "com.nonolithlabs.cee*":
					break
		else:
			raise Exception('Device not found.')

		self.devID = deviceEntry['id']
		self.deviceResource = "/rest/v1/devices/{0}/".format(self.devID)

		self.getInfo()

		self.stopOnClose = False
		atexit.register(self._onClose)

		if start:
			self.start(True)

	def request(self, path, method='GET', encoding='url', jsonReply=True, **kwds):
		"""Send a request to the server.
			`path` is relative to the device resource if it does not begin with '/'.
			Keyword arguments are passed as POST parameters.
		"""
		if not path.startswith('/'): path = self.deviceResource + path

		#print method, path, kwds

		if method == 'GET':
			self.connection.request(method, path)
		elif method == 'POST' and encoding == 'url':
			headers = {"Content-Type": "application/x-www-form-urlencoded"}
			body = urllib.urlencode(kwds)
			self.connection.request(method, path, body, headers)
		else:
			raise ValueError('Unknown content encoding: '+encoding)

		r = self.connection.getresponse().read()
		if jsonReply:
			r = json.loads(r)
		return r

	def getInfo(self):
		"""Refresh the device metadata"""
		self.devInfo = self.request('')

	def start(self, stopOnClose=False):
		"""Start sampling. If stopOnClose is true, the CEE will stop automatically when python exits."""
		self.request('', 'POST', capture='on')
		self.stopOnClose = stopOnClose

	def pause(self):
		"""Stop sampling."""
		self.request('', 'POST', capture='off')

	def setSampleRate(self, sampleRate):
		"""Set the sample rate of the device"""
		if sampleRate < 1000:
			sampleRate *= 1000

		if sampleRate not in [1000, 5000, 10000, 20000, 40000, 80000, 100000]:
			raise ValueError("Invalid sample rate")

		sampleTime = 1.0 / sampleRate
		if sampleTime == self.devInfo['sampleTime']:
			return True

		if sampleTime < self.devInfo.get('minSampleTime', 1.0/40e3):
			raise ValueError("The device does not support this sample rate.")

		nsamples = int(self.devInfo['samples'] * self.devInfo['sampleTime'] / sampleTime)

		self.request('configuration', 'POST', sampleTime=sampleTime, samples=nsamples)
		self.getInfo()

		if self.stopOnClose:
			self.start(True)

	def _onClose(self):
		if self.stopOnClose:
			self.pause()
		self.connection.close()

	def getOutput(self, channel = "a"):
		""" Return a dictionary containing the output state of a given channel."""
		return self.request('{0}/output'.format(channel))

	def setOutputConstant(self, channel = "a", mode = "d", value = 0):
		""" Set the output state for a given channel.
			'mode' can be 'v' to set voltage, 'i' to set current, or 'd' for high impedance mode.
			'value' is a number either in volts or milliamps specifying the target value."""
		return self.request('{0}/output'.format(channel), 'POST', mode=mode, value=value)

	def setOutputWave(self, channel = "a", mode = "d", value = 0, wave="square", amplitude = 0, frequency = 0, relPhase = 1, phase = 0):
		""" Set the output state for a given channel.
			'mode' can be 'v' to set voltage, 'i' to set current, or 'd' for high impedance mode.
			'value' is a number either in volts or milliamps specifying the center value in AC mode.
			'wave' can be either triangle,' 'square,' or 'sine'.
			'amplitude' determines the maximum offset from center.
			'frequency' is the cycles per second.
			'relPhase' determines whether the starting value is based off of the previous output setting to provide seamless change in frequency.
			'phase' is the phase offset in seconds from the beginning of the stream (relPhase=0) or from the previous source (relPhase=1)."""

		if wave not in ["square", "triangle", "sine"]:
			raise ValueError('Invalid option for "wave"')

		return self.request('{0}/output'.format(channel), 'POST',
			mode = mode,
			wave = wave,
			value = value,
			amplitude = amplitude,
			frequency = frequency,
			relPhase = relPhase,
			phase = phase
		)

	# deprecated alias
	setOutputRepeating = setOutputWave

	def setOutputArbitrary(self, channel = "a", mode = "d", times = [], values = None, repeat=1, phase=-1):
		""" Set the output state for a given channel.
			'mode' can be 'v' to set voltage, 'i' to set current, or 'd' for high impedance mode.
			'times' is a list of times in seconds, or a list of (time, value) tuples if 'values' is None.
			'values' is a list of values, either in V or mA depending on mode, or None if the values are included in the 'times' list.
			'repeat' is the number of times to repeat the waveform. -1 for infinite
			'phase' is the offset of the start time in seconds. -1 means start at the time the source takes effect"""

		if values is not None:
			values = zip(times, values)
		else:
			# because times comes first, so it can be passed positionally
			values = times

		values.sort(key=lambda x: x[0])

		if len(values) < 1:
			raise ValueError("Arb wave must have at least one point.")

		if values[0][0] != 0:
			raise ValueError("Arb wave first point must have t=0.")

		period = values[-1][0]
		if period == 0 and repeat != 1:
			raise ValueError("Arb wave with repeat must have nonzero period.")

		#print values

		points = ','.join(
			"{0}:{1}".format(t,v) for t,v, in values
		)

		return self.request('{0}/output'.format(channel), 'POST',
			mode = mode,
			wave = 'arb',
			points = points,
			repeat = repeat,
			phase = phase
		)

	def setInput(self, channel = "a", vGain = 1, iGain = 1):
		""" Set the input gain for both streams of a given channel."""
		Gains = [0.5,1,2,4,8,16,32,64]
		if iGain == "0.5":
			iGain = float(iGain)
		elif iGain == 0.5:
			pass
		else:
			iGain = int(iGain)
		vGain = int(vGain)
		if vGain not in Gains[1::]:
			raise Exception("Invalid voltage gain.")
		if iGain not in Gains[0:-1]:
			raise Exception("Invalid current gain.")
		options = {"gain_v":vGain, "gain_i":iGain}
		return self.request('{0}/input'.format(channel), 'POST', **options)

	def getInput(self, channel = "a", resample = .01, count = 1, start = None):
		""" Returns a pair of lists indicating the measured state of the specified channel.
			The first list is measured voltage, the second list is measured current.
			Each list contains 'count' samples, averaged over 'resample' seconds, separated by 'resample' seconds.
			'start' is the sample index from which to start measuring."""
		options = {"resample":resample, "count":count, "header":0}
		if start != None:
			options['start'] = start

		response = self.request('{0}/input?{1}'.format(channel, urllib.urlencode(options)), jsonReply=False)

		values = [[float(item) for item in item.split(',')]
			for item in response.split('\n')
			if item != '']
		values = map(list, zip(*values))
		if count == 1:
			return [value[0] for value in values]
		else:
			return values
<|endoftext|>