<commit_before>"""
General binary file parser.

(C) 2015 Jeroen F.J. Laros <J.F.J.Laros@lumc.nl>
"""

import sys

import yaml

from functions import BinReadFunctions, BinWriteFunctions, operators

class BinParser(object):
    def __init__(
            self, structure_handle, types_handle, functions=BinReadFunctions,
            debug=0, log=sys.stderr):
        """
        Constructor.

        :arg stream structure_handle: Open readable handle to the structure
            definition.
        :arg stream types_handle: Open readable handle to the types definition.
        :arg object functions: Object containing parsing functions.
        :arg int debug: Debugging level.
        :arg stream log: Debug stream to write to.
        """
        self._internal = {}

        self._debug = debug
        self._log = log

        self._functions = functions()

        self.constants = {}
        self.defaults = {
            'delimiter': [],
            'name': '',
            'size': 0,
            'type': 'text',
            'unknown_destination': 'raw',
            'unknown_function': 'raw'
        }
        self.types = {
            'int': {},
            'raw': {}
        }

        types_data = yaml.load(types_handle)
        if 'constants' in types_data:
            self.constants.update(types_data['constants'])
        if 'defaults' in types_data:
            self.defaults.update(types_data['defaults'])
        if 'types' in types_data:
            self.types.update(types_data['types'])

        self._structure = yaml.load(structure_handle)

        if self._debug > 1:
            self._log.write('--- PARSING DETAILS ---\n\n')

    def _call(self, name, data, *args, **kwargs):
        return getattr(self._functions, name)(data, *args, **kwargs)

    def _get_value(self, name):
        """
        Resolve the value of a variable.

        First look in the cache to see if `name` is defined, then check the set
        of constants. If nothing can be found, the variable is considered to be
        a literal.

        :arg any name: The name or value of a variable.
        :returns: The resolved value.
        """
        if name in self._internal:
            return self._internal[name]
        if name in self.constants:
            return self.constants[name]
        return name

    def _get_default(self, item, dtype, name):
        """
        """
        if name in item:
            return item[name]
        if dtype in self.types and name in self.types[dtype]:
            return self.types[dtype][name]
        if name in self.defaults:
            return self.defaults[name]
        return None

    def _get_function(self, item, dtype):
        """
        """
        delim = self._get_default(item, dtype, 'delimiter')
        size = self._get_default(item, dtype, 'size')
        if not (delim or size):
            size = 1

        # Determine the function and its arguments.
        func = dtype
        kwargs = {}
        if 'function' in self.types[dtype]:
            if 'name' in self.types[dtype]['function']:
                func = self.types[dtype]['function']['name']
            if 'args' in self.types[dtype]['function']:
                kwargs = self.types[dtype]['function']['args']

        return delim, size, func, kwargs

    def _evaluate(self, expression):
        """
        Evaluate an expression.

        An expression is represented by a dictionary with the following
        structure:

            expression = {
                'operator': '',
                'operands': []
            }

        :arg dict expression: An expression.
        :returns any: Result of the evaluation.
        """
        operands = map(lambda x: self._get_value(x), expression['operands'])

        if len(operands) == 1 and 'operator' not in expression:
            return operands[0]
        return operators[expression['operator']](*operands)

class BinReader(BinParser):
    """
    General binary file reader.
    """
    def __init__(
            self, input_handle, structure_handle, types_handle,
            functions=BinReadFunctions, debug=0, log=sys.stderr):
        """
        Constructor.

        :arg stream input_handle: Open readable handle to a binary file.
        :arg stream structure_handle: Open readable handle to the structure
            definition.
        :arg stream types_handle: Open readable handle to the types definition.
        :arg object functions: Object containing parsing functions.
        :arg int debug: Debugging level.
        :arg stream log: Debug stream to write to.
        """
        super(BinReader, self).__init__(
            structure_handle, types_handle, functions, debug, log)

        self.data = input_handle.read()
        self.parsed = {}
        self._offset = 0
        self._raw_byte_count = 0

        try:
            self._parse(self._structure, self.parsed)
        except StopIteration:
            pass

    def _get_field(self, size=0, delimiter=[]):
        """
        Extract a field from {self.data} using either a fixed size, or a
        delimiter. After reading, {self._offset} is set to the next field.

        :arg int size: Size of fixed size field.
        :arg list(char) delimiter: Delimiter for variable sized fields.

        :return str: Content of the requested field.
        """
        if self._offset >= len(self.data):
            raise StopIteration

        separator = ''.join(map(chr, delimiter))
        if size:
            # Fixed sized field.
            field = self.data[self._offset:self._offset + size]
            extracted = size
            if delimiter:
                # A variable sized field in a fixed sized field.
                field = field.split(separator)[0]
        else:
            # Variable sized field.
            field = self.data[self._offset:].split(separator)[0]
            extracted = len(field) + 1

        if self._debug > 1:
            self._log.write('0x{:06x}: '.format(self._offset))
            if size:
                self._log.write('{} ({})'.format(self._call(
                    'raw', field), size))
            else:
                self._log.write('{}'.format(field))

        self._offset += extracted
        return field

    def _parse_primitive(self, item, dtype, dest, name):
        """
        Parse a primitive data type.

        :arg dict item: A dictionary.
        :arg str dtype: Data type.
        :arg dict dest: Destination dictionary.
        :arg str name: Field name used in the destination dictionary.
        """
        delim, size, func, kwargs = self._get_function(item, dtype)

        if name:
            # Read and process the data.
            result = self._call(func, self._get_field(size, delim), **kwargs)
            if type(result) == dict:
                # Unpack dictionaries in order to use the items in evaluations.
                for member in result:
                    self._internal[member] = result[member]
            else:
                self._internal[name] = result
            dest[name] = result
        else:
            # Stow unknown data away in a list.
            unknown_dest = self._get_default(
                item, dtype, 'unknown_destination')
            if unknown_dest not in dest:
                dest[unknown_dest] = []
            dest[unknown_dest].append(
                self._call(
                    self._get_default(item, dtype, 'unknown_function'),
                    self._get_field(size)))
            self._raw_byte_count += size

    def _parse_for(self, item, dest, name):
        """
        Parse a for loop.

        :arg dict item: A dictionary.
        :arg dict dest: Destination dictionary.
        :arg str name: Field name used in the destination dictionary.
        """
        length = item['for']
        if type(length) != int:
            length = self._internal[length]

        for _ in range(length):
            structure_dict = {}
            self._parse(item['structure'], structure_dict)
            dest[name].append(structure_dict)

    def _parse_do_while(self, item, dest, name):
        """
        Parse a do-while loop.

        :arg dict item: A dictionary.
        :arg dict dest: Destination dictionary.
        :arg str name: Field name used in the destination dictionary.
        """
        while True:
            structure_dict = {}
            self._parse(item['structure'], structure_dict)
            dest[name].append(structure_dict)
            if not self._evaluate(item['do_while']):
                break

    def _parse_while(self, item, dest, name):
        """
        Parse a while loop.

        :arg dict item: A dictionary.
        :arg dict dest: Destination dictionary.
        :arg str name: Field name used in the destination dictionary.
        """
        delim = item['structure'][0]
        dest[name] = [{}]

        self._parse([delim], dest[name][0])
        while True:
            if not self._evaluate(item['while']):
                break
            self._parse(item['structure'][1:], dest[name][-1])
            dest[name].append({})
            self._parse([delim], dest[name][-1])

        dest[item['while']['term']] = dest[name].pop(-1).values()[0]

    def _parse(self, structure, dest):
        """
        Parse a binary file.

        :arg dict structure: Structure of the binary file.
        :arg dict dest: Destination dictionary.
        """
        for item in structure:
            if 'if' in item:
                # Conditional statement.
                if not self._evaluate(item['if']):
                    continue

            dtype = self._get_default(item, '', 'type')
            name = self._get_default(item, dtype, 'name')

            if 'structure' not in item:
                # Primitive data types.
                self._parse_primitive(item, dtype, dest, name)
            else:
                # Nested structures.
                if self._debug > 1:
                    self._log.write('-- {}\n'.format(name))

                if name not in dest:
                    if set(['for', 'do_while', 'while']) & set(item):
                        dest[name] = []
                    else:
                        dest[name] = {}

                if 'for' in item:
                    self._parse_for(item, dest, name)
                elif 'do_while' in item:
                    self._parse_do_while(item, dest, name)
                elif 'while' in item:
                    self._parse_while(item, dest, name)
                else:
                    self._parse(item['structure'], dest[name])

            if self._debug > 1:
                self._log.write(' --> {}\n'.format(name))

    def write(self, output_handle):
        """
        Write the parsed binary file to a stream.

        :arg stream output_handle: Open writable handle.
        """
        yaml.dump(
            self.parsed, output_handle, width=76, default_flow_style=False)

        if self._debug:
            if self._debug > 1:
                self._log.write('\n\n')
            self._log.write('--- INTERNAL VARIABLES ---\n\n')
            yaml.dump(
                self._internal, self._log, width=76,
                default_flow_style=False, encoding=None)

            data_length = len(self.data)
            parsed = data_length - self._raw_byte_count

            self._log.write('\n\n--- DEBUG INFO ---\n\n')
            self._log.write('Reached byte {} out of {}.\n'.format(
                self._offset, data_length))
            self._log.write('{} bytes parsed ({:d}%).\n'.format(
                parsed, parsed * 100 // data_length))

class BinWriter(BinParser):
    """
    General binary file writer.
    """
    def __init__(
            self, input_handle, structure_handle, types_handle,
            functions=BinWriteFunctions, debug=0, log=sys.stderr):
        """
        Constructor.

        :arg stream input_handle: Open readable handle to a yaml file.
        :arg stream structure_handle: Open readable handle to the structure
            definition.
        :arg stream types_handle: Open readable handle to the types definition.
        :arg object functions: Object containing parsing functions.
        :arg int debug: Debugging level.
        :arg stream log: Debug stream to write to.
        """
        super(BinWriter, self).__init__(
            structure_handle, types_handle, functions, debug, log)

        self.data = ''
        self.parsed = yaml.load(input_handle)

        self._encode(self._structure, self.parsed)

    def _set_field(self, data, size=0, delimiter=[]):
        """
        Append a field to {self.data} using either a fixed size, or a
        delimiter.

        :arg int data: The content of the field.
        :arg int size: Size of fixed size field.
        :arg list(char) delimiter: Delimiter for variable sized fields.
        """
        field = data

        if delimiter:
            # Add the delimiter for variable length fields.
            field += ''.join(map(chr, delimiter))
        if size:
            # Clip the field if it is too large.
            # NOTE: This can result in a non-delimited trimmed field.
            field = field[:size]
        if len(field) < size:
            # Pad the field if necessary.
            field += chr(0x00) * (size - len(field))

        self.data += field

    def _encode_primitive(self, item, dtype, value, name):
        """
        Encode a primitive data type.

        :arg dict item: A dictionary.
        :arg str dtype: Data type.
        :arg unknown value: Value to be stored.
        :arg str name: Field name used in the destination dictionary.
        """
        delim, size, func, kwargs = self._get_function(item, dtype)

        if type(value) == dict:
            # Unpack dictionaries in order to use the items in evaluations.
            for member in value:
                self._internal[member] = value[member]
        else:
            self._internal[name] = value

        self._set_field(self._call(func, value, **kwargs), size, delim)

    def _get_item(self, item):
        """
        """
        for operand in item['while']['operands']:
            for field in item['structure']:
                if operand == field['name']:
                    return field

    def _encode(self, structure, source):
        """
        Encode to a file.

        :arg dict structure: Structure of the binary file.
        :arg dict source: Source dictionary.
        """
        raw_counter = 0

        for item in structure:
            if 'if' in item:
                # Conditional statement.
                if not self._evaluate(item['if']):
                    continue

            dtype = self._get_default(item, '', 'type')
            name = self._get_default(item, dtype, 'name')

            if not name:
                # NOTE: Not sure if this is correct.
                dtype = self._get_default(item, dtype, 'unknown_function')
                value = source[self._get_default(
                    item, dtype, 'unknown_destination')][raw_counter]
                raw_counter += 1
            else:
                value = source[name]

            if 'structure' not in item:
                # Primitive data types.
                if self._debug > 1:
                    self._log.write(
                        '0x{:06x}: {} --> {}\n'.format(
                        len(self.data), name, value))

                self._encode_primitive(item, dtype, value, name)
            else:
                # Nested structures.
                if self._debug > 1:
                    self._log.write('-- {}\n'.format(name))

                if set(['for', 'do_while', 'while']) & set(item):
                    for subitem in value:
                        self._encode(item['structure'], subitem)
                    if 'while' in item:
                        term = self._get_item(item)
                        self._encode(
                            [term],
                            {term['name']: source[item['while']['term']]})
                else:
                    self._encode(item['structure'], value)

                if self._debug > 1:
                    self._log.write(' --> {}\n'.format(name))

    def write(self, output_handle):
        """
        Write the encoded file to a stream.

        :arg stream output_handle: Open writable handle.
        """
        output_handle.write(self.data)

        if self._debug:
            if self._debug > 1:
                self._log.write('\n\n')

            self._log.write('--- INTERNAL VARIABLES ---\n\n')
            yaml.dump(
                self._internal, self._log, width=76,
                default_flow_style=False, encoding=None)

            self._log.write('\n\n--- DEBUG INFO ---\n\n')
            self._log.write('{} bytes written.\n'.format(len(self.data)))
<commit_msg>Using official YAML syntax.<commit_after>"""
General binary file parser.

(C) 2015 Jeroen F.J. Laros <J.F.J.Laros@lumc.nl>
"""

import sys

import yaml

from functions import BinReadFunctions, BinWriteFunctions, operators

class BinParser(object):
    def __init__(
            self, structure_handle, types_handle, functions=BinReadFunctions,
            debug=0, log=sys.stderr):
        """
        Constructor.

        :arg stream structure_handle: Open readable handle to the structure
            definition.
        :arg stream types_handle: Open readable handle to the types definition.
        :arg object functions: Object containing parsing functions.
        :arg int debug: Debugging level.
        :arg stream log: Debug stream to write to.
        """
        self._internal = {}

        self._debug = debug
        self._log = log

        self._functions = functions()

        self.constants = {}
        self.defaults = {
            'delimiter': [],
            'name': '',
            'size': 0,
            'type': 'text',
            'unknown_destination': 'raw',
            'unknown_function': 'raw'
        }
        self.types = {
            'int': {},
            'raw': {}
        }

        types_data = yaml.safe_load(types_handle)
        if 'constants' in types_data:
            self.constants.update(types_data['constants'])
        if 'defaults' in types_data:
            self.defaults.update(types_data['defaults'])
        if 'types' in types_data:
            self.types.update(types_data['types'])

        self._structure = yaml.safe_load(structure_handle)

        if self._debug > 1:
            self._log.write('--- PARSING DETAILS ---\n\n')

    def _call(self, name, data, *args, **kwargs):
        return getattr(self._functions, name)(data, *args, **kwargs)

    def _get_value(self, name):
        """
        Resolve the value of a variable.

        First look in the cache to see if `name` is defined, then check the set
        of constants. If nothing can be found, the variable is considered to be
        a literal.

        :arg any name: The name or value of a variable.
        :returns: The resolved value.
        """
        if name in self._internal:
            return self._internal[name]
        if name in self.constants:
            return self.constants[name]
        return name

    def _get_default(self, item, dtype, name):
        """
        """
        if name in item:
            return item[name]
        if dtype in self.types and name in self.types[dtype]:
            return self.types[dtype][name]
        if name in self.defaults:
            return self.defaults[name]
        return None

    def _get_function(self, item, dtype):
        """
        """
        delim = self._get_default(item, dtype, 'delimiter')
        size = self._get_default(item, dtype, 'size')
        if not (delim or size):
            size = 1

        # Determine the function and its arguments.
        func = dtype
        kwargs = {}
        if 'function' in self.types[dtype]:
            if 'name' in self.types[dtype]['function']:
                func = self.types[dtype]['function']['name']
            if 'args' in self.types[dtype]['function']:
                kwargs = self.types[dtype]['function']['args']

        return delim, size, func, kwargs

    def _evaluate(self, expression):
        """
        Evaluate an expression.

        An expression is represented by a dictionary with the following
        structure:

            expression = {
                'operator': '',
                'operands': []
            }

        :arg dict expression: An expression.
        :returns any: Result of the evaluation.
        """
        operands = map(lambda x: self._get_value(x), expression['operands'])

        if len(operands) == 1 and 'operator' not in expression:
            return operands[0]
        return operators[expression['operator']](*operands)

class BinReader(BinParser):
    """
    General binary file reader.
    """
    def __init__(
            self, input_handle, structure_handle, types_handle,
            functions=BinReadFunctions, debug=0, log=sys.stderr):
        """
        Constructor.

        :arg stream input_handle: Open readable handle to a binary file.
        :arg stream structure_handle: Open readable handle to the structure
            definition.
        :arg stream types_handle: Open readable handle to the types definition.
        :arg object functions: Object containing parsing functions.
        :arg int debug: Debugging level.
        :arg stream log: Debug stream to write to.
        """
        super(BinReader, self).__init__(
            structure_handle, types_handle, functions, debug, log)

        self.data = input_handle.read()
        self.parsed = {}
        self._offset = 0
        self._raw_byte_count = 0

        try:
            self._parse(self._structure, self.parsed)
        except StopIteration:
            pass

    def _get_field(self, size=0, delimiter=[]):
        """
        Extract a field from {self.data} using either a fixed size, or a
        delimiter. After reading, {self._offset} is set to the next field.

        :arg int size: Size of fixed size field.
        :arg list(char) delimiter: Delimiter for variable sized fields.

        :return str: Content of the requested field.
        """
        if self._offset >= len(self.data):
            raise StopIteration

        separator = ''.join(map(chr, delimiter))
        if size:
            # Fixed sized field.
            field = self.data[self._offset:self._offset + size]
            extracted = size
            if delimiter:
                # A variable sized field in a fixed sized field.
                field = field.split(separator)[0]
        else:
            # Variable sized field.
            field = self.data[self._offset:].split(separator)[0]
            extracted = len(field) + 1

        if self._debug > 1:
            self._log.write('0x{:06x}: '.format(self._offset))
            if size:
                self._log.write('{} ({})'.format(self._call(
                    'raw', field), size))
            else:
                self._log.write('{}'.format(field))

        self._offset += extracted
        return field

    def _parse_primitive(self, item, dtype, dest, name):
        """
        Parse a primitive data type.

        :arg dict item: A dictionary.
        :arg str dtype: Data type.
        :arg dict dest: Destination dictionary.
        :arg str name: Field name used in the destination dictionary.
        """
        delim, size, func, kwargs = self._get_function(item, dtype)

        if name:
            # Read and process the data.
            result = self._call(func, self._get_field(size, delim), **kwargs)
            if type(result) == dict:
                # Unpack dictionaries in order to use the items in evaluations.
                for member in result:
                    self._internal[member] = result[member]
            else:
                self._internal[name] = result
            dest[name] = result
        else:
            # Stow unknown data away in a list.
            unknown_dest = self._get_default(
                item, dtype, 'unknown_destination')
            if unknown_dest not in dest:
                dest[unknown_dest] = []
            dest[unknown_dest].append(
                self._call(
                    self._get_default(item, dtype, 'unknown_function'),
                    self._get_field(size)))
            self._raw_byte_count += size

    def _parse_for(self, item, dest, name):
        """
        Parse a for loop.

        :arg dict item: A dictionary.
        :arg dict dest: Destination dictionary.
        :arg str name: Field name used in the destination dictionary.
        """
        length = item['for']
        if type(length) != int:
            length = self._internal[length]

        for _ in range(length):
            structure_dict = {}
            self._parse(item['structure'], structure_dict)
            dest[name].append(structure_dict)

    def _parse_do_while(self, item, dest, name):
        """
        Parse a do-while loop.

        :arg dict item: A dictionary.
        :arg dict dest: Destination dictionary.
        :arg str name: Field name used in the destination dictionary.
        """
        while True:
            structure_dict = {}
            self._parse(item['structure'], structure_dict)
            dest[name].append(structure_dict)
            if not self._evaluate(item['do_while']):
                break

    def _parse_while(self, item, dest, name):
        """
        Parse a while loop.

        :arg dict item: A dictionary.
        :arg dict dest: Destination dictionary.
        :arg str name: Field name used in the destination dictionary.
        """
        delim = item['structure'][0]
        dest[name] = [{}]

        self._parse([delim], dest[name][0])
        while True:
            if not self._evaluate(item['while']):
                break
            self._parse(item['structure'][1:], dest[name][-1])
            dest[name].append({})
            self._parse([delim], dest[name][-1])

        dest[item['while']['term']] = dest[name].pop(-1).values()[0]

    def _parse(self, structure, dest):
        """
        Parse a binary file.

        :arg dict structure: Structure of the binary file.
        :arg dict dest: Destination dictionary.
        """
        for item in structure:
            if 'if' in item:
                # Conditional statement.
                if not self._evaluate(item['if']):
                    continue

            dtype = self._get_default(item, '', 'type')
            name = self._get_default(item, dtype, 'name')

            if 'structure' not in item:
                # Primitive data types.
                self._parse_primitive(item, dtype, dest, name)
            else:
                # Nested structures.
                if self._debug > 1:
                    self._log.write('-- {}\n'.format(name))

                if name not in dest:
                    if set(['for', 'do_while', 'while']) & set(item):
                        dest[name] = []
                    else:
                        dest[name] = {}

                if 'for' in item:
                    self._parse_for(item, dest, name)
                elif 'do_while' in item:
                    self._parse_do_while(item, dest, name)
                elif 'while' in item:
                    self._parse_while(item, dest, name)
                else:
                    self._parse(item['structure'], dest[name])

            if self._debug > 1:
                self._log.write(' --> {}\n'.format(name))

    def write(self, output_handle):
        """
        Write the parsed binary file to a stream.

        :arg stream output_handle: Open writable handle.
        """
        yaml.safe_dump(
            self.parsed, output_handle, width=76, default_flow_style=False)

        if self._debug:
            if self._debug > 1:
                self._log.write('\n\n')
            self._log.write('--- INTERNAL VARIABLES ---\n\n')
            yaml.safe_dump(
                self._internal, self._log, width=76,
                default_flow_style=False, encoding=None)

            data_length = len(self.data)
            parsed = data_length - self._raw_byte_count

            self._log.write('\n\n--- DEBUG INFO ---\n\n')
            self._log.write('Reached byte {} out of {}.\n'.format(
                self._offset, data_length))
            self._log.write('{} bytes parsed ({:d}%).\n'.format(
                parsed, parsed * 100 // data_length))

class BinWriter(BinParser):
    """
    General binary file writer.
    """
    def __init__(
            self, input_handle, structure_handle, types_handle,
            functions=BinWriteFunctions, debug=0, log=sys.stderr):
        """
        Constructor.

        :arg stream input_handle: Open readable handle to a yaml file.
        :arg stream structure_handle: Open readable handle to the structure
            definition.
        :arg stream types_handle: Open readable handle to the types definition.
        :arg object functions: Object containing parsing functions.
        :arg int debug: Debugging level.
        :arg stream log: Debug stream to write to.
        """
        super(BinWriter, self).__init__(
            structure_handle, types_handle, functions, debug, log)

        self.data = ''
        self.parsed = yaml.safe_load(input_handle)

        self._encode(self._structure, self.parsed)

    def _set_field(self, data, size=0, delimiter=[]):
        """
        Append a field to {self.data} using either a fixed size, or a
        delimiter.

        :arg int data: The content of the field.
        :arg int size: Size of fixed size field.
        :arg list(char) delimiter: Delimiter for variable sized fields.
        """
        field = data

        if delimiter:
            # Add the delimiter for variable length fields.
            field += ''.join(map(chr, delimiter))
        if size:
            # Clip the field if it is too large.
            # NOTE: This can result in a non-delimited trimmed field.
            field = field[:size]
        if len(field) < size:
            # Pad the field if necessary.
            field += chr(0x00) * (size - len(field))

        self.data += field

    def _encode_primitive(self, item, dtype, value, name):
        """
        Encode a primitive data type.

        :arg dict item: A dictionary.
        :arg str dtype: Data type.
        :arg unknown value: Value to be stored.
        :arg str name: Field name used in the destination dictionary.
        """
        delim, size, func, kwargs = self._get_function(item, dtype)

        if type(value) == dict:
            # Unpack dictionaries in order to use the items in evaluations.
            for member in value:
                self._internal[member] = value[member]
        else:
            self._internal[name] = value

        self._set_field(self._call(func, value, **kwargs), size, delim)

    def _get_item(self, item):
        """
        """
        for operand in item['while']['operands']:
            for field in item['structure']:
                if operand == field['name']:
                    return field

    def _encode(self, structure, source):
        """
        Encode to a file.

        :arg dict structure: Structure of the binary file.
        :arg dict source: Source dictionary.
        """
        raw_counter = 0

        for item in structure:
            if 'if' in item:
                # Conditional statement.
                if not self._evaluate(item['if']):
                    continue

            dtype = self._get_default(item, '', 'type')
            name = self._get_default(item, dtype, 'name')

            if not name:
                # NOTE: Not sure if this is correct.
                dtype = self._get_default(item, dtype, 'unknown_function')
                value = source[self._get_default(
                    item, dtype, 'unknown_destination')][raw_counter]
                raw_counter += 1
            else:
                value = source[name]

            if 'structure' not in item:
                # Primitive data types.
                if self._debug > 1:
                    self._log.write(
                        '0x{:06x}: {} --> {}\n'.format(
                        len(self.data), name, value))

                self._encode_primitive(item, dtype, value, name)
            else:
                # Nested structures.
                if self._debug > 1:
                    self._log.write('-- {}\n'.format(name))

                if set(['for', 'do_while', 'while']) & set(item):
                    for subitem in value:
                        self._encode(item['structure'], subitem)
                    if 'while' in item:
                        term = self._get_item(item)
                        self._encode(
                            [term],
                            {term['name']: source[item['while']['term']]})
                else:
                    self._encode(item['structure'], value)

                if self._debug > 1:
                    self._log.write(' --> {}\n'.format(name))

    def write(self, output_handle):
        """
        Write the encoded file to a stream.

        :arg stream output_handle: Open writable handle.
        """
        output_handle.write(self.data)

        if self._debug:
            if self._debug > 1:
                self._log.write('\n\n')

            self._log.write('--- INTERNAL VARIABLES ---\n\n')
            yaml.safe_dump(
                self._internal, self._log, width=76,
                default_flow_style=False, encoding=None)

            self._log.write('\n\n--- DEBUG INFO ---\n\n')
            self._log.write('{} bytes written.\n'.format(len(self.data)))
<|endoftext|>


<commit_before># Copyright (c) 2018 Micro Focus or one of its affiliates.
# Copyright (c) 2018 Uber Technologies, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# Copyright (c) 2013-2017 Uber Technologies, Inc.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.

from __future__ import print_function, division, absolute_import

import re

#############################################
# dbapi errors
#############################################
class Error(Exception):
    pass

# noinspection PyShadowingBuiltins
class Warning(Exception):
    pass

class InterfaceError(Error):
    pass

class DatabaseError(Error):
    pass

class InternalError(DatabaseError):
    pass

class OperationalError(DatabaseError):
    pass

class ProgrammingError(DatabaseError):
    pass

class IntegrityError(DatabaseError):
    pass

class DataError(DatabaseError):
    pass

class NotSupportedError(DatabaseError):
    pass

#
# Other Errors
#

class TimedOutError(OperationalError):
    pass

class ConnectionError(DatabaseError):
    pass

class SSLNotSupported(ConnectionError):
    pass

class MessageError(InternalError):
    pass

class EmptyQueryError(ProgrammingError):
    pass

class QueryError(ProgrammingError):
    def __init__(self, error_response, sql):
        self.error_response = error_response
        self.sql = sql
        ProgrammingError.__init__(self,
                                  "{0}, SQL: {1}".format(error_response.error_message(),
                                                         repr(self.one_line_sql())))

    def one_line_sql(self):
        if self.sql:
            return re.sub(r"[\r\n]+", ' ', self.sql)
        else:
            return ''

    @classmethod
    def from_error_response(cls, error_response, sql):
        klass = QUERY_ERROR_CLASSES.get(error_response.sqlstate, None)
        if klass is None:
            klass = cls
        return klass(error_response, sql)

class LockFailure(QueryError):
    pass

class InsufficientResources(QueryError):
    pass

class OutOfMemory(QueryError):
    pass

class VerticaSyntaxError(QueryError):
    pass

class MissingSchema(QueryError):
    pass

class MissingRelation(QueryError):
    pass

class MissingColumn(QueryError):
    pass

class CopyRejected(QueryError):
    pass

class PermissionDenied(QueryError):
    pass

class InvalidDatetimeFormat(QueryError):
    pass

class DuplicateObject(QueryError):
    pass

class QueryCanceled(QueryError):
    pass

class ConnectionFailure(QueryError):
    pass

QUERY_ERROR_CLASSES = {
    b'55V03': LockFailure,
    b'53000': InsufficientResources,
    b'53200': OutOfMemory,
    b'42601': VerticaSyntaxError,
    b'3F000': MissingSchema,
    b'42V01': MissingRelation,
    b'42703': MissingColumn,
    b'22V04': CopyRejected,
    b'42501': PermissionDenied,
    b'22007': InvalidDatetimeFormat,
    b'42710': DuplicateObject,
    b'57014': QueryCanceled,
    b'08006': ConnectionFailure
}
<commit_msg>Add lost connectivity error (#245)<commit_after># Copyright (c) 2018 Micro Focus or one of its affiliates.
# Copyright (c) 2018 Uber Technologies, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# Copyright (c) 2013-2017 Uber Technologies, Inc.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.

from __future__ import print_function, division, absolute_import

import re

#############################################
# dbapi errors
#############################################
class Error(Exception):
    pass

# noinspection PyShadowingBuiltins
class Warning(Exception):
    pass

class InterfaceError(Error):
    pass

class DatabaseError(Error):
    pass

class InternalError(DatabaseError):
    pass

class OperationalError(DatabaseError):
    pass

class ProgrammingError(DatabaseError):
    pass

class IntegrityError(DatabaseError):
    pass

class DataError(DatabaseError):
    pass

class NotSupportedError(DatabaseError):
    pass

#
# Other Errors
#

class TimedOutError(OperationalError):
    pass

class ConnectionError(DatabaseError):
    pass

class SSLNotSupported(ConnectionError):
    pass

class MessageError(InternalError):
    pass

class EmptyQueryError(ProgrammingError):
    pass

class QueryError(ProgrammingError):
    def __init__(self, error_response, sql):
        self.error_response = error_response
        self.sql = sql
        ProgrammingError.__init__(self,
                                  "{0}, SQL: {1}".format(error_response.error_message(),
                                                         repr(self.one_line_sql())))

    def one_line_sql(self):
        if self.sql:
            return re.sub(r"[\r\n]+", ' ', self.sql)
        else:
            return ''

    @classmethod
    def from_error_response(cls, error_response, sql):
        klass = QUERY_ERROR_CLASSES.get(error_response.sqlstate, None)
        if klass is None:
            klass = cls
        return klass(error_response, sql)

class LockFailure(QueryError):
    pass

class InsufficientResources(QueryError):
    pass

class OutOfMemory(QueryError):
    pass

class VerticaSyntaxError(QueryError):
    pass

class MissingSchema(QueryError):
    pass

class MissingRelation(QueryError):
    pass

class MissingColumn(QueryError):
    pass

class CopyRejected(QueryError):
    pass

class PermissionDenied(QueryError):
    pass

class InvalidDatetimeFormat(QueryError):
    pass

class DuplicateObject(QueryError):
    pass

class QueryCanceled(QueryError):
    pass

class ConnectionFailure(QueryError):
    pass

class LostConnectivityFailure(QueryError):
    pass

QUERY_ERROR_CLASSES = {
    b'55V03': LockFailure,
    b'53000': InsufficientResources,
    b'53200': OutOfMemory,
    b'42601': VerticaSyntaxError,
    b'3F000': MissingSchema,
    b'42V01': MissingRelation,
    b'42703': MissingColumn,
    b'22V04': CopyRejected,
    b'42501': PermissionDenied,
    b'22007': InvalidDatetimeFormat,
    b'42710': DuplicateObject,
    b'57014': QueryCanceled,
    b'08006': ConnectionFailure,
    b'V1001': LostConnectivityFailure
}
<|endoftext|>


<commit_before>#  Copyright 2008-2011 Nokia Siemens Networks Oyj
#
#  Licensed under the Apache License, Version 2.0 (the "License"self);
#  you may not use this file except in compliance with the License.
#  You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
#  Unless required by applicable law or agreed to in writing, software
#  distributed under the License is distributed on an "AS IS" BASIS,
#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#  See the License for the specific language governing permissions and
#  limitations under the License.
import os
from robotide.controller import NewDatafile
from robotide.controller.commands import AddSuite, AddTestCase, AddKeyword, AddVariable, ChangeCellValue, AddRow, DeleteRow, InsertCell, DeleteCell, MoveRowsUp, MoveRowsDown, ExtractKeyword, RenameKeywordOccurrences, RenameTest, Undo, Redo, SaveFile, NullObserver, SaveAll, CommentRow, UncommentRow, CopyMacroAs
from robotide.namespace import Namespace
from robotide.controller.chiefcontroller import ChiefController

class RIDE(object):

    def __init__(self, random, path):
        print 'chief = ChiefController(Namespace())'
        self._chief = ChiefController(Namespace())
        self._path = path
        self._suite = None
        self._test = None
        self._keyword = None
        self._random = random
        self._skip = False

    def _skip_until_notified(self):
        self._skip = True

    def _do_not_skip(self):
        self._skip = False

    def _open_test_dir(self):
        self._open(os.path.join(self._path, 'testdir'))
        print 'suite = chief.data.children[0]'
        self._suite = self._chief.data.children[0]
        print 'test = list(t for t in suite.tests)[0]'
        self._test = list(t for t in self._suite.tests)[0]
        print 'keyword = list(k for k in suite.keywords)[0]'
        self._keyword = list(k for k in self._suite.keywords)[0]

    def _open_suite_file(self):
        self._open(os.path.join(self._path, 'testdir', 'Suite.txt'))
        self._suite = self._chief.data
        self._test = list(t for t in self._suite.tests)[0]
        self._keyword = list(k for k in self._suite.keywords)[0]

    def _open_resource_file(self):
        self._open(os.path.join(self._path, 'testdir', 'resources', 'resu.txt'))
        self._suite = None
        self._test = None
        self._keyword = None

    def _open(self, path):
        print 'chief.load_data("%s", NullObserver())' % path
        self._chief.load_data(path, NullObserver())

    def _create_suite(self):
        filename = os.path.join(self._path,'path_to_foo%s.txt' % str(self._rand()))
        print 'suite = chief.data.execute(AddSuite(NewDatafile("%s", False)))' % filename
        self._suite = self._chief.data.execute(AddSuite(NewDatafile(filename, False)))

    def create_test(self):
        if self._skip:
            self._rand()
            return
        testname = 'foobar'+str(self._rand())
        print 'test = suite.execute(AddTestCase("%s"))' % testname
        self._test = self._suite.execute(AddTestCase(testname))

    def _rand(self):
        return self._random.random()

    def _rand_row(self):
        return self._random.randint(0,100)

    def _rand_col(self):
        return self._random.randint(0, 30)

    def create_keyword(self):
        if self._skip:
            self._rand()
            return
        keyword_name = 'kwFoobar'+str(self._rand())
        print 'keyword = suite.execute(AddKeyword("%s"))' % keyword_name
        self._keyword = self._suite.execute(AddKeyword(keyword_name))

    def add_variable(self):
        if self._skip:
            self._rand()
            self._rand()
            return
        command = AddVariable('${var%s}' % str(self._rand()), str(self._rand()), 'comment')
        print 'suite.execute(%s)' % str(command)
        self._suite.execute(command)

    def write_cell_data(self):
        self._macro_execute(ChangeCellValue(self._rand_row(), self._rand_col(), 'foobar%s' % str(self._rand())))

    def _macro_execute(self, command):
        macro = self._random.choice([c for c in [self._test, self._keyword] if c])
        if not self._skip:
            print '%s.execute(%s)' % (self._name(macro), str(command))
            macro.execute(command)

    def _name(self, macro):
        if macro == self._test:
            return 'test'
        return 'keyword'

    def add_row(self):
        self._macro_execute(AddRow(self._rand_row()))

    def remove_row(self):
        self._macro_execute(DeleteRow(self._rand_row()))

    def add_cell(self):
        self._macro_execute(InsertCell(self._rand_row(), self._rand_col()))

    def remove_cell(self):
        self._macro_execute(DeleteCell(self._rand_row(), self._rand_col()))

    def move_row_up(self):
        self._macro_execute(MoveRowsUp([self._rand_row()]))

    def move_row_down(self):
        self._macro_execute(MoveRowsDown([self._rand_row()]))

    def comment_row(self):
        self._macro_execute(CommentRow(self._rand_row()))

    def uncomment_row(self):
        self._macro_execute(UncommentRow(self._rand_row()))

    def extract_keyword(self):
        first_row = self._rand_row()
        self._macro_execute(ExtractKeyword('foo', '', [first_row, first_row+self._random.randint(1,10)]))

    def rename_keyword(self):
        class Observer(object):
            def notify(self, *args):
                pass
            def finish(self, *args):
                pass
        self._macro_execute(RenameKeywordOccurrences('foo', 'bar', Observer()))

    def rename_test(self):
        if self._skip:
            self._rand()
            return
        self._test.execute(RenameTest('new_name%s' % str(self._rand())))

    def undo(self):
        self._macro_execute(Undo())

    def redo(self):
        self._macro_execute(Redo())

    def save(self):
        if self._skip:
            return
        command = SaveFile()
        print 'suite.execute(%s)' % str(command)
        self._suite.execute(command)

    def save_all(self):
        if self._skip:
            return
        command = SaveAll()
        print 'chief.execute(%s)' % str(command)
        self._chief.execute(command)

    def copy_test(self):
        if self._skip:
            self._rand()
            return
        command = CopyMacroAs('name test %s' % str(self._rand()))
        print 'test.execute(%s)' % str(command)
        self._test.execute(command)

    def copy_keyword(self):
        if self._skip:
            return
        command = CopyMacroAs('name keyword %s' % str(self._rand()))
        print 'test.execute(%s)' % str(command)
        self._keyword.execute(command)
<commit_msg>add tag<commit_after>#  Copyright 2008-2011 Nokia Siemens Networks Oyj
#
#  Licensed under the Apache License, Version 2.0 (the "License"self);
#  you may not use this file except in compliance with the License.
#  You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
#  Unless required by applicable law or agreed to in writing, software
#  distributed under the License is distributed on an "AS IS" BASIS,
#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#  See the License for the specific language governing permissions and
#  limitations under the License.
import os
from robotide.controller.tags import Tag
from robotide.controller import NewDatafile
from robotide.controller.commands import AddSuite, AddTestCase, AddKeyword, AddVariable, ChangeCellValue, AddRow, DeleteRow, InsertCell, DeleteCell, MoveRowsUp, MoveRowsDown, ExtractKeyword, RenameKeywordOccurrences, RenameTest, Undo, Redo, SaveFile, NullObserver, SaveAll, CommentRow, UncommentRow, CopyMacroAs, ChangeTag
from robotide.namespace import Namespace
from robotide.controller.chiefcontroller import ChiefController

class RIDE(object):

    def __init__(self, random, path):
        print 'chief = ChiefController(Namespace())'
        self._chief = ChiefController(Namespace())
        self._path = path
        self._suite = None
        self._test = None
        self._keyword = None
        self._random = random
        self._skip = False

    def _skip_until_notified(self):
        self._skip = True

    def _do_not_skip(self):
        self._skip = False

    def _open_test_dir(self):
        self._open(os.path.join(self._path, 'testdir'))
        print 'suite = chief.data.children[0]'
        self._suite = self._chief.data.children[0]
        print 'test = list(t for t in suite.tests)[0]'
        self._test = list(t for t in self._suite.tests)[0]
        print 'keyword = list(k for k in suite.keywords)[0]'
        self._keyword = list(k for k in self._suite.keywords)[0]

    def _open_suite_file(self):
        self._open(os.path.join(self._path, 'testdir', 'Suite.txt'))
        self._suite = self._chief.data
        self._test = list(t for t in self._suite.tests)[0]
        self._keyword = list(k for k in self._suite.keywords)[0]

    def _open_resource_file(self):
        self._open(os.path.join(self._path, 'testdir', 'resources', 'resu.txt'))
        self._suite = None
        self._test = None
        self._keyword = None

    def _open(self, path):
        print 'chief.load_data("%s", NullObserver())' % path
        self._chief.load_data(path, NullObserver())

    def _create_suite(self):
        filename = os.path.join(self._path,'path_to_foo%s.txt' % str(self._rand()))
        print 'suite = chief.data.execute(AddSuite(NewDatafile("%s", False)))' % filename
        self._suite = self._chief.data.execute(AddSuite(NewDatafile(filename, False)))

    def create_test(self):
        if self._skip:
            self._rand()
            return
        testname = 'foobar'+str(self._rand())
        print 'test = suite.execute(AddTestCase("%s"))' % testname
        self._test = self._suite.execute(AddTestCase(testname))

    def _rand(self):
        return self._random.random()

    def _rand_row(self):
        return self._random.randint(0,100)

    def _rand_col(self):
        return self._random.randint(0, 30)

    def create_keyword(self):
        if self._skip:
            self._rand()
            return
        keyword_name = 'kwFoobar'+str(self._rand())
        print 'keyword = suite.execute(AddKeyword("%s"))' % keyword_name
        self._keyword = self._suite.execute(AddKeyword(keyword_name))

    def add_variable(self):
        if self._skip:
            self._rand()
            self._rand()
            return
        command = AddVariable('${var%s}' % str(self._rand()), str(self._rand()), 'comment')
        print 'suite.execute(%s)' % str(command)
        self._suite.execute(command)

    def write_cell_data(self):
        self._macro_execute(ChangeCellValue(self._rand_row(), self._rand_col(), 'foobar%s' % str(self._rand())))

    def _macro_execute(self, command):
        macro = self._random.choice([c for c in [self._test, self._keyword] if c])
        if not self._skip:
            print '%s.execute(%s)' % (self._name(macro), str(command))
            macro.execute(command)

    def _name(self, macro):
        if macro == self._test:
            return 'test'
        return 'keyword'

    def add_row(self):
        self._macro_execute(AddRow(self._rand_row()))

    def remove_row(self):
        self._macro_execute(DeleteRow(self._rand_row()))

    def add_cell(self):
        self._macro_execute(InsertCell(self._rand_row(), self._rand_col()))

    def remove_cell(self):
        self._macro_execute(DeleteCell(self._rand_row(), self._rand_col()))

    def move_row_up(self):
        self._macro_execute(MoveRowsUp([self._rand_row()]))

    def move_row_down(self):
        self._macro_execute(MoveRowsDown([self._rand_row()]))

    def comment_row(self):
        self._macro_execute(CommentRow(self._rand_row()))

    def uncomment_row(self):
        self._macro_execute(UncommentRow(self._rand_row()))

    def extract_keyword(self):
        first_row = self._rand_row()
        self._macro_execute(ExtractKeyword('foo', '', [first_row, first_row+self._random.randint(1,10)]))

    def rename_keyword(self):
        class Observer(object):
            def notify(self, *args):
                pass
            def finish(self, *args):
                pass
        self._macro_execute(RenameKeywordOccurrences('foo', 'bar', Observer()))

    def rename_test(self):
        if self._skip:
            self._rand()
            return
        self._test.execute(RenameTest('new_name%s' % str(self._rand())))

    def undo(self):
        self._macro_execute(Undo())

    def redo(self):
        self._macro_execute(Redo())

    def save(self):
        if self._skip:
            return
        command = SaveFile()
        print 'suite.execute(%s)' % str(command)
        self._suite.execute(command)

    def save_all(self):
        if self._skip:
            return
        command = SaveAll()
        print 'chief.execute(%s)' % str(command)
        self._chief.execute(command)

    def copy_test(self):
        if self._skip:
            self._rand()
            return
        command = CopyMacroAs('name test %s' % str(self._rand()))
        print 'test.execute(%s)' % str(command)
        self._test.execute(command)

    def copy_keyword(self):
        if self._skip:
            self._rand()
            return
        command = CopyMacroAs('name keyword %s' % str(self._rand()))
        print 'test.execute(%s)' % str(command)
        self._keyword.execute(command)

    def add_tag_to_test(self):
        if self._skip:
            self._rand()
            return
        tag_name = 'tag%s' % str(self._rand())
        print 'test.tags.execute(ChangeTag(Tag(""), "%s"))' % tag_name
        self._test.tags.execute(ChangeTag(Tag(""), tag_name))
<|endoftext|>


<commit_before>import pygame
import pygame.locals
import random

X,Y = 512,384
LEN = 20
FONT_SIZE = 40
RANDOM_FONT = False
RANDOM_COLOR = True

def make_label(text, cx, cy):
    rect = text.get_rect()
    rect.centerx = cx
    rect.centery = cy
    return (text, rect)

def render(render, font, *args):
    return getattr(font, render)(*args)

pygame.display.init()
screen = pygame.display.set_mode((X,Y), (pygame.locals.NOFRAME | pygame.locals.FULLSCREEN))
colors = {
          'red': (255,0,0),
          'blue': (0,0,255),
          'green': (0,255,0),
          'yellow': (255,255,0),
          'white': (255,255,255),
          'grey': (128,128,128),
          }
all_colors = colors.keys()

pygame.font.init()
all_fonts = pygame.font.get_fonts()
fonts = {}
for font in all_fonts:
    path = pygame.font.match_font(font)
    if path:
        fonts[font] = pygame.font.Font(path, FONT_SIZE)

default_font = pygame.font.get_default_font()
default_font = (f for f in all_fonts if default_font.startswith(f)).next()

if RANDOM_FONT: next_font = lambda: random.choice(all_fonts)
else: next_font = lambda: default_font

if RANDOM_COLOR: next_color = lambda: random.choice(all_colors)
else: next_color = lambda: 'white'

quit = False
text = "RubenWriter"
font = next_font()
color = next_color()

while not quit:
    screen.fill((0,0,0))

    # draw screen
    rendered = fonts[font].render(text + '_', True, colors[color])
    screen.blit(*make_label(rendered,X/2,Y/2))

    rendered = fonts[font].render('CTRL+SHIFT+ESC to exit', True, colors[color])
    screen.blit(*make_label(rendered,X/2,Y-FONT_SIZE))

    pygame.display.flip()

    # get keyboard input
    for event in pygame.event.get():
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_ESCAPE and shift and ctrl:
                quit = True
            elif event.key == pygame.K_BACKSPACE:
                text = text[:-1]
            else:
                try: char = event.unicode
                except: char = ''

                shift = event.mod&pygame.KMOD_SHIFT
                ctrl = event.mod&pygame.KMOD_CTRL

                if char:
                    text = text[-(LEN-1):] + char
                    font = next_font()
                    color = next_color()

<commit_msg>Less harsh colors.<commit_after>import pygame
import pygame.locals
import random

X,Y = 512,384
LEN = 20
FONT_SIZE = 40
RANDOM_FONT = False
RANDOM_COLOR = True

def make_label(text, cx, cy):
    rect = text.get_rect()
    rect.centerx = cx
    rect.centery = cy
    return (text, rect)

def render(render, font, *args):
    return getattr(font, render)(*args)

pygame.display.init()
screen = pygame.display.set_mode((X,Y), (pygame.locals.NOFRAME | pygame.locals.FULLSCREEN))
colors = {
          'red': (255,32,32),
          'blue': (32,32,255),
          'green': (32,255,32),
          'yellow': (255,255,32),
          'white': (255,255,255),
          'grey': (128,128,128),
          }
all_colors = colors.keys()

pygame.font.init()
all_fonts = pygame.font.get_fonts()
fonts = {}
for font in all_fonts:
    path = pygame.font.match_font(font)
    if path:
        fonts[font] = pygame.font.Font(path, FONT_SIZE)

default_font = pygame.font.get_default_font()
default_font = (f for f in all_fonts if default_font.startswith(f)).next()

if RANDOM_FONT: next_font = lambda: random.choice(all_fonts)
else: next_font = lambda: default_font

if RANDOM_COLOR: next_color = lambda: random.choice(all_colors)
else: next_color = lambda: 'white'

quit = False
text = "RubenWriter"
font = next_font()
color = next_color()

while not quit:
    screen.fill((0,0,0))

    # draw screen
    rendered = fonts[font].render(text + '_', True, colors[color])
    screen.blit(*make_label(rendered,X/2,Y/2))

    rendered = fonts[font].render('CTRL+SHIFT+ESC to exit', True, colors[color])
    screen.blit(*make_label(rendered,X/2,Y-FONT_SIZE))

    pygame.display.flip()

    # get keyboard input
    for event in pygame.event.get():
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_ESCAPE and shift and ctrl:
                quit = True
            elif event.key == pygame.K_BACKSPACE:
                text = text[:-1]
            else:
                try: char = event.unicode
                except: char = ''

                shift = event.mod&pygame.KMOD_SHIFT
                ctrl = event.mod&pygame.KMOD_CTRL

                if char:
                    text = text[-(LEN-1):] + char
                    font = next_font()
                    color = next_color()

<|endoftext|>


<commit_before># Copyright (C) 2015 SINTEF ICT,
# Applied Mathematics, Norway.
#
# Contact information:
# E-mail: eivind.fonn@sintef.no
# SINTEF ICT, Department of Applied Mathematics,
# P.O. Box 4760 Sluppen,
# 7045 Trondheim, Norway.
#
# This file is part of BADGER.
#
# BADGER is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# BADGER is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public
# License along with BADGER. If not, see
# <http://www.gnu.org/licenses/>.
#
# In accordance with Section 7(b) of the GNU Affero General Public
# License, a covered work must retain the producer line in every data
# file that is created or manipulated using BADGER.
#
# Other Usage
# You can be released from the requirements of the license by purchasing
# a commercial license. Buying such a license is mandatory as soon as you
# develop commercial activities involving BADGER without disclosing the
# source code of your own applications.
#
# This file may be used in accordance with the terms contained in a
# written agreement between you and SINTEF ICT.

from yaml import dump as yaml_dump
from numpy import array, ones, savetxt

FORMATS = ['yaml', 'py', 'txt']

def yaml(data, types, fn):
    with open(fn, 'w') as f:
        yaml_dump(data, f, default_flow_style=False)

def txt(data, types, fn):
    getfmt = lambda t: '%d' if t is int else '%.4e'
    keys, values, fmt, sh = [], [], [], []
    # Parameters in first columns, repeated as needed
    for d in data['parameters']:
        keys.append(d['name'])
        values.append(d['values'])
        fmt.append(getfmt(type(values[-1][0])))
        sh.append(len(values[-1]))
    template = ones(sh)
    for i in range(len(values)):
        sh = len(keys)*[1]
        sh[i] = -1
        new = array(values[i]).reshape(*sh)*template
        values[i] = new.flatten().tolist()
    # Results in ensuing columns
    for k, v in data['results'].items():
        keys.append(k)
        values.append(v)
        fmt.append(getfmt(eval(types[keys[-1]])))
    savetxt(fn, array(values).T, fmt=' '.join(fmt), header=' '.join(keys), comments='')

def py(data, types, fn):
    code = """from numpy import array, zeros, object_

metadata = {'hostname': '%(hostname)s',
            'time': '%(time)s'}
""" % {'hostname': data['metadata']['hostname'],
       'time': data['metadata']['time']}

    def fmt(v):
        if isinstance(v, str):
            return "'%s'" % v
        elif isinstance(v, list):
            return '[{}]'.format(', '.join(fmt(u) for u in v))
        return str(v)

    size = []
    for p in data['parameters']:
        code += '{} = array([{}])\n'.format(p['name'], ', '.join(fmt(d) for d in p['values']))
        size.append(len(p['values']))
    size = '({},)'.format(', '.join(str(s) for s in size))

    for k, vals in data['results'].items():
        dtype = types[k]
        if isinstance(dtype, list):
            dtype = 'object_'
        code += '{} = zeros({}, dtype={})\n'.format(k, size, dtype)
        for i, v in enumerate(vals):
            code += '{}.flat[{}] = {}\n'.format(k, i, fmt(v))

    with open(fn, 'w') as f:
        f.write(code)
<commit_msg>fix: allow non-numeric columns in .txt output<commit_after># Copyright (C) 2015 SINTEF ICT,
# Applied Mathematics, Norway.
#
# Contact information:
# E-mail: eivind.fonn@sintef.no
# SINTEF ICT, Department of Applied Mathematics,
# P.O. Box 4760 Sluppen,
# 7045 Trondheim, Norway.
#
# This file is part of BADGER.
#
# BADGER is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# BADGER is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public
# License along with BADGER. If not, see
# <http://www.gnu.org/licenses/>.
#
# In accordance with Section 7(b) of the GNU Affero General Public
# License, a covered work must retain the producer line in every data
# file that is created or manipulated using BADGER.
#
# Other Usage
# You can be released from the requirements of the license by purchasing
# a commercial license. Buying such a license is mandatory as soon as you
# develop commercial activities involving BADGER without disclosing the
# source code of your own applications.
#
# This file may be used in accordance with the terms contained in a
# written agreement between you and SINTEF ICT.

from yaml import dump as yaml_dump
from numpy import array, tile

FORMATS = ['yaml', 'py', 'txt']

def yaml(data, types, fn):
    with open(fn, 'w') as f:
        yaml_dump(data, f, default_flow_style=False)

def txt(data, types, fn):
    keys, values, sh0 = [], [], []
    # Parameters in first columns, repeated as needed
    for d in data['parameters']:
        keys.append(d['name'])
        values.append(d['values'])
        sh0.append(len(values[-1]))
    for i in range(len(values)):
        sh, reps = len(keys)*[1], sh0+[]
        sh[i] = -1
        reps[i] = 1
        new = tile(array(values[i]).reshape(*sh), reps)
        values[i] = new.flatten().tolist()
    # Results in ensuing columns
    for k, v in data['results'].items():
        keys.append(k)
        values.append(v)
    with open(fn, 'w') as f:
        f.write(' '.join(keys) + '\n')
        for row in array(values, dtype=str).T.tolist():
            f.write(' '.join(row) + '\n')

def py(data, types, fn):
    code = """from numpy import array, zeros, object_

metadata = {'hostname': '%(hostname)s',
            'time': '%(time)s'}
""" % {'hostname': data['metadata']['hostname'],
       'time': data['metadata']['time']}

    def fmt(v):
        if isinstance(v, str):
            return "'%s'" % v
        elif isinstance(v, list):
            return '[{}]'.format(', '.join(fmt(u) for u in v))
        return str(v)

    size = []
    for p in data['parameters']:
        code += '{} = array([{}])\n'.format(p['name'], ', '.join(fmt(d) for d in p['values']))
        size.append(len(p['values']))
    size = '({},)'.format(', '.join(str(s) for s in size))

    for k, vals in data['results'].items():
        dtype = types[k]
        if isinstance(dtype, list):
            dtype = 'object_'
        code += '{} = zeros({}, dtype={})\n'.format(k, size, dtype)
        for i, v in enumerate(vals):
            code += '{}.flat[{}] = {}\n'.format(k, i, fmt(v))

    with open(fn, 'w') as f:
        f.write(code)
<|endoftext|>


<commit_before>from IPython.core.magic import (register_line_magic, register_cell_magic, register_line_cell_magic)
import marshal, os, subprocess, sys, errno, tempfile, IPython, thread
from IPython.utils.warn import (warn, error)
import textwrap

if sys.platform == 'darwin':
	LD_LIBRARY_PATH='DYLD_LIBRARY_PATH'
else:
	LD_LIBRARY_PATH='LD_LIBRARY_PATH'

EUPS_DIR_DEFAULT = os.path.join(os.path.expanduser("~"), '.eups', 'default')

def update_sys_path(new, old):
	# update sys.path to reflect the new state of the PYTHONPATH
	# variable, while retaining

	env = dict(os.environ)
	env['PYTHONPATH'] = new

	cmd = """%s -m IPython -c 'import sys;
for p in sys.path:
	print p'
""" % (sys.executable)

	pypath = subprocess.check_output(cmd, shell=True, env=env).split('\n')

	sys.path = pypath

def _purge_linkfarm(libdir):
	# delete the directory
	for fn in os.listdir(libdir):
		fn = os.path.join(libdir, fn)
		if not os.path.islink(fn):
			raise Exception("linkfarm cleanup: the file %s is not a symbolic link. aborting out of caution." % fn )
		os.remove(fn)
	os.rmdir(libdir)

def rebuild_ld_library_path_linkfarm(paths):
	# Make sure we have a linkfarm to work with
	try:
		linkfarm = os.environ['IPYTHON_EUPS_LIB_LINKFARM']
	except KeyError:
		error(
			("The product you're setting up is attempting to modify %s, and\n" +
			"IPython hasn't been started via the ipython_eups wrapper. It's likely that the\n" +
			"product won't be setup-ed correctly, so I'm refusing to prceed.\n\n" +
			"Maybe you forgot to `setup ipython_eups' before starting ipython?") % LD_LIBRARY_PATH
		)
		return

	# create a temporary $linkfarm/lib directory
	dest = tempfile.mkdtemp(prefix='ipython-eups-linkfarm.%d.' % os.getpid(), dir=linkfarm)

	# link all items in paths into the joint path
	for path in paths.split(':'):
		if not path:
			continue

		if path.startswith(linkfarm + os.path.sep):
			continue

		if not os.path.isdir(path):
			continue

#		print "LINKING: %s" % path
#		print "     LF: %s" % linkfarm

		path = os.path.realpath(path)
		for fn in os.listdir(path):
			src = os.path.join(path, fn)
			lnk = os.path.join(dest, fn)
			try:
				os.symlink(src, lnk)
			except OSError as e:
				# Skip over links that already exist. Items from directories
				# earlier on the path will shadow those that come later.
				if e.errno != errno.EEXIST:
					raise

	libdir = os.path.join(linkfarm, 'lib')
	oldlibdir = os.path.realpath(libdir) if os.path.exists(libdir) else None

	# atomic replacement of the old directory
	tmplink = '%s.%d.%d' % (dest, thread.get_ident(), os.getpid())	# Unique temporary name
	os.symlink(os.path.basename(dest), tmplink)
	os.rename(tmplink, libdir)

	# delete the old directory; ignore any errors that may be encountered. as
	# those can come from race conditions if (say) two threads are trying to delete
	# the same directory (should be _very_ uncommon, though).
	try:
		if oldlibdir is not None:
			_purge_linkfarm(oldlibdir)
	except Exception as e:
		warn(str(e))

def init_eups(eups_loc='default', eups_path=None, set_default=False):
	"""
		If the user forgot to run setups.sh, initialize EUPS
		from scratch. Do it by running setups.sh and replacing our
		current environment with the environment it will generate.

		Arguments:

		   eups_loc:    directory where EUPS is installed (where
		                bin/setups.sh will be found). If not
		                given, a default from ~/.eups/default
		                will be assumed

		   eups_path:   The location of the EUPS product stack
		                (EUPS_PATH environment variable). Optional.

		   set_default: If set, eups_loc will be symlinked to
		   		~/.eups/default.
	"""

	# Locate EUPS
	if eups_loc == 'default':
		if not os.path.isdir(EUPS_DIR_DEFAULT):
			error(textwrap.dedent("""\
				You're trying to initialize EUPS without specifying its location,
				and the default in %(default)s does not exist (or is inaccessible).

				Either rerun the command as '%%eups init <eups_location>', or symlink
				the path to EUPS (the location where 'bin/setups.sh' can be found)
				as %(default)s .
			""" % { 'default': EUPS_DIR_DEFAULT } ).replace('\n', ' ').replace('  ', '\n\n'))
			return
		else:
			eups_loc = EUPS_DIR_DEFAULT

	# Verify that EUPS exists
	setups_sh = os.path.join(eups_loc, 'bin', 'setups.sh')
	if not os.path.isfile(setups_sh):
		error(textwrap.dedent("""\
			Cannot find %s.

			Are you sure that EUPS has been installed in %s?
		""" % (setups_sh, eups_loc) ).replace('\n', ' ').replace('  ', '\n\n'))
		return

	print "Initializing EUPS from %s" % eups_loc

	# Load the environment
	cmd = r"""
source %(setups_sh)s >/dev/null
%(python)s -c '
import os, sys;
for k, v in os.environ.iteritems():
    sys.stdout.write("%%s\0%%s\0" %% (k, v))
'""" % { 'python' : sys.executable, 'setups_sh' : setups_sh }

	envl = subprocess.check_output(cmd, shell=True).split('\0')
	env = { k: v for k, v in zip(envl[::2], envl[1::2]) }

	os.environ.clear()
	os.environ.update(dict=env)

	# Override EUPS_PATH, if requested
	if eups_path is not None:
		os.environ['EUPS_PATH'] = eups_path

	print "Using EUPS_PATH: %s" % os.environ['EUPS_PATH']

	if eups_loc != EUPS_DIR_DEFAULT:
		if set_default:
			if os.path.islink(EUPS_DIR_DEFAULT):
				os.unlink(EUPS_DIR_DEFAULT)
			os.symlink(eups_loc, EUPS_DIR_DEFAULT)
			print "Setting as default: %s symlinked to %s" % (eups_loc, EUPS_DIR_DEFAULT)
		elif not os.path.islink(EUPS_DIR_DEFAULT):
			print "To set this EUPS as default, rerun as `%%eups init --set-default %s'" % eups_loc

# Re-initialize the link farm every time IPython is started, so that the environment
# is properly cleaned of any left-overs from prior runs. E.g., this may happen
# when IPython notebook kernel is restarted by the user.
if 'IPYTHON_EUPS_LIB_LINKFARM' in os.environ and LD_LIBRARY_PATH in os.environ:
	rebuild_ld_library_path_linkfarm(os.environ[LD_LIBRARY_PATH])

def eups(line):
	"my line magic"

	import sys, os, os.path, re
	import subprocess
	from collections import OrderedDict

	from IPython import display

	split = line.split()
	cmd, args = split[0], split[1:]

	if cmd == "unsetup":
		cmd = "setup"
		args.insert(0, '--unsetup')

	if cmd == "init":
		# find the '--set-default' flag
		set_default = '--set-default' in args
		if set_default:
			args.remove('--set-default')
		return init_eups(*args, set_default=set_default)
	elif cmd == "setup":
		# run 'setup'
		setupimpl = os.path.join(os.environ['EUPS_DIR'], 'bin/eups_setup_impl.py')
		setupcmd = "python '%s' %s" % (setupimpl, ' '.join(args))

		try:
			ret = subprocess.check_output(setupcmd, stderr=subprocess.STDOUT, shell=True).strip().split('\n')
		except subprocess.CalledProcessError as e:
			error("%s\n%s" % (str(e), e.output))
		else:
			if not len(ret) or ret[-1] == 'false':
				# setup failed; return the error message
				error(str('\n'.join(ret[:-1])))
			else:
				exportRe = re.compile('export\s+(\w+)=(.*?);?$')
				unsetRe  = re.compile('unset\s+(\w+);?$')
				export = OrderedDict()
				unset  = set()
				for line in ret[:-1]:
					m = exportRe.match(line)
					if m:
						export[m.group(1)] = m.group(2)
						continue

					m = unsetRe.match(line)
					if m:
						unset.add(m.group(1))
						continue

					error("EUPS told me to '%s' but I don't know how to handle that. Aborting." % (line))

				# do the variable (un)setups. We do this only after
				# the entire output is processed above, to avoid
				# aborting half-way in case of errors (and leaving
				# the environment in an incoherent state).

				for var, value in export.iteritems():
					value = subprocess.check_output('/bin/echo -n %s' % value, shell=True)
					if var == "PYTHONPATH":
						update_sys_path(value, os.environ[var])
					if var == LD_LIBRARY_PATH:
						rebuild_ld_library_path_linkfarm(value)
					os.environ[var] = value
					#print "set: %s=[%s]" % (var, os.environ[var])
				for var in unset:
					#print "unset: " + var
					del os.environ[var]
	else:
		#setupcmd = "script -q /dev/null ~/bin/tst.py"
		#setupcmd = "script -q /dev/null eups %s %s 1>&2" % (cmd, ' '.join(args))
		#setupcmd = "~/bin/tst.py"
		setupcmd = "eups %s %s" % (cmd, ' '.join(args))

		with tempfile.NamedTemporaryFile() as fp:
			# test for existance and flavor of 'script'. If it exists,
			# run setupcmd through it so we can get unbuffered stdio.
			# See http://stackoverflow.com/a/1402389/897575 for details.
			#
			# The named temporary file helps us safely execute the command
			# line on Linux, if it had quoted arguments (script -c expects
			# a single arg. on Linux)
			if os.path.exists('/usr/bin/script'):
				print >>fp, setupcmd
				fp.flush()

				if sys.platform == 'darwin':
					setupcmd = "script -q /dev/null sh %s" % fp.name
				else:
					setupcmd = "script -q /dev/null -c 'sh %s'" % fp.name

			#print setupcmd
			# run EUPS
			try:
				pipe = subprocess.Popen(setupcmd, stderr=subprocess.STDOUT, stdout=subprocess.PIPE, shell=True)
				for line in iter(lambda : pipe.stdout.read(1), ""):
					sys.stdout.write(line)
					sys.stdout.flush()
			except subprocess.CalledProcessError as e:
				error("%s\n%s" % (str(e), e.output))

def load_ipython_extension(ipython):
	# The `ipython` argument is the currently active `InteractiveShell`
	# instance, which can be used in any way. This allows you to register
	# new magics or aliases, for example.
	ipython.register_magic_function(eups)

	# Check if EUPS has been setup, if not, try to set it up
	# from the default environment.
	if 'EUPS_DIR' not in os.environ:
		if os.path.isdir(EUPS_DIR_DEFAULT):
			init_eups()
		else:
			warn(("EUPS not initialized, and no default EUPS has been symlinked as %s. " +
			      "Make sure to initialize it with `%%eups init <path_to_eups>'") % EUPS_DIR_DEFAULT)

#def unload_ipython_extension(ipython):
#	# If you want your extension to be unloadable, put that logic here.
<commit_msg>python/eups_magic.py: use IPython.utils.process to run eups commands<commit_after>from IPython.core.magic import (register_line_magic, register_cell_magic, register_line_cell_magic)
import marshal, os, subprocess, sys, errno, tempfile, IPython, thread
from IPython.utils.warn import (warn, error)
import textwrap

if sys.platform == 'darwin':
	LD_LIBRARY_PATH='DYLD_LIBRARY_PATH'
else:
	LD_LIBRARY_PATH='LD_LIBRARY_PATH'

EUPS_DIR_DEFAULT = os.path.join(os.path.expanduser("~"), '.eups', 'default')

def update_sys_path(new, old):
	# update sys.path to reflect the new state of the PYTHONPATH
	# variable, while retaining

	env = dict(os.environ)
	env['PYTHONPATH'] = new

	cmd = """%s -m IPython -c 'import sys;
for p in sys.path:
	print p'
""" % (sys.executable)

	pypath = subprocess.check_output(cmd, shell=True, env=env).split('\n')

	sys.path = pypath

def _purge_linkfarm(libdir):
	# delete the directory
	for fn in os.listdir(libdir):
		fn = os.path.join(libdir, fn)
		if not os.path.islink(fn):
			raise Exception("linkfarm cleanup: the file %s is not a symbolic link. aborting out of caution." % fn )
		os.remove(fn)
	os.rmdir(libdir)

def rebuild_ld_library_path_linkfarm(paths):
	# Make sure we have a linkfarm to work with
	try:
		linkfarm = os.environ['IPYTHON_EUPS_LIB_LINKFARM']
	except KeyError:
		error(
			("The product you're setting up is attempting to modify %s, and\n" +
			"IPython hasn't been started via the ipython_eups wrapper. It's likely that the\n" +
			"product won't be setup-ed correctly, so I'm refusing to prceed.\n\n" +
			"Maybe you forgot to `setup ipython_eups' before starting ipython?") % LD_LIBRARY_PATH
		)
		return

	# create a temporary $linkfarm/lib directory
	dest = tempfile.mkdtemp(prefix='ipython-eups-linkfarm.%d.' % os.getpid(), dir=linkfarm)

	# link all items in paths into the joint path
	for path in paths.split(':'):
		if not path:
			continue

		if path.startswith(linkfarm + os.path.sep):
			continue

		if not os.path.isdir(path):
			continue

#		print "LINKING: %s" % path
#		print "     LF: %s" % linkfarm

		path = os.path.realpath(path)
		for fn in os.listdir(path):
			src = os.path.join(path, fn)
			lnk = os.path.join(dest, fn)
			try:
				os.symlink(src, lnk)
			except OSError as e:
				# Skip over links that already exist. Items from directories
				# earlier on the path will shadow those that come later.
				if e.errno != errno.EEXIST:
					raise

	libdir = os.path.join(linkfarm, 'lib')
	oldlibdir = os.path.realpath(libdir) if os.path.exists(libdir) else None

	# atomic replacement of the old directory
	tmplink = '%s.%d.%d' % (dest, thread.get_ident(), os.getpid())	# Unique temporary name
	os.symlink(os.path.basename(dest), tmplink)
	os.rename(tmplink, libdir)

	# delete the old directory; ignore any errors that may be encountered. as
	# those can come from race conditions if (say) two threads are trying to delete
	# the same directory (should be _very_ uncommon, though).
	try:
		if oldlibdir is not None:
			_purge_linkfarm(oldlibdir)
	except Exception as e:
		warn(str(e))

def init_eups(eups_loc='default', eups_path=None, set_default=False):
	"""
		If the user forgot to run setups.sh, initialize EUPS
		from scratch. Do it by running setups.sh and replacing our
		current environment with the environment it will generate.

		Arguments:

		   eups_loc:    directory where EUPS is installed (where
		                bin/setups.sh will be found). If not
		                given, a default from ~/.eups/default
		                will be assumed

		   eups_path:   The location of the EUPS product stack
		                (EUPS_PATH environment variable). Optional.

		   set_default: If set, eups_loc will be symlinked to
		   		~/.eups/default.
	"""

	# Locate EUPS
	if eups_loc == 'default':
		if not os.path.isdir(EUPS_DIR_DEFAULT):
			error(textwrap.dedent("""\
				You're trying to initialize EUPS without specifying its location,
				and the default in %(default)s does not exist (or is inaccessible).

				Either rerun the command as '%%eups init <eups_location>', or symlink
				the path to EUPS (the location where 'bin/setups.sh' can be found)
				as %(default)s .
			""" % { 'default': EUPS_DIR_DEFAULT } ).replace('\n', ' ').replace('  ', '\n\n'))
			return
		else:
			eups_loc = EUPS_DIR_DEFAULT

	# Verify that EUPS exists
	setups_sh = os.path.join(eups_loc, 'bin', 'setups.sh')
	if not os.path.isfile(setups_sh):
		error(textwrap.dedent("""\
			Cannot find %s.

			Are you sure that EUPS has been installed in %s?
		""" % (setups_sh, eups_loc) ).replace('\n', ' ').replace('  ', '\n\n'))
		return

	print "Initializing EUPS from %s" % eups_loc

	# Load the environment
	cmd = r"""
source %(setups_sh)s >/dev/null
%(python)s -c '
import os, sys;
for k, v in os.environ.iteritems():
    sys.stdout.write("%%s\0%%s\0" %% (k, v))
'""" % { 'python' : sys.executable, 'setups_sh' : setups_sh }

	envl = subprocess.check_output(cmd, shell=True).split('\0')
	env = { k: v for k, v in zip(envl[::2], envl[1::2]) }

	os.environ.clear()
	os.environ.update(dict=env)

	# Override EUPS_PATH, if requested
	if eups_path is not None:
		os.environ['EUPS_PATH'] = eups_path

	print "Using EUPS_PATH: %s" % os.environ['EUPS_PATH']

	if eups_loc != EUPS_DIR_DEFAULT:
		if set_default:
			if os.path.islink(EUPS_DIR_DEFAULT):
				os.unlink(EUPS_DIR_DEFAULT)
			os.symlink(eups_loc, EUPS_DIR_DEFAULT)
			print "Setting as default: %s symlinked to %s" % (eups_loc, EUPS_DIR_DEFAULT)
		elif not os.path.islink(EUPS_DIR_DEFAULT):
			print "To set this EUPS as default, rerun as `%%eups init --set-default %s'" % eups_loc

# Re-initialize the link farm every time IPython is started, so that the environment
# is properly cleaned of any left-overs from prior runs. E.g., this may happen
# when IPython notebook kernel is restarted by the user.
if 'IPYTHON_EUPS_LIB_LINKFARM' in os.environ and LD_LIBRARY_PATH in os.environ:
	rebuild_ld_library_path_linkfarm(os.environ[LD_LIBRARY_PATH])

def eups(line):
	"my line magic"

	import sys, os, os.path, re
	import subprocess
	from collections import OrderedDict

	from IPython import display

	split = line.split()
	cmd, args = split[0], split[1:]

	if cmd == "unsetup":
		cmd = "setup"
		args.insert(0, '--unsetup')

	if cmd == "init":
		# find the '--set-default' flag
		set_default = '--set-default' in args
		if set_default:
			args.remove('--set-default')
		return init_eups(*args, set_default=set_default)
	elif cmd == "setup":
		# run 'setup'
		setupimpl = os.path.join(os.environ['EUPS_DIR'], 'bin/eups_setup_impl.py')
		setupcmd = "python '%s' %s" % (setupimpl, ' '.join(args))

		try:
			ret = subprocess.check_output(setupcmd, stderr=subprocess.STDOUT, shell=True).strip().split('\n')
		except subprocess.CalledProcessError as e:
			error("%s\n%s" % (str(e), e.output))
		else:
			if not len(ret) or ret[-1] == 'false':
				# setup failed; return the error message
				error(str('\n'.join(ret[:-1])))
			else:
				exportRe = re.compile('export\s+(\w+)=(.*?);?$')
				unsetRe  = re.compile('unset\s+(\w+);?$')
				export = OrderedDict()
				unset  = set()
				for line in ret[:-1]:
					m = exportRe.match(line)
					if m:
						export[m.group(1)] = m.group(2)
						continue

					m = unsetRe.match(line)
					if m:
						unset.add(m.group(1))
						continue

					error("EUPS told me to '%s' but I don't know how to handle that. Aborting." % (line))

				# do the variable (un)setups. We do this only after
				# the entire output is processed above, to avoid
				# aborting half-way in case of errors (and leaving
				# the environment in an incoherent state).

				for var, value in export.iteritems():
					value = subprocess.check_output('/bin/echo -n %s' % value, shell=True)
					if var == "PYTHONPATH":
						update_sys_path(value, os.environ[var])
					if var == LD_LIBRARY_PATH:
						rebuild_ld_library_path_linkfarm(value)
					os.environ[var] = value
					#print "set: %s=[%s]" % (var, os.environ[var])
				for var in unset:
					#print "unset: " + var
					del os.environ[var]
	else:
		setupcmd = "eups %s %s" % (cmd, ' '.join(args))
		from IPython.utils.process import system

		system(setupcmd)

def load_ipython_extension(ipython):
	# The `ipython` argument is the currently active `InteractiveShell`
	# instance, which can be used in any way. This allows you to register
	# new magics or aliases, for example.
	ipython.register_magic_function(eups)

	# Check if EUPS has been setup, if not, try to set it up
	# from the default environment.
	if 'EUPS_DIR' not in os.environ:
		if os.path.isdir(EUPS_DIR_DEFAULT):
			init_eups()
		else:
			warn(("EUPS not initialized, and no default EUPS has been symlinked as %s. " +
			      "Make sure to initialize it with `%%eups init <path_to_eups>'") % EUPS_DIR_DEFAULT)

#def unload_ipython_extension(ipython):
#	# If you want your extension to be unloadable, put that logic here.
<|endoftext|>