예제 #1
0
 def get_fn_conditions(self, ctxfn: FunctionInfo) -> Optional[Conditions]:
     fn_and_sig = ctxfn.get_callable()
     if fn_and_sig is None:
         return None
     (fn, sig) = fn_and_sig
     filename, first_line, _lines = sourcelines(fn)
     if isinstance(fn, types.BuiltinFunctionType):
         return Conditions(fn, fn, [], [], frozenset(), sig, frozenset(),
                           [])
     lines = list(get_doc_lines(fn))
     parse = parse_sections(lines, ("pre", "post", "raises"), filename)
     pre: List[ConditionExpr] = []
     raises: Set[Type[BaseException]] = set()
     post_conditions: List[ConditionExpr] = []
     mutable_args: Optional[FrozenSet[str]] = None
     if parse.mutable_expr is not None:
         mutable_args = frozenset(expr.strip().split(".")[0]
                                  for expr in parse.mutable_expr.split(",")
                                  if expr != "")
     for line_num, expr in parse.sections["pre"]:
         pre.append(
             condition_from_source_text(filename, line_num, expr,
                                        fn_globals(fn)))
     for line_num, expr in parse.sections["raises"]:
         if "#" in expr:
             expr = expr.split("#")[0]
         for exc_source in expr.split(","):
             try:
                 exc_type = eval(exc_source)
             except:
                 e = sys.exc_info()[1]
                 parse.syntax_messages.append(
                     ConditionSyntaxMessage(filename, line_num, str(e)))
                 continue
             if not issubclass(exc_type, BaseException):
                 parse.syntax_messages.append(
                     ConditionSyntaxMessage(
                         filename,
                         line_num,
                         f'"{exc_type}" is not an exception class',
                     ))
                 continue
             raises.add(exc_type)
     for line_num, expr in parse.sections["post"]:
         post_conditions.append(
             condition_from_source_text(filename, line_num, expr,
                                        fn_globals(fn)))
     return Conditions(
         fn,
         fn,
         pre,
         post_conditions,
         frozenset(raises),
         sig,
         mutable_args,
         parse.syntax_messages,
     )
예제 #2
0
    def get_fn_conditions(self, ctxfn: FunctionInfo) -> Optional[Conditions]:
        fn_and_sig = ctxfn.get_callable()
        if fn_and_sig is None:
            return None
        (fn, sig) = fn_and_sig
        # TODO replace this guard with package-level configuration?
        if (getattr(fn, "__module__", False)
                and fn.__module__.startswith("crosshair.")
                and not fn.__module__.endswith("_test")):
            return None
        try:
            first_body_line = AssertsParser.get_first_body_line(fn)
        except OSError:
            return None
        if first_body_line is None:
            return None

        filename, first_line, _lines = sourcelines(fn)

        @wraps(fn)
        def wrappedfn(*a, **kw):
            try:
                return NoEnforce(fn)(*a, **kw)
            except AssertionError as e:
                # TODO: check that this isn't failing at an early line in a different
                # file?
                _, lineno = frame_summary_for_fn(
                    fn, traceback.extract_tb(e.__traceback__))
                if lineno >= first_body_line:
                    raise

        post = [
            ConditionExpr(
                POSTCONDIITON,
                lambda _: True,
                filename,
                first_line,
                "",
            )
        ]
        return Conditions(
            wrappedfn,
            fn,
            [],  # (pre)
            post,
            raises=frozenset(parse_sphinx_raises(fn)),
            sig=sig,
            mutable_args=None,
            fn_syntax_messages=[],
        )
예제 #3
0
    def get_fn_conditions(self, ctxfn: FunctionInfo) -> Optional[Conditions]:
        fn_and_sig = ctxfn.get_callable()
        if fn_and_sig is None:
            return None
        (fn, sig) = fn_and_sig
        if not getattr(fn, "is_hypothesis_test", False):
            return None
        fuzz_one = getattr(getattr(fn, "hypothesis", None), "fuzz_one_input",
                           None)
        if fuzz_one is None:
            return None

        filename, first_line, _lines = sourcelines(fn)
        post = [
            ConditionExpr(
                POSTCONDIITON,
                lambda _: True,
                filename,
                first_line,
                "",
            )
        ]
        sig = inspect.Signature(parameters=[
            inspect.Parameter(
                "payload", inspect.Parameter.POSITIONAL_ONLY, annotation=bytes)
        ])

        return Conditions(
            fuzz_one,
            fn,
            [],  # (pre)
            post,
            raises=frozenset(),
            sig=sig,
            mutable_args=None,
            fn_syntax_messages=[],
            counterexample_description_maker=partial(
                self._format_counterexample, fn),
        )
예제 #4
0
    def get_fn_conditions(self, ctxfn: FunctionInfo) -> Optional[Conditions]:
        if icontract is None:
            return None
        fn_and_sig = ctxfn.get_callable()
        if fn_and_sig is None:
            return None
        (fn, sig) = fn_and_sig

        checker = icontract._checkers.find_checker(func=fn)  # type: ignore
        contractless_fn = fn  # type: ignore
        while (hasattr(contractless_fn, "__is_invariant_check__")
               or hasattr(contractless_fn, "__preconditions__")
               or hasattr(contractless_fn, "__postconditions__")):
            contractless_fn = contractless_fn.__wrapped__  # type: ignore
        if checker is None:
            return Conditions(contractless_fn, contractless_fn, [], [],
                              frozenset(), sig, None, [])

        pre: List[ConditionExpr] = []
        post: List[ConditionExpr] = []

        def eval_contract(contract, kwargs):
            condition_kwargs = icontract._checkers.select_condition_kwargs(
                contract=contract, resolved_kwargs=kwargs)
            return contract.condition(**condition_kwargs)

        disjunction = checker.__preconditions__  # type: ignore
        if len(disjunction) == 0:
            pass
        elif len(disjunction) == 1:
            for contract in disjunction[0]:
                evalfn = functools.partial(eval_contract, contract)
                filename, line_num, _lines = sourcelines(contract.condition)
                pre.append(
                    ConditionExpr(evalfn, filename, line_num,
                                  self.contract_text(contract)))
        else:

            def eval_disjunction(disjunction, kwargs) -> bool:
                for conjunction in disjunction:
                    ok = True
                    for contract in conjunction:
                        if not eval_contract(contract, kwargs):
                            ok = False
                            break
                    if ok:
                        return True
                return False

            evalfn = functools.partial(eval_disjunction, disjunction)
            filename, line_num, _lines = sourcelines(contractless_fn)
            source = ("(" + ") or (".join([
                " and ".join([self.contract_text(c) for c in conj])
                for conj in disjunction
            ]) + ")")
            pre.append(ConditionExpr(evalfn, filename, line_num, source))

        snapshots = checker.__postcondition_snapshots__  # type: ignore

        def take_snapshots(**kwargs):
            old_as_mapping: MutableMapping[str, Any] = {}
            for snap in snapshots:
                snap_kwargs = icontract._checkers.select_capture_kwargs(
                    a_snapshot=snap, resolved_kwargs=kwargs)
                old_as_mapping[snap.name] = snap.capture(**snap_kwargs)
            return icontract._checkers.Old(mapping=old_as_mapping)

        def post_eval(contract, kwargs):
            _old = kwargs.pop("__old__")
            kwargs["OLD"] = take_snapshots(**_old.__dict__)
            kwargs["result"] = kwargs.pop("__return__")
            del kwargs["_"]
            condition_kwargs = icontract._checkers.select_condition_kwargs(
                contract=contract, resolved_kwargs=kwargs)
            return contract.condition(**condition_kwargs)

        for postcondition in checker.__postconditions__:  # type: ignore
            evalfn = functools.partial(post_eval, postcondition)
            filename, line_num, _lines = sourcelines(postcondition.condition)
            post.append(
                ConditionExpr(evalfn, filename, line_num,
                              self.contract_text(postcondition)))
        return Conditions(
            contractless_fn,
            contractless_fn,
            pre,
            post,
            raises=frozenset(parse_sphinx_raises(fn)),
            sig=sig,
            mutable_args=None,
            fn_syntax_messages=[],
        )