From 35550e048bde73b08fad28c2a8d844dcbdea7f35 Mon Sep 17 00:00:00 2001 From: Todd Leonhardt Date: Sun, 23 Sep 2018 18:51:30 -0400 Subject: Fixed several hack classes build to simulate file descriptors Now there is a single class, StdSim in utils.py, which is intended to simulate stdout and stderr file objects. This class replaced the following: - pyscript_bridge.py::CopyStream - transcript.py::OutputTrap - conftest.py::StdOut --- cmd2/utils.py | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) (limited to 'cmd2/utils.py') diff --git a/cmd2/utils.py b/cmd2/utils.py index 735221c8..83185603 100644 --- a/cmd2/utils.py +++ b/cmd2/utils.py @@ -246,3 +246,57 @@ def natural_sort(list_to_sort: List[str]) -> List[str]: :return: the list sorted naturally """ return sorted(list_to_sort, key=natural_keys) + + +class StdSim(object): + """Class to simulate behavior of sys.stdout or sys.stderr. + + Stores contents in internal buffer and optionally echos to the inner stream it is simulating. + """ + class ByteBuf(object): + """Inner class which stores an actual bytes buffer and does the actual output if echo is enabled.""" + def __init__(self, inner_stream, echo: bool = False) -> None: + self.byte_buf = b'' + self.inner_stream = inner_stream + self.echo = echo + + def write(self, b: bytes) -> None: + """Add bytes to internal bytes buffer and if echo is True, echo contents to inner stream.""" + self.byte_buf += b + if self.echo: + self.inner_stream.buffer.write(b) + + def __init__(self, inner_stream, echo: bool = False) -> None: + self.buffer = self.ByteBuf(inner_stream, echo) + self.inner_stream = inner_stream + + def write(self, s: str) -> None: + """Add str to internal bytes buffer and if echo is True, echo contents to inner stream.""" + b = s.encode() + self.buffer.write(b) + + def getvalue(self) -> str: + """Get the internal contents as a str. + + :return string from the internal contents + """ + return self.buffer.byte_buf.decode() + + def read(self) -> str: + """Read from the internal contents as a str and then clear them out. + + :return: string from the internal contents + """ + result = self.getvalue() + self.clear() + return result + + def clear(self) -> None: + """Clear the internal contents.""" + self.buffer.byte_buf = b'' + + def __getattr__(self, item: str): + if item in self.__dict__: + return self.__dict__[item] + else: + return getattr(self.inner_stream, item) -- cgit v1.2.1 From ca4ac5cfe4fae041463674cd8ee40b62444693f8 Mon Sep 17 00:00:00 2001 From: Todd Leonhardt Date: Mon, 24 Sep 2018 09:49:46 -0400 Subject: StdSim write methods now raise a TypeError exception if passed the wrong type Also: - Added explicit unit tests for StdSim to test_utils.py --- cmd2/utils.py | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'cmd2/utils.py') diff --git a/cmd2/utils.py b/cmd2/utils.py index 83185603..bdb488cc 100644 --- a/cmd2/utils.py +++ b/cmd2/utils.py @@ -262,6 +262,8 @@ class StdSim(object): def write(self, b: bytes) -> None: """Add bytes to internal bytes buffer and if echo is True, echo contents to inner stream.""" + if not isinstance(b, bytes): + raise TypeError('a bytes-like object is required, not {}'.format(type(b))) self.byte_buf += b if self.echo: self.inner_stream.buffer.write(b) @@ -272,6 +274,8 @@ class StdSim(object): def write(self, s: str) -> None: """Add str to internal bytes buffer and if echo is True, echo contents to inner stream.""" + if not isinstance(s, str): + raise TypeError('write() argument must be str, not {}'.format(type(s))) b = s.encode() self.buffer.write(b) -- cgit v1.2.1