From 06ee33924ba060bb40a85b52e26e6353e1adc70d Mon Sep 17 00:00:00 2001 From: Martin Di Paola Date: Sat, 8 Aug 2020 02:01:33 +0000 Subject: [PATCH] Issue-128: allow use Barnett's regexs in pexpect Pexpect checks explicitly for Python's regexs rejecting Barnett's one. The adapter closes the gap between this two and allow to use Barnett's regex with pexpect. --- byexample/runner.py | 41 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/byexample/runner.py b/byexample/runner.py index f2ca9fbe..0d2016a5 100644 --- a/byexample/runner.py +++ b/byexample/runner.py @@ -1,6 +1,6 @@ from __future__ import unicode_literals import pexpect, time, termios, operator, os, itertools, contextlib -import re as re_orig +import re as python_re from . import regex as re from functools import reduce, partial from .executor import TimeoutException, InputPrefixNotFound @@ -80,6 +80,43 @@ def cancel(self, example, options): return False +class PexpectSpawnAdapter(pexpect.spawn): + def compile_pattern_list(self, patterns): + ''' This is an extension of pexpect.spawn.compile_pattern_list + to accept not only Python's regex objects (re module) but + also Barnett's regexs (third-party regex module). + + This is a workaround for the issue #655 + (https://github.com/pexpect/pexpect/issues/655) + ''' + if patterns is None: + return [] + if not isinstance(patterns, list): + patterns = [patterns] + + # Allow dot to match \n + compile_flags = python_re.DOTALL + if self.ignorecase: + compile_flags = compile_flags | python_re.IGNORECASE + compiled_pattern_list = [] + cls = pexpect.spawnbase + for idx, p in enumerate(patterns): + if isinstance(p, self.allowed_string_types): + p = self._coerce_expect_string(p) + compiled_pattern_list.append(python_re.compile(p, compile_flags)) + elif p is cls.EOF: + compiled_pattern_list.append(cls.EOF) + elif p is cls.TIMEOUT: + compiled_pattern_list.append(cls.TIMEOUT) + elif isinstance(p, type(python_re.compile(''))): + compiled_pattern_list.append(p) + elif isinstance(p, type(re.compile(''))): # <-- the workaround + compiled_pattern_list.append(p) + else: + self._pattern_type_err(p) + return compiled_pattern_list + + class PexpectMixin(object): def __init__(self, PS1_re, any_PS_re): self.PS1_re = re.compile(PS1_re) @@ -106,7 +143,7 @@ def _spawn_interpreter( env.update({'LINES': str(rows), 'COLUMNS': str(cols)}) self._drop_output() # there shouldn't be any output yet but... - self.interpreter = pexpect.spawn( + self.interpreter = PexpectSpawnAdapter( cmd, echo=False, encoding=self.encoding,