From 21cf7d3fa8ece85ef8447cef27afdda2b6141e2d Mon Sep 17 00:00:00 2001 From: Vladimir Turov Date: Thu, 16 Dec 2021 01:12:46 +0300 Subject: [PATCH] Catch errors if some non-important libs aren't installed --- hstest/common/reflection_utils.py | 11 +++------- hstest/dynamic/output/output_handler.py | 16 +++++++++++--- hstest/exception/failure_handler.py | 14 ++++++++++--- hstest/stage/stage_test.py | 2 +- .../testing/execution/main_module_executor.py | 2 ++ .../execution/searcher/python_searcher.py | 4 ++++ hstest/testing/plotting/matplotlib_handler.py | 18 +++++++++++----- hstest/testing/plotting/pandas_handler.py | 21 ++++++++++++------- hstest/testing/plotting/seaborn_handler.py | 7 +++++-- 9 files changed, 66 insertions(+), 29 deletions(-) diff --git a/hstest/common/reflection_utils.py b/hstest/common/reflection_utils.py index 095febad..0e39f8a1 100644 --- a/hstest/common/reflection_utils.py +++ b/hstest/common/reflection_utils.py @@ -1,9 +1,9 @@ import inspect import os -import sys -import traceback from typing import List +from hstest.exception.failure_handler import get_traceback_stack + def is_tests(stage): package = inspect.getmodule(stage).__package__ @@ -21,12 +21,7 @@ def setup_cwd(stage): def get_stacktrace(ex: BaseException, hide_internals=False) -> str: - exc_tb = ex.__traceback__ - - if sys.version_info >= (3, 10): - traceback_stack = traceback.format_exception(ex) - else: - traceback_stack = traceback.format_exception(etype=type(ex), value=ex, tb=exc_tb) + traceback_stack = get_traceback_stack(ex) if not hide_internals: return ''.join(traceback_stack) diff --git a/hstest/dynamic/output/output_handler.py b/hstest/dynamic/output/output_handler.py index 3a9f41bb..aa5f921b 100644 --- a/hstest/dynamic/output/output_handler.py +++ b/hstest/dynamic/output/output_handler.py @@ -25,13 +25,23 @@ def print(obj): lines = obj.strip().split('\n') - prepend = f'[{ThreadGroup.curr_group().name}] ' + group = ThreadGroup.curr_group() + + if group: + name = group.name + else: + name = "Root" + + prepend = f'[{name}] ' output = prepend + ('\n' + prepend).join(lines) full = BLUE + output + '\n' + RESET - OutputHandler.get_real_out().write(full) - OutputHandler.get_real_out().flush() + if group: + OutputHandler.get_real_out().write(full) + OutputHandler.get_real_out().flush() + else: + print(full, end='') @staticmethod def get_real_out() -> io.TextIOWrapper: diff --git a/hstest/exception/failure_handler.py b/hstest/exception/failure_handler.py index 4969b76c..198b47a0 100644 --- a/hstest/exception/failure_handler.py +++ b/hstest/exception/failure_handler.py @@ -1,5 +1,7 @@ import platform +import sys import traceback +from typing import List from hstest.testing.execution_options import inside_docker @@ -20,7 +22,13 @@ def get_report(): return 'Submitted via web' +def get_traceback_stack(ex: BaseException) -> List[str]: + if sys.version_info >= (3, 10): + return traceback.format_exception(ex) + else: + exc_tb = ex.__traceback__ + return traceback.format_exception(etype=type(ex), value=ex, tb=exc_tb) + + def get_exception_text(ex: BaseException) -> str: - exc_tb = ex.__traceback__ - traceback_stack = traceback.format_exception(etype=type(ex), value=ex, tb=exc_tb) - return ''.join(traceback_stack) + return ''.join(get_traceback_stack(ex)) diff --git a/hstest/stage/stage_test.py b/hstest/stage/stage_test.py index cf638a8d..85ae9bb3 100644 --- a/hstest/stage/stage_test.py +++ b/hstest/stage/stage_test.py @@ -146,7 +146,7 @@ def run_tests(self, *, debug=False) -> Tuple[int, str]: if isinstance(new_ex, OutcomeError): ex = new_ex - build = 'hs-test-python version build 2021.11.10.2' + build = 'hs-test-python' try: report = build + "\n\n" + get_report() diff --git a/hstest/testing/execution/main_module_executor.py b/hstest/testing/execution/main_module_executor.py index 7e203de5..bb0966c7 100644 --- a/hstest/testing/execution/main_module_executor.py +++ b/hstest/testing/execution/main_module_executor.py @@ -5,6 +5,7 @@ from typing import Optional from hstest.common.process_utils import DaemonThreadPoolExecutor +from hstest.dynamic.output.output_handler import OutputHandler from hstest.dynamic.security.exit_exception import ExitException from hstest.dynamic.security.thread_group import ThreadGroup from hstest.dynamic.system_handler import SystemHandler @@ -16,6 +17,7 @@ class MainModuleExecutor(ProgramExecutor): def __init__(self, source_name: str = None): super().__init__() + OutputHandler.print(f'MainModuleExecutor instantiating, source = {source_name}') self.runnable = PythonSearcher().find(source_name) self.__executor: Optional[DaemonThreadPoolExecutor] = None self.__task: Optional[Future] = None diff --git a/hstest/testing/execution/searcher/python_searcher.py b/hstest/testing/execution/searcher/python_searcher.py index f9b2935b..dfafbd03 100644 --- a/hstest/testing/execution/searcher/python_searcher.py +++ b/hstest/testing/execution/searcher/python_searcher.py @@ -1,6 +1,8 @@ +import os import re from typing import Optional +from hstest.dynamic.output.output_handler import OutputHandler from hstest.testing.execution.filtering.file_filter import FileFilter, Folder, Sources from hstest.testing.execution.filtering.main_filter import MainFilter from hstest.testing.execution.runnable.python_runnable_file import PythonRunnableFile @@ -48,5 +50,7 @@ def init_regexes(_: Folder, sources: Sources): ) def find(self, source: Optional[str]) -> PythonRunnableFile: + OutputHandler.print(f'PythonSearcher source = {source}, cwd = {os.getcwd()}') runnable = super().find(source) + OutputHandler.print(f'PythonSearcher found runnable: {runnable.folder}/{runnable.file}') return PythonRunnableFile(runnable.folder, runnable.file, runnable.file[:-len(self.extension)]) diff --git a/hstest/testing/plotting/matplotlib_handler.py b/hstest/testing/plotting/matplotlib_handler.py index 1133088a..f05b4fe9 100644 --- a/hstest/testing/plotting/matplotlib_handler.py +++ b/hstest/testing/plotting/matplotlib_handler.py @@ -2,7 +2,10 @@ from importlib import reload from typing import TYPE_CHECKING -import pandas as pd +try: + import pandas as pd +except ImportError: + pass from hstest.testing.plotting.drawing.drawing import Drawing from hstest.testing.plotting.drawing.drawing_builder import DrawingBuilder @@ -49,10 +52,15 @@ def hist(x, *args, data=None, **kw): x = data[x] except: pass - if type(x) == pd.DataFrame: - for col in x.columns: - hist(x[col], *args, **kw) - return + # TODO potential unresolved reference if pandas is not installed, but matplotlib is + # for now wrapped with bare try-except, but need better solution + try: + if type(x) == pd.DataFrame: + for col in x.columns: + hist(x[col], *args, **kw) + return + except: + pass drawings.append( DrawingBuilder.get_hist_drawing( diff --git a/hstest/testing/plotting/pandas_handler.py b/hstest/testing/plotting/pandas_handler.py index c0fc5a89..08fc91ee 100644 --- a/hstest/testing/plotting/pandas_handler.py +++ b/hstest/testing/plotting/pandas_handler.py @@ -1,8 +1,15 @@ from typing import TYPE_CHECKING -import numpy as np -import pandas as pd -from pandas.api.types import is_numeric_dtype +try: + import numpy as np +except ImportError: + pass + +try: + import pandas as pd + from pandas.api.types import is_numeric_dtype +except ImportError: + pass from hstest.testing.plotting.drawing.drawing import Drawing from hstest.testing.plotting.drawing.drawing_builder import DrawingBuilder @@ -42,7 +49,7 @@ class PandasHandler: } @staticmethod - def get_hist_drawings_with_normalized_data(data: pd.DataFrame, x, y): + def get_hist_drawings_with_normalized_data(data: 'pd.DataFrame', x, y): drawings = [] if y is not None: @@ -122,7 +129,7 @@ def get_scatter_drawings_with_normalized_data(data, x, y): ] @staticmethod - def get_pie_drawings_with_normalized_data(data: pd.DataFrame, x, y): + def get_pie_drawings_with_normalized_data(data: 'pd.DataFrame', x, y): if type(data) == pd.Series: drawing = DrawingBuilder.get_pie_drawing( @@ -154,7 +161,7 @@ def get_pie_drawings_with_normalized_data(data: pd.DataFrame, x, y): return drawings @staticmethod - def get_bar_drawings_with_normalized_data(data: pd.DataFrame, x, y): + def get_bar_drawings_with_normalized_data(data: 'pd.DataFrame', x, y): drawings = [] if x is not None: @@ -183,7 +190,7 @@ def get_bar_drawings_with_normalized_data(data: pd.DataFrame, x, y): return drawings @staticmethod - def get_box_drawings_with_normalized_data(data: pd.DataFrame, x, y): + def get_box_drawings_with_normalized_data(data: 'pd.DataFrame', x, y): drawings = [] diff --git a/hstest/testing/plotting/seaborn_handler.py b/hstest/testing/plotting/seaborn_handler.py index 0aa77790..61749173 100644 --- a/hstest/testing/plotting/seaborn_handler.py +++ b/hstest/testing/plotting/seaborn_handler.py @@ -1,8 +1,11 @@ from importlib import reload from typing import TYPE_CHECKING -import pandas as pd -from pandas.api.types import is_numeric_dtype +try: + import pandas as pd + from pandas.api.types import is_numeric_dtype +except ImportError: + pass from hstest.testing.plotting.drawing.drawing import Drawing from hstest.testing.plotting.drawing.drawing_builder import DrawingBuilder