Exemplo n.º 1
0
 def __init__(self,
              batch_mode=False,
              config_file: str = None,
              extra_config_options: Iterable[str] = None,
              cli_ns=NONE_NS):
     self._should_exit = False
     self._preserved_text = ''
     self.capture = NoOpCapture()
     self.batch_mode = batch_mode
     self.config = get_config(config_file, extra_config_options)
     self.cli_ns = cli_ns
     self._init_logging()
     self.history = SqLiteHistory(self.config.as_int('history_max'))
     self.completer = PeekCompleter(self)
     self.display = Display(self)
     self.parser = PeekParser()
     self.vm = self._init_vm()
     self.prompt = self._init_prompt()
     monkey_patch_completion_state()
     # TODO: better name for signal payload json reformat
     self.is_pretty = True
     self._init_es_client_manager()
     self.ecm_backup_data = self.es_client_manager.to_dict()
     self._on_startup()
Exemplo n.º 2
0
def peek_vm():
    mock_app = MagicMock(name='PeekApp')

    vm = PeekVM(mock_app)
    mock_app.vm = vm
    from peek import __file__ as package_root
    package_root = os.path.dirname(package_root)
    package_config_file = os.path.join(package_root, 'peekrc')

    mock_app.config = ConfigObj(package_config_file)
    mock_app.parser = PeekParser()
    vm.context['debug'] = MagicMock(return_value=None)
    mock_app.display.info = MagicMock(return_value=None)
    mock_app.display.error = MagicMock(return_value=None)
    es_client = MagicMock(name='EsClient')
    mock_app.es_client_manager.current = es_client
    mock_app.es_client_manager.get_client = MagicMock(return_value=es_client)
    es_client.perform_request = MagicMock(
        return_value='{"foo": [1, 2, 3, 4], "bar": {"hello": [42, "world"]}}')
    return vm
Exemplo n.º 3
0
    def get_completions(self, document: Document,
                        complete_event: CompleteEvent) -> Iterable[Completion]:
        _logger.debug(f'Document: {document}, Event: {complete_event}')

        text_before_cursor = document.text_before_cursor
        _logger.debug(f'Text before cursor: {text_before_cursor!r}')
        if text_before_cursor.strip() == '':
            return []

        state_tracker = ParserStateTracker(text_before_cursor)
        try:
            PeekParser((state_tracker, )).parse(text_before_cursor,
                                                fail_fast_on_error_token=True,
                                                last_stmt_only=True,
                                                log_level='WARNING')
        except Exception:
            pass

        if not state_tracker.is_completion_possible:
            _logger.debug(
                'No completion is available according to state_tracker')
            return []

        stmt_token = state_tracker.stmt_token
        if stmt_token.ttype is ShellOut:
            _logger.debug('Completing for shell out')
            return _SYSTEM_COMPLETER.get_completions(
                Document(text_before_cursor[stmt_token.index + 1:]),
                complete_event)

        if state_tracker.is_cursor_on_whitespace:
            return self._get_completions_for_whitespace(
                document, complete_event, state_tracker)

        else:
            return self._get_completions_for_non_white(document,
                                                       complete_event,
                                                       state_tracker)
Exemplo n.º 4
0
 def parse(self):
     if self.source is None:
         self.source = self._extract_all()
     parser = PeekParser()
     self.nodes = parser.parse(self.source, log_level='WARNING')
     return self.nodes
Exemplo n.º 5
0
                with open(os.path.join(root, f)) as ins:
                    file_key = os.path.join('/', prefix, root[len(base_dir) + 1:], f[:-3])
                    spec_file_contents[f'{file_key}'] = ins.read()

        return spec_file_contents

    def _trim_semicolon(self, line):
        return line[:-1] if line.endswith(';') else line


mock_app = MagicMock()
ConfigObj({
    'load_extension': False,
})
mock_app.display = MagicMock()
mock_app.parser = PeekParser()


class JsSpecEvaluator(PeekVM):

    def __init__(self):
        def flexible_dot(left_operand, right_operand):
            if isinstance(left_operand, list) and right_operand == 'sort':
                return lambda app: _sort(left_operand)
            elif isinstance(left_operand, list) and right_operand == 'flatMap':
                return lambda app, func: functools.partial(_flat_map, left_operand)(app, func)
            else:
                return _BIN_OP_FUNCS['.'](left_operand, right_operand)

        def flexible_mod(left_operand, right_operand):
            if left_operand == self.builtins['_']['splat']:
Exemplo n.º 6
0
def parser():
    return PeekParser()
Exemplo n.º 7
0
class PeekApp:
    def __init__(self,
                 batch_mode=False,
                 config_file: str = None,
                 extra_config_options: Iterable[str] = None,
                 cli_ns=NONE_NS):
        self._should_exit = False
        self._preserved_text = ''
        self.capture = NoOpCapture()
        self.batch_mode = batch_mode
        self.config = get_config(config_file, extra_config_options)
        self.cli_ns = cli_ns
        self._init_logging()
        self.history = SqLiteHistory(self.config.as_int('history_max'))
        self.completer = PeekCompleter(self)
        self.display = Display(self)
        self.parser = PeekParser()
        self.vm = self._init_vm()
        self.prompt = self._init_prompt()
        monkey_patch_completion_state()
        # TODO: better name for signal payload json reformat
        self.is_pretty = True
        self._init_es_client_manager()
        self.ecm_backup_data = self.es_client_manager.to_dict()
        self._on_startup()

    def run(self):
        try:
            while not self._should_exit:
                try:
                    text: str = self.prompt.prompt(
                        message=self._get_message(),
                        default=self._get_default_text(),
                    )
                    _logger.debug(f'input: {text!r}')
                    if self._should_exit:
                        raise EOFError()
                    if text.strip() == '':
                        continue
                    self.process_input(text)
                except KeyboardInterrupt:
                    continue
                except EOFError:
                    break
        finally:
            self.on_exit()

    def process_input(self, text, echo=False):
        try:
            nodes = self.parser.parse(text)
        except PeekSyntaxError as e:
            self.display.error(e)
            return

        for node in nodes:
            try:
                if echo:
                    self.display.info(str(node))
                self.execute_node(node)
            except PeekError as e:
                self.display.error(e)
            except Exception as e:
                self.display.error(e)
                _logger.exception('Error on node execution')

    def execute_node(self, node):
        self.vm.execute_node(node)

    def signal_exit(self):
        self._should_exit = True

    def start_capture(self, f=None):
        if not isinstance(self.capture, NoOpCapture):
            raise PeekError(
                f'Cannot capture when one is currently running: {self.capture.status()}'
            )

        if f is None:
            f = f'{datetime.now().strftime("%Y%m%d%H%M%S")}.es'
        self.capture = FileCapture(f)
        return self.capture.status()

    def stop_capture(self):
        if not isinstance(self.capture, NoOpCapture):
            self.capture.stop()
            self.capture = NoOpCapture()
            return 'Capture stopped'
        else:
            return 'No capture is running'

    @property
    def preserved_text(self):
        return self._preserved_text

    @preserved_text.setter
    def preserved_text(self, value: str):
        self._preserved_text = value

    def input(self, message='', is_secret=False):
        return prompt(message=message, is_password=is_secret)

    def reset(self):
        self.completer.init_api_specs()
        self.vm = self._init_vm()
        self._repopulate_clients(
            EsClientManager.from_dict(self, self.ecm_backup_data))
        self._on_startup()

    def _get_message(self):
        idx = self.es_client_manager.index_current
        if idx is None:
            return FormattedText([
                (PeekStyle.styles[Heading], '>>>'),
                (PeekStyle.styles[TipsMinor], ' No Connection\n'),
            ])
        else:
            info_line = f' [{idx}] {self.es_client_manager.current}'
            if len(info_line) > 100:
                info_line = info_line[:97] + '...'
            return FormattedText([
                (PeekStyle.styles[Heading], '>>>'),
                (PeekStyle.styles[TipsMinor], info_line + '\n'),
            ])

    def _get_default_text(self):
        text = self.preserved_text
        if text:
            self.preserved_text = ''
        return text

    def _init_logging(self):
        log_file = self.config['log_file']
        log_level = self.config['log_level'].upper()
        if log_level == 'NONE':
            handler = logging.NullHandler()
        elif log_file == 'stderr':
            handler = logging.StreamHandler(sys.stderr)
        elif log_file == 'stdout':
            handler = logging.StreamHandler(sys.stdout)
        else:
            handler = logging.handlers.RotatingFileHandler(
                config_location() + log_file,
                maxBytes=10 * 1024 * 1024,
                backupCount=5)

        log_level = getattr(logging, log_level, logging.WARNING)

        formatter = logging.Formatter(
            '%(asctime)s (%(process)d/%(threadName)s) '
            '%(name)s %(levelname)s - %(message)s')
        handler.setFormatter(formatter)

        root_logger = logging.getLogger(__package__)
        root_logger.addHandler(handler)
        root_logger.setLevel(log_level)

    def _init_prompt(self):
        if self.batch_mode:
            return None
        else:
            try:
                from prompt_toolkit.clipboard.pyperclip import PyperclipClipboard
                clipboard = PyperclipClipboard()
            except ImportError:
                clipboard = None

            return PromptSession(
                style=style_from_pygments_cls(PeekStyle),
                lexer=PygmentsLexer(PeekLexer),
                auto_suggest=AutoSuggestFromHistory(),
                completer=self.completer,
                history=self.history,
                multiline=True,
                key_bindings=key_bindings(self),
                enable_open_in_editor=True,
                enable_system_prompt=False,
                enable_suspend=True,
                search_ignore_case=True,
                clipboard=clipboard,
                mouse_support=Condition(self._should_support_mouse),
                swap_light_and_dark_colors=self.config.as_bool('swap_colour'),
                input_processors=[
                    HighlightMatchingBracketProcessor(chars="[](){}"),
                ],
            )

    def _init_es_client_manager(self):
        if self.cli_ns.zero_connection:
            self._repopulate_clients(EsClientManager())
            return

        options = {}
        keys = [
            'name',
            'hosts',
            'cloud_id',
            'username',
            'password',
            'api_key',
            'token',
            'use_ssl',
            'verify_certs',
            'assert_hostname',
            'ca_certs',
            'client_cert',
            'client_key',
            'force_prompt',
            'no_prompt',
        ]
        for k in keys:
            v = getattr(self.cli_ns, k, None)
            if v is not None:
                options[k] = v

        if self._should_auto_load_session(options):
            _logger.info('Auto-loading connection state')
            data = self.history.load_session(AUTO_SAVE_NAME)
            if data is not None:
                self._repopulate_clients(
                    EsClientManager.from_dict(self, json.loads(data)))
                return

        es_client_manager = EsClientManager()
        es_client_manager.add(connect(self, **options))
        self._repopulate_clients(es_client_manager)

    def _repopulate_clients(self, m: EsClientManager):
        """
        Detour to populate the clients due to dependency, e.g. on_add callback gets a reference of the App
        """
        self.es_client_manager = EsClientManager(
            listeners=[DelegatingListener(on_add=self._on_client_add)])
        for es_client in m.clients():
            self.es_client_manager.add(es_client)
        idx_current = m.index_current
        if idx_current is not None and idx_current < len(
                self.es_client_manager.clients()):
            self.es_client_manager.set_current(idx_current)

    def _init_vm(self):
        return PeekVM(self)

    def on_exit(self):
        if not self.batch_mode and self.config.as_bool('auto_save_session'):
            _logger.info('Auto-saving connection state')
            data = self.es_client_manager.to_dict()
            self.history.save_session(AUTO_SAVE_NAME, json.dumps(data))

    def _should_auto_load_session(self, options):
        """
        Auto load last auto-saved session only when:
        * configuration says so
        * running in interactive mode
        * No explicit connection parameters are specified (include those specified in connection section of rc file)
        """
        return (self.config.as_bool('auto_load_session')
                and not self.batch_mode and not options
                and self.config.get('connection') is None)

    def _should_support_mouse(self) -> bool:
        return self.config.as_bool('mouse_support')

    def _on_client_add(self, es_client_manager: EsClientManager):
        on_connection_add = self.config.get('on_connection_add')
        if on_connection_add is not None:
            self.process_input(on_connection_add)

    def _on_startup(self):
        on_startup = self.config.get('on_startup')
        if on_startup is not None:
            self.process_input(on_startup)