Exemplo n.º 1
0
    def test_extract_default_with_parens(self) -> None:
        """Tests that `extract_default` works when wrapped in parentheses"""
        sample = "learning rate (default: 1)"
        self.assertTupleEqual(
            extract_default(sample, emit_default_doc=True),
            (sample, 1),
        )

        sample = (
            "tolerance_change (float): termination tolerance on function\n"
            "             value/parameter changes (default: 1e-9).")
        self.assertTupleEqual(
            extract_default(sample, emit_default_doc=True),
            (sample, 1e-9),
        )
Exemplo n.º 2
0
def sqlalchemy_table(call_or_name):
    """
    Parse out a `sqlalchemy.Table`, or a `name = sqlalchemy.Table`, into the IR

    :param call_or_name: The call to `sqlalchemy.Table` or an assignment followed by the call
    :type call_or_name: ```Union[AnnAssign, Assign, Call]```

    :returns: a dictionary of form
        {  "name": Optional[str],
           "type": Optional[str],
           "doc": Optional[str],
           "params": OrderedDict[str, {'typ': str, 'doc': Optional[str], 'default': Any}]
           "returns": Optional[OrderedDict[Literal['return_type'],
                                           {'typ': str, 'doc': Optional[str], 'default': Any}),)]] }
    :rtype: ```dict```
    """
    if isinstance(call_or_name, Assign):
        name, call_or_name = call_or_name.targets[0].id, call_or_name.value
    elif isinstance(call_or_name, AnnAssign):
        name, call_or_name = call_or_name.target.id, call_or_name.value
    else:
        if not isinstance(call_or_name, Call):
            call_or_name = get_value(call_or_name)
        name = get_value(call_or_name.args[0])

    # Binding should be same name as table… I guess?
    assert_equal(get_value(call_or_name.args[0]), name)

    comment = next(
        map(
            get_value,
            map(
                get_value, filter(lambda kw: kw.arg == "comment", call_or_name.keywords)
            ),
        ),
        None,
    )
    intermediate_repr = (
        {"type": None, "doc": "", "params": OrderedDict()}
        if comment is None
        else docstring(comment)
    )
    intermediate_repr["name"] = name
    assert isinstance(call_or_name, Call)
    assert_equal(call_or_name.func.id.rpartition(".")[2], "Table")
    assert len(call_or_name.args) > 2

    merge_ir = {
        "params": OrderedDict(map(column_call_to_param, call_or_name.args[2:])),
        "returns": None,
    }
    ir_merge(target=intermediate_repr, other=merge_ir)
    if intermediate_repr["returns"] and intermediate_repr["returns"].get(
        "return_type", {}
    ).get("doc"):
        intermediate_repr["returns"]["return_type"]["doc"] = extract_default(
            intermediate_repr["returns"]["return_type"]["doc"], emit_default_doc=False
        )[0]

    return intermediate_repr
Exemplo n.º 3
0
 def test_extract_default_with_int(self) -> None:
     """Tests that `extract_default` works for an integer default"""
     sample = "learning rate. Defaults to 0001."
     self.assertTupleEqual(
         extract_default(sample, emit_default_doc=False),
         ("learning rate.", 1),
     )
Exemplo n.º 4
0
 def test_extract_default_with_float(self) -> None:
     """Tests that `extract_default` works when there is a `.` in the default referring to a decimal place"""
     sample = "learning rate. Defaults to 0.001."
     self.assertTupleEqual(
         extract_default(sample, emit_default_doc=False),
         ("learning rate.", 0.001),
     )
Exemplo n.º 5
0
 def test_extract_default_with_dot(self) -> None:
     """Tests that `extract_default` works when there is a `.` in the default"""
     sample = "This. defaults to (np.empty(0), np.empty(0))"
     self.assertTupleEqual(
         extract_default(sample, emit_default_doc=False),
         ("This.", "(np.empty(0), np.empty(0))"),
     )
Exemplo n.º 6
0
 def test_extract_default_with_ast_default(self) -> None:
     """Tests that `extract_default` works when default parses to an AST type"""
     sample = ("maximal number of function evaluations per optimization\n"
               "        step (default: max_iter * 1.25).")
     self.assertTupleEqual(
         extract_default(sample, emit_default_doc=True),
         (sample, "max_iter * 1.25"),
     )
Exemplo n.º 7
0
    def test_extract_default_middle(self) -> None:
        """Tests that `extract_default` produces the expected output"""
        sample = "Why would you. Have this defaults to something. In the middle?"
        default = "something"
        self.assertTupleEqual(extract_default(sample), (sample, default))

        self.assertTupleEqual(
            extract_default(sample,
                            rstrip_default=False,
                            emit_default_doc=False),
            ("Why would you. Have this. In the middle?", default),
        )
        self.assertTupleEqual(
            extract_default(sample,
                            rstrip_default=True,
                            emit_default_doc=False),
            ("Why would you. Have thisIn the middle?", default),
        )
Exemplo n.º 8
0
 def test_extract_default_with_many_parens(self) -> None:
     """Tests that `extract_default` works when default parses to an AST type"""
     sample = (
         "betas (Tuple[float, float], optional): coefficients used for computing\n"
         "        running averages of gradient and its square (default: (0.9, 0.999))"
     )
     default = "(0.9, 0.999)"
     self.assertTupleEqual(
         extract_default(sample, emit_default_doc=True),
         (sample, default),
     )
     self.assertTupleEqual(
         extract_default(sample, emit_default_doc=False),
         (
             "betas (Tuple[float, float], optional): coefficients used for computing\n"
             "        running averages of gradient and its square",
             default,
         ),
     )
Exemplo n.º 9
0
 def test_extract_default_with_bool(self) -> None:
     """Tests that `extract_default` works for an integer default"""
     sample = (
         "Boolean. Whether to apply AMSGrad variant of this algorithm from"
         'the paper "On the Convergence of Adam and beyond". Defaults to `True`.'
     )
     self.assertTupleEqual(
         extract_default(sample, emit_default_doc=True),
         (sample, True),
     )
Exemplo n.º 10
0
def _parse_return(e, intermediate_repr, function_def, emit_default_doc):
    """
    Parse return into a param dict

    :param e: Return AST node
    :type e: Return

    :param intermediate_repr: a dictionary of form
        {  "name": Optional[str],
           "type": Optional[str],
           "doc": Optional[str],
           "params": OrderedDict[str, {'typ': str, 'doc': Optional[str], 'default': Any}]
           "returns": Optional[OrderedDict[Literal['return_type'],
                                           {'typ': str, 'doc': Optional[str], 'default': Any}),)]] }
    :type intermediate_repr: ```dict```

    :param function_def: AST node for function definition
    :type function_def: ```FunctionDef```

    :param emit_default_doc: Whether help/docstring should include 'With default' text
    :type emit_default_doc: ```bool```

    :returns: Name, dict with keys: 'typ', 'doc', 'default'
    :rtype: ```Tuple[str, dict]```
    """
    assert isinstance(e, Return)

    return set_default_doc(
        (
            "return_type",
            {
                "doc":
                extract_default(
                    next(
                        line.partition(",")[2].lstrip() for line in get_value(
                            function_def.body[0].value).split("\n")
                        if line.lstrip().startswith(":return")),
                    emit_default_doc=emit_default_doc,
                )[0],
                "default":
                to_code(e.value.elts[1]).rstrip("\n"),
                "typ":
                to_code(
                    get_value(
                        ast.parse(
                            intermediate_repr["returns"]["return_type"]
                            ["typ"]).body[0].value.slice).elts[1]).rstrip()
                # 'Tuple[ArgumentParser, {typ}]'.format(typ=intermediate_repr['returns']['typ'])
            },
        ),
        emit_default_doc=emit_default_doc,
    )
Exemplo n.º 11
0
def interpolate_defaults(param,
                         default_search_announce=None,
                         require_default=False,
                         emit_default_doc=True):
    """
    Correctly set the 'default' and 'doc' parameters

    :param param: Name, dict with keys: 'typ', 'doc', 'default'
    :type param: ```Tuple[str, dict]```

    :param default_search_announce: Default text(s) to look for. If None, uses default specified in default_utils.
    :type default_search_announce: ```Optional[Union[str, Iterable[str]]]```

    :param require_default: Whether a default is required, if not found in doc, infer the proper default from type
    :type require_default: ```bool```

    :param emit_default_doc: Whether help/docstring should include 'With default' text
    :type emit_default_doc: ```bool```

    :returns: Name, dict with keys: 'typ', 'doc', 'default'
    :rtype: ```Tuple[str, dict]```
    """
    name, _param = param
    del param
    if "doc" in _param:
        doc, default = extract_default(
            _param["doc"],
            typ=_param.get("typ"),
            default_search_announce=default_search_announce,
            emit_default_doc=emit_default_doc,
        )
        _param["doc"] = doc
        if default is not None:
            _param["default"] = unquote(default)
    if require_default and _param.get("default") is None:
        # if (
        #     "typ" in _param
        #     and _param["typ"] not in frozenset(("Any", "object"))
        #     and not _param["typ"].startswith("Optional")
        # ):
        #     _param["typ"] = "Optional[{}]".format(_param["typ"])
        _param["default"] = (simple_types[_param["typ"]] if _param.get(
            "typ", memoryview) in simple_types else NoneStr)

    return name, _param
Exemplo n.º 12
0
def parse_out_param(expr, require_default=False, emit_default_doc=True):
    """
    Turns the class_def repr of '--dataset_name', type=str, help='name of dataset.', required=True, default='mnist'
      into
           Tuple[Literal['dataset_name'], {"typ": Literal["str"], "doc": Literal["name of dataset."],
                                           "default": Literal["mnist"]}]

    :param expr: Expr
    :type expr: ```Expr```

    :param require_default: Whether a default is required, if not found in doc, infer the proper default from type
    :type require_default: ```bool```

    :param emit_default_doc: Whether help/docstring should include 'With default' text
    :type emit_default_doc: ```bool```

    :returns: Name, dict with keys: 'typ', 'doc', 'default'
    :rtype: ```Tuple[str, dict]```
    """
    required = get_value(
        get_value(
            next(
                (keyword for keyword in expr.value.keywords
                 if keyword.arg == "required"),
                set_value(False),
            )))

    typ = next(
        (_handle_value(get_value(key_word))
         for key_word in expr.value.keywords if key_word.arg == "type"),
        "str",
    )
    name = get_value(expr.value.args[0])[len("--"):]
    default = next(
        (get_value(key_word.value)
         for key_word in expr.value.keywords if key_word.arg == "default"),
        None,
    )
    doc = (lambda help_: help_ if help_ is None else
           (help_ if default is None or emit_default_doc is False or
            (hasattr(default, "__len__") and len(default) == 0
             ) or "defaults to" in help_ or "Defaults to" in help_ else
            "{help} Defaults to {default}".format(
                help=help_ if help_.endswith(".") else "{}.".format(help_),
                default=default,
            )))(next(
                (get_value(key_word.value) for key_word in expr.value.keywords
                 if key_word.arg == "help" and key_word.value),
                None,
            ))
    if default is None:
        doc, default = extract_default(doc, emit_default_doc=emit_default_doc)
    if default is None:
        if required:
            # if name.endswith("kwargs"):
            #    default = NoneStr
            # else:
            default = simple_types[typ] if typ in simple_types else NoneStr

        elif require_default or typ.startswith("Optional"):
            default = NoneStr

    action = next(
        (get_value(key_word.value)
         for key_word in expr.value.keywords if key_word.arg == "action"),
        None,
    )

    typ = next(
        (_handle_keyword(keyword, typ)
         for keyword in expr.value.keywords if keyword.arg == "choices"),
        typ,
    )
    if action == "append":
        typ = "List[{typ}]".format(typ=typ)

    if not required and "Optional" not in typ:
        typ = "Optional[{typ}]".format(typ=typ)

    return name, dict(doc=doc,
                      typ=typ,
                      **({} if default is None else {
                          "default": default
                      }))
Exemplo n.º 13
0
 def test_extract_default(self) -> None:
     """Tests that `extract_default` produces the expected output"""
     sample = "This defaults to foo."
     self.assertTupleEqual(extract_default(sample), (sample, "foo"))
     self.assertTupleEqual(extract_default(sample, emit_default_doc=False),
                           ("This", "foo"))
Exemplo n.º 14
0
def param2argparse_param(param, word_wrap=True, emit_default_doc=True):
    """
    Converts a param to an Expr `argparse.add_argument` call

    :param param: Name, dict with keys: 'typ', 'doc', 'default'
    :type param: ```Tuple[str, Dict[str, Any]]```

    :param word_wrap: Whether to word-wrap. Set `DOCTRANS_LINE_LENGTH` to configure length.
    :type word_wrap: ```bool```

    :param emit_default_doc: Whether help/docstring should include 'With default' text
    :type emit_default_doc: ```bool```

    :returns: `argparse.add_argument` call—with arguments—as an AST node
    :rtype: ```Expr```
    """
    name, _param = param
    del param
    typ, choices, required, action = (
        "str",
        None,
        _param.get("default") is not None,
        None,
    )
    _param.setdefault("typ", "Any")
    action, choices, required, typ, (name, _param) = _resolve_arg(
        action, choices, (name, _param), required, typ
    )
    # is_kwarg = param[0].endswith("kwargs")

    _param.setdefault("doc", "")
    doc, _default = extract_default(_param["doc"], emit_default_doc=emit_default_doc)
    _action, default, _required, _typ = infer_type_and_default(
        action,
        _param.get("default", _default),
        typ,
        required=required
        # _default, _param, action, required, typ#
    )
    if default is None and _param.get("default") == NoneStr:
        required = False
    if _action:
        action = _action
    if _typ is not None:
        typ = _typ
    if typ == "pickle.loads":
        required = False
    elif typ == "str" and action is None:
        typ = None  # Because `str` is default anyway

    return Expr(
        Call(
            args=[set_value("--{name}".format(name=name))],
            func=Attribute(
                Name("argument_parser", Load()),
                "add_argument",
                Load(),
            ),
            keywords=list(
                filter(
                    None,
                    (
                        typ
                        if typ is None
                        else keyword(
                            arg="type",
                            value=FALLBACK_ARGPARSE_TYP
                            if typ == "globals().__getitem__"
                            else Name(typ, Load()),
                            identifier=None,
                        ),
                        choices
                        if choices is None
                        else keyword(
                            arg="choices",
                            value=Tuple(
                                ctx=Load(),
                                elts=list(map(set_value, choices)),
                                expr=None,
                            ),
                            identifier=None,
                        ),
                        action
                        if action is None
                        else keyword(
                            arg="action",
                            value=set_value(action),
                            identifier=None,
                        ),
                        keyword(
                            arg="help",
                            value=set_value((fill if word_wrap else identity)(doc)),
                            identifier=None,
                        )
                        if doc
                        else None,
                        keyword(
                            arg="required",
                            value=set_value(True),
                            identifier=None,
                        )
                        if required is True
                        else None,
                        default
                        if default is None
                        else keyword(
                            arg="default",
                            value=set_value(default),
                            identifier=None,
                        ),
                    ),
                )
            ),
            expr=None,
            expr_func=None,
        )
    )