<commit_before>#  Copyright 2008-2013 Nokia Siemens Networks Oyj
#
#  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.

from __future__ import with_statement

from robot import utils
from robot.errors import DataError
from robot.variables import is_list_var

from .arguments import (PythonArgumentParser, JavaArgumentParser,
                        DynamicArgumentParser, ArgumentResolver,
                        ArgumentValidator, ArgumentMapper, JavaArgumentCoercer)
from .keywords import Keywords, Keyword
from .outputcapture import OutputCapturer
from .runkwregister import RUN_KW_REGISTER
from .signalhandler import STOP_SIGNAL_MONITOR

if utils.is_jython:
    from org.python.core import PyReflectedFunction, PyReflectedConstructor

    def _is_java_init(init):
        return isinstance(init, PyReflectedConstructor)
    def _is_java_method(method):
        return hasattr(method, 'im_func') \
               and isinstance(method.im_func, PyReflectedFunction)
else:
    _is_java_init = _is_java_method = lambda item: False

def Handler(library, name, method):
    if RUN_KW_REGISTER.is_run_keyword(library.orig_name, name):
        return _RunKeywordHandler(library, name, method)
    if _is_java_method(method):
        return _JavaHandler(library, name, method)
    else:
        return _PythonHandler(library, name, method)

def DynamicHandler(library, name, method, doc, argspec):
    if RUN_KW_REGISTER.is_run_keyword(library.orig_name, name):
        return _DynamicRunKeywordHandler(library, name, method, doc, argspec)
    return _DynamicHandler(library, name, method, doc, argspec)

def InitHandler(library, method, docgetter=None):
    Init = _PythonInitHandler if not _is_java_init(method) else _JavaInitHandler
    return Init(library, '__init__', method, docgetter)

class _RunnableHandler(object):
    type = 'library'
    _doc = ''

    def __init__(self, library, handler_name, handler_method):
        self.library = library
        self.name = utils.printable_name(handler_name, code_style=True)
        self.arguments = self._parse_arguments(handler_method)
        self._handler_name = handler_name
        self._method = self._get_initial_handler(library, handler_name,
                                                 handler_method)
        self._argument_resolver = self._get_argument_resolver(self.arguments)

    def _parse_arguments(self, handler_method):
        raise NotImplementedError

    def _get_argument_resolver(self, argspec):
        return ArgumentResolver(argspec)

    def _get_initial_handler(self, library, name, method):
        if library.scope == 'GLOBAL':
            return self._get_global_handler(method, name)
        return None

    def resolve_arguments(self, args, variables):
        return self._argument_resolver.resolve(args, variables)

    @property
    def doc(self):
        return self._doc

    @property
    def longname(self):
        return '%s.%s' % (self.library.name, self.name)

    @property
    def shortdoc(self):
        return self.doc.splitlines()[0] if self.doc else ''

    @property
    def libname(self):
        return self.library.name

    def init_keyword(self, varz):
        pass

    def run(self, context, args):
        if context.dry_run:
            return self._dry_run(context, args)
        return self._run(context, args)

    def _dry_run(self, context, args):
        if self.longname == 'BuiltIn.Import Library':
            return self._run(context, args)
        ArgumentValidator(self.arguments).validate_dry_run(args)
        return None

    def _run(self, context, args):
        positional, named = \
            self.resolve_arguments(args, context.variables)
        context.output.trace(lambda: self._log_args(positional, named))
        runner = self._runner_for(self._current_handler(), context, positional,
                                  named, self._get_timeout(context))
        return self._run_with_output_captured_and_signal_monitor(runner, context)

    def _log_args(self, positional, named):
        positional = [utils.safe_repr(arg) for arg in positional]
        named = ['%s=%s' % (utils.unic(name), utils.safe_repr(value))
                 for name, value in named.items()]
        return 'Arguments: [ %s ]' % ' | '.join(positional + named)

    def _runner_for(self, handler, context, positional, named, timeout):
        if timeout and timeout.active:
            context.output.debug(timeout.get_message)
            return lambda: timeout.run(handler, args=positional, kwargs=named)
        return lambda: handler(*positional, **named)

    def _run_with_output_captured_and_signal_monitor(self, runner, context):
        with OutputCapturer():
            return self._run_with_signal_monitoring(runner, context)

    def _run_with_signal_monitoring(self, runner, context):
        try:
            STOP_SIGNAL_MONITOR.start_running_keyword(context.in_teardown)
            return runner()
        finally:
            STOP_SIGNAL_MONITOR.stop_running_keyword()

    def _current_handler(self):
        if self._method:
            return self._method
        return self._get_handler(self.library.get_instance(), self._handler_name)

    def _get_global_handler(self, method, name):
        return method

    def _get_handler(self, lib_instance, handler_name):
        return getattr(lib_instance, handler_name)

    def _get_timeout(self, context):
        timeouts = self._get_timeouts(context)
        return None if not timeouts else min(timeouts)

    def _get_timeouts(self, context):
        timeouts = [kw.timeout for kw in context.keywords]
        if context.test and not context.in_test_teardown:
            timeouts.append(context.test.timeout)
        return [timeout for timeout in timeouts if timeout]

class _PythonHandler(_RunnableHandler):

    def __init__(self, library, handler_name, handler_method):
        _RunnableHandler.__init__(self, library, handler_name, handler_method)
        self._doc = utils.getdoc(handler_method)

    def _parse_arguments(self, handler_method):
        return PythonArgumentParser().parse(self.longname, handler_method)

class _JavaHandler(_RunnableHandler):

    def __init__(self, library, handler_name, handler_method):
        _RunnableHandler.__init__(self, library, handler_name, handler_method)
        signatures = self._get_signatures(handler_method)
        self._arg_coercer = JavaArgumentCoercer(signatures, self.arguments)

    def _parse_arguments(self, handler_method):
        signatures = self._get_signatures(handler_method)
        return JavaArgumentParser().parse(self.longname, signatures)

    def _get_argument_resolver(self, argspec):
        return ArgumentResolver(argspec, resolve_named=False)

    def _get_signatures(self, handler):
        code_object = getattr(handler, 'im_func', handler)
        return code_object.argslist[:code_object.nargs]

    def resolve_arguments(self, args, variables):
        positional, named = self._argument_resolver.resolve(args, variables)
        positional = self._arg_coercer.coerce(positional)
        return positional, named

class _DynamicHandler(_RunnableHandler):

    def __init__(self, library, handler_name, handler_method, doc='',
                 argspec=None):
        self._argspec = argspec
        _RunnableHandler.__init__(self, library, handler_name, handler_method)
        self._run_keyword_method_name = handler_method.__name__
        self._doc = doc is not None and utils.unic(doc) or ''

    def _parse_arguments(self, handler_method):
        return DynamicArgumentParser().parse(self.longname, self._argspec)

    def resolve_arguments(self, arguments, variables):
        positional, named = _RunnableHandler.resolve_arguments(self, arguments, variables)
        arguments, kwargs = ArgumentMapper(self.arguments).map(positional, named, prune_trailing_defaults=True)
        return arguments, kwargs

    def _get_handler(self, lib_instance, handler_name):
        runner = getattr(lib_instance, self._run_keyword_method_name)
        return self._get_dynamic_handler(runner, handler_name)

    def _get_global_handler(self, method, name):
        return self._get_dynamic_handler(method, name)

    def _get_dynamic_handler(self, runner, name):
        def handler(*positional, **kwargs):
            if kwargs:
                return runner(name, positional, kwargs)
            else: # For backwards compatibility
                # --> run_keyword methods with kwargs should define a default
                return runner(name, positional)
        return handler

class _RunKeywordHandler(_PythonHandler):

    def __init__(self, library, handler_name, handler_method):
        _PythonHandler.__init__(self, library, handler_name, handler_method)
        self._handler_method = handler_method

    def _run_with_signal_monitoring(self, runner, context):
        # With run keyword variants, only the keyword to be run can fail
        # and therefore monitoring should not raise exception yet.
        return runner()

    def _get_argument_resolver(self, argspec):
        resolve_until = self._get_args_to_process()
        return ArgumentResolver(argspec, resolve_named=False,
                                resolve_variables_until=resolve_until)

    def _get_args_to_process(self):
        return RUN_KW_REGISTER.get_args_to_process(self.library.orig_name,
                                                   self.name)

    def _get_timeout(self, namespace):
        return None

    def _dry_run(self, context, args):
        _RunnableHandler._dry_run(self, context, args)
        keywords = self._get_runnable_dry_run_keywords(context, args)
        keywords.run(context)

    def _get_runnable_dry_run_keywords(self, context, args):
        keywords = Keywords([])
        for keyword in self._get_dry_run_keywords(args):
            if self._variable_syntax_in(keyword.name, context):
                continue
            keywords.add_keyword(keyword)
        return keywords

    def _variable_syntax_in(self, kw_name, context):
        try:
            resolved = context.namespace.variables.replace_string(kw_name)
            #Variable can contain value, but it might be wrong,
            #therefore it cannot be returned
            return resolved != kw_name
        except DataError:
            return True

    def _get_dry_run_keywords(self, args):
        if self._handler_name == 'run_keyword_if':
            return list(self._get_run_kw_if_keywords(args))
        if self._handler_name == 'run_keywords':
            return list(self._get_run_kws_keywords(args))
        if 'name' in self.arguments.positional and self._get_args_to_process() > 0:
            return self._get_default_run_kw_keywords(args)
        return []

    def _get_run_kw_if_keywords(self, given_args):
        for kw_call in self._get_run_kw_if_calls(given_args):
            if kw_call:
                yield Keyword(kw_call[0], kw_call[1:])

    def _get_run_kw_if_calls(self, given_args):
        while 'ELSE IF' in given_args:
            kw_call, given_args = self._split_run_kw_if_args(given_args, 'ELSE IF', 2)
            yield kw_call
        if 'ELSE' in given_args:
            kw_call, else_call = self._split_run_kw_if_args(given_args, 'ELSE', 1)
            yield kw_call
            yield else_call
        elif self._validate_kw_call(given_args):
            expr, kw_call = given_args[0], given_args[1:]
            if not is_list_var(expr):
                yield kw_call

    def _split_run_kw_if_args(self, given_args, control_word, required_after):
        index = list(given_args).index(control_word)
        expr_and_call = given_args[:index]
        remaining = given_args[index+1:]
        if not (self._validate_kw_call(expr_and_call) and
                self._validate_kw_call(remaining, required_after)):
            raise DataError("Invalid 'Run Keyword If' usage.")
        if is_list_var(expr_and_call[0]):
            return (), remaining
        return expr_and_call[1:], remaining

    def _validate_kw_call(self, kw_call, min_length=2):
        if len(kw_call) >= min_length:
            return True
        return any(is_list_var(item) for item in kw_call)

    def _get_run_kws_keywords(self, given_args):
        for kw_call in self._get_run_kws_calls(given_args):
            yield Keyword(kw_call[0], kw_call[1:])

    def _get_run_kws_calls(self, given_args):
        if 'AND' not in given_args:
            for kw_call in given_args:
                yield [kw_call,]
        else:
            while 'AND' in given_args:
                index = list(given_args).index('AND')
                kw_call, given_args = given_args[:index], given_args[index + 1:]
                yield kw_call
            if given_args:
                yield given_args

    def _get_default_run_kw_keywords(self, given_args):
        index = list(self.arguments.positional).index('name')
        return [Keyword(given_args[index], given_args[index+1:])]

class _XTimesHandler(_RunKeywordHandler):

    def __init__(self, handler, name):
        _RunKeywordHandler.__init__(self, handler.library, handler.name,
                                    handler._handler_method)
        self.name = name
        self._doc = "*DEPRECATED* Replace X times syntax with 'Repeat Keyword'."

    def run(self, context, args):
        resolved_times = context.namespace.variables.replace_string(self.name)
        _RunnableHandler.run(self, context, (resolved_times,) + tuple(args))

    @property
    def longname(self):
        return self.name

class _DynamicRunKeywordHandler(_DynamicHandler, _RunKeywordHandler):
    _parse_arguments = _RunKeywordHandler._parse_arguments
    _get_timeout = _RunKeywordHandler._get_timeout
    _get_argument_resolver = _RunKeywordHandler._get_argument_resolver

class _PythonInitHandler(_PythonHandler):

    def __init__(self, library, handler_name, handler_method, docgetter):
        _PythonHandler.__init__(self, library, handler_name, handler_method)
        self._docgetter = docgetter

    @property
    def doc(self):
        if self._docgetter:
            self._doc = self._docgetter() or self._doc
            self._docgetter = None
        return self._doc

    def _parse_arguments(self, handler_method):
        parser = PythonArgumentParser(type='Test Library')
        return parser.parse(self.library.name, handler_method)

class _JavaInitHandler(_JavaHandler):

    def __init__(self, library, handler_name, handler_method, docgetter):
        _JavaHandler.__init__(self, library, handler_name, handler_method)
        self._docgetter = docgetter

    @property
    def doc(self):
        if self._docgetter:
            self._doc = self._docgetter() or self._doc
            self._docgetter = None
        return self._doc

    def _parse_arguments(self, handler_method):
        parser = JavaArgumentParser(type='Test Library')
        signatures = self._get_signatures(handler_method)
        return parser.parse(self.library.name, signatures)
<commit_msg>robot.running.handlers._DynamicHandler: Explicitly check handler_method's argspec for kwargs support<commit_after>#  Copyright 2008-2013 Nokia Siemens Networks Oyj
#
#  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.

from __future__ import with_statement

import inspect

from robot import utils
from robot.errors import DataError
from robot.variables import is_list_var

from .arguments import (PythonArgumentParser, JavaArgumentParser,
                        DynamicArgumentParser, ArgumentResolver,
                        ArgumentValidator, ArgumentMapper, JavaArgumentCoercer)
from .keywords import Keywords, Keyword
from .outputcapture import OutputCapturer
from .runkwregister import RUN_KW_REGISTER
from .signalhandler import STOP_SIGNAL_MONITOR

if utils.is_jython:
    from org.python.core import PyReflectedFunction, PyReflectedConstructor

    def _is_java_init(init):
        return isinstance(init, PyReflectedConstructor)
    def _is_java_method(method):
        return hasattr(method, 'im_func') \
               and isinstance(method.im_func, PyReflectedFunction)
else:
    _is_java_init = _is_java_method = lambda item: False

def Handler(library, name, method):
    if RUN_KW_REGISTER.is_run_keyword(library.orig_name, name):
        return _RunKeywordHandler(library, name, method)
    if _is_java_method(method):
        return _JavaHandler(library, name, method)
    else:
        return _PythonHandler(library, name, method)

def DynamicHandler(library, name, method, doc, argspec):
    if RUN_KW_REGISTER.is_run_keyword(library.orig_name, name):
        return _DynamicRunKeywordHandler(library, name, method, doc, argspec)
    return _DynamicHandler(library, name, method, doc, argspec)

def InitHandler(library, method, docgetter=None):
    Init = _PythonInitHandler if not _is_java_init(method) else _JavaInitHandler
    return Init(library, '__init__', method, docgetter)

class _RunnableHandler(object):
    type = 'library'
    _doc = ''

    def __init__(self, library, handler_name, handler_method):
        self.library = library
        self.name = utils.printable_name(handler_name, code_style=True)
        self.arguments = self._parse_arguments(handler_method)
        self._handler_name = handler_name
        self._method = self._get_initial_handler(library, handler_name,
                                                 handler_method)
        self._argument_resolver = self._get_argument_resolver(self.arguments)

    def _parse_arguments(self, handler_method):
        raise NotImplementedError

    def _get_argument_resolver(self, argspec):
        return ArgumentResolver(argspec)

    def _get_initial_handler(self, library, name, method):
        if library.scope == 'GLOBAL':
            return self._get_global_handler(method, name)
        return None

    def resolve_arguments(self, args, variables):
        return self._argument_resolver.resolve(args, variables)

    @property
    def doc(self):
        return self._doc

    @property
    def longname(self):
        return '%s.%s' % (self.library.name, self.name)

    @property
    def shortdoc(self):
        return self.doc.splitlines()[0] if self.doc else ''

    @property
    def libname(self):
        return self.library.name

    def init_keyword(self, varz):
        pass

    def run(self, context, args):
        if context.dry_run:
            return self._dry_run(context, args)
        return self._run(context, args)

    def _dry_run(self, context, args):
        if self.longname == 'BuiltIn.Import Library':
            return self._run(context, args)
        ArgumentValidator(self.arguments).validate_dry_run(args)
        return None

    def _run(self, context, args):
        positional, named = \
            self.resolve_arguments(args, context.variables)
        context.output.trace(lambda: self._log_args(positional, named))
        runner = self._runner_for(self._current_handler(), context, positional,
                                  named, self._get_timeout(context))
        return self._run_with_output_captured_and_signal_monitor(runner, context)

    def _log_args(self, positional, named):
        positional = [utils.safe_repr(arg) for arg in positional]
        named = ['%s=%s' % (utils.unic(name), utils.safe_repr(value))
                 for name, value in named.items()]
        return 'Arguments: [ %s ]' % ' | '.join(positional + named)

    def _runner_for(self, handler, context, positional, named, timeout):
        if timeout and timeout.active:
            context.output.debug(timeout.get_message)
            return lambda: timeout.run(handler, args=positional, kwargs=named)
        return lambda: handler(*positional, **named)

    def _run_with_output_captured_and_signal_monitor(self, runner, context):
        with OutputCapturer():
            return self._run_with_signal_monitoring(runner, context)

    def _run_with_signal_monitoring(self, runner, context):
        try:
            STOP_SIGNAL_MONITOR.start_running_keyword(context.in_teardown)
            return runner()
        finally:
            STOP_SIGNAL_MONITOR.stop_running_keyword()

    def _current_handler(self):
        if self._method:
            return self._method
        return self._get_handler(self.library.get_instance(), self._handler_name)

    def _get_global_handler(self, method, name):
        return method

    def _get_handler(self, lib_instance, handler_name):
        return getattr(lib_instance, handler_name)

    def _get_timeout(self, context):
        timeouts = self._get_timeouts(context)
        return None if not timeouts else min(timeouts)

    def _get_timeouts(self, context):
        timeouts = [kw.timeout for kw in context.keywords]
        if context.test and not context.in_test_teardown:
            timeouts.append(context.test.timeout)
        return [timeout for timeout in timeouts if timeout]

class _PythonHandler(_RunnableHandler):

    def __init__(self, library, handler_name, handler_method):
        _RunnableHandler.__init__(self, library, handler_name, handler_method)
        self._doc = utils.getdoc(handler_method)

    def _parse_arguments(self, handler_method):
        return PythonArgumentParser().parse(self.longname, handler_method)

class _JavaHandler(_RunnableHandler):

    def __init__(self, library, handler_name, handler_method):
        _RunnableHandler.__init__(self, library, handler_name, handler_method)
        signatures = self._get_signatures(handler_method)
        self._arg_coercer = JavaArgumentCoercer(signatures, self.arguments)

    def _parse_arguments(self, handler_method):
        signatures = self._get_signatures(handler_method)
        return JavaArgumentParser().parse(self.longname, signatures)

    def _get_argument_resolver(self, argspec):
        return ArgumentResolver(argspec, resolve_named=False)

    def _get_signatures(self, handler):
        code_object = getattr(handler, 'im_func', handler)
        return code_object.argslist[:code_object.nargs]

    def resolve_arguments(self, args, variables):
        positional, named = self._argument_resolver.resolve(args, variables)
        positional = self._arg_coercer.coerce(positional)
        return positional, named

class _DynamicHandler(_RunnableHandler):

    def __init__(self, library, handler_name, handler_method, doc='',
                 argspec=None):
        self._argspec = argspec
        _RunnableHandler.__init__(self, library, handler_name, handler_method)
        self._run_keyword_method_name = handler_method.__name__
        self._doc = doc is not None and utils.unic(doc) or ''
        # Check **kwargs handling requirements:
        self._handler_argspec = inspect.getargspec(handler_method)
        if argspec and argspec[-1].startswith('**'):
            handler_args = self._handler_argspec.args
            if len(handler_args) < 4:
                raise DataError(
                  "Too few '%s' method parameters"
                  " for **kwargs support: %s" % (
                      self._run_keyword_method_name, handler_args))

    def _parse_arguments(self, handler_method):
        return DynamicArgumentParser().parse(self.longname, self._argspec)

    def resolve_arguments(self, arguments, variables):
        positional, named = _RunnableHandler.resolve_arguments(self, arguments, variables)
        arguments, kwargs = ArgumentMapper(self.arguments).map(positional, named, prune_trailing_defaults=True)
        return arguments, kwargs

    def _get_handler(self, lib_instance, handler_name):
        runner = getattr(lib_instance, self._run_keyword_method_name)
        return self._get_dynamic_handler(runner, handler_name)

    def _get_global_handler(self, method, name):
        return self._get_dynamic_handler(method, name)

    def _get_dynamic_handler(self, runner, name):
        def handler(*positional, **kwargs):
            # Does the runner have **kwargs support?
            if len(self._handler_argspec.args) > 3:
                return runner(name, positional, kwargs)
            else:
                return runner(name, positional)
        return handler

class _RunKeywordHandler(_PythonHandler):

    def __init__(self, library, handler_name, handler_method):
        _PythonHandler.__init__(self, library, handler_name, handler_method)
        self._handler_method = handler_method

    def _run_with_signal_monitoring(self, runner, context):
        # With run keyword variants, only the keyword to be run can fail
        # and therefore monitoring should not raise exception yet.
        return runner()

    def _get_argument_resolver(self, argspec):
        resolve_until = self._get_args_to_process()
        return ArgumentResolver(argspec, resolve_named=False,
                                resolve_variables_until=resolve_until)

    def _get_args_to_process(self):
        return RUN_KW_REGISTER.get_args_to_process(self.library.orig_name,
                                                   self.name)

    def _get_timeout(self, namespace):
        return None

    def _dry_run(self, context, args):
        _RunnableHandler._dry_run(self, context, args)
        keywords = self._get_runnable_dry_run_keywords(context, args)
        keywords.run(context)

    def _get_runnable_dry_run_keywords(self, context, args):
        keywords = Keywords([])
        for keyword in self._get_dry_run_keywords(args):
            if self._variable_syntax_in(keyword.name, context):
                continue
            keywords.add_keyword(keyword)
        return keywords

    def _variable_syntax_in(self, kw_name, context):
        try:
            resolved = context.namespace.variables.replace_string(kw_name)
            #Variable can contain value, but it might be wrong,
            #therefore it cannot be returned
            return resolved != kw_name
        except DataError:
            return True

    def _get_dry_run_keywords(self, args):
        if self._handler_name == 'run_keyword_if':
            return list(self._get_run_kw_if_keywords(args))
        if self._handler_name == 'run_keywords':
            return list(self._get_run_kws_keywords(args))
        if 'name' in self.arguments.positional and self._get_args_to_process() > 0:
            return self._get_default_run_kw_keywords(args)
        return []

    def _get_run_kw_if_keywords(self, given_args):
        for kw_call in self._get_run_kw_if_calls(given_args):
            if kw_call:
                yield Keyword(kw_call[0], kw_call[1:])

    def _get_run_kw_if_calls(self, given_args):
        while 'ELSE IF' in given_args:
            kw_call, given_args = self._split_run_kw_if_args(given_args, 'ELSE IF', 2)
            yield kw_call
        if 'ELSE' in given_args:
            kw_call, else_call = self._split_run_kw_if_args(given_args, 'ELSE', 1)
            yield kw_call
            yield else_call
        elif self._validate_kw_call(given_args):
            expr, kw_call = given_args[0], given_args[1:]
            if not is_list_var(expr):
                yield kw_call

    def _split_run_kw_if_args(self, given_args, control_word, required_after):
        index = list(given_args).index(control_word)
        expr_and_call = given_args[:index]
        remaining = given_args[index+1:]
        if not (self._validate_kw_call(expr_and_call) and
                self._validate_kw_call(remaining, required_after)):
            raise DataError("Invalid 'Run Keyword If' usage.")
        if is_list_var(expr_and_call[0]):
            return (), remaining
        return expr_and_call[1:], remaining

    def _validate_kw_call(self, kw_call, min_length=2):
        if len(kw_call) >= min_length:
            return True
        return any(is_list_var(item) for item in kw_call)

    def _get_run_kws_keywords(self, given_args):
        for kw_call in self._get_run_kws_calls(given_args):
            yield Keyword(kw_call[0], kw_call[1:])

    def _get_run_kws_calls(self, given_args):
        if 'AND' not in given_args:
            for kw_call in given_args:
                yield [kw_call,]
        else:
            while 'AND' in given_args:
                index = list(given_args).index('AND')
                kw_call, given_args = given_args[:index], given_args[index + 1:]
                yield kw_call
            if given_args:
                yield given_args

    def _get_default_run_kw_keywords(self, given_args):
        index = list(self.arguments.positional).index('name')
        return [Keyword(given_args[index], given_args[index+1:])]

class _XTimesHandler(_RunKeywordHandler):

    def __init__(self, handler, name):
        _RunKeywordHandler.__init__(self, handler.library, handler.name,
                                    handler._handler_method)
        self.name = name
        self._doc = "*DEPRECATED* Replace X times syntax with 'Repeat Keyword'."

    def run(self, context, args):
        resolved_times = context.namespace.variables.replace_string(self.name)
        _RunnableHandler.run(self, context, (resolved_times,) + tuple(args))

    @property
    def longname(self):
        return self.name

class _DynamicRunKeywordHandler(_DynamicHandler, _RunKeywordHandler):
    _parse_arguments = _RunKeywordHandler._parse_arguments
    _get_timeout = _RunKeywordHandler._get_timeout
    _get_argument_resolver = _RunKeywordHandler._get_argument_resolver

class _PythonInitHandler(_PythonHandler):

    def __init__(self, library, handler_name, handler_method, docgetter):
        _PythonHandler.__init__(self, library, handler_name, handler_method)
        self._docgetter = docgetter

    @property
    def doc(self):
        if self._docgetter:
            self._doc = self._docgetter() or self._doc
            self._docgetter = None
        return self._doc

    def _parse_arguments(self, handler_method):
        parser = PythonArgumentParser(type='Test Library')
        return parser.parse(self.library.name, handler_method)

class _JavaInitHandler(_JavaHandler):

    def __init__(self, library, handler_name, handler_method, docgetter):
        _JavaHandler.__init__(self, library, handler_name, handler_method)
        self._docgetter = docgetter

    @property
    def doc(self):
        if self._docgetter:
            self._doc = self._docgetter() or self._doc
            self._docgetter = None
        return self._doc

    def _parse_arguments(self, handler_method):
        parser = JavaArgumentParser(type='Test Library')
        signatures = self._get_signatures(handler_method)
        return parser.parse(self.library.name, signatures)
<|endoftext|>


<commit_before>#  Copyright 2008-2012 Nokia Siemens Networks Oyj
#
#  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.

from robot.utils import (format_assign_message, get_elapsed_time,
                         get_error_message, get_timestamp, plural_or_not)
from robot.errors import (DataError, ExecutionFailed, ExecutionFailures,
                          HandlerExecutionFailed)
from robot.common import BaseKeyword
from robot.variables import is_scalar_var, VariableAssigner

class Keywords(object):

    def __init__(self, steps, template=None):
        self._keywords = []
        self._templated = bool(template)
        if self._templated:
            steps = [s.apply_template(template) for s in steps]
        for s in steps:
            self._add_step(s, template)

    def _add_step(self, step, template):
        if step.is_comment():
            return
        if step.is_for_loop():
            keyword = ForLoop(step, template)
        else:
            keyword = Keyword(step.keyword, step.args, step.assign)
        self.add_keyword(keyword)

    def add_keyword(self, keyword):
        self._keywords.append(keyword)

    def run(self, context):
        errors = []
        for kw in self._keywords:
            try:
                kw.run(context)
            except ExecutionFailed, err:
                errors.extend(err.get_errors())
                if not err.can_continue(context.teardown, self._templated,
                                        context.dry_run):
                    break
        if errors:
            raise ExecutionFailures(errors)

    def __nonzero__(self):
        return bool(self._keywords)

    def __iter__(self):
        return iter(self._keywords)

class Keyword(BaseKeyword):

    def __init__(self, name, args, assign=None, type='kw'):
        BaseKeyword.__init__(self, name, args, type=type)
        self.assign = assign or []
        self.handler_name = name

    def run(self, context):
        handler = self._start(context)
        try:
            return_value = self._run(handler, context)
        except ExecutionFailed, err:
            self.status = 'FAIL' if not err.exit_for_loop else 'PASS'
            self._end(context, error=err)
            raise
        else:
            if not (context.dry_run and handler.type == 'library'):
                self.status = 'PASS'
            self._end(context, return_value)
            return return_value

    def _start(self, context):
        handler = context.get_handler(self.handler_name)
        handler.init_keyword(context.get_current_vars())
        self.name = self._get_name(handler.longname)
        self.doc = handler.shortdoc
        self.timeout = getattr(handler, 'timeout', '')
        self.starttime = get_timestamp()
        context.start_keyword(self)
        if self.doc.startswith('*DEPRECATED*'):
            msg = self.doc.replace('*DEPRECATED*', '', 1).strip()
            name = self.name.split('} = ', 1)[-1]  # Remove possible variable
            context.warn("Keyword '%s' is deprecated. %s" % (name, msg))
        return handler

    def _get_name(self, handler_longname):
        if not self.assign:
            return handler_longname
        return '%s = %s' % (', '.join(a.rstrip('= ') for a in self.assign),
                            handler_longname)

    def _run(self, handler, context):
        try:
            return handler.run(context, self.args[:])
        except ExecutionFailed:
            raise
        except:
            self._report_failure(context)

    def _end(self, context, return_value=None, error=None):
        self.endtime = get_timestamp()
        self.elapsedtime = get_elapsed_time(self.starttime, self.endtime)
        try:
            if not error or error.can_continue(context.teardown):
                self._set_variables(context, return_value, error)
        finally:
            context.end_keyword(self)

    def _set_variables(self, context, return_value, error):
        if error:
            return_value = error.return_value
        try:
            VariableAssigner(self.assign).assign(context, return_value)
        except DataError, err:
            self.status = 'FAIL'
            msg = unicode(err)
            context.output.fail(msg)
            raise ExecutionFailed(msg, syntax=True)

    def _report_failure(self, context):
        failure = HandlerExecutionFailed()
        if not failure.exit_for_loop:
            context.output.fail(failure.full_message)
            if failure.traceback:
                context.output.debug(failure.traceback)
        raise failure

class ForLoop(BaseKeyword):

    def __init__(self, forstep, template=None):
        BaseKeyword.__init__(self, self._get_name(forstep), type='for')
        self.vars = forstep.vars
        self.items = forstep.items
        self.range = forstep.range
        self.keywords = Keywords(forstep.steps, template)
        self._templated = bool(template)

    def _get_name(self, data):
        return '%s %s [ %s ]' % (' | '.join(data.vars),
                                 'IN' if not data.range else 'IN RANGE',
                                 ' | '.join(data.items))

    def run(self, context):
        self.starttime = get_timestamp()
        context.start_keyword(self)
        try:
            self._validate()
            self._run(context)
        except ExecutionFailed, err:
            error = err
        except DataError, err:
            msg = unicode(err)
            context.output.fail(msg)
            error = ExecutionFailed(msg, syntax=True)
        else:
            error = None
        self.status = 'PASS' if not error else 'FAIL'
        self.endtime = get_timestamp()
        self.elapsedtime = get_elapsed_time(self.starttime, self.endtime)
        context.end_keyword(self)
        if error:
            raise error

    def _validate(self):
        if not self.vars:
            raise DataError('FOR loop has no loop variables.')
        for var in self.vars:
            if not is_scalar_var(var):
                raise DataError("Invalid FOR loop variable '%s'." % var)
        if not self.items:
            raise DataError('FOR loop has no loop values.')
        if not self.keywords:
            raise DataError('FOR loop contains no keywords.')

    def _run(self, context):
        errors = []
        items, iteration_steps = self._get_items_and_iteration_steps(context)
        for i in iteration_steps:
            values = items[i:i+len(self.vars)]
            err = self._run_one_round(context, self.vars, values)
            if err:
                if err.exit_for_loop:
                    break
                errors.extend(err.get_errors())
                if not err.can_continue(context.teardown, self._templated,
                                        context.dry_run):
                    break
        if errors:
            raise ExecutionFailures(errors)

    def _get_items_and_iteration_steps(self, context):
        if context.dry_run:
            return self.vars, [0]
        items = self._replace_vars_from_items(context.get_current_vars())
        return items, range(0, len(items), len(self.vars))

    def _run_one_round(self, context, variables, values):
        foritem = _ForItem(variables, values)
        context.start_keyword(foritem)
        for var, value in zip(variables, values):
            context.get_current_vars()[var] = value
        try:
            self.keywords.run(context)
        except ExecutionFailed, err:
            error = err
        except DataError, err:
            msg = unicode(err)
            context.output.fail(msg)
            error = ExecutionFailed(unicode(err), syntax=True)
        else:
            error = None
        foritem.end('PASS' if not error or error.exit_for_loop else 'FAIL')
        context.end_keyword(foritem)
        return error

    def _replace_vars_from_items(self, variables):
        items = variables.replace_list(self.items)
        if self.range:
            items = self._get_range_items(items)
        if len(items) % len(self.vars) == 0:
            return items
        raise DataError('Number of FOR loop values should be multiple of '
                        'variables. Got %d variables but %d value%s.'
                        % (len(self.vars), len(items), plural_or_not(items)))

    def _get_range_items(self, items):
        try:
            items = [self._to_int_with_arithmetics(item) for item in items]
        except:
            raise DataError('Converting argument of FOR IN RANGE failed: %s'
                            % get_error_message())
        if not 1 <= len(items) <= 3:
            raise DataError('FOR IN RANGE expected 1-3 arguments, '
                            'got %d instead.' % len(items))
        return range(*items)

    def _to_int_with_arithmetics(self, item):
        item = str(item)
        try:
            return int(item)
        except ValueError:
            return int(eval(item))

class _ForItem(BaseKeyword):

    def __init__(self, vars, items):
        name = ', '.join(format_assign_message(var, item)
                         for var, item in zip(vars, items))
        BaseKeyword.__init__(self, name, type='foritem')
        self.starttime = get_timestamp()

    def end(self, status):
        self.status = status
        self.endtime = get_timestamp()
        self.elapsedtime = get_elapsed_time(self.starttime, self.endtime)
<commit_msg>remove duplication<commit_after>#  Copyright 2008-2012 Nokia Siemens Networks Oyj
#
#  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.

from robot.utils import (format_assign_message, get_elapsed_time,
                         get_error_message, get_timestamp, plural_or_not)
from robot.errors import (DataError, ExecutionFailed, ExecutionFailures,
                          HandlerExecutionFailed)
from robot.common import BaseKeyword
from robot.variables import is_scalar_var, VariableAssigner

class Keywords(object):

    def __init__(self, steps, template=None):
        self._keywords = []
        self._templated = bool(template)
        if self._templated:
            steps = [s.apply_template(template) for s in steps]
        for s in steps:
            self._add_step(s, template)

    def _add_step(self, step, template):
        if step.is_comment():
            return
        if step.is_for_loop():
            keyword = ForLoop(step, template)
        else:
            keyword = Keyword(step.keyword, step.args, step.assign)
        self.add_keyword(keyword)

    def add_keyword(self, keyword):
        self._keywords.append(keyword)

    def run(self, context):
        errors = []
        for kw in self._keywords:
            try:
                kw.run(context)
            except ExecutionFailed, err:
                errors.extend(err.get_errors())
                if not err.can_continue(context.teardown, self._templated,
                                        context.dry_run):
                    break
        if errors:
            raise ExecutionFailures(errors)

    def __nonzero__(self):
        return bool(self._keywords)

    def __iter__(self):
        return iter(self._keywords)

class Keyword(BaseKeyword):

    def __init__(self, name, args, assign=None, type='kw'):
        BaseKeyword.__init__(self, name, args, type=type)
        self.assign = assign or []
        self.handler_name = name

    def run(self, context):
        handler = self._start(context)
        try:
            return_value = self._run(handler, context)
        except ExecutionFailed, err:
            self.status = 'FAIL' if not err.exit_for_loop else 'PASS'
            self._end(context, error=err)
            raise
        else:
            if not (context.dry_run and handler.type == 'library'):
                self.status = 'PASS'
            self._end(context, return_value)
            return return_value

    def _start(self, context):
        handler = context.get_handler(self.handler_name)
        handler.init_keyword(context.get_current_vars())
        self.name = self._get_name(handler.longname)
        self.doc = handler.shortdoc
        self.timeout = getattr(handler, 'timeout', '')
        self.starttime = get_timestamp()
        context.start_keyword(self)
        if self.doc.startswith('*DEPRECATED*'):
            msg = self.doc.replace('*DEPRECATED*', '', 1).strip()
            name = self.name.split('} = ', 1)[-1]  # Remove possible variable
            context.warn("Keyword '%s' is deprecated. %s" % (name, msg))
        return handler

    def _get_name(self, handler_longname):
        if not self.assign:
            return handler_longname
        return '%s = %s' % (', '.join(a.rstrip('= ') for a in self.assign),
                            handler_longname)

    def _run(self, handler, context):
        try:
            return handler.run(context, self.args[:])
        except ExecutionFailed:
            raise
        except:
            self._report_failure(context)

    def _end(self, context, return_value=None, error=None):
        self.endtime = get_timestamp()
        self.elapsedtime = get_elapsed_time(self.starttime, self.endtime)
        try:
            if not error or error.can_continue(context.teardown):
                self._set_variables(context, return_value, error)
        finally:
            context.end_keyword(self)

    def _set_variables(self, context, return_value, error):
        if error:
            return_value = error.return_value
        try:
            VariableAssigner(self.assign).assign(context, return_value)
        except DataError, err:
            self.status = 'FAIL'
            msg = unicode(err)
            context.output.fail(msg)
            raise ExecutionFailed(msg, syntax=True)

    def _report_failure(self, context):
        failure = HandlerExecutionFailed()
        if not failure.exit_for_loop:
            context.output.fail(failure.full_message)
            if failure.traceback:
                context.output.debug(failure.traceback)
        raise failure

class ForLoop(BaseKeyword):

    def __init__(self, forstep, template=None):
        BaseKeyword.__init__(self, self._get_name(forstep), type='for')
        self.vars = forstep.vars
        self.items = forstep.items
        self.range = forstep.range
        self.keywords = Keywords(forstep.steps, template)
        self._templated = bool(template)

    def _get_name(self, data):
        return '%s %s [ %s ]' % (' | '.join(data.vars),
                                 'IN' if not data.range else 'IN RANGE',
                                 ' | '.join(data.items))

    def run(self, context):
        self.starttime = get_timestamp()
        context.start_keyword(self)
        error = self._run_with_error_handling(self._validate_and_run, context)
        self.status = 'PASS' if not error else 'FAIL'
        self.endtime = get_timestamp()
        self.elapsedtime = get_elapsed_time(self.starttime, self.endtime)
        context.end_keyword(self)
        if error:
            raise error

    def _run_with_error_handling(self, runnable, context):
        try:
            runnable(context)
        except ExecutionFailed, err:
            return err
        except DataError, err:
            msg = unicode(err)
            context.output.fail(msg)
            return ExecutionFailed(msg, syntax=True)
        else:
            return None

    def _validate_and_run(self, context):
        self._validate()
        self._run(context)

    def _validate(self):
        if not self.vars:
            raise DataError('FOR loop has no loop variables.')
        for var in self.vars:
            if not is_scalar_var(var):
                raise DataError("Invalid FOR loop variable '%s'." % var)
        if not self.items:
            raise DataError('FOR loop has no loop values.')
        if not self.keywords:
            raise DataError('FOR loop contains no keywords.')

    def _run(self, context):
        errors = []
        items, iteration_steps = self._get_items_and_iteration_steps(context)
        for i in iteration_steps:
            values = items[i:i+len(self.vars)]
            err = self._run_one_round(context, self.vars, values)
            if err:
                if err.exit_for_loop:
                    break
                errors.extend(err.get_errors())
                if not err.can_continue(context.teardown, self._templated,
                                        context.dry_run):
                    break
        if errors:
            raise ExecutionFailures(errors)

    def _get_items_and_iteration_steps(self, context):
        if context.dry_run:
            return self.vars, [0]
        items = self._replace_vars_from_items(context.get_current_vars())
        return items, range(0, len(items), len(self.vars))

    def _run_one_round(self, context, variables, values):
        foritem = _ForItem(variables, values)
        context.start_keyword(foritem)
        for var, value in zip(variables, values):
            context.get_current_vars()[var] = value
        error = self._run_with_error_handling(self.keywords.run, context)
        foritem.end('PASS' if not error or error.exit_for_loop else 'FAIL')
        context.end_keyword(foritem)
        return error

    def _replace_vars_from_items(self, variables):
        items = variables.replace_list(self.items)
        if self.range:
            items = self._get_range_items(items)
        if len(items) % len(self.vars) == 0:
            return items
        raise DataError('Number of FOR loop values should be multiple of '
                        'variables. Got %d variables but %d value%s.'
                        % (len(self.vars), len(items), plural_or_not(items)))

    def _get_range_items(self, items):
        try:
            items = [self._to_int_with_arithmetics(item) for item in items]
        except:
            raise DataError('Converting argument of FOR IN RANGE failed: %s'
                            % get_error_message())
        if not 1 <= len(items) <= 3:
            raise DataError('FOR IN RANGE expected 1-3 arguments, '
                            'got %d instead.' % len(items))
        return range(*items)

    def _to_int_with_arithmetics(self, item):
        item = str(item)
        try:
            return int(item)
        except ValueError:
            return int(eval(item))

class _ForItem(BaseKeyword):

    def __init__(self, vars, items):
        name = ', '.join(format_assign_message(var, item)
                         for var, item in zip(vars, items))
        BaseKeyword.__init__(self, name, type='foritem')
        self.starttime = get_timestamp()

    def end(self, status):
        self.status = status
        self.endtime = get_timestamp()
        self.elapsedtime = get_elapsed_time(self.starttime, self.endtime)
<|endoftext|>


<commit_before>import logging; logger = logging.getLogger("robot." + __name__)

import os

from robots.lowlevel import *
from robots.exception import RobotError, UnknownFrameError

from robots.action import *
from robots.helpers import position
from robots.helpers.cb import nop

from robots.actions.configuration import setpose

#TODO HACK: I create here a new action performer for background "tracking"
# actions to avoid pypoco multithreading issues
actionPerformerForTracking = None

###############################################################################
###############################################################################

def clip(v, vmin, vmax):
    return max(min(v, vmax), vmin)

@tested("21/11/2012")
@workswith({POCOLIBS:"pr2SoftMotion"})
@workswith({POCOLIBS:"platine"})
@workswith(NAOQI)
@action
def look_at(robot, place, callback = None):
    """ Orders the robot to look at a given place of object.

    If available, uses pr2SoftMotion::moveHead. Else tries with the platine-genom
    module.

    :param place: any valid pyrobots place (spark id, ROS frame, [x,y,z],...)
    """

    if not place:
        return []

    try:
        place = robot.poses[place]
    except UnknownFrameError:
        logger.warning("Could not resolve the pose %s. Skipping look_at." %place)
        return []

    if robot.hasmodule("pr2SoftMotion"):
        return look_at_xyz_with_moveHead(robot, place['x'], place['y'], place['z'], place['frame'], callback)

    elif robot.hasmodule("platine"):

        raw = robot.execute([genom_request("spark", "GetJointAbsPose", [place, "HeadX"])])

        ok, res = raw
        if not ok:
            # Object probably does not exist
            return []
        yaw, pitch, roll, x, y, z = [float(x) for x in res]

        actions = [
            genom_request("platine",
                "AimAtTargetPoint",
                [0.0, 0.0, 0.0,
                0.0, 0.0, 0.0,
                "POM_FRAME_ORIGIN",
                0,
                x,
                y,
                z
                ],
                wait_for_completion = False if callback else True,
                callback = callback)
            ]
        return actions

    elif robot.supports(NAOQI):
        yaw, pitch = robot.poses.ros.xyz2pantilt(robot.poses[place],
                                                 headframe="gaze")
        yaw = clip(yaw, -2.0857, 2.0857)
        pitch = clip(-pitch, -0.6720, 0.5149) #beware the '-pitch'!
        return setpose(robot, {"HEAD": (yaw, pitch)}, relative = True)
    else:
        logger.warning("No module available to execute a 'look_at'. Skipping this action.")
        return []

###############################################################################

@tested("22/02/2012")
@action
def look_at_xyz_with_moveHead(robot, x,y,z, frame = "map", callback = None):
    """ Look at via pr2SoftMotion.

    :param x: the x coordinate
    :param y: the y coordinate
    :param z: the z coordinate
    :param frame: the frame in which coordinates are interpreted. By default, '/map'
    """
    logger.debug("Looking at " + str([x,y,z]) + " in " + frame)
    actions = [
        genom_request("pr2SoftMotion",
            "MoveHead",
            [x,y,z,frame],
        wait_for_completion = False if callback else True,
        callback = callback
        )
    ]
    return actions

###############################################################################

@tested("15/06/2012")
@action
@same_requirements_as(look_at)
def track(robot, target):
    """ Tracks an object with the head.

    This uses pr2SoftMotion.

    This is a background action. Can be cancelled with cancel_track.

    :param target: a pyRobots pose to track. At each step, the pose is re-evaluated is needed (eg for a TF frame or a SPARK object)    """

    return [background_task(TrackAction, [target])]

###############################################################################

from threading import Thread
import time

# TODO: move head only if robot/target has moved
class TrackAction(Thread):
    def __init__(self, robot, target):
        global actionPerformerForTracking

        Thread.__init__(self)

        # At first track, initialize a new action performer
	#if not actionPerformerForTracking:
        #    from lowlevel import ActionPerformer
        #    actionPerformerForTracking = ActionPerformer('pr2c2', 9472, use_ros = False)

        self.running = False
        self.robot = robot
        self.target = target

    def run(self):
        self.running = True

        while self.running:
            if self.target:
                self.robot.look_at(self.target)
                #actionPerformerForTracking.execute(look_at, self.target)
            time.sleep(0.5)

    def stop(self):
        self.running = False

###############################################################################

@tested("15/06/2012")
@action
@same_requirements_as(look_at)
def cancel_track(robot):
    """ If running, interrupt a current track action.
    """
    return [background_task(TrackAction, abort=True)]

###############################################################################

@broken
@tested("22/02/2012")
@action
@workswith({ROS:["/head_traj_controller/point_head_action"]})
def look_at_ros(robot, place):
    """ Create the client and the goal.

    :param place: a dictionary which contains object position parameters.
    Cf look_at for details.
    """

    #import roslib; roslib.load_manifest('p_actionlib')
    import rospy

    import actionlib
    import pr2_controllers_msgs.msg
    import geometry_msgs.msg

    place = robot.poses[place]
    x = place['x']
    y = place['y']
    z = place['z']

    try:
       frame = place['frame']
    except KeyError:
       frame = "/map"

    # Creates the SimpleActionClient, passing the type of the action
    # (MoveBaseAction) to the constructor.
    client = actionlib.SimpleActionClient('/head_traj_controller/point_head_action', pr2_controllers_msgs.msg.PointHeadAction)

    # Waits for the action server to come up
    client.wait_for_server()
    ok = client.wait_for_server()
    if not ok:
            logger.error("Could not connect to the ROS client! Aborting action")
            return

    # Creates a goal to send to the action server.
    goal = pr2_controllers_msgs.msg.PointHeadGoal()

    # Definition of the goal
    point = geometry_msgs.msg.PointStamped()
    point.header.frame_id = frame
    point.point.x = x
    point.point.y = y
    point.point.z = z

    goal.target = point
    goal.pointing_frame = 'high_def_frame'
    goal.min_duration = rospy.Duration(0.5)
    goal.max_velocity = 1.0

    return [ros_request(client, goal)]

###############################################################################

@tested("22/02/2012")
@action
@same_requirements_as(look_at)
def glance_to(robot, place):
    """ Briefly look at a given location, and come back to the
    currently pose.
    """

    pose_head_base = {"HEAD": robot.state.getpose()["HEAD"]}

    actions = look_at(robot, place)
    actions += [wait(2)]
    actions += setpose(robot, pose_head_base)
    return actions

###############################################################################

@tested("22/02/2012")
@action
@workswith({POCOLIBS:['pr2SoftMotion']})
def sweep(robot, amplitude = 90, speed = 0.2):
    """ Makes a sweep movement with the robot head via pr2SoftMotion compared with its current position

    :param amplitude: Number of degrees of the sweeping head movement (default:
    90 deg)
    :param speed: Speed of the movement (default: 0.2)
    """
    import math
    actions =[]

    amplitude_rd = math.radians(float(amplitude))

    head_tilt = robot.state.getjoint('head_tilt_joint')
    head_pan = robot.state.getjoint('head_pan_joint')

    pose_head_base = {"HEAD": (head_pan,  head_tilt)}
    pose_head1 = {"HEAD": (head_pan + amplitude_rd/2,  head_tilt)}
    pose_head2 = {"HEAD": (head_pan - amplitude_rd/2,  head_tilt)}

    actions =[
        genom_request("pr2SoftMotion", "SetTimeScale",[1.0, 1.0, speed, 1.0, 1.0, 1.0])
    ]

    actions += setpose(robot, pose_head1)
    actions += setpose(robot, pose_head2)
    actions +=[
        genom_request("pr2SoftMotion", "SetTimeScale",[1.0, 1.0, 1.0, 1.0, 1.0, 1.0])
    ]
    actions += setpose(robot, pose_head_base)

    return actions

###############################################################################
@tested("21/11/2012")
@action
@workswith(ROS)
def switch_active_stereo_pair(robot, pair = "wide_stereo"):
    os.system("rosservice call /viman_bridge/switch_cameras %s" % pair)

<commit_msg>[actions/look_at] support 'sweep' on Nao<commit_after>import logging; logger = logging.getLogger("robot." + __name__)

import os

from robots.lowlevel import *
from robots.exception import RobotError, UnknownFrameError

from robots.action import *
from robots.helpers import position
from robots.helpers.cb import nop

from robots.actions.configuration import setpose

#TODO HACK: I create here a new action performer for background "tracking"
# actions to avoid pypoco multithreading issues
actionPerformerForTracking = None

###############################################################################
###############################################################################

def clip(v, vmin, vmax):
    return max(min(v, vmax), vmin)

@tested("21/11/2012")
@workswith({POCOLIBS:"pr2SoftMotion"})
@workswith({POCOLIBS:"platine"})
@workswith(NAOQI)
@action
def look_at(robot, place, callback = None):
    """ Orders the robot to look at a given place of object.

    If available, uses pr2SoftMotion::moveHead. Else tries with the platine-genom
    module.

    :param place: any valid pyrobots place (spark id, ROS frame, [x,y,z],...)
    """

    if not place:
        return []

    try:
        place = robot.poses[place]
    except UnknownFrameError:
        logger.warning("Could not resolve the pose %s. Skipping look_at." %place)
        return []

    if robot.hasmodule("pr2SoftMotion"):
        return look_at_xyz_with_moveHead(robot, place['x'], place['y'], place['z'], place['frame'], callback)

    elif robot.hasmodule("platine"):

        raw = robot.execute([genom_request("spark", "GetJointAbsPose", [place, "HeadX"])])

        ok, res = raw
        if not ok:
            # Object probably does not exist
            return []
        yaw, pitch, roll, x, y, z = [float(x) for x in res]

        actions = [
            genom_request("platine",
                "AimAtTargetPoint",
                [0.0, 0.0, 0.0,
                0.0, 0.0, 0.0,
                "POM_FRAME_ORIGIN",
                0,
                x,
                y,
                z
                ],
                wait_for_completion = False if callback else True,
                callback = callback)
            ]
        return actions

    elif robot.supports(NAOQI):
        yaw, pitch = robot.poses.ros.xyz2pantilt(robot.poses[place],
                                                 headframe="gaze")
        yaw = clip(yaw, -2.0857, 2.0857)
        pitch = clip(-pitch, -0.6720, 0.5149) #beware the '-pitch'!
        return setpose(robot, {"HEAD": (yaw, pitch)}, relative = True)
    else:
        logger.warning("No module available to execute a 'look_at'. Skipping this action.")
        return []

###############################################################################

@tested("22/02/2012")
@action
def look_at_xyz_with_moveHead(robot, x,y,z, frame = "map", callback = None):
    """ Look at via pr2SoftMotion.

    :param x: the x coordinate
    :param y: the y coordinate
    :param z: the z coordinate
    :param frame: the frame in which coordinates are interpreted. By default, '/map'
    """
    logger.debug("Looking at " + str([x,y,z]) + " in " + frame)
    actions = [
        genom_request("pr2SoftMotion",
            "MoveHead",
            [x,y,z,frame],
        wait_for_completion = False if callback else True,
        callback = callback
        )
    ]
    return actions

###############################################################################

@tested("15/06/2012")
@action
@same_requirements_as(look_at)
def track(robot, target):
    """ Tracks an object with the head.

    This uses pr2SoftMotion.

    This is a background action. Can be cancelled with cancel_track.

    :param target: a pyRobots pose to track. At each step, the pose is re-evaluated is needed (eg for a TF frame or a SPARK object)    """

    return [background_task(TrackAction, [target])]

###############################################################################

from threading import Thread
import time

# TODO: move head only if robot/target has moved
class TrackAction(Thread):
    def __init__(self, robot, target):
        global actionPerformerForTracking

        Thread.__init__(self)

        # At first track, initialize a new action performer
	#if not actionPerformerForTracking:
        #    from lowlevel import ActionPerformer
        #    actionPerformerForTracking = ActionPerformer('pr2c2', 9472, use_ros = False)

        self.running = False
        self.robot = robot
        self.target = target

    def run(self):
        self.running = True

        while self.running:
            if self.target:
                self.robot.look_at(self.target)
                #actionPerformerForTracking.execute(look_at, self.target)
            time.sleep(0.5)

    def stop(self):
        self.running = False

###############################################################################

@tested("15/06/2012")
@action
@same_requirements_as(look_at)
def cancel_track(robot):
    """ If running, interrupt a current track action.
    """
    return [background_task(TrackAction, abort=True)]

###############################################################################

@broken
@tested("22/02/2012")
@action
@workswith({ROS:["/head_traj_controller/point_head_action"]})
def look_at_ros(robot, place):
    """ Create the client and the goal.

    :param place: a dictionary which contains object position parameters.
    Cf look_at for details.
    """

    #import roslib; roslib.load_manifest('p_actionlib')
    import rospy

    import actionlib
    import pr2_controllers_msgs.msg
    import geometry_msgs.msg

    place = robot.poses[place]
    x = place['x']
    y = place['y']
    z = place['z']

    try:
       frame = place['frame']
    except KeyError:
       frame = "/map"

    # Creates the SimpleActionClient, passing the type of the action
    # (MoveBaseAction) to the constructor.
    client = actionlib.SimpleActionClient('/head_traj_controller/point_head_action', pr2_controllers_msgs.msg.PointHeadAction)

    # Waits for the action server to come up
    client.wait_for_server()
    ok = client.wait_for_server()
    if not ok:
            logger.error("Could not connect to the ROS client! Aborting action")
            return

    # Creates a goal to send to the action server.
    goal = pr2_controllers_msgs.msg.PointHeadGoal()

    # Definition of the goal
    point = geometry_msgs.msg.PointStamped()
    point.header.frame_id = frame
    point.point.x = x
    point.point.y = y
    point.point.z = z

    goal.target = point
    goal.pointing_frame = 'high_def_frame'
    goal.min_duration = rospy.Duration(0.5)
    goal.max_velocity = 1.0

    return [ros_request(client, goal)]

###############################################################################

@tested("22/02/2012")
@action
@same_requirements_as(look_at)
def glance_to(robot, place):
    """ Briefly look at a given location, and come back to the
    currently pose.
    """

    pose_head_base = {"HEAD": robot.state.getpose()["HEAD"]}

    actions = look_at(robot, place)
    actions += [wait(2)]
    actions += setpose(robot, pose_head_base)
    return actions

###############################################################################

@tested("22/02/2012")
@action
@same_requirements_as(look_at)
def sweep(robot, amplitude = 90, speed = 0.2):
    """ Makes a sweep movement with the robot head via pr2SoftMotion compared with its current position

    :param amplitude: Number of degrees of the sweeping head movement (default:
    90 deg)
    :param speed: Speed of the movement (default: 0.2)
    """
    import math
    actions=[]

    amplitude_rd = math.radians(float(amplitude))

    head_pan, head_tilt = robot.state.getpose()["HEAD"]

    pose_head_base = {"HEAD": (head_pan,  head_tilt)}
    pose_head1 = {"HEAD": (head_pan + amplitude_rd/2,  head_tilt)}
    pose_head2 = {"HEAD": (head_pan - amplitude_rd/2,  head_tilt)}

    actions = []
    if robot.hasmodule("pr2SoftMotion"):
        actions += [genom_request("pr2SoftMotion", "SetTimeScale",[1.0, 1.0, speed, 1.0, 1.0, 1.0])]

    actions += setpose(robot, pose_head1)
    actions += setpose(robot, pose_head2)

    if robot.hasmodule("pr2SoftMotion"):
        actions +=[genom_request("pr2SoftMotion", "SetTimeScale",[1.0, 1.0, 1.0, 1.0, 1.0, 1.0])]

    actions += setpose(robot, pose_head_base)

    return actions

###############################################################################
@tested("21/11/2012")
@action
@workswith(ROS)
def switch_active_stereo_pair(robot, pair = "wide_stereo"):
    os.system("rosservice call /viman_bridge/switch_cameras %s" % pair)

<|endoftext|>


<commit_before>#########
# Copyright (c) 2015 GigaSpaces Technologies Ltd. All rights reserved
#
# 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.

import ldap

from flask.ext.securest.models import User
from flask.ext.securest.userstores.abstract_userstore import AbstractUserstore

class LDAPUserstore(AbstractUserstore):
    """
    This class is an example of a concrete implementation of a user store.
    It implements an LDAP user store.
    """

    def __init__(self,
                 identifying_attribute,
                 directory_url,
                 admin_dn,
                 admin_password,
                 root_dn,
                 username_attribute,
                 user_password_attribute,
                 user_email_attribute=None,
                 is_active_attribute=None):
        # initialize ldap with url, admin and password
        self._identifying_attribute = identifying_attribute
        self.root_dn = root_dn
        self.ldapObject = ldap.initialize(directory_url)
        self.ldapObject.bind(admin_dn, admin_password, ldap.AUTH_SIMPLE)
        self.username_attribute = username_attribute
        self.user_password_attribute = user_password_attribute
        self.user_email_attribute = user_email_attribute
        self.is_active_attribute = is_active_attribute

    def __del__(self):
        self.ldapObject.unbind()

    def get_user(self, user_identifier):
        if not user_identifier:
            raise ValueError('user identifier is missing or empty')

        return self._get_user_object(user_identifier)

    def _get_user_object(self, user_identifier):
        search_result = self.ldapObject.search_s(
            '{0}'.format(self.root_dn),
            ldap.SCOPE_SUBTREE,
            '({0}={1})'.format(self._identifying_attribute, user_identifier))
        if not search_result:
            return None
        user_entry = search_result[0][1]

        user_email = LDAPUserstore.get_attribute_if_exists(
            self.user_email_attribute, user_entry, None)
        is_active = LDAPUserstore.get_attribute_if_exists(
            self.is_active_attribute, user_entry, True)

        return User(user_entry[self.username_attribute][0],
                    user_entry[self.user_password_attribute][0],
                    user_email,
                    active=is_active)

    @staticmethod
    def get_attribute_if_exists(attr_name, user_entry, default_value=None):
        value = default_value
        if attr_name:
            attr_list = user_entry.get(attr_name)
            if attr_list:
                value = attr_list[0]
        return value
<commit_msg>Update ldap_userstore.py<commit_after>#########
# Copyright (c) 2015 GigaSpaces Technologies Ltd. All rights reserved
#
# 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.

import ldap

from flask.ext.securest.models import User
from flask.ext.securest.userstores.abstract_userstore import AbstractUserstore

class LDAPUserstore(AbstractUserstore):
    """
    This class is an example implementation of an LDAP user store.
    It is for demonstration purposes only- not an official user store!
    """

    def __init__(self,
                 identifying_attribute,
                 directory_url,
                 admin_dn,
                 admin_password,
                 root_dn,
                 username_attribute,
                 user_password_attribute,
                 user_email_attribute=None,
                 is_active_attribute=None):
        # initialize ldap with url, admin and password
        self._identifying_attribute = identifying_attribute
        self.root_dn = root_dn
        self.ldapObject = ldap.initialize(directory_url)
        self.ldapObject.bind(admin_dn, admin_password, ldap.AUTH_SIMPLE)
        self.username_attribute = username_attribute
        self.user_password_attribute = user_password_attribute
        self.user_email_attribute = user_email_attribute
        self.is_active_attribute = is_active_attribute

    def __del__(self):
        self.ldapObject.unbind()

    def get_user(self, user_identifier):
        if not user_identifier:
            raise ValueError('user identifier is missing or empty')

        return self._get_user_object(user_identifier)

    def _get_user_object(self, user_identifier):
        search_result = self.ldapObject.search_s(
            '{0}'.format(self.root_dn),
            ldap.SCOPE_SUBTREE,
            '({0}={1})'.format(self._identifying_attribute, user_identifier))
        if not search_result:
            return None
        user_entry = search_result[0][1]

        user_email = LDAPUserstore.get_attribute_if_exists(
            self.user_email_attribute, user_entry, None)
        is_active = LDAPUserstore.get_attribute_if_exists(
            self.is_active_attribute, user_entry, True)

        return User(user_entry[self.username_attribute][0],
                    user_entry[self.user_password_attribute][0],
                    user_email,
                    active=is_active)

    @staticmethod
    def get_attribute_if_exists(attr_name, user_entry, default_value=None):
        value = default_value
        if attr_name:
            attr_list = user_entry.get(attr_name)
            if attr_list:
                value = attr_list[0]
        return value
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
# pylint: disable=bad-continuation
""" ‘Double Click’ – Extensions to `Click <http://click.pocoo.org/4/>`_.
"""
# Copyright ©  2015 Jürgen Hermann <jh@web.de>
#
# 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.
from __future__ import absolute_import, unicode_literals, print_function

import os
import re
import sys

import configobj
from bunch import Bunch
from click import *  # pylint: disable=wildcard-import
from click import __all__

from .._compat import encode_filename

__all__ = list(__all__) + [
    'pretty_path', 'serror',
    'LoggedFailure', 'AliasedGroup', 'Configuration',
]
__all__ = [encode_filename(_) for _ in __all__]

def pretty_path(path, _home_re=re.compile('^' + re.escape(os.path.expanduser('~') + os.sep))):
    """Prettify path for humans, and make it Unicode."""
    path = format_filename(path)
    path = _home_re.sub('~' + os.sep, path)
    return path

def serror(message, *args, **kwargs):
    """Print a styled error message, while using any arguments to format the message."""
    if args or kwargs:
        message = message.format(*args, **kwargs)
    return secho(message, fg='white', bg='red', bold=True)

class LoggedFailure(UsageError):
    """Report a failure condition to the user."""

    def __init__(self, message):
        message = style(message, fg='white', bg='red', bold=True)
        UsageError.__init__(self, message)

class AliasedGroup(Group):
    """ A command group with alias names.

        Inherit from this class and define a ``MAP`` class variable,
        which is a mapping from alias names to canonical command names.
        Then use that derived class as the ``cls`` parameter for a
        ``click.group`` decorator.
    """

    MAP = {}

    def get_command(self, ctx, cmd_name):
        """Map some aliases to their 'real' names."""
        cmd_name = self.MAP.get(cmd_name, cmd_name)
        return super(AliasedGroup, self).get_command(ctx, cmd_name)

class Configuration(object):
    """ Configuration container that is initialized early in the main command.

        The default instance is available via the Click context as ``ctx.obj.cfg``.
        Configuration is lazily loaded, on first access.
    """

    NO_DEFAULT = object()
    DEFAULT_PATH = [
        '/etc/{appname}.conf',
        '/etc/{appname}.d/',
        '{appcfg}.conf',
    ]
    DEFAULT_CONFIG_OPTS = dict(
        encoding='utf-8',
        default_encoding='utf-8',
    )

    @classmethod
    def from_context(cls, ctx, config_paths=None, project=None):
        """Create a configuration object, and initialize the Click context with it."""
        if ctx.obj is None:
            ctx.obj = Bunch()
        ctx.obj.cfg = cls(ctx.info_name, config_paths, project=project)
        return ctx.obj.cfg

    def __init__(self, name, config_paths=None, project=None):
        """ Set up static knowledge about configuration.

            ``config_paths`` is a list of PATHs to config files or directories.
            If that is non-empty, exactly those paths will be considered; an empty
            path element represents the default locations (just like in MANPATH).

            If the environment variable ``<prefix>_CONFIG`` is set, its value will
            be appended to the default locations.
        """
        self.values = configobj.ConfigObj({}, **self.DEFAULT_CONFIG_OPTS)
        self.project = project
        self.name = name
        self.config_paths = []
        self.loaded = False

        env_config = os.environ.get((self.name + '-config').upper().replace('-', '_'), '')
        defaults = [i.format(appname=os.sep.join([self.project, self.name]) if project else self.name,
                             appdir=get_app_dir(self.project or self.name),
                             appcfg=get_app_dir(self.project) + os.sep + self.name if self.project else get_app_dir(self.name))
                for i in self.DEFAULT_PATH
            ] + [i for i in env_config.split(os.pathsep) if i]

        for path in config_paths or []:
            for name in path.split(os.pathsep):
                if name:
                    self.config_paths.append(name)
                else:
                    self.config_paths.extend(defaults)

        if not self.config_paths:
            self.config_paths = defaults

    def locations(self, exists=True):
        """ Return the location of the config file(s).

            A given directory will be scanned for ``*.conf`` files, in alphabetical order.
            Any duplicates will be eliminated.

            If ``exists`` is True, only existing configuration locations are returned.
        """
        result = []
        for config_files in self.config_paths:
            if not config_files:
                continue
            if os.path.isdir(config_files):
                config_files = [os.path.join(config_files, i)
                                for i in sorted(os.listdir(config_files))
                                if i.endswith('.conf')]
            else:
                config_files = [config_files]
            for config_file in config_files:
                if not exists or os.path.exists(config_file):
                    config_file = os.path.abspath(config_file)
                    if config_file in result:
                        result.remove(config_file)
                    result.append(config_file)
        return result

    def load(self):
        """Load configuration from the defined locations."""
        if not self.loaded:
            self.values = configobj.ConfigObj({}, **self.DEFAULT_CONFIG_OPTS)
            for path in self.locations():
                try:
                    part = configobj.ConfigObj(infile=path, **self.DEFAULT_CONFIG_OPTS)
                except configobj.ConfigObjError as cause:
                    raise LoggedFailure("Error in file '{path}': {cause}".format(path=pretty_path(path), cause=cause))
                self.values.merge(part)
            self.loaded = True
        return self.values

    def dump(self, to=None):  # pylint: disable=invalid-name
        """Dump the merged configuration to a stream or stdout."""
        self.load().write(to or sys.stdout)

    def section(self, ctx):
        """
            Return section of the config for a specific context (sub-command).

            Parameters:
                ctx (Context): The Click context object.

            Returns:
                Section: The configuration section belonging to
                    the active (sub-)command (based on ``ctx.info_name``).

        """
        values = self.load()
        try:
            return values[ctx.info_name]
        except KeyError:
            raise LoggedFailure("Configuration section '{}' not found!".format(ctx.info_name))

    def get(self, name, default=NO_DEFAULT):
        """
            Return the specified name from the root section.

            Parameters:
                name (str): The name of the requested value.
                default (optional): If set, the default value to use
                    instead of raising :class:`LoggedFailure` for
                    unknown names.

            Returns:
                The value for `name`.

            Raises:
                LoggedFailure: The requested `name` was not found.
        """
        values = self.load()
        try:
            return values[name]
        except KeyError:
            if default is self.NO_DEFAULT:
                raise LoggedFailure("Configuration value '{}' not found in root section!".format(name))
            return default
<commit_msg>click config: add 'optional' param to section()<commit_after># -*- coding: utf-8 -*-
# pylint: disable=bad-continuation
""" ‘Double Click’ – Extensions to `Click <http://click.pocoo.org/4/>`_.
"""
# Copyright ©  2015 Jürgen Hermann <jh@web.de>
#
# 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.
from __future__ import absolute_import, unicode_literals, print_function

import os
import re
import sys

import configobj
from bunch import Bunch
from click import *  # pylint: disable=wildcard-import
from click import __all__

from .._compat import encode_filename

__all__ = list(__all__) + [
    'pretty_path', 'serror',
    'LoggedFailure', 'AliasedGroup', 'Configuration',
]
__all__ = [encode_filename(_) for _ in __all__]

def pretty_path(path, _home_re=re.compile('^' + re.escape(os.path.expanduser('~') + os.sep))):
    """Prettify path for humans, and make it Unicode."""
    path = format_filename(path)
    path = _home_re.sub('~' + os.sep, path)
    return path

def serror(message, *args, **kwargs):
    """Print a styled error message, while using any arguments to format the message."""
    if args or kwargs:
        message = message.format(*args, **kwargs)
    return secho(message, fg='white', bg='red', bold=True)

class LoggedFailure(UsageError):
    """Report a failure condition to the user."""

    def __init__(self, message):
        message = style(message, fg='white', bg='red', bold=True)
        UsageError.__init__(self, message)

class AliasedGroup(Group):
    """ A command group with alias names.

        Inherit from this class and define a ``MAP`` class variable,
        which is a mapping from alias names to canonical command names.
        Then use that derived class as the ``cls`` parameter for a
        ``click.group`` decorator.
    """

    MAP = {}

    def get_command(self, ctx, cmd_name):
        """Map some aliases to their 'real' names."""
        cmd_name = self.MAP.get(cmd_name, cmd_name)
        return super(AliasedGroup, self).get_command(ctx, cmd_name)

class Configuration(object):
    """ Configuration container that is initialized early in the main command.

        The default instance is available via the Click context as ``ctx.obj.cfg``.
        Configuration is lazily loaded, on first access.
    """

    NO_DEFAULT = object()
    DEFAULT_PATH = [
        '/etc/{appname}.conf',
        '/etc/{appname}.d/',
        '{appcfg}.conf',
    ]
    DEFAULT_CONFIG_OPTS = dict(
        encoding='utf-8',
        default_encoding='utf-8',
    )

    @classmethod
    def from_context(cls, ctx, config_paths=None, project=None):
        """Create a configuration object, and initialize the Click context with it."""
        if ctx.obj is None:
            ctx.obj = Bunch()
        ctx.obj.cfg = cls(ctx.info_name, config_paths, project=project)
        return ctx.obj.cfg

    def __init__(self, name, config_paths=None, project=None):
        """ Set up static knowledge about configuration.

            ``config_paths`` is a list of PATHs to config files or directories.
            If that is non-empty, exactly those paths will be considered; an empty
            path element represents the default locations (just like in MANPATH).

            If the environment variable ``<prefix>_CONFIG`` is set, its value will
            be appended to the default locations.
        """
        self.values = configobj.ConfigObj({}, **self.DEFAULT_CONFIG_OPTS)
        self.project = project
        self.name = name
        self.config_paths = []
        self.loaded = False

        env_config = os.environ.get((self.name + '-config').upper().replace('-', '_'), '')
        defaults = [i.format(appname=os.sep.join([self.project, self.name]) if project else self.name,
                             appdir=get_app_dir(self.project or self.name),
                             appcfg=get_app_dir(self.project) + os.sep + self.name if self.project else get_app_dir(self.name))
                for i in self.DEFAULT_PATH
            ] + [i for i in env_config.split(os.pathsep) if i]

        for path in config_paths or []:
            for name in path.split(os.pathsep):
                if name:
                    self.config_paths.append(name)
                else:
                    self.config_paths.extend(defaults)

        if not self.config_paths:
            self.config_paths = defaults

    def locations(self, exists=True):
        """ Return the location of the config file(s).

            A given directory will be scanned for ``*.conf`` files, in alphabetical order.
            Any duplicates will be eliminated.

            If ``exists`` is True, only existing configuration locations are returned.
        """
        result = []
        for config_files in self.config_paths:
            if not config_files:
                continue
            if os.path.isdir(config_files):
                config_files = [os.path.join(config_files, i)
                                for i in sorted(os.listdir(config_files))
                                if i.endswith('.conf')]
            else:
                config_files = [config_files]
            for config_file in config_files:
                if not exists or os.path.exists(config_file):
                    config_file = os.path.abspath(config_file)
                    if config_file in result:
                        result.remove(config_file)
                    result.append(config_file)
        return result

    def load(self):
        """Load configuration from the defined locations."""
        if not self.loaded:
            self.values = configobj.ConfigObj({}, **self.DEFAULT_CONFIG_OPTS)
            for path in self.locations():
                try:
                    part = configobj.ConfigObj(infile=path, **self.DEFAULT_CONFIG_OPTS)
                except configobj.ConfigObjError as cause:
                    raise LoggedFailure("Error in file '{path}': {cause}".format(path=pretty_path(path), cause=cause))
                self.values.merge(part)
            self.loaded = True
        return self.values

    def dump(self, to=None):  # pylint: disable=invalid-name
        """Dump the merged configuration to a stream or stdout."""
        self.load().write(to or sys.stdout)

    def section(self, ctx, optional=False):
        """
            Return section of the config for a specific context (sub-command).

            Parameters:
                ctx (Context): The Click context object.
                optional (bool): If ``True``, return an empty config object when section is missing.

            Returns:
                Section: The configuration section belonging to
                    the active (sub-)command (based on ``ctx.info_name``).

        """
        values = self.load()
        try:
            return values[ctx.info_name]
        except KeyError:
            if optional:
                return configobj.ConfigObj({}, **self.DEFAULT_CONFIG_OPTS)
            raise LoggedFailure("Configuration section '{}' not found!".format(ctx.info_name))

    def get(self, name, default=NO_DEFAULT):
        """
            Return the specified name from the root section.

            Parameters:
                name (str): The name of the requested value.
                default (optional): If set, the default value to use
                    instead of raising :class:`LoggedFailure` for
                    unknown names.

            Returns:
                The value for `name`.

            Raises:
                LoggedFailure: The requested `name` was not found.
        """
        values = self.load()
        try:
            return values[name]
        except KeyError:
            if default is self.NO_DEFAULT:
                raise LoggedFailure("Configuration value '{}' not found in root section!".format(name))
            return default
<|endoftext|>


<commit_before>####this file is only used for continuous evaluation test!

import os
import sys
#sys.path.insert(0, os.environ['ceroot'])
from kpi import CostKpi, DurationKpi, AccKpi

#### NOTE kpi.py should shared in models in some way!!!!

train_cost_card1_kpi = CostKpi('train_cost_card1', 0.02, 0, actived=True)
test_cost_card1_kpi = CostKpi('test_cost_card1', 0.005, 0, actived=True)
train_duration_card1_kpi = DurationKpi(
    'train_duration_card1', 0.06, 0, actived=True)
train_cost_card4_kpi = CostKpi('train_cost_card4', 0.01, 0, actived=True)
test_cost_card4_kpi = CostKpi('test_cost_card4', 0.005, 0, actived=True)
train_duration_card4_kpi = DurationKpi(
    'train_duration_card4', 0.06, 0, actived=True)

tracking_kpis = [
    train_cost_card1_kpi,
    test_cost_card1_kpi,
    train_duration_card1_kpi,
    train_cost_card4_kpi,
    test_cost_card4_kpi,
    train_duration_card4_kpi,
]

def parse_log(log):
    '''
    This method should be implemented by model developers.
    The suggestion:
    each line in the log should be key, value, for example:
    "
    train_cost\t1.0
    test_cost\t1.0
    train_cost\t1.0
    train_cost\t1.0
    train_acc\t1.2
    "
    '''
    for line in log.split('\n'):
        fs = line.strip().split('\t')
        print(fs)
        if len(fs) == 3 and fs[0] == 'kpis':
            print("-----%s" % fs)
            kpi_name = fs[1]
            kpi_value = float(fs[2])
            yield kpi_name, kpi_value

def log_to_ce(log):
    kpi_tracker = {}
    for kpi in tracking_kpis:
        kpi_tracker[kpi.name] = kpi

    for (kpi_name, kpi_value) in parse_log(log):
        print(kpi_name, kpi_value)
        kpi_tracker[kpi_name].add_record(kpi_value)
        kpi_tracker[kpi_name].persist()

if __name__ == '__main__':
    log = sys.stdin.read()
    print("*****")
    print(log)
    print("****")
    log_to_ce(log)
<commit_msg>update machine_reading_comprehension _ce.py<commit_after>####this file is only used for continuous evaluation test!

import os
import sys
#sys.path.insert(0, os.environ['ceroot'])
sys.path.append(os.environ['ceroot'])
from kpi import CostKpi, DurationKpi, AccKpi

#### NOTE kpi.py should shared in models in some way!!!!

train_cost_card1_kpi = CostKpi('train_cost_card1', 0.02, 0, actived=True)
test_cost_card1_kpi = CostKpi('test_cost_card1', 0.005, 0, actived=True)
train_duration_card1_kpi = DurationKpi(
    'train_duration_card1', 0.06, 0, actived=True)
train_cost_card4_kpi = CostKpi('train_cost_card4', 0.01, 0, actived=True)
test_cost_card4_kpi = CostKpi('test_cost_card4', 0.005, 0, actived=True)
train_duration_card4_kpi = DurationKpi(
    'train_duration_card4', 0.06, 0, actived=True)

tracking_kpis = [
    train_cost_card1_kpi,
    test_cost_card1_kpi,
    train_duration_card1_kpi,
    train_cost_card4_kpi,
    test_cost_card4_kpi,
    train_duration_card4_kpi,
]

def parse_log(log):
    '''
    This method should be implemented by model developers.
    The suggestion:
    each line in the log should be key, value, for example:
    "
    train_cost\t1.0
    test_cost\t1.0
    train_cost\t1.0
    train_cost\t1.0
    train_acc\t1.2
    "
    '''
    for line in log.split('\n'):
        fs = line.strip().split('\t')
        print(fs)
        if len(fs) == 3 and fs[0] == 'kpis':
            print("-----%s" % fs)
            kpi_name = fs[1]
            kpi_value = float(fs[2])
            yield kpi_name, kpi_value

def log_to_ce(log):
    kpi_tracker = {}
    for kpi in tracking_kpis:
        kpi_tracker[kpi.name] = kpi

    for (kpi_name, kpi_value) in parse_log(log):
        print(kpi_name, kpi_value)
        kpi_tracker[kpi_name].add_record(kpi_value)
        kpi_tracker[kpi_name].persist()

if __name__ == '__main__':
    log = sys.stdin.read()
    print("*****")
    print(log)
    print("****")
    log_to_ce(log)
<|endoftext|>