예제 #1
0
def add_arguments_to_command(cmd, fn, abbrevs=None):
    doc_str = fn.__doc__ or ""
    doc_params = parse_doc_params(doc_str)
    abbrevs = abbrevs or ["-h"]
    for var_name, default in get_var_name_and_default(fn):
        tp, tp_name, default, container_type = get_fn_info(fn, var_name, default)
        if is_pydantic(tp):
            # msg = f"Cannot use pydantic just yet, argument {var_name!r} (type {tp.__name__}) on cmd {cmd.prog!r}"
            # raise ValueError(msg)
            add_group(cmd, tp, fn, var_name, abbrevs)
            continue
        doc_text = doc_params.get(var_name, "")
        # changing the name to "no_X" in case the default is True for X, since we should set a flag to invert it
        # e.g. --sums becomes --no-sums
        if tp == bool and default == True:
            var_name = "no_" + var_name
            bool_inverted.add(var_name)
            default = False
            default_help = f"Default: {default} | " if default != "--1" else ""
            default = True
        else:
            if isinstance(default, Enum):
                default_fmt = default.name
            elif default == "--1":
                default_fmt = ""
            else:
                default_fmt = default
            default_help = f"Default: {default_fmt} | " if default != "--1" else ""
        arg_desc = f"|{tp_name}| {default_help}" + doc_text
        add_argument(cmd, tp, container_type, var_name, default, arg_desc, abbrevs)
    return abbrevs
예제 #2
0
def add_arguments_to_command(cmd, fn):
    doc_str = fn.__doc__ or ""
    arg_count = fn.__code__.co_argcount
    defs = fn.__defaults__ or tuple()
    defaults = (("--1", ) * arg_count + defs)[-arg_count:]
    doc_params = parse_doc_params(doc_str)
    abbrevs = ["-h"]
    for var_name, default in zip(fn.__code__.co_varnames, defaults):
        default_help = f"Default: {default} | " if default != "--1" else ""
        default_type = type(
            default) if default != "--1" and default is not None else None
        tp = fn.__annotations__.get(var_name, default_type or str)
        # List, Iterable, Set, Tuple
        container_type = False
        if default_type in [list, set, tuple]:
            for value in default:
                break
            else:
                value = ""
            container_type = default_type
            if "typing" not in str(tp):
                tp_args = ", ".join(set(type(x).__name__
                                        for x in default)) or "str"
                tp_name = "1 or more of: " + tp_args
                tp = None
            else:
                tp_args = ", ".join(x.__name__ for x in tp.__args__)
                tp_name = "1 or more of: " + tp_args
                # tp = type(value)
                tp = None
        else:
            try:
                container_type = tp._name in [
                    "List", "Iterable", "Set", "Tuple"
                ]
            except AttributeError:
                pass
            if container_type:
                if tp.__args__ and "Union" in str(tp.__args__[0]):
                    # cannot cast
                    tp_arg = "str"
                elif tp.__args__:
                    tp_arg = tp.__args__[0].__name__
                else:
                    tp_arg = "str"
                tp_name = "1 or more of: " + tp_arg
            else:
                tp_name = tp.__name__
        if is_pydantic(tp):
            # msg = f"Cannot use pydantic just yet, argument {var_name!r} (type {tp.__name__}) on cmd {cmd.prog!r}"
            # raise ValueError(msg)
            add_group(cmd, tp, fn, var_name, abbrevs)
            continue
        arg_desc = f"|{tp_name}| {default_help}" + doc_params.get(var_name, "")
        add_argument(cmd, tp, container_type, var_name, default, arg_desc,
                     abbrevs)
예제 #3
0
def test_sphinx_docstr():
    inp = """ Explanation

        :param first: First
        :param second: Second
        """
    assert parse_doc_params(inp) == {
        'first': 'First',
        'second': 'Second',
    }
예제 #4
0
def test_google_docstr():
    inp = """
      Args:
          msg (str): Human readable string describing the exception.
          code (:obj:`int`, optional): Error code.
      """
    assert parse_doc_params(inp) == {
        'msg': 'Human readable string describing the exception.',
        'code': 'Error code.',
    }
예제 #5
0
def add_arguments_to_command(cmd, fn, abbrevs=None):
    doc_str = fn.__doc__ or ""
    doc_params = parse_doc_params(doc_str)
    abbrevs = abbrevs or ["-h"]
    for var_name, default in get_var_name_and_default(fn):
        default_type = type(default) if default != "--1" and default is not None else None
        tp = fn.__annotations__.get(var_name, default_type or str)
        # List, Iterable, Set, Tuple
        container_type = False
        if default_type in [list, set, tuple]:
            for value in default:
                break
            else:
                value = ""
            container_type = default_type
            if "typing" not in str(tp):
                tp_args = ", ".join(set(type(x).__name__ for x in default)) or "str"
                tp_name = "1 or more of: " + tp_args
            else:
                tp_args = ", ".join(x.__name__ for x in tp.__args__)
                tp_name = "1 or more of: " + tp_args
            if len(default) > 1:
                tp = None
            elif default:
                tp = type(list(default)[0])
            elif hasattr(tp, "__args__"):
                tp = tp.__args__[0]
            else:
                tp = str
        else:
            try:
                if getattr(tp, "__origin__") == Union:
                    tp = tp.__args__[0]
                container_type = CONTAINER_MAPPING.get(tp._name)
            except AttributeError:
                pass
            if container_type:
                if tp.__args__ and "Union" in str(tp.__args__[0]):
                    # cannot cast
                    tp_arg = "str"
                elif tp.__args__:
                    tp_arg = tp.__args__[0].__name__
                else:
                    tp_arg = "str"
                tp_name = "0 or more of: " + tp_arg
                tp = tp.__args__[0]
            elif tp == "str":
                tp = str
                tp_name = "str"
            else:
                tp_name = tp.__name__
        if is_pydantic(tp):
            # msg = f"Cannot use pydantic just yet, argument {var_name!r} (type {tp.__name__}) on cmd {cmd.prog!r}"
            # raise ValueError(msg)
            add_group(cmd, tp, fn, var_name, abbrevs)
            continue
        doc_text = doc_params.get(var_name, "")
        # changing the name to "no_X" in case the default is True for X, since we should set a flag to invert it
        # e.g. --sums becomes --no-sums
        if tp == bool and default == True:
            var_name = "no_" + var_name
            bool_inverted.add(var_name)
            default = False
            default_help = f"Default: {default} | " if default != "--1" else ""
            default = True
        else:
            if isinstance(default, Enum):
                default_fmt = default.name
            elif default == "--1":
                default_fmt = ""
            else:
                default_fmt = default
            default_help = f"Default: {default_fmt} | " if default != "--1" else ""
        arg_desc = f"|{tp_name}| {default_help}" + doc_text
        add_argument(cmd, tp, container_type, var_name, default, arg_desc, abbrevs)
    return abbrevs