From fa3106abdfe1acc96687fec9e7242e25afc0c68d Mon Sep 17 00:00:00 2001 From: geisserml Date: Thu, 15 Feb 2024 15:16:06 +0100 Subject: [PATCH] More sophisticated pre-processor error handling --- src/ctypesgen/__main__.py | 38 ++++++++++++++++++++++++++-- src/ctypesgen/parser/preprocessor.py | 10 ++++++-- 2 files changed, 44 insertions(+), 4 deletions(-) diff --git a/src/ctypesgen/__main__.py b/src/ctypesgen/__main__.py index 20f01d5..0b4f00f 100644 --- a/src/ctypesgen/__main__.py +++ b/src/ctypesgen/__main__.py @@ -167,6 +167,34 @@ def _is_relative_to(path, other): return path == other or other in path.parents +# -- Argument Parser (Backports) -- + +if sys.version_info >= (3, 9): + from argparse import BooleanOptionalAction + +else: + # backport, adapted from argparse sources + class BooleanOptionalAction (argparse.Action): + def __init__(self, option_strings, dest, **kwargs): + + _option_strings = [] + for option_string in option_strings: + _option_strings.append(option_string) + + if option_string.startswith('--'): + option_string = '--no-' + option_string[2:] + _option_strings.append(option_string) + + super().__init__(option_strings=_option_strings, dest=dest, nargs=0, **kwargs) + + def __call__(self, parser, namespace, values, option_string=None): + if option_string in self.option_strings: + setattr(namespace, self.dest, not option_string.startswith('--no-')) + + def format_usage(self): + return ' | '.join(self.option_strings) + + # -- Argument Parser --- def generic_path_t(p): @@ -174,7 +202,7 @@ def generic_path_t(p): def checked_path_t(p, check, exc): p = generic_path_t(p) - if not check(p): raise exc(f"{p}") + # if not check(p): raise exc(f"{p}") return p def input_file_t(p): @@ -187,7 +215,7 @@ def input_dir_t(p): def get_parser(): # FIXME argparse parameters are not ordered consistently... - # TODO consider BooleanOptionalAction (with compat backport) + # TODO expand use of BooleanOptionalAction parser = argparse.ArgumentParser(prog="ctypesgen") @@ -340,6 +368,12 @@ def __call__(self, parser, namespace, values, option_string=None): metavar="FILENAME", help="Save preprocessor output to the specified FILENAME", ) + parser.add_argument( + "--preproc-errcheck", + action=BooleanOptionalAction, + help="Whether to fail fast if the preprocessor returned a non-zero exit code. Defaults to True, unless on Windows.", + default=not sys.platform.startswith("win"), + ) parser.add_argument( "--optimize-lexer", action="store_true", diff --git a/src/ctypesgen/parser/preprocessor.py b/src/ctypesgen/parser/preprocessor.py index 48f626e..c4ecc24 100755 --- a/src/ctypesgen/parser/preprocessor.py +++ b/src/ctypesgen/parser/preprocessor.py @@ -15,7 +15,7 @@ from ctypesgen.parser import pplexer, lex from ctypesgen.parser.lex import LexError -from ctypesgen.messages import warning_message +from ctypesgen.messages import warning_message, status_message IS_WINDOWS = sys.platform.startswith("win") @@ -141,8 +141,14 @@ def parse(self, filename): cmd, universal_newlines=False, # binary stdout=subprocess.PIPE, - check=not IS_WINDOWS, ) + status_message(f"Pre-processor returned exit code {pp.returncode}") + if pp.returncode != 0: + msg = f"Pre-processor returned non-zero exit code {pp.returncode}" + if self.options.preproc_errcheck: + assert False, msg + else: + warning_message(msg) if IS_MAC: ppout = pp.stdout.decode("utf-8", errors="replace")