def parse_directives( directive_lines: Iterable[Tuple[int, int, str]]) -> AnalysisOptionSet: """ Parse options from directives in comments. >>> parse_directives([(1, 0, "off")]).enabled False """ result = AnalysisOptionSet() for lineno, _colno, directive in directive_lines: for part in directive.split(): if part == "on": part = "enabled=1" if part == "off": part = "enabled=" pair = part.split("=", 2) if len(pair) != 2: raise InvalidDirective(f'Malformed option: "{part}"', lineno) key, strvalue = pair if key not in AnalysisOptionSet.directive_fields: raise InvalidDirective(f'Unknown option: "{key}"', lineno) value = AnalysisOptionSet.parse_field(key, strvalue) if value is None: raise InvalidDirective( f'"{strvalue}" is not a valid "{key}" value', lineno) if getattr(result, key) is not None: raise InvalidDirective( f'Option "{key}" is set multiple times at the same scope', lineno) result = result.overlay(AnalysisOptionSet(**{key: value})) return result
def check_fail( fn: Callable, optionset: AnalysisOptionSet = AnalysisOptionSet() ) -> ComparableLists: local_opts = AnalysisOptionSet(max_iterations=40, per_condition_timeout=5) options = local_opts.overlay(optionset) states = [m.state for m in run_checkables(analyze_function(fn, options))] return (states, [MessageType.POST_FAIL])
def check_post_err( fn: Callable, optionset: AnalysisOptionSet = AnalysisOptionSet() ) -> ComparableLists: local_opts = AnalysisOptionSet(max_iterations=20) options = local_opts.overlay(optionset) states = [m.state for m in run_checkables(analyze_function(fn, options))] return (states, [MessageType.POST_ERR])
def collect_options(thing: Any) -> AnalysisOptionSet: parent_opts = AnalysisOptionSet() is_package = thing.__name__ == getattr(thing, "__package__", None) if getattr(thing, "__module__", None): parent_opts = collect_options(sys.modules[thing.__module__]) elif getattr(thing, "__package__", None): if is_package: parent_pkg, _, _ = thing.__package__.rpartition(".") else: parent_pkg = thing.__package__ if parent_pkg: parent_opts = collect_options(sys.modules[parent_pkg]) lines: Iterable[str] if is_package: try: lines = importlib.resources.read_text(thing, "__init__.py").splitlines() except FileNotFoundError: lines = [] else: _file, _start, lines = sourcelines(thing) directives = get_directives(lines) if inspect.ismodule(thing): # Only look at toplevel comments in modules # (we don't want to catch directives for functions inside it) # TODO: detect directives at other levels like classes etc and warn that they # will be ignored. directives = [(l, c, t) for (l, c, t) in directives if c == 0] my_opts = parse_directives(directives) return parent_opts.overlay(my_opts)
def check_unknown( fn: Callable, optionset: AnalysisOptionSet = AnalysisOptionSet() ) -> ComparableLists: local_opts = AnalysisOptionSet(max_iterations=40, per_condition_timeout=3) options = local_opts.overlay(optionset) messages = [(m.state, m.message, m.traceback) for m in run_checkables(analyze_function(fn, options))] return (messages, [(MessageType.CANNOT_CONFIRM, "Not confirmed.", "")])
def check_ok( fn: Callable, optionset: AnalysisOptionSet = AnalysisOptionSet() ) -> ComparableLists: local_opts = AnalysisOptionSet(per_condition_timeout=5) options = local_opts.overlay(optionset) messages = [ message for message in run_checkables(analyze_function(fn, options)) if message.state != MessageType.CONFIRMED ] return (messages, [])
def check_exec_err( fn: Callable, message_prefix="", optionset: AnalysisOptionSet = AnalysisOptionSet() ) -> ComparableLists: local_opts = AnalysisOptionSet(max_iterations=20, per_condition_timeout=5) options = local_opts.overlay(optionset) messages = run_checkables(analyze_function(fn, options)) if all(m.message.startswith(message_prefix) for m in messages): return ([m.state for m in messages], [MessageType.EXEC_ERR]) else: return ( [(m.state, m.message) for m in messages], [(MessageType.EXEC_ERR, message_prefix)], )
def collect_options(thing: Any) -> AnalysisOptionSet: parent_opts = AnalysisOptionSet() if getattr(thing, "__module__", None): parent_opts = collect_options(sys.modules[thing.__module__]) elif hasattr(thing, "__package__"): if thing.__package__ and thing.__package__ != thing.__name__: parent_opts = collect_options(sys.modules[thing.__package__]) _file, start, lines = sourcelines(thing) directives = get_directives(lines) if inspect.ismodule(thing): # Only look at toplevel comments in modules # (we don't want to catch directives for functions inside it) # TODO: detect directives at other levels like classes etc and warn that they # will be ignored. directives = [(l, c, t) for (l, c, t) in directives if c == 0] my_opts = parse_directives(directives) return parent_opts.overlay(my_opts)
def check_states( fn: Callable, optionset: AnalysisOptionSet = AnalysisOptionSet() ) -> Set[MessageType]: local_opts = AnalysisOptionSet(max_iterations=40, per_condition_timeout=5) options = local_opts.overlay(optionset) return set([m.state for m in run_checkables(analyze_function(fn, options))])