<commit_before>"""
Select rows from a HXL dataset.
David Megginson
October 2014

Supply a list of simple <hashtag><operator><value> pairs, and return
the rows in the HXL dataset that contain matches for any of them.

License: Public Domain
Documentation: https://github.com/HXLStandard/libhxl-python/wiki
"""

import sys
import re
import operator
import argparse
from hxl.model import DataProvider, TagPattern
from hxl.filters import make_input, make_output
from hxl.io import StreamInput, HXLReader, write_hxl

def operator_re(s, pattern):
    """Regular-expression comparison operator."""
    return re.match(pattern, s)

def operator_nre(s, pattern):
    """Regular-expression negative comparison operator."""
    return not re.match(pattern, s)

class Query(object):
    """Query to execute against a row of HXL data."""

    def __init__(self, pattern, op, value):
        self.pattern = pattern
        self.op = op
        self.value = value
        self._saved_indices = None
        try:
            float(value)
            self._is_numeric = True
        except:
            self._is_numeric = False

    def match_row(self, row):
        """Check if a key-value pair appears in a HXL row"""
        indices = self._get_saved_indices(row.columns)
        length = len(row.values)
        for i in indices:
            if i < length and row.values[i] and self.match_value(row.values[i]):
                    return True
        return False

    def match_value(self, value):
        """Try an operator as numeric first, then string"""
        # TODO add dates
        # TODO use knowledge about HXL tags
        if self._is_numeric:
            try:
                return self.op(float(value), float(self.value))
            except ValueError:
                pass
        else:
            return self.op(value, self.value)

    def _get_saved_indices(self, columns):
        """Cache the column tests, so that we run them only once."""
        # FIXME - assuming that the columns never change
        if self._saved_indices is None:
            self._saved_indices = []
            for i in range(len(columns)):
                if self.pattern.match(columns[i]):
                    self._saved_indices.append(i)
        return self._saved_indices

    @staticmethod
    def parse(s):
        """Parse a filter expression"""
        parts = re.split(r'([<>]=?|!?=|!?~)', s, maxsplit=1)
        pattern = TagPattern.parse(parts[0])
        op = Query.OPERATOR_MAP[parts[1]]
        value = parts[2]
        return Query(pattern, op, value)

    # Constant map of comparison operators
    OPERATOR_MAP = {
        '=': operator.eq,
        '!=': operator.ne,
        '<': operator.lt,
        '<=': operator.le,
        '>': operator.gt,
        '>=': operator.ge,
        '~': operator_re,
        '!~': operator_nre
    }

class SelectFilter(DataProvider):
    """
    Composable filter class to select rows from a HXL dataset.

    This is the class supporting the hxlselect command-line utility.

    Because this class is a {@link hxl.model.DataProvider}, you can use
    it as the source to an instance of another filter class to build a
    dynamic, single-threaded processing pipeline.

    Usage:

    source = HXLReader(sys.stdin)
    filter = SelectFilter(source, queries=[(TagPattern.parse('#org'), operator.eq, 'OXFAM')])
    write_hxl(sys.stdout, filter)

    """

    def __init__(self, source, queries=[], reverse=False):
        """
        Constructor
        @param source the HXL data source
        @param queries a series for parsed queries
        @param reverse True to reverse the sense of the select
        """
        self.source = source
        self.queries = queries
        self.reverse = reverse

    @property
    def columns(self):
        """Pass on the source columns unmodified."""
        return self.source.columns

    def __next__(self):
        """
        Return the next row that matches the select.
        """
        row = next(self.source)
        while not self.match_row(row):
            row = next(self.source)
        return row

    next = __next__

    def match_row(self, row):
        """Check if any of the queries matches the row (implied OR)."""
        for query in self.queries:
            if query.match_row(row):
                return not self.reverse
        return self.reverse

#
# Command-line support
#

def run(args, stdin=sys.stdin, stdout=sys.stdout, stderr=sys.stderr):
    """
    Run hxlselect with command-line arguments.
    @param args A list of arguments, excluding the script name
    @param stdin Standard input for the script
    @param stdout Standard output for the script
    @param stderr Standard error for the script
    """

    # Command-line arguments
    parser = argparse.ArgumentParser(description = 'Filter rows in a HXL dataset.')
    parser.add_argument(
        'infile',
        help='HXL file to read (if omitted, use standard input).',
        nargs='?'
        )
    parser.add_argument(
        'outfile',
        help='HXL file to write (if omitted, use standard output).',
        nargs='?'
        )
    parser.add_argument(
        '-q',
        '--query',
        help='query expression for selecting rows (use multiple times for logical OR): <hashtag><op><value>, where <op> is =, !=, <, <=, >, >=, ~, or !~',
        action='append',
        metavar='tag=value, etc.',
        default=[],
        type=Query.parse
        )
    parser.add_argument(
        '-r',
        '--reverse',
        help='Show only lines *not* matching criteria',
        action='store_const',
        const=True,
        default=False
        )
    args = parser.parse_args(args)

    with make_input(args.infile, stdin) as input, make_output(args.outfile, stdout) as output:
        source = HXLReader(input)
        filter = SelectFilter(source, queries=args.query, reverse=args.reverse)
        write_hxl(output.output, filter)

# end
<commit_msg>Fixed select filter per #40.<commit_after>"""
Select rows from a HXL dataset.
David Megginson
October 2014

Supply a list of simple <hashtag><operator><value> pairs, and return
the rows in the HXL dataset that contain matches for any of them.

License: Public Domain
Documentation: https://github.com/HXLStandard/libhxl-python/wiki
"""

import sys
import re
import operator
import argparse
from hxl.model import DataProvider, TagPattern
from hxl.filters import make_input, make_output
from hxl.io import StreamInput, HXLReader, write_hxl

def operator_re(s, pattern):
    """Regular-expression comparison operator."""
    return re.match(pattern, s)

def operator_nre(s, pattern):
    """Regular-expression negative comparison operator."""
    return not re.match(pattern, s)

class Query(object):
    """Query to execute against a row of HXL data."""

    def __init__(self, pattern, op, value):
        self.pattern = pattern
        self.op = op
        self.value = value
        self._saved_indices = None
        try:
            float(value)
            self._is_numeric = True
        except:
            self._is_numeric = False

    def match_row(self, row):
        """Check if a key-value pair appears in a HXL row"""
        indices = self._get_saved_indices(row.columns)
        length = len(row.values)
        for i in indices:
            if i < length and row.values[i] and self.match_value(row.values[i]):
                    return True
        return False

    def match_value(self, value):
        """Try an operator as numeric first, then string"""
        # TODO add dates
        # TODO use knowledge about HXL tags
        if self._is_numeric:
            try:
                return self.op(float(value), float(self.value))
            except ValueError:
                pass
        else:
            return self.op(value, self.value)

    def _get_saved_indices(self, columns):
        """Cache the column tests, so that we run them only once."""
        # FIXME - assuming that the columns never change
        if self._saved_indices is None:
            self._saved_indices = []
            for i in range(len(columns)):
                if self.pattern.match(columns[i]):
                    self._saved_indices.append(i)
        return self._saved_indices

    @staticmethod
    def parse(s):
        """Parse a filter expression"""
        parts = re.split(r'([<>]=?|!?=|!?~)', s, maxsplit=1)
        pattern = TagPattern.parse(parts[0])
        op = Query.OPERATOR_MAP[parts[1]]
        value = parts[2]
        return Query(pattern, op, value)

    # Constant map of comparison operators
    OPERATOR_MAP = {
        '=': operator.eq,
        '!=': operator.ne,
        '<': operator.lt,
        '<=': operator.le,
        '>': operator.gt,
        '>=': operator.ge,
        '~': operator_re,
        '!~': operator_nre
    }

class SelectFilter(DataProvider):
    """
    Composable filter class to select rows from a HXL dataset.

    This is the class supporting the hxlselect command-line utility.

    Because this class is a {@link hxl.model.DataProvider}, you can use
    it as the source to an instance of another filter class to build a
    dynamic, single-threaded processing pipeline.

    Usage:

    source = HXLReader(sys.stdin)
    filter = SelectFilter(source, queries=[(TagPattern.parse('#org'), operator.eq, 'OXFAM')])
    write_hxl(sys.stdout, filter)

    """

    def __init__(self, source, queries=[], reverse=False):
        """
        Constructor
        @param source the HXL data source
        @param queries a series for parsed queries
        @param reverse True to reverse the sense of the select
        """
        self.source = source
        self.queries = queries
        self.reverse = reverse

    @property
    def columns(self):
        """Pass on the source columns unmodified."""
        return self.source.columns

    def __iter__(self):
        return SelectFilter.Iterator(self)

    class Iterator:

        def __init__(self, outer):
            self.outer = outer
            self.iterator = iter(outer.source)

        def __next__(self):
            """
            Return the next row that matches the select.
            """
            row = next(self.iterator)
            while not self.match_row(row):
                row = next(self.iterator)
            return row

        next = __next__

        def match_row(self, row):
            """Check if any of the queries matches the row (implied OR)."""
            for query in self.outer.queries:
                if query.match_row(row):
                    return not self.outer.reverse
            return self.outer.reverse

#
# Command-line support
#

def run(args, stdin=sys.stdin, stdout=sys.stdout, stderr=sys.stderr):
    """
    Run hxlselect with command-line arguments.
    @param args A list of arguments, excluding the script name
    @param stdin Standard input for the script
    @param stdout Standard output for the script
    @param stderr Standard error for the script
    """

    # Command-line arguments
    parser = argparse.ArgumentParser(description = 'Filter rows in a HXL dataset.')
    parser.add_argument(
        'infile',
        help='HXL file to read (if omitted, use standard input).',
        nargs='?'
        )
    parser.add_argument(
        'outfile',
        help='HXL file to write (if omitted, use standard output).',
        nargs='?'
        )
    parser.add_argument(
        '-q',
        '--query',
        help='query expression for selecting rows (use multiple times for logical OR): <hashtag><op><value>, where <op> is =, !=, <, <=, >, >=, ~, or !~',
        action='append',
        metavar='tag=value, etc.',
        default=[],
        type=Query.parse
        )
    parser.add_argument(
        '-r',
        '--reverse',
        help='Show only lines *not* matching criteria',
        action='store_const',
        const=True,
        default=False
        )
    args = parser.parse_args(args)

    with make_input(args.infile, stdin) as input, make_output(args.outfile, stdout) as output:
        source = HXLReader(input)
        filter = SelectFilter(source, queries=args.query, reverse=args.reverse)
        write_hxl(output.output, filter)

# end
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
"""
Main plugin file.
"""

from __future__ import absolute_import
import configparser
import requests

from ee_plugin.icons import resources
import webbrowser
from builtins import object
import os.path
import json

from qgis.PyQt.QtCore import QSettings, QTranslator, qVersion, QCoreApplication
from qgis.PyQt.QtWidgets import QAction
from qgis.PyQt.QtGui import QIcon
from qgis.core import QgsProject

import ee
from ee_plugin import utils
from ee_plugin import provider

# read the plugin version from metadata
cfg = configparser.ConfigParser()
cfg.read(os.path.join(os.path.dirname(__file__), 'metadata.txt'))
VERSION = cfg.get('general', 'version')
version_checked = False

class GoogleEarthEnginePlugin(object):
    """QGIS Plugin Implementation."""

    def __init__(self, iface):
        """Constructor.

        :param iface: An interface instance that will be passed to this class
            which provides the hook by which you can manipulate the QGIS
            application at run time.
        :type iface: QgsInterface
        """
        # Save reference to the QGIS interface
        self.iface = iface

        # initialize plugin directory
        self.plugin_dir = os.path.dirname(__file__)

        # initialize locale
        locale = QSettings().value('locale/userLocale')[0:2]
        locale_path = os.path.join(
            self.plugin_dir,
            'i18n',
            'GoogleEarthEnginePlugin_{}.qm'.format(locale))

        if os.path.exists(locale_path):
            self.translator = QTranslator()
            self.translator.load(locale_path)

            if qVersion() > '4.3.3':
                QCoreApplication.installTranslator(self.translator)

        self.menu_name_plugin = self.tr("Google Earth Engine Plugin")

        # Create and register the ee data provider
        provider.register_data_provider()

    # noinspection PyMethodMayBeStatic
    def tr(self, message):
        """Get the translation for a string using Qt translation API.

        We implement this ourselves since we do not inherit QObject.

        :param message: String for translation.
        :type message: str, QString

        :returns: Translated version of message.
        :rtype: QString
        """
        # noinspection PyTypeChecker,PyArgumentList,PyCallByClass
        return QCoreApplication.translate('GoogleEarthEngine', message)

    def initGui(self):
        ### Main dockwidget menu
        # Create action that will start plugin configuration
        icon_path = ':/plugins/ee_plugin/icons/earth_engine.svg'
        self.dockable_action = QAction(
            QIcon(icon_path), "User Guide", self.iface.mainWindow())
        # connect the action to the run method
        self.dockable_action.triggered.connect(self.run)
        # Add menu item
        self.iface.addPluginToMenu(self.menu_name_plugin, self.dockable_action)
        # Register signal to initialize EE layers on project load
        self.iface.projectRead.connect(self.updateLayers)

    def run(self):
        # open user guide in external web browser
        webbrowser.open_new(
            "http://qgis-ee-plugin.appspot.com/user-guide")

    def check_version(self):
        global version_checked

        if version_checked:
            return

        try:
            latest_version = requests.get('https://qgis-ee-plugin.appspot.com/get_latest_version').text

            if VERSION != latest_version:
                self.iface.messageBar().pushMessage(u'Earth Engine plugin says', u'Hey there, there is a more recent version of the ee_plugin available {0} and you have {1}, please upgrade!'.format(latest_version, VERSION), duration=6)
        except:
            print('Error occurrend when checking for recent plugin version, skipping ...')

        finally:
            version_checked = True

    def unload(self):
        # Remove the plugin menu item and icon
        self.iface.removePluginMenu(
            self.menu_name_plugin, self.dockable_action)

    def updateLayers(self):
        layers = QgsProject.instance().mapLayers().values()

        for l in filter(lambda layer: layer.customProperty('ee-layer'), layers):
            ee_object = l.customProperty('ee-object')
            ee_object_vis = l.customProperty('ee-object-vis')

            ee_object = ee.deserializer.fromJSON(ee_object)
            ee_object_vis = json.loads(ee_object_vis)

            # update loaded EE layer

            # get existing values for name, visibility, and opacity
            # TODO: this should not be needed, refactor add_or_update_ee_layer to update_ee_layer
            name = l.name()
            shown = QgsProject.instance().layerTreeRoot().findLayer(l.id()).itemVisibilityChecked()
            opacity = l.renderer().opacity()

            utils.add_or_update_ee_layer(ee_object, ee_object_vis, name, shown, opacity)
<commit_msg>Improving the message bar text<commit_after># -*- coding: utf-8 -*-
"""
Main plugin file.
"""

from __future__ import absolute_import
import configparser
import requests

from ee_plugin.icons import resources
import webbrowser
from builtins import object
import os.path
import json

from qgis.PyQt.QtCore import QSettings, QTranslator, qVersion, QCoreApplication
from qgis.PyQt.QtWidgets import QAction
from qgis.PyQt.QtGui import QIcon
from qgis.core import QgsProject

import ee
from ee_plugin import utils
from ee_plugin import provider

# read the plugin version from metadata
cfg = configparser.ConfigParser()
cfg.read(os.path.join(os.path.dirname(__file__), 'metadata.txt'))
VERSION = cfg.get('general', 'version')
version_checked = False

class GoogleEarthEnginePlugin(object):
    """QGIS Plugin Implementation."""

    def __init__(self, iface):
        """Constructor.

        :param iface: An interface instance that will be passed to this class
            which provides the hook by which you can manipulate the QGIS
            application at run time.
        :type iface: QgsInterface
        """
        # Save reference to the QGIS interface
        self.iface = iface

        # initialize plugin directory
        self.plugin_dir = os.path.dirname(__file__)

        # initialize locale
        locale = QSettings().value('locale/userLocale')[0:2]
        locale_path = os.path.join(
            self.plugin_dir,
            'i18n',
            'GoogleEarthEnginePlugin_{}.qm'.format(locale))

        if os.path.exists(locale_path):
            self.translator = QTranslator()
            self.translator.load(locale_path)

            if qVersion() > '4.3.3':
                QCoreApplication.installTranslator(self.translator)

        self.menu_name_plugin = self.tr("Google Earth Engine Plugin")

        # Create and register the ee data provider
        provider.register_data_provider()

    # noinspection PyMethodMayBeStatic
    def tr(self, message):
        """Get the translation for a string using Qt translation API.

        We implement this ourselves since we do not inherit QObject.

        :param message: String for translation.
        :type message: str, QString

        :returns: Translated version of message.
        :rtype: QString
        """
        # noinspection PyTypeChecker,PyArgumentList,PyCallByClass
        return QCoreApplication.translate('GoogleEarthEngine', message)

    def initGui(self):
        ### Main dockwidget menu
        # Create action that will start plugin configuration
        icon_path = ':/plugins/ee_plugin/icons/earth_engine.svg'
        self.dockable_action = QAction(
            QIcon(icon_path), "User Guide", self.iface.mainWindow())
        # connect the action to the run method
        self.dockable_action.triggered.connect(self.run)
        # Add menu item
        self.iface.addPluginToMenu(self.menu_name_plugin, self.dockable_action)
        # Register signal to initialize EE layers on project load
        self.iface.projectRead.connect(self.updateLayers)

    def run(self):
        # open user guide in external web browser
        webbrowser.open_new(
            "http://qgis-ee-plugin.appspot.com/user-guide")

    def check_version(self):
        global version_checked

        if version_checked:
            return

        try:
            latest_version = requests.get('https://qgis-ee-plugin.appspot.com/get_latest_version').text

            if VERSION != latest_version:
                self.iface.messageBar().pushMessage('Earth Engine plugin:',
                    'There is a more recent version of the ee_plugin available {0} and you have {1}, please upgrade!'.format(latest_version, VERSION), duration=15)
        except:
            print('Error occurred when checking for recent plugin version, skipping ...')

        finally:
            version_checked = True

    def unload(self):
        # Remove the plugin menu item and icon
        self.iface.removePluginMenu(
            self.menu_name_plugin, self.dockable_action)

    def updateLayers(self):
        layers = QgsProject.instance().mapLayers().values()

        for l in filter(lambda layer: layer.customProperty('ee-layer'), layers):
            ee_object = l.customProperty('ee-object')
            ee_object_vis = l.customProperty('ee-object-vis')

            ee_object = ee.deserializer.fromJSON(ee_object)
            ee_object_vis = json.loads(ee_object_vis)

            # update loaded EE layer

            # get existing values for name, visibility, and opacity
            # TODO: this should not be needed, refactor add_or_update_ee_layer to update_ee_layer
            name = l.name()
            shown = QgsProject.instance().layerTreeRoot().findLayer(l.id()).itemVisibilityChecked()
            opacity = l.renderer().opacity()

            utils.add_or_update_ee_layer(ee_object, ee_object_vis, name, shown, opacity)
<|endoftext|>


<commit_before># -*- coding: utf8 -*-
# This file is part of PyBossa.
#
# Copyright (C) 2013 Daniel Lombraña González
#
# PyBossa 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.
#
# PyBossa 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 PyBossa. If not, see <http://www.gnu.org/licenses/>.
from pybossa.core import create_app

if __name__ == "__main__":  # pragma: no cover
    app = create_app()
    #logging.basicConfig(level=logging.NOTSET)
    app.run(host=app.config['HOST'], port=app.config['PORT'],
            debug=app.config.get('DEBUG', True))
else:
    app = create_app()
<commit_msg>Change IP.<commit_after># -*- coding: utf8 -*-
# This file is part of PyBossa.
#
# Copyright (C) 2015 SciFabric LTD.
#
# PyBossa 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.
#
# PyBossa 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 PyBossa. If not, see <http://www.gnu.org/licenses/>.
from pybossa.core import create_app

if __name__ == "__main__":  # pragma: no cover
    app = create_app()
    #logging.basicConfig(level=logging.NOTSET)
    app.run(host=app.config['HOST'], port=app.config['PORT'],
            debug=app.config.get('DEBUG', True))
else:
    app = create_app()
<|endoftext|>


<commit_before>#!/usr/bin/env python
import os
import yaml
import threading

import rospy
import rospkg
import roslaunch

from rqt_launchtree.launchtree_loader import LaunchtreeLoader
from rqt_launchtree.launchtree_config import LaunchtreeConfig, LaunchtreeArg, LaunchtreeRemap

from python_qt_binding import loadUi
from python_qt_binding.QtCore import Qt, Signal
from python_qt_binding.QtGui import QFileDialog, QWidget, QIcon, QTreeWidgetItem, QColor

class LaunchtreeEntryItem(QTreeWidgetItem):
	_type_order = [dict, roslaunch.core.Node, LaunchtreeArg, roslaunch.core.Param, LaunchtreeRemap, object]
	#inconsistent = False
	def __init__(self, *args, **kw ):
		super(LaunchtreeEntryItem, self).__init__(*args, **kw)
		self.inconsistent = False
	def __ge__(self, other):
		own_type_idx = map(lambda t: isinstance(self.instance, t), self._type_order).index(True)
		other_type_idx = map(lambda t: isinstance(other.instance, t), self._type_order).index(True)
		if own_type_idx != other_type_idx:
			return own_type_idx >= other_type_idx
		return self.text(0) >= other.text(0)
	def __lt__(self, other):
		return not self.__ge__(other)

class LaunchtreeWidget(QWidget):

	update_launch_view = Signal(object)

	def __init__(self, context):
		super(LaunchtreeWidget, self).__init__()

		self._rp = rospkg.RosPack()
		res_folder = os.path.join(self._rp.get_path('rqt_launchtree'), 'resource')
		ui_file = os.path.join(res_folder, 'launchtree_widget.ui')
		loadUi(ui_file, self)

		self.setObjectName('LaunchtreeWidget')
		self.reload_button.setIcon(QIcon.fromTheme('view-refresh'))

		self._properties_empty_ui = os.path.join(res_folder, 'properties_empty.ui')
		self._properties_param_ui = os.path.join(res_folder, 'properties_param.ui')

		self._icon_include = QIcon(os.path.join(res_folder, 'img/include.png'))
		self._icon_node = QIcon(os.path.join(res_folder, 'img/node.png'))
		self._icon_param = QIcon(os.path.join(res_folder, 'img/param.png'))
		self._icon_arg = QIcon(os.path.join(res_folder, 'img/arg.png'))
		self._icon_remap = QIcon(os.path.join(res_folder, 'img/remap.png'))
		self._icon_default = QIcon(os.path.join(res_folder, 'img/default.png'))
		self._icon_warn = QIcon(os.path.join(res_folder, 'img/warn.png'))
		self._launch_separator = '  --  '
		self._highlight_color = QColor(255, 255, 150)
		self._neutral_color = QColor(255, 255, 255, 0)

		# connect signals
		self.update_launch_view.connect(self._update_launch_view)
		self.package_select.currentIndexChanged.connect(self.update_launchfiles)
		self.launchfile_select.currentIndexChanged.connect(lambda idx: self.load_launchfile())
		self.reload_button.clicked.connect(self.load_launchfile)
		self.open_button.clicked.connect(self._root_open_clicked)
		self.launch_view.currentItemChanged.connect(self.launch_entry_changed)
		self.filter_nodes.toggled.connect(lambda t: self._filter_launch_view())
		self.filter_params.toggled.connect(lambda t: self._filter_launch_view())
		self.filter_args.toggled.connect(lambda t: self._filter_launch_view())
		self.filter_remaps.toggled.connect(lambda t: self._filter_launch_view())
		self.filter_empty.toggled.connect(lambda t: self._filter_launch_view())
		self.search_input.textChanged.connect(lambda t: self._filter_launch_view(collapse=t==''))
		self.launch_open_button.clicked.connect(self._launch_open_clicked)

		self.reset()

	def reset(self):
		self._launch_config = LaunchtreeConfig()
		self._package_list = list()
		self._load_thread = None
		self.properties_content.setCurrentIndex(0)

		self.update_package_list()

	def load_launchfile(self):
		self.launch_view.clear()
		filename = os.path.join(
			self._rp.get_path(self.package_select.currentText()),
			'launch',
			self.launchfile_select.currentText()
		)
		if os.path.isfile(filename):
			self.progress_bar.setValue(self.progress_bar.minimum())
			self._load_thread = threading.Thread(target=self._load_launch_items, args=[filename])
			self._load_thread.daemon = True
			self._load_thread.start()

	def _load_launch_items(self, filename):
		self._launch_config = LaunchtreeConfig()
		loader = LaunchtreeLoader()
		loader.load(filename, self._launch_config, verbose=False)
		items = self.display_config_tree(self._launch_config.tree)
		self.update_launch_view.emit(items)

	def display_config_tree(self, config_tree):
		items = list()
		for key, instance in config_tree.items():
			if key == '_root': continue
			i = LaunchtreeEntryItem()
			i.instance = instance
			if isinstance(i.instance, roslaunch.core.Param):
				i.inconsistent = i.instance.inconsistent
			if isinstance(instance, dict):
				childItems = self.display_config_tree(instance)
				i.inconsistent = any(c.inconsistent for c in childItems)
				i.addChildren(childItems)
				i.instance = instance.get('_root', instance)
			if isinstance(i.instance, dict):
				i.setText(0, self._filename_to_label(key))
				i.setIcon(0, self._icon_include if not i.inconsistent else self._icon_warn)
			else:
				i.setText(0, key)
				i.setIcon(0,
					self._icon_warn if i.inconsistent else
					self._icon_node if isinstance(i.instance, roslaunch.core.Node) else
					self._icon_param if isinstance(i.instance, roslaunch.core.Param) else
					self._icon_arg if isinstance(i.instance, LaunchtreeArg) else
					self._icon_remap if isinstance(i.instance, LaunchtreeRemap) else
					self._icon_default)
			items.append(i)
		return items

	def _update_launch_view(self, items):
		self.launch_view.clear()
		self.launch_view.addTopLevelItems(items)
		self.launch_view.sortItems(0, Qt.AscendingOrder)
		self._filter_launch_view()
		self.progress_bar.setValue(self.progress_bar.maximum())
		self._load_thread = None

	def update_package_list(self):
		self._package_list = sorted(filter(lambda p:
			os.path.isdir(os.path.join(self._rp.get_path(p), 'launch')),
			self._rp.list()
		))
		self.package_select.clear()
		self.package_select.addItems(self._package_list)
		self.package_select.setCurrentIndex(0)

	def update_launchfiles(self, idx):
		package = self.package_select.itemText(idx)
		folder = os.path.join(self._rp.get_path(package), 'launch')
		launchfiles = sorted(
			map(lambda p: os.path.split(p)[1],
				filter(os.path.isfile,
					map(lambda f: os.path.join(folder, f),
						os.listdir(folder)
					)
				)
			)
		)
		self.launchfile_select.clear()
		self.launchfile_select.addItems(launchfiles)

	def launch_entry_changed(self, current, previous):
		#clear properties
		if current is None:
			return
		# traverse displayed tree up
		tree_path = list()
		item = current
		while item is not None:
			key = item.text(0)
			if self._launch_separator in key:
				(p, l) = key.split(self._launch_separator)
				key = os.path.join(self._rp.get_path(p), l)
			item = item.parent()
			tree_path.append(key)
		# traverse model tree down
		data = self._launch_config.tree
		for key in reversed(tree_path):
			data = data[key]
		if isinstance(data, dict) and data.has_key('_root'):
			data = data['_root']
		if isinstance(data, roslaunch.core.Param):
			self.properties_content.setCurrentIndex(1)
			self.param_name.setText(data.key.split('/')[-1] + ':')
			if len(str(data.value)) < 100:
				self.param_value.setText(str(data.value))
				self.param_value_panel.setCurrentIndex(0)
			else:
				self.param_value_long.setPlainText(str(data.value))
				self.param_value_panel.setCurrentIndex(1)
		elif isinstance(data, roslaunch.core.Node):
			self.properties_content.setCurrentIndex(2)
			self.node_package.setText(data.package)
			self.node_type.setText(data.type)
			self.node_namespace.setText(str(data.namespace))
			self.node_args.setText(str(data.args))
			self.node_args.setEnabled(data.args != '')
			self.node_prefix.setText(str(data.launch_prefix) if data.launch_prefix is not None else '')
			self.node_prefix.setEnabled(data.launch_prefix is not None)
			self.node_machine.setText(str(data.machine_name) if data.machine_name is not None else '')
			self.node_machine.setEnabled(data.machine_name is not None)
		elif isinstance(data, LaunchtreeArg):
			self.properties_content.setCurrentIndex(4)
			self.arg_name.setText(data.name)
			self.arg_value.setText(str(data.value) if data.value is not None else '')
			self.arg_default.setText(str(data.default) if data.default is not None else '')
			self.arg_doc.setText(str(data.doc) if data.doc is not None else '')
			self.arg_value.setEnabled(data.value is not None)
			self.arg_default.setEnabled(not self.arg_value.isEnabled())
		elif isinstance(data, LaunchtreeRemap):
			self.properties_content.setCurrentIndex(5)
			self.remap_from.setText(data.from_topic)
			self.remap_to.setText(data.to_topic)
		elif isinstance(data, roslaunch.core.Machine):
			self.properties_content.setCurrentIndex(6)
			self.machine_address.setText(str(data.address))
			self.machine_port.setText(str(data.ssh_port))
			self.machine_user.setText(str(data.user) if data.user is not None else '')
			self.machine_user.setEnabled(data.user is not None)
			self.machine_loader.setText(str(data.env_loader) if data.env_loader is not None else '')
			self.machine_loader.setEnabled(data.env_loader is not None)
		elif isinstance(data, dict):
			self.properties_content.setCurrentIndex(3)
			(p, l) = self.launch_view.currentItem().text(0).split(self._launch_separator)
			(d, f) = os.path.split(l)
			self.launch_package.setText(p)
			self.launch_file.setText(f)

		else:
			self.properties_content.setCurrentIndex(0)

	def _filter_launch_view(self, collapse=False):
		show_nodes = self.filter_nodes.isChecked()
		show_params = self.filter_params.isChecked()
		show_args = self.filter_args.isChecked()
		show_remaps = self.filter_remaps.isChecked()
		show_empty = self.filter_empty.isChecked()
		search_text = self.search_input.text()
		highlight = search_text != ''
		expand = not collapse and highlight

		def filter_launch_entry(entry):
			show = True

			# param
			if isinstance(entry.instance, roslaunch.core.Param):
				show = show_params
			# node
			elif isinstance(entry.instance, roslaunch.core.Node):
				show = show_nodes
			# arg
			elif isinstance(entry.instance, LaunchtreeArg):
				show = show_args
			# remap
			elif isinstance(entry.instance, LaunchtreeRemap):
				show = show_remaps

			if entry.childCount() > 0:
				not_empty = any(map(filter_launch_entry, map(entry.child, range(entry.childCount()))))
				show &= show_empty or not_empty
				entry.setExpanded(not collapse and (expand or entry.isExpanded()))

			else:
				show &= search_text in entry.text(0)
				if show:
					entry.setBackgroundColor(0, self._highlight_color if highlight else self._neutral_color)

			entry.setHidden(not show)
			return show

		for idx in range(self.launch_view.topLevelItemCount()):
			filter_launch_entry(self.launch_view.topLevelItem(idx))

	def _launch_open_clicked(self):
		(p, l) = self.launch_view.currentItem().text(0).split(self._launch_separator)
		filename = os.path.join(self._rp.get_path(p), l)
		thread = threading.Thread(target=os.system, args=['gedit %s' % filename])
		thread.daemon = True
		thread.start()

	def _root_open_clicked(self):
		filename = os.path.join(
			self._rp.get_path(self.package_select.currentText()),
			'launch',
			self.launchfile_select.currentText()
		)
		thread = threading.Thread(target=os.system, args=['gedit %s' % filename])
		thread.daemon = True
		thread.start()

	def shutdown(self):
		pass

	def save_settings(self, plugin_settings, instance_settings):
		pass

	def restore_settings(self, plugin_settings, instance_settings):
		pass

	def _filename_to_label(self, filename):
		tail = list()
		for d in reversed(filename.split('/')):
			if d in self._package_list:
				return '%s%s%s' % (d, self._launch_separator, '/'.join(reversed(tail)))
			else:
				tail.append(d)<commit_msg>Catch XmlParseExceptions, e.g., from undefined arguments<commit_after>#!/usr/bin/env python
import os
import yaml
import threading

import rospy
import rospkg
import roslaunch

from rqt_launchtree.launchtree_loader import LaunchtreeLoader
from rqt_launchtree.launchtree_config import LaunchtreeConfig, LaunchtreeArg, LaunchtreeRemap

from python_qt_binding import loadUi
from python_qt_binding.QtCore import Qt, Signal
from python_qt_binding.QtGui import QFileDialog, QWidget, QIcon, QTreeWidgetItem, QColor

class LaunchtreeEntryItem(QTreeWidgetItem):
	_type_order = [dict, roslaunch.core.Node, LaunchtreeArg, roslaunch.core.Param, LaunchtreeRemap, object]
	#inconsistent = False
	def __init__(self, *args, **kw ):
		super(LaunchtreeEntryItem, self).__init__(*args, **kw)
		self.inconsistent = False
	def __ge__(self, other):
		own_type_idx = map(lambda t: isinstance(self.instance, t), self._type_order).index(True)
		other_type_idx = map(lambda t: isinstance(other.instance, t), self._type_order).index(True)
		if own_type_idx != other_type_idx:
			return own_type_idx >= other_type_idx
		return self.text(0) >= other.text(0)
	def __lt__(self, other):
		return not self.__ge__(other)

class LaunchtreeWidget(QWidget):

	update_launch_view = Signal(object)

	def __init__(self, context):
		super(LaunchtreeWidget, self).__init__()

		self._rp = rospkg.RosPack()
		res_folder = os.path.join(self._rp.get_path('rqt_launchtree'), 'resource')
		ui_file = os.path.join(res_folder, 'launchtree_widget.ui')
		loadUi(ui_file, self)

		self.setObjectName('LaunchtreeWidget')
		self.reload_button.setIcon(QIcon.fromTheme('view-refresh'))

		self._properties_empty_ui = os.path.join(res_folder, 'properties_empty.ui')
		self._properties_param_ui = os.path.join(res_folder, 'properties_param.ui')

		self._icon_include = QIcon(os.path.join(res_folder, 'img/include.png'))
		self._icon_node = QIcon(os.path.join(res_folder, 'img/node.png'))
		self._icon_param = QIcon(os.path.join(res_folder, 'img/param.png'))
		self._icon_arg = QIcon(os.path.join(res_folder, 'img/arg.png'))
		self._icon_remap = QIcon(os.path.join(res_folder, 'img/remap.png'))
		self._icon_default = QIcon(os.path.join(res_folder, 'img/default.png'))
		self._icon_warn = QIcon(os.path.join(res_folder, 'img/warn.png'))
		self._launch_separator = '  --  '
		self._highlight_color = QColor(255, 255, 150)
		self._neutral_color = QColor(255, 255, 255, 0)

		# connect signals
		self.update_launch_view.connect(self._update_launch_view)
		self.package_select.currentIndexChanged.connect(self.update_launchfiles)
		self.launchfile_select.currentIndexChanged.connect(lambda idx: self.load_launchfile())
		self.reload_button.clicked.connect(self.load_launchfile)
		self.open_button.clicked.connect(self._root_open_clicked)
		self.launch_view.currentItemChanged.connect(self.launch_entry_changed)
		self.filter_nodes.toggled.connect(lambda t: self._filter_launch_view())
		self.filter_params.toggled.connect(lambda t: self._filter_launch_view())
		self.filter_args.toggled.connect(lambda t: self._filter_launch_view())
		self.filter_remaps.toggled.connect(lambda t: self._filter_launch_view())
		self.filter_empty.toggled.connect(lambda t: self._filter_launch_view())
		self.search_input.textChanged.connect(lambda t: self._filter_launch_view(collapse=t==''))
		self.launch_open_button.clicked.connect(self._launch_open_clicked)

		self.reset()

	def reset(self):
		self._launch_config = LaunchtreeConfig()
		self._package_list = list()
		self._load_thread = None
		self.properties_content.setCurrentIndex(0)

		self.update_package_list()

	def load_launchfile(self):
		self.launch_view.clear()
		filename = os.path.join(
			self._rp.get_path(self.package_select.currentText()),
			'launch',
			self.launchfile_select.currentText()
		)
		if os.path.isfile(filename):
			self.progress_bar.setValue(self.progress_bar.minimum())
			self._load_thread = threading.Thread(target=self._load_launch_items, args=[filename])
			self._load_thread.daemon = True
			self._load_thread.start()

	def _load_launch_items(self, filename):
		self._launch_config = LaunchtreeConfig()
		items = list()
		try:
			loader = LaunchtreeLoader()
			loader.load(filename, self._launch_config, verbose=False)
			items = self.display_config_tree(self._launch_config.tree)
		except roslaunch.xmlloader.XmlParseException as e:
			rospy.logerr('Invalid launch file:\n%s' % str(e))
		self.update_launch_view.emit(items)

	def display_config_tree(self, config_tree):
		items = list()
		for key, instance in config_tree.items():
			if key == '_root': continue
			i = LaunchtreeEntryItem()
			i.instance = instance
			if isinstance(i.instance, roslaunch.core.Param):
				i.inconsistent = i.instance.inconsistent
			if isinstance(instance, dict):
				childItems = self.display_config_tree(instance)
				i.inconsistent = any(c.inconsistent for c in childItems)
				i.addChildren(childItems)
				i.instance = instance.get('_root', instance)
			if isinstance(i.instance, dict):
				i.setText(0, self._filename_to_label(key))
				i.setIcon(0, self._icon_include if not i.inconsistent else self._icon_warn)
			else:
				i.setText(0, key)
				i.setIcon(0,
					self._icon_warn if i.inconsistent else
					self._icon_node if isinstance(i.instance, roslaunch.core.Node) else
					self._icon_param if isinstance(i.instance, roslaunch.core.Param) else
					self._icon_arg if isinstance(i.instance, LaunchtreeArg) else
					self._icon_remap if isinstance(i.instance, LaunchtreeRemap) else
					self._icon_default)
			items.append(i)
		return items

	def _update_launch_view(self, items):
		self.launch_view.clear()
		self.launch_view.addTopLevelItems(items)
		self.launch_view.sortItems(0, Qt.AscendingOrder)
		self._filter_launch_view()
		self.progress_bar.setValue(self.progress_bar.maximum())
		self._load_thread = None

	def update_package_list(self):
		self._package_list = sorted(filter(lambda p:
			os.path.isdir(os.path.join(self._rp.get_path(p), 'launch')),
			self._rp.list()
		))
		self.package_select.clear()
		self.package_select.addItems(self._package_list)
		self.package_select.setCurrentIndex(0)

	def update_launchfiles(self, idx):
		package = self.package_select.itemText(idx)
		folder = os.path.join(self._rp.get_path(package), 'launch')
		launchfiles = sorted(
			map(lambda p: os.path.split(p)[1],
				filter(os.path.isfile,
					map(lambda f: os.path.join(folder, f),
						os.listdir(folder)
					)
				)
			)
		)
		self.launchfile_select.clear()
		self.launchfile_select.addItems(launchfiles)

	def launch_entry_changed(self, current, previous):
		#clear properties
		if current is None:
			return
		# traverse displayed tree up
		tree_path = list()
		item = current
		while item is not None:
			key = item.text(0)
			if self._launch_separator in key:
				(p, l) = key.split(self._launch_separator)
				key = os.path.join(self._rp.get_path(p), l)
			item = item.parent()
			tree_path.append(key)
		# traverse model tree down
		data = self._launch_config.tree
		for key in reversed(tree_path):
			data = data[key]
		if isinstance(data, dict) and data.has_key('_root'):
			data = data['_root']
		if isinstance(data, roslaunch.core.Param):
			self.properties_content.setCurrentIndex(1)
			self.param_name.setText(data.key.split('/')[-1] + ':')
			if len(str(data.value)) < 100:
				self.param_value.setText(str(data.value))
				self.param_value_panel.setCurrentIndex(0)
			else:
				self.param_value_long.setPlainText(str(data.value))
				self.param_value_panel.setCurrentIndex(1)
		elif isinstance(data, roslaunch.core.Node):
			self.properties_content.setCurrentIndex(2)
			self.node_package.setText(data.package)
			self.node_type.setText(data.type)
			self.node_namespace.setText(str(data.namespace))
			self.node_args.setText(str(data.args))
			self.node_args.setEnabled(data.args != '')
			self.node_prefix.setText(str(data.launch_prefix) if data.launch_prefix is not None else '')
			self.node_prefix.setEnabled(data.launch_prefix is not None)
			self.node_machine.setText(str(data.machine_name) if data.machine_name is not None else '')
			self.node_machine.setEnabled(data.machine_name is not None)
		elif isinstance(data, LaunchtreeArg):
			self.properties_content.setCurrentIndex(4)
			self.arg_name.setText(data.name)
			self.arg_value.setText(str(data.value) if data.value is not None else '')
			self.arg_default.setText(str(data.default) if data.default is not None else '')
			self.arg_doc.setText(str(data.doc) if data.doc is not None else '')
			self.arg_value.setEnabled(data.value is not None)
			self.arg_default.setEnabled(not self.arg_value.isEnabled())
		elif isinstance(data, LaunchtreeRemap):
			self.properties_content.setCurrentIndex(5)
			self.remap_from.setText(data.from_topic)
			self.remap_to.setText(data.to_topic)
		elif isinstance(data, roslaunch.core.Machine):
			self.properties_content.setCurrentIndex(6)
			self.machine_address.setText(str(data.address))
			self.machine_port.setText(str(data.ssh_port))
			self.machine_user.setText(str(data.user) if data.user is not None else '')
			self.machine_user.setEnabled(data.user is not None)
			self.machine_loader.setText(str(data.env_loader) if data.env_loader is not None else '')
			self.machine_loader.setEnabled(data.env_loader is not None)
		elif isinstance(data, dict):
			self.properties_content.setCurrentIndex(3)
			(p, l) = self.launch_view.currentItem().text(0).split(self._launch_separator)
			(d, f) = os.path.split(l)
			self.launch_package.setText(p)
			self.launch_file.setText(f)

		else:
			self.properties_content.setCurrentIndex(0)

	def _filter_launch_view(self, collapse=False):
		show_nodes = self.filter_nodes.isChecked()
		show_params = self.filter_params.isChecked()
		show_args = self.filter_args.isChecked()
		show_remaps = self.filter_remaps.isChecked()
		show_empty = self.filter_empty.isChecked()
		search_text = self.search_input.text()
		highlight = search_text != ''
		expand = not collapse and highlight

		def filter_launch_entry(entry):
			show = True

			# param
			if isinstance(entry.instance, roslaunch.core.Param):
				show = show_params
			# node
			elif isinstance(entry.instance, roslaunch.core.Node):
				show = show_nodes
			# arg
			elif isinstance(entry.instance, LaunchtreeArg):
				show = show_args
			# remap
			elif isinstance(entry.instance, LaunchtreeRemap):
				show = show_remaps

			if entry.childCount() > 0:
				not_empty = any(map(filter_launch_entry, map(entry.child, range(entry.childCount()))))
				show &= show_empty or not_empty
				entry.setExpanded(not collapse and (expand or entry.isExpanded()))

			else:
				show &= search_text in entry.text(0)
				if show:
					entry.setBackgroundColor(0, self._highlight_color if highlight else self._neutral_color)

			entry.setHidden(not show)
			return show

		for idx in range(self.launch_view.topLevelItemCount()):
			filter_launch_entry(self.launch_view.topLevelItem(idx))

	def _launch_open_clicked(self):
		(p, l) = self.launch_view.currentItem().text(0).split(self._launch_separator)
		filename = os.path.join(self._rp.get_path(p), l)
		thread = threading.Thread(target=os.system, args=['gedit %s' % filename])
		thread.daemon = True
		thread.start()

	def _root_open_clicked(self):
		filename = os.path.join(
			self._rp.get_path(self.package_select.currentText()),
			'launch',
			self.launchfile_select.currentText()
		)
		thread = threading.Thread(target=os.system, args=['gedit %s' % filename])
		thread.daemon = True
		thread.start()

	def shutdown(self):
		pass

	def save_settings(self, plugin_settings, instance_settings):
		pass

	def restore_settings(self, plugin_settings, instance_settings):
		pass

	def _filename_to_label(self, filename):
		tail = list()
		for d in reversed(filename.split('/')):
			if d in self._package_list:
				return '%s%s%s' % (d, self._launch_separator, '/'.join(reversed(tail)))
			else:
				tail.append(d)<|endoftext|>


<commit_before><commit_msg>Disabled Mouse Scrolling<commit_after><|endoftext|>


<commit_before>"""Utilities for validating user input to the API."""
import arrow
from arrow.parser import ParserError
from flanker.addresslib import address
from flask.ext.restful import reqparse
from sqlalchemy.orm.exc import NoResultFound
from inbox.models import Calendar, Tag, Thread, Block, Message
from inbox.models.when import parse_as_when
from inbox.api.err import InputError, NotFoundError, ConflictError
from inbox.search.query import MessageQuery, ThreadQuery

MAX_LIMIT = 1000

class ValidatableArgument(reqparse.Argument):
    def handle_validation_error(self, error):
        raise InputError(str(error))

# Custom parameter types

def bounded_str(value, key):
    if len(value) > 255:
        raise ValueError('Value {} for {} is too long'.format(value, key))
    return value

def strict_bool(value, key):
    if value.lower() not in ['true', 'false']:
        raise ValueError('Value must be "true" or "false" (not "{}") for {}'
                         .format(value, key))
    return value.lower() == 'true'

def view(value, key):
    allowed_views = ["count", "ids", "expanded"]
    if value not in allowed_views:
        raise ValueError('Unknown view type {}.'.format(value))
    return value

def limit(value):
    try:
        value = int(value)
    except ValueError:
        raise ValueError('Limit parameter must be an integer.')
    if value < 0:
        raise ValueError('Limit parameter must be nonnegative.')
    if value > MAX_LIMIT:
        raise ValueError('Cannot request more than {} resources at once.'.
                         format(MAX_LIMIT))
    return value

def offset(value):
    try:
        value = int(value)
    except ValueError:
        raise ValueError('Offset parameter must be an integer.')
    if value < 0:
        raise ValueError('Offset parameter must be nonnegative.')
    return value

def valid_public_id(value):
    try:
        # raise ValueError on malformed public ids
        # raise TypeError if an integer is passed in
        int(value, 36)
    except (TypeError, ValueError):
        raise InputError(u'Invalid id: {}'.format(value))
    return value

def timestamp(value, key):
    try:
        return arrow.get(value).datetime
    except ValueError:
        raise ValueError('Invalid timestamp value {} for {}'.
                         format(value, key))
    except ParserError:
        raise ValueError('Invalid datetime value {} for {}'.format(value, key))

def strict_parse_args(parser, raw_args):
    """
    Wrapper around parser.parse_args that raises a ValueError if unexpected
    arguments are present.

    """
    args = parser.parse_args()
    unexpected_params = (set(raw_args) - {allowed_arg.name for allowed_arg in
                                          parser.args})
    if unexpected_params:
        raise InputError('Unexpected query parameters {}'.format(
                         unexpected_params))
    return args

def get_draft(draft_public_id, version, namespace_id, db_session):
    valid_public_id(draft_public_id)
    if version is None:
        raise InputError('Must specify draft version')
    try:
        version = int(version)
    except ValueError:
        raise InputError('Invalid draft version')
    try:
        draft = db_session.query(Message).filter(
            Message.public_id == draft_public_id,
            Message.namespace_id == namespace_id).one()
    except NoResultFound:
        raise NotFoundError("Couldn't find draft {}".format(draft_public_id))

    if draft.is_sent or not draft.is_draft:
        raise InputError('Message {} is not a draft'.format(draft_public_id))
    if draft.version != version:
        raise ConflictError(
            'Draft {0}.{1} has already been updated to version {2}'.
            format(draft_public_id, version, draft.version))
    return draft

def get_tags(tag_public_ids, namespace_id, db_session):
    tags = set()
    if tag_public_ids is None:
        return tags
    if not isinstance(tag_public_ids, list):
        raise InputError('{} is not a list of tag ids'.format(tag_public_ids))
    for tag_public_id in tag_public_ids:
        # Validate public id before querying with it
        valid_public_id(tag_public_id)
        try:
            # We're trading a bit of performance for more meaningful error
            # messages here by looking these up one-by-one.
            tag = db_session.query(Tag). \
                filter(Tag.namespace_id == namespace_id,
                       Tag.public_id == tag_public_id,
                       Tag.user_created).one()
            tags.add(tag)
        except NoResultFound:
            raise InputError('Invalid tag public id {}'.format(tag_public_id))
    return tags

def get_attachments(block_public_ids, namespace_id, db_session):
    attachments = set()
    if block_public_ids is None:
        return attachments
    if not isinstance(block_public_ids, list):
        raise InputError('{} is not a list of block ids'.
                         format(block_public_ids))
    for block_public_id in block_public_ids:
        # Validate public ids before querying with them
        valid_public_id(block_public_id)
        try:
            block = db_session.query(Block). \
                filter(Block.public_id == block_public_id,
                       Block.namespace_id == namespace_id).one()
            # In the future we may consider discovering the filetype from the
            # data by using #magic.from_buffer(data, mime=True))
            attachments.add(block)
        except NoResultFound:
            raise InputError('Invalid block public id {}'.
                             format(block_public_id))
    return attachments

def get_message(message_public_id, namespace_id, db_session):
    if message_public_id is None:
        return None
    valid_public_id(message_public_id)
    try:
        return db_session.query(Message). \
            filter(Message.public_id == message_public_id,
                   Message.namespace_id == namespace_id).one()
    except NoResultFound:
        raise InputError('Invalid message public id {}'.
                         format(message_public_id))

def get_thread(thread_public_id, namespace_id, db_session):
    if thread_public_id is None:
        return None
    valid_public_id(thread_public_id)
    try:
        return db_session.query(Thread). \
            filter(Thread.public_id == thread_public_id,
                   Thread.namespace_id == namespace_id).one()
    except NoResultFound:
        raise InputError('Invalid thread public id {}'.
                         format(thread_public_id))

def get_recipients(recipients, field):
    if recipients is None:
        return None
    if not isinstance(recipients, list):
        raise InputError('Invalid {} field'.format(field))

    for r in recipients:
        if not (isinstance(r, dict) and 'email' in r and
                isinstance(r['email'], basestring)):
            raise InputError('Invalid {} field'.format(field))
        if 'name' in r and not isinstance(r['name'], basestring):
            raise InputError('Invalid {} field'.format(field))

    return [(r.get('name', ''), r.get('email', '')) for r in recipients]

def get_calendar(calendar_public_id, namespace, db_session):
    valid_public_id(calendar_public_id)
    try:
        return db_session.query(Calendar). \
            filter(Calendar.public_id == calendar_public_id,
                   Calendar.namespace_id == namespace.id).one()
    except NoResultFound:
        raise NotFoundError('Calendar {} not found'.format(calendar_public_id))

def valid_when(when):
    try:
        parse_as_when(when)
    except (ValueError, ParserError) as e:
        raise InputError(str(e))

def valid_event(event):
    if 'when' not in event:
        raise InputError("Must specify 'when' when creating an event.")

    valid_when(event['when'])

    if 'busy' in event and event.get('busy') is not None:
        # client libraries can send busy: None
        if not isinstance(event.get('busy'), bool):
            raise InputError("'busy' must be true or false")

    participants = event.get('participants')
    if participants is None:
        participants = []
    for p in participants:
        if 'email' not in p:
            raise InputError("'participants' must must have email")
        if 'status' in p:
            if p['status'] not in ('yes', 'no', 'maybe', 'noreply'):
                raise InputError("'participants' status must be one of: "
                                 "yes, no, maybe, noreply")

def valid_event_update(event, namespace, db_session):
    if 'when' in event:
        valid_when(event['when'])

    if 'busy' in event and not isinstance(event.get('busy'), bool):
        raise InputError("'busy' must be true or false")

    participants = event.get('participants', [])
    for p in participants:
        if 'email' not in p:
            raise InputError("'participants' must have email")
        if 'status' in p:
            if p['status'] not in ('yes', 'no', 'maybe', 'noreply'):
                raise InputError("'participants' status must be one of: "
                                 "yes, no, maybe, noreply")

def valid_delta_object_types(types_arg):
    types = [item.strip() for item in types_arg.split(',')]
    allowed_types = ('contact', 'message', 'event', 'file', 'message', 'tag',
                     'thread', 'calendar')
    for type_ in types:
        if type_ not in allowed_types:
            raise InputError('Invalid object type {}'.format(type_))
    return types

def validate_draft_recipients(draft):
    """Check that a draft has at least one recipient, and that all recipient
    emails are at least plausible email addresses, before we try to send it."""
    if not any((draft.to_addr, draft.bcc_addr, draft.cc_addr)):
        raise InputError('No recipients specified')
    for field in draft.to_addr, draft.bcc_addr, draft.cc_addr:
        if field is not None:
            for _, email_address in field:
                parsed = address.parse(email_address, addr_spec_only=True)
                if not isinstance(parsed, address.EmailAddress):
                    raise InputError(u'Invalid recipient address {}'.
                                     format(email_address))

def validate_search_query(query):
    if query is None:
        # No query defaults to 'all'
        return

    if not isinstance(query, list):
        raise InputError('Search query must be a list')

    queried_fields = []
    query_values = []
    for subquery in query:
        queried_fields.extend(subquery.keys())
        query_values.extend(subquery.values())

    if len(query) > 1:
        # We can't OR together 'all' queries, so check they are not supplied
        if not all([k != 'all' for k in queried_fields]):
            raise InputError("Cannot perform OR search with 'all' subquery")

    # valid search attributes - we search across children/parents if the
    # attribute isn't present on the type being queried.
    attrs = [a for a in MessageQuery.attrs]
    attrs.extend(ThreadQuery.attrs)
    attrs.append('all')
    attrs.append('weights')

    if not all([k in attrs for k in queried_fields]):
        raise InputError('Invalid search fields specified')

    if any([isinstance(v, list) for v in query_values]):
        raise InputError('Search query value cannot be a list')

def validate_search_sort(sort):
    if sort not in ('datetime', 'relevance', None):
        raise InputError("Sort order must be 'datetime' or 'relevance'")
<commit_msg>Also allow drafts to be excluded from delta API.<commit_after>"""Utilities for validating user input to the API."""
import arrow
from arrow.parser import ParserError
from flanker.addresslib import address
from flask.ext.restful import reqparse
from sqlalchemy.orm.exc import NoResultFound
from inbox.models import Calendar, Tag, Thread, Block, Message
from inbox.models.when import parse_as_when
from inbox.api.err import InputError, NotFoundError, ConflictError
from inbox.search.query import MessageQuery, ThreadQuery

MAX_LIMIT = 1000

class ValidatableArgument(reqparse.Argument):
    def handle_validation_error(self, error):
        raise InputError(str(error))

# Custom parameter types

def bounded_str(value, key):
    if len(value) > 255:
        raise ValueError('Value {} for {} is too long'.format(value, key))
    return value

def strict_bool(value, key):
    if value.lower() not in ['true', 'false']:
        raise ValueError('Value must be "true" or "false" (not "{}") for {}'
                         .format(value, key))
    return value.lower() == 'true'

def view(value, key):
    allowed_views = ["count", "ids", "expanded"]
    if value not in allowed_views:
        raise ValueError('Unknown view type {}.'.format(value))
    return value

def limit(value):
    try:
        value = int(value)
    except ValueError:
        raise ValueError('Limit parameter must be an integer.')
    if value < 0:
        raise ValueError('Limit parameter must be nonnegative.')
    if value > MAX_LIMIT:
        raise ValueError('Cannot request more than {} resources at once.'.
                         format(MAX_LIMIT))
    return value

def offset(value):
    try:
        value = int(value)
    except ValueError:
        raise ValueError('Offset parameter must be an integer.')
    if value < 0:
        raise ValueError('Offset parameter must be nonnegative.')
    return value

def valid_public_id(value):
    try:
        # raise ValueError on malformed public ids
        # raise TypeError if an integer is passed in
        int(value, 36)
    except (TypeError, ValueError):
        raise InputError(u'Invalid id: {}'.format(value))
    return value

def timestamp(value, key):
    try:
        return arrow.get(value).datetime
    except ValueError:
        raise ValueError('Invalid timestamp value {} for {}'.
                         format(value, key))
    except ParserError:
        raise ValueError('Invalid datetime value {} for {}'.format(value, key))

def strict_parse_args(parser, raw_args):
    """
    Wrapper around parser.parse_args that raises a ValueError if unexpected
    arguments are present.

    """
    args = parser.parse_args()
    unexpected_params = (set(raw_args) - {allowed_arg.name for allowed_arg in
                                          parser.args})
    if unexpected_params:
        raise InputError('Unexpected query parameters {}'.format(
                         unexpected_params))
    return args

def get_draft(draft_public_id, version, namespace_id, db_session):
    valid_public_id(draft_public_id)
    if version is None:
        raise InputError('Must specify draft version')
    try:
        version = int(version)
    except ValueError:
        raise InputError('Invalid draft version')
    try:
        draft = db_session.query(Message).filter(
            Message.public_id == draft_public_id,
            Message.namespace_id == namespace_id).one()
    except NoResultFound:
        raise NotFoundError("Couldn't find draft {}".format(draft_public_id))

    if draft.is_sent or not draft.is_draft:
        raise InputError('Message {} is not a draft'.format(draft_public_id))
    if draft.version != version:
        raise ConflictError(
            'Draft {0}.{1} has already been updated to version {2}'.
            format(draft_public_id, version, draft.version))
    return draft

def get_tags(tag_public_ids, namespace_id, db_session):
    tags = set()
    if tag_public_ids is None:
        return tags
    if not isinstance(tag_public_ids, list):
        raise InputError('{} is not a list of tag ids'.format(tag_public_ids))
    for tag_public_id in tag_public_ids:
        # Validate public id before querying with it
        valid_public_id(tag_public_id)
        try:
            # We're trading a bit of performance for more meaningful error
            # messages here by looking these up one-by-one.
            tag = db_session.query(Tag). \
                filter(Tag.namespace_id == namespace_id,
                       Tag.public_id == tag_public_id,
                       Tag.user_created).one()
            tags.add(tag)
        except NoResultFound:
            raise InputError('Invalid tag public id {}'.format(tag_public_id))
    return tags

def get_attachments(block_public_ids, namespace_id, db_session):
    attachments = set()
    if block_public_ids is None:
        return attachments
    if not isinstance(block_public_ids, list):
        raise InputError('{} is not a list of block ids'.
                         format(block_public_ids))
    for block_public_id in block_public_ids:
        # Validate public ids before querying with them
        valid_public_id(block_public_id)
        try:
            block = db_session.query(Block). \
                filter(Block.public_id == block_public_id,
                       Block.namespace_id == namespace_id).one()
            # In the future we may consider discovering the filetype from the
            # data by using #magic.from_buffer(data, mime=True))
            attachments.add(block)
        except NoResultFound:
            raise InputError('Invalid block public id {}'.
                             format(block_public_id))
    return attachments

def get_message(message_public_id, namespace_id, db_session):
    if message_public_id is None:
        return None
    valid_public_id(message_public_id)
    try:
        return db_session.query(Message). \
            filter(Message.public_id == message_public_id,
                   Message.namespace_id == namespace_id).one()
    except NoResultFound:
        raise InputError('Invalid message public id {}'.
                         format(message_public_id))

def get_thread(thread_public_id, namespace_id, db_session):
    if thread_public_id is None:
        return None
    valid_public_id(thread_public_id)
    try:
        return db_session.query(Thread). \
            filter(Thread.public_id == thread_public_id,
                   Thread.namespace_id == namespace_id).one()
    except NoResultFound:
        raise InputError('Invalid thread public id {}'.
                         format(thread_public_id))

def get_recipients(recipients, field):
    if recipients is None:
        return None
    if not isinstance(recipients, list):
        raise InputError('Invalid {} field'.format(field))

    for r in recipients:
        if not (isinstance(r, dict) and 'email' in r and
                isinstance(r['email'], basestring)):
            raise InputError('Invalid {} field'.format(field))
        if 'name' in r and not isinstance(r['name'], basestring):
            raise InputError('Invalid {} field'.format(field))

    return [(r.get('name', ''), r.get('email', '')) for r in recipients]

def get_calendar(calendar_public_id, namespace, db_session):
    valid_public_id(calendar_public_id)
    try:
        return db_session.query(Calendar). \
            filter(Calendar.public_id == calendar_public_id,
                   Calendar.namespace_id == namespace.id).one()
    except NoResultFound:
        raise NotFoundError('Calendar {} not found'.format(calendar_public_id))

def valid_when(when):
    try:
        parse_as_when(when)
    except (ValueError, ParserError) as e:
        raise InputError(str(e))

def valid_event(event):
    if 'when' not in event:
        raise InputError("Must specify 'when' when creating an event.")

    valid_when(event['when'])

    if 'busy' in event and event.get('busy') is not None:
        # client libraries can send busy: None
        if not isinstance(event.get('busy'), bool):
            raise InputError("'busy' must be true or false")

    participants = event.get('participants')
    if participants is None:
        participants = []
    for p in participants:
        if 'email' not in p:
            raise InputError("'participants' must must have email")
        if 'status' in p:
            if p['status'] not in ('yes', 'no', 'maybe', 'noreply'):
                raise InputError("'participants' status must be one of: "
                                 "yes, no, maybe, noreply")

def valid_event_update(event, namespace, db_session):
    if 'when' in event:
        valid_when(event['when'])

    if 'busy' in event and not isinstance(event.get('busy'), bool):
        raise InputError("'busy' must be true or false")

    participants = event.get('participants', [])
    for p in participants:
        if 'email' not in p:
            raise InputError("'participants' must have email")
        if 'status' in p:
            if p['status'] not in ('yes', 'no', 'maybe', 'noreply'):
                raise InputError("'participants' status must be one of: "
                                 "yes, no, maybe, noreply")

def valid_delta_object_types(types_arg):
    types = [item.strip() for item in types_arg.split(',')]
    allowed_types = ('contact', 'message', 'event', 'file', 'tag',
                     'thread', 'calendar', 'draft')
    for type_ in types:
        if type_ not in allowed_types:
            raise InputError('Invalid object type {}'.format(type_))
    return types

def validate_draft_recipients(draft):
    """Check that a draft has at least one recipient, and that all recipient
    emails are at least plausible email addresses, before we try to send it."""
    if not any((draft.to_addr, draft.bcc_addr, draft.cc_addr)):
        raise InputError('No recipients specified')
    for field in draft.to_addr, draft.bcc_addr, draft.cc_addr:
        if field is not None:
            for _, email_address in field:
                parsed = address.parse(email_address, addr_spec_only=True)
                if not isinstance(parsed, address.EmailAddress):
                    raise InputError(u'Invalid recipient address {}'.
                                     format(email_address))

def validate_search_query(query):
    if query is None:
        # No query defaults to 'all'
        return

    if not isinstance(query, list):
        raise InputError('Search query must be a list')

    queried_fields = []
    query_values = []
    for subquery in query:
        queried_fields.extend(subquery.keys())
        query_values.extend(subquery.values())

    if len(query) > 1:
        # We can't OR together 'all' queries, so check they are not supplied
        if not all([k != 'all' for k in queried_fields]):
            raise InputError("Cannot perform OR search with 'all' subquery")

    # valid search attributes - we search across children/parents if the
    # attribute isn't present on the type being queried.
    attrs = [a for a in MessageQuery.attrs]
    attrs.extend(ThreadQuery.attrs)
    attrs.append('all')
    attrs.append('weights')

    if not all([k in attrs for k in queried_fields]):
        raise InputError('Invalid search fields specified')

    if any([isinstance(v, list) for v in query_values]):
        raise InputError('Search query value cannot be a list')

def validate_search_sort(sort):
    if sort not in ('datetime', 'relevance', None):
        raise InputError("Sort order must be 'datetime' or 'relevance'")
<|endoftext|>


<commit_before><commit_msg>change test set report printing format<commit_after><|endoftext|>


<commit_before>import tensorflow as tf
from hypergan.util.ops import *
from hypergan.util.hc_tf import *
import hyperchamber as hc

from hypergan.losses import wgan_loss, standard_gan_loss, lsgan_loss

def config(
        reduce=tf.reduce_mean,
        reverse=False,
        discriminator=None,
        label_smooth=list(np.linspace(0.15, 0.35, num=10)),
        alpha=0.6,
        beta=0.2,
        labels=[[1,0,-1]]
    ):
    selector = hc.Selector()
    selector.set("reduce", reduce)
    selector.set('reverse', reverse)
    selector.set('discriminator', discriminator)
    selector.set("label_smooth", label_smooth)
    selector.set('create', create)
    selector.set('alpha', alpha)
    selector.set('beta', beta)
    selector.set('labels', labels)

    return selector.random_config()

def create(config, gan):
    alpha = config.alpha
    beta = config.beta
    wgan_loss_d, wgan_loss_g = wgan_loss.create(config, gan)
    lsgan_loss_d, lsgan_loss_g = lsgan_loss.create(config, gan)
    config['reduce']=standard_gan_loss.linear_projection
    standard_loss_d, standard_loss_g = standard_gan_loss.create(config, gan)

    total = min(alpha + beta,1)

    d_loss = wgan_loss_d*alpha + lsgan_loss_d*beta + (1-total)*standard_loss_d
    g_loss = wgan_loss_g*alpha + lsgan_loss_g*beta + (1-total)*standard_loss_g

    return [d_loss, g_loss]

<commit_msg>[defaults] better lambgan defaults<commit_after>import tensorflow as tf
from hypergan.util.ops import *
from hypergan.util.hc_tf import *
import hyperchamber as hc

from hypergan.losses import wgan_loss, standard_gan_loss, lsgan_loss

def config(
        reduce=wgan_loss.linear_projection,
        reverse=False,
        discriminator=None,
        label_smooth=list(np.linspace(0.15, 0.35, num=10)),
        alpha=0.001,
        beta=0.2,
        labels=[[0.5,0,-0.5]]
    ):
    selector = hc.Selector()
    selector.set("reduce", reduce)
    selector.set('reverse', reverse)
    selector.set('discriminator', discriminator)
    selector.set("label_smooth", label_smooth)
    selector.set('create', create)
    selector.set('alpha', alpha)
    selector.set('beta', beta)
    selector.set('labels', labels)

    return selector.random_config()

def create(config, gan):
    alpha = config.alpha
    beta = config.beta
    wgan_loss_d, wgan_loss_g = wgan_loss.create(config, gan)
    lsgan_loss_d, lsgan_loss_g = lsgan_loss.create(config, gan)
    config['reduce']=standard_gan_loss.linear_projection
    standard_loss_d, standard_loss_g = standard_gan_loss.create(config, gan)

    total = min(alpha + beta,1)

    d_loss = wgan_loss_d*alpha + lsgan_loss_d*beta + (1-total)*standard_loss_d
    g_loss = wgan_loss_g*alpha + lsgan_loss_g*beta + (1-total)*standard_loss_g

    return [d_loss, g_loss]

<|endoftext|>


<commit_before>from collections import defaultdict
import json
from django.core.urlresolvers import reverse
from django.http import Http404
from django.shortcuts import get_object_or_404, redirect
from django.views.generic import FormView, CreateView, TemplateView, View
from braces.views import LoginRequiredMixin, JSONResponseMixin, AjaxResponseMixin

from .forms import ApplicationStageTransitionForm, ApplicationMessageForm
from .models import Application, ApplicationAnswer, ApplicationMessage, ApplicationStageTransition
from .threaded_discussion import group
from companysettings.models import InterviewStage
from core.views import RestrictedListView
from openings.models import Opening

class ApplicationListView(LoginRequiredMixin, RestrictedListView):
    def get_context_data(self, **kwargs):
        kwargs['context_opening'] = get_object_or_404(
            Opening, pk=self.kwargs['opening_id']
        )
        return super(ApplicationListView, self).get_context_data(**kwargs)

    def get_queryset(self):
        opening = get_object_or_404(Opening, pk=self.kwargs['opening_id'])
        return Application.objects.filter(opening=opening)

class AllApplicationListView(LoginRequiredMixin, RestrictedListView):
    def get_queryset(self):
        return Application.objects.filter(
            opening__company=self.request.user.company
        ).order_by("opening").prefetch_related("applicant", "opening")

class ApplicationMessageCreateView(LoginRequiredMixin, CreateView):
    model = ApplicationMessage
    form_class = ApplicationMessageForm
    action = 'created'

    def dispatch(self, request, application_id, **kwargs):
        self.application = get_object_or_404(Application,
                opening__company=self.request.user.company,
                pk=application_id)
        return super(ApplicationMessageCreateView, self).dispatch(
                request, application_id, **kwargs)

    def get_success_url(self):
        return "%s#notes" % reverse('applications:application_detail',
                args=(self.application.id,))

    def form_valid(self, form):
        new_message = form.save(commit=False)
        new_message.application = self.application
        new_message.user = self.request.user
        return super(ApplicationMessageCreateView, self).form_valid(form)

class ApplicationDetailView(LoginRequiredMixin, FormView):
    model = Application
    form_class = ApplicationStageTransitionForm
    template_name = "applications/application_detail.html"

    def get_application(self):
        try:
            return Application.objects.get(
                pk=self.kwargs["pk"],
                opening__company=self.request.user.company
            )
        except Application.DoesNotExist:
            raise Http404

    def get_form_kwargs(self):
        default_kwargs = super(ApplicationDetailView, self).get_form_kwargs()
        default_kwargs["company"] = self.request.user.company
        return default_kwargs

    def get_context_data(self, **kwargs):
        context = super(ApplicationDetailView, self).get_context_data(**kwargs)
        context['user'] = self.request.user
        application = self.get_application()
        context['application'] = application
        context['discussion'] = group(application.applicationmessage_set.all())
        context['new_message_form'] = ApplicationMessageForm()
        context['answers'] = ApplicationAnswer.objects.filter(
            application=context['application'])
        return context

    def form_valid(self, form):
        transition = form.save(commit=False)
        transition.application = self.get_application()
        transition.user = self.request.user
        transition.save()
        return redirect('applications:application_detail',
            pk=self.kwargs['pk'])

class BoardView(LoginRequiredMixin, TemplateView):
    template_name = "applications/_kanban.html"

    def get_context_data(self, **kwargs):
        context = super(BoardView, self).get_context_data(**kwargs)

        board_data = defaultdict(list)

        stages = InterviewStage.objects.filter(company=self.request.user.company)
        applications = Application.objects.filter(
            opening__company=self.request.user.company
        ).prefetch_related("stage_transitions__stage", "applicant")
        for stage in stages:
            board_data[stage] = []
            for application in applications:
                if stage == application.current_stage():
                    board_data[stage].append(application)

        context['board'] = board_data
        context['full_width'] = True
        return context

class UpdatePositionsAjaxView(JSONResponseMixin, AjaxResponseMixin, View):
    def post_ajax(self, request, *args, **kwargs):
        data = json.loads(request.POST.get('data'))

        if data.get('stage'):
            stage = int(data.get('stage'))

        positions = data.get('positions')

        if positions:
            for position in positions:
                application_id = position[0]
                new_position = position[1]

                application = Application.objects.filter(
                    id=int(application_id),
                    opening__company=self.request.user.company
                ).prefetch_related("stage_transitions__stage")[0]

                application.position = new_position
                application.save()

                if data.get('stage'):
                    current_stage = application.current_stage()
                    if not current_stage or current_stage.id != stage:
                        ApplicationStageTransition.objects.create(
                            application=application,
                            user = self.request.user,
                            stage=InterviewStage.objects.get(id=stage)
                        )

                result = {'status': 'success'}
        else:
            result = {'status': 'error'}

        return self.render_json_response(result)
<commit_msg>applications: Tiny readability improvement<commit_after>from collections import defaultdict
import json
from django.core.urlresolvers import reverse
from django.http import Http404
from django.shortcuts import get_object_or_404, redirect
from django.views.generic import FormView, CreateView, TemplateView, View
from braces.views import LoginRequiredMixin, JSONResponseMixin, AjaxResponseMixin

from .forms import ApplicationStageTransitionForm, ApplicationMessageForm
from .models import Application, ApplicationAnswer, ApplicationMessage, ApplicationStageTransition
from .threaded_discussion import group
from companysettings.models import InterviewStage
from core.views import RestrictedListView
from openings.models import Opening

class ApplicationListView(LoginRequiredMixin, RestrictedListView):
    def get_context_data(self, **kwargs):
        kwargs['context_opening'] = get_object_or_404(
            Opening, pk=self.kwargs['opening_id']
        )
        return super(ApplicationListView, self).get_context_data(**kwargs)

    def get_queryset(self):
        opening = get_object_or_404(Opening, pk=self.kwargs['opening_id'])
        return Application.objects.filter(opening=opening)

class AllApplicationListView(LoginRequiredMixin, RestrictedListView):
    def get_queryset(self):
        return Application.objects.filter(
            opening__company=self.request.user.company
        ).order_by("opening").prefetch_related("applicant", "opening")

class ApplicationMessageCreateView(LoginRequiredMixin, CreateView):
    model = ApplicationMessage
    form_class = ApplicationMessageForm
    action = 'created'

    def dispatch(self, request, application_id, **kwargs):
        self.application = get_object_or_404(Application,
                opening__company=self.request.user.company,
                pk=application_id)
        return super(ApplicationMessageCreateView, self).dispatch(
                request, application_id, **kwargs)

    def get_success_url(self):
        return "%s#notes" % reverse('applications:application_detail',
                args=(self.application.id,))

    def form_valid(self, form):
        new_message = form.save(commit=False)
        new_message.application = self.application
        new_message.user = self.request.user
        return super(ApplicationMessageCreateView, self).form_valid(form)

class ApplicationDetailView(LoginRequiredMixin, FormView):
    model = Application
    form_class = ApplicationStageTransitionForm
    template_name = "applications/application_detail.html"

    def get_application(self):
        try:
            return Application.objects.get(
                pk=self.kwargs["pk"],
                opening__company=self.request.user.company
            )
        except Application.DoesNotExist:
            raise Http404

    def get_form_kwargs(self):
        default_kwargs = super(ApplicationDetailView, self).get_form_kwargs()
        default_kwargs["company"] = self.request.user.company
        return default_kwargs

    def get_context_data(self, **kwargs):
        context = super(ApplicationDetailView, self).get_context_data(**kwargs)
        context['user'] = self.request.user
        application = self.get_application()
        context['application'] = application
        context['discussion'] = group(application.applicationmessage_set.all())
        context['new_message_form'] = ApplicationMessageForm()
        context['answers'] = ApplicationAnswer.objects.filter(
            application=context['application'])
        return context

    def form_valid(self, form):
        transition = form.save(commit=False)
        transition.application = self.get_application()
        transition.user = self.request.user
        transition.save()
        return redirect('applications:application_detail',
            pk=self.kwargs['pk'])

class BoardView(LoginRequiredMixin, TemplateView):
    template_name = "applications/_kanban.html"

    def get_context_data(self, **kwargs):
        context = super(BoardView, self).get_context_data(**kwargs)

        board_data = defaultdict(list)

        stages = InterviewStage.objects.filter(company=self.request.user.company)
        applications = Application.objects.filter(
            opening__company=self.request.user.company
        ).prefetch_related("stage_transitions__stage", "applicant")
        for stage in stages:
            board_data[stage] = []
            for application in applications:
                if stage == application.current_stage():
                    board_data[stage].append(application)

        context['board'] = board_data
        context['full_width'] = True
        return context

class UpdatePositionsAjaxView(JSONResponseMixin, AjaxResponseMixin, View):
    def post_ajax(self, request, *args, **kwargs):
        data = json.loads(request.POST.get('data'))

        if data.get('stage'):
            stage = int(data.get('stage'))

        positions = data.get('positions')

        if positions:
            for position in positions:
                application_id, new_position = position

                application = Application.objects.filter(
                    id=int(application_id),
                    opening__company=self.request.user.company
                ).prefetch_related("stage_transitions__stage")[0]

                application.position = new_position
                application.save()

                if data.get('stage'):
                    current_stage = application.current_stage()
                    if not current_stage or current_stage.id != stage:
                        ApplicationStageTransition.objects.create(
                            application=application,
                            user = self.request.user,
                            stage=InterviewStage.objects.get(id=stage)
                        )

                result = {'status': 'success'}
        else:
            result = {'status': 'error'}

        return self.render_json_response(result)
<|endoftext|>