def test_list_of_dicts_success():
    arg_defs = dict(people=dict(
        arg_type="list",
        elements="dict",
        options=dict(
            name=dict(arg_type="str", required=True, default="testname"),
            age=dict(arg_type="int", required=False),
        ),
    ))
    parser = BetterArgParser(arg_defs)
    result = parser.parse_args({
        "people": [
            {
                "name": "blake",
                "age": 23
            },
            {
                "name": "oldguy",
                "age": 95
            },
            {
                "age": 30
            },
        ]
    })
    assert len(result.get("people")) == 3
def test_list_of_dicts_nested_function_arg_type():
    arg_defs = dict(people=dict(
        arg_type="list",
        elements="dict",
        options=dict(
            name=dict(arg_type="str", required=True, default="testname"),
            age=dict(arg_type=to_string, required=False),
        ),
    ))
    parser = BetterArgParser(arg_defs)
    result = parser.parse_args({
        "people": [
            {
                "name": "blake",
                "age": 23
            },
            {
                "name": "oldguy",
                "age": 95
            },
            {
                "age": 30
            },
            {
                "name": "unknown age guy"
            },
        ]
    })
    assert len(result.get("people")) == 4
    for person in result.get("people"):
        if person.get("age"):
            assert isinstance(person.get("age"), str)
def test_dict_of_dict():
    arg_defs = dict(person=dict(
        arg_type="dict",
        options=dict(
            name=dict(arg_type="str", required=True, default="testname"),
            age=dict(arg_type="int", required=False),
            address=dict(
                arg_type="dict",
                options=dict(street=dict(arg_type="str"),
                             number=dict(arg_type="int")),
            ),
        ),
    ))
    parser = BetterArgParser(arg_defs)
    result = parser.parse_args({
        "person": {
            "name": "blake",
            "age": 23,
            "address": {
                "street": "bailey ave",
                "number": 555
            },
        }
    })
    assert result.get("person").get("address").get("number") == 555
def test_dict_of_dict_fail_on_nested_arg_type():
    arg_defs = dict(person=dict(
        arg_type="dict",
        options=dict(
            name=dict(arg_type="str", required=True, default="testname"),
            age=dict(arg_type="int", required=False),
            address=dict(
                arg_type="dict",
                options=dict(street=dict(arg_type="str"),
                             number=dict(arg_type="str")),
            ),
        ),
    ))
    parser = BetterArgParser(arg_defs)
    with pytest.raises(ValueError):
        parser.parse_args({
            "person": {
                "name": "blake",
                "age": 23,
                "address": {
                    "street": "bailey ave",
                    "number": 555
                },
            }
        })
def test_unknown_arg_ignore():
    default_name = "samplename"
    arg_defs = dict(
        name=dict(arg_type="str", required=True, default=default_name))
    parser = BetterArgParser(arg_defs)
    result = parser.parse_args({"otherarg": "testing"})
    assert "otherarg" not in result.keys()
def test_required_top_level_with_default():
    default_name = "samplename"
    arg_defs = dict(
        name=dict(arg_type="str", required=True, default=default_name))
    parser = BetterArgParser(arg_defs)
    result = parser.parse_args({})
    assert result.get("name") == default_name
def test_bool_type_validation_failure(arg_val):
    arg_defs = dict(somebool=dict(
        arg_type="bool",
        required=True,
    ))
    parser = BetterArgParser(arg_defs)
    with pytest.raises(ValueError):
        parser.parse_args({"somebool": arg_val})
def test_basic_user_provided_type_func(arg_type, expected):
    arg_defs = dict(someval=dict(
        arg_type=arg_type,
        required=True,
    ))
    parser = BetterArgParser(arg_defs)
    result = parser.parse_args({"someval": expected})
    assert result.get("someval") == expected
def test_bool_type_validation_success(arg_val):
    arg_defs = dict(somebool=dict(
        arg_type="bool",
        required=True,
    ))
    parser = BetterArgParser(arg_defs)
    result = parser.parse_args({"somebool": arg_val})
    assert result.get("somebool") == arg_val
def test_str_type_validation_failure(arg_val):
    arg_defs = dict(name=dict(
        arg_type="str",
        required=True,
    ))
    parser = BetterArgParser(arg_defs)
    with pytest.raises(ValueError):
        parser.parse_args({"name": arg_val})
def test_int_type_validation_success(arg_val):
    arg_defs = dict(somenum=dict(
        arg_type="int",
        required=True,
    ))
    parser = BetterArgParser(arg_defs)
    result = parser.parse_args({"somenum": arg_val})
    assert result.get("somenum") == int(arg_val)
def test_str_type_validation_success(arg_val):
    arg_defs = dict(name=dict(
        arg_type="str",
        required=True,
    ))
    parser = BetterArgParser(arg_defs)
    result = parser.parse_args({"name": arg_val})
    assert result.get("name") == arg_val
def test_list_of_strings_success():
    arg_defs = dict(names=dict(
        arg_type="list",
        elements="str",
        required=True,
    ))
    parser = BetterArgParser(arg_defs)
    result = parser.parse_args({"names": ["name1", "name2", "name3", "name4"]})
    assert len(result.get("names")) == 4
def test_list_of_strings_function_for_arg_type_success():
    arg_defs = dict(
        names=dict(arg_type="list", elements=make_uppercase, required=True,)
    )
    parser = BetterArgParser(arg_defs)
    result = parser.parse_args({"names": ["name1", "name2", "name3", "name4"]})
    assert len(result.get("names")) == 4
    for name in result.get("names"):
        assert name == name.upper()
def test_list_of_strings_failure():
    arg_defs = dict(names=dict(
        arg_type="list",
        elements="str",
        required=True,
    ))
    parser = BetterArgParser(arg_defs)
    with pytest.raises(ValueError):
        parser.parse_args({"names": [1, True, "name3", "name4"]})
def test_dependent_required():
    arg_defs = dict(
        uppername=dict(arg_type="str", required=True,),
        verifier=dict(
            arg_type="str", required=is_dependency_uppercase, dependencies=["uppername"]
        ),
    )
    parser = BetterArgParser(arg_defs)
    result = parser.parse_args({"uppername": "dadafasdf"})
    assert result.get("verifier") is None
def test_dependent_required_fail():
    arg_defs = dict(
        uppername=dict(arg_type="str", required=True,),
        verifier=dict(
            arg_type="str", required=is_dependency_uppercase, dependencies=["uppername"]
        ),
    )
    parser = BetterArgParser(arg_defs)
    with pytest.raises(ValueError):
        result = parser.parse_args({"uppername": "DAFASDFA"})
def test_dependent_default(arg_val, expected):
    arg_defs = dict(
        uppername=dict(arg_type="str", required=True,),
        verifier=dict(
            arg_type="bool", default=is_dependency_uppercase, dependencies=["uppername"]
        ),
    )
    parser = BetterArgParser(arg_defs)
    result = parser.parse_args({"uppername": arg_val})
    assert result.get("verifier") == expected
def test_mutually_exclusive_parameters_two_values_set_top_level_defaults():
    arg_defs = dict(
        name=dict(arg_type="str", required=True, default="samplename"),
        date=dict(arg_type="str", default="may 1, 2020"),
        time=dict(arg_type="int", default="3945297"),
        mutually_exclusive=[["date", "time"]],
    )
    parser = BetterArgParser(arg_defs)
    with pytest.raises(ValueError):
        parser.parse_args({})
def test_user_provided_type_func_with_dependencies():
    arg_defs = dict(
        uppername=dict(arg_type=make_uppercase, required=True,),
        verifier=dict(
            arg_type=is_dependency_uppercase, required=True, dependencies=["uppername"]
        ),
    )
    parser = BetterArgParser(arg_defs)
    result = parser.parse_args({"uppername": "dadafasdf", "verifier": "doesntmatter"})
    assert result.get("verifier")
def test_user_provided_type_func_with_dependencies_make_fail():
    arg_defs = dict(
        uppername=dict(
            arg_type=make_uppercase, required=True, dependencies=["verifier"]
        ),
        verifier=dict(arg_type=is_dependency_uppercase, required=True,),
    )
    parser = BetterArgParser(arg_defs)
    with pytest.raises(TypeError):
        parser.parse_args({"uppername": "dadafasdf", "verifier": "doesntmatter"})
def test_custom_defined_values_second_level():
    def special_names_get_uppercase(value, dependencies, kwargs):
        if value in kwargs.get("special_names", []):
            return value.upper()
        return value

    arg_defs = dict(
        person=dict(
            arg_type="dict",
            options=dict(
                name=dict(
                    arg_type=special_names_get_uppercase,
                    required=True,
                    default="testname",
                    special_names=[
                        "blake",
                        "demetri",
                        "ping",
                        "crystal",
                        "asif",
                        "luke",
                    ],
                ),
                age=dict(arg_type="int", required=False),
                address=dict(
                    arg_type="dict",
                    options=dict(
                        street=dict(arg_type="str"), number=dict(arg_type="int")
                    ),
                ),
            ),
        )
    )
    parser = BetterArgParser(arg_defs)
    result = parser.parse_args(
        {
            "person": {
                "name": "blake",
                "age": 23,
                "address": {"street": "bailey ave", "number": 555},
            }
        }
    )
    assert result.get("person").get("name") == "BLAKE"
    result = parser.parse_args(
        {
            "person": {
                "name": "john",
                "age": 23,
                "address": {"street": "bailey ave", "number": 555},
            }
        }
    )
    assert result.get("person").get("name") == "john"
def test_alias_resolution(provided_args):
    arg_defs = dict(
        name=dict(arg_type="str", required=True, default="samplename",),
        date=dict(arg_type="str", default="may 1, 2020", aliases=["bestdate", "dt"]),
        time=dict(arg_type="int", default="3945297", aliases=["sometime", "datetime"]),
    )
    parser = BetterArgParser(arg_defs)
    result = parser.parse_args(provided_args)
    result_simple = [str(x) for x in result.values()]
    for val in provided_args.values():
        assert str(val) in result_simple
    assert "name" in result.keys()
    assert "date" in result.keys()
    assert "time" in result.keys()
def test_second_level_defaults():
    arg_defs = dict(
        name=dict(arg_type="str", required=True, default="samplename"),
        date=dict(
            arg_type="dict",
            options=dict(
                month=dict(arg_type="str", default="hello"),
                day=dict(arg_type="int", default=1),
            ),
        ),
    )
    parser = BetterArgParser(arg_defs)
    result = parser.parse_args({"name": "blake", "date": {"month": "may"}})
    assert result.get("date").get("day") is not None
def test_invalid_dependency_independent_does_not_exist():
    arg_defs = dict(
        person=dict(arg_type="str", dependencies=["nonexistent"]),
        animal=dict(arg_type="str", dependencies=["person"]),
    )
    with pytest.raises(ValueError):
        BetterArgParser(arg_defs)
def test_custom_defined_values_top_level():
    def special_names_get_uppercase(value, dependencies, kwargs):
        if value in kwargs.get("special_names", []):
            return value.upper()
        return value

    arg_defs = dict(
        name=dict(
            arg_type=special_names_get_uppercase,
            required=True,
            default="samplename",
            special_names=["blake", "demetri", "ping", "crystal", "asif", "luke"],
        ),
        date=dict(arg_type="str", default="may 1, 2020"),
        time=dict(arg_type="int"),
    )
    parser = BetterArgParser(arg_defs)
    result = parser.parse_args({"name": "blake"})
    assert result.get("name") == "BLAKE"
    result = parser.parse_args({"name": "john"})
    assert result.get("name") == "john"
def test_custom_defined_values_top_level_required():
    def special_user(value, dependencies, kwargs):
        if dependencies.get("name") in kwargs.get("special_names", []):
            return True
        return False

    arg_defs = dict(
        name=dict(arg_type="str", required=True, default="samplename",),
        date=dict(arg_type="str", default="may 1, 2020"),
        time=dict(arg_type="int"),
        age=dict(
            arg_type="int",
            required=special_user,
            dependencies=["name"],
            special_names=["blake", "demetri", "ping", "crystal", "asif", "luke"],
        ),
    )
    parser = BetterArgParser(arg_defs)
    with pytest.raises(ValueError):
        parser.parse_args({"name": "blake"})
    result = parser.parse_args({"name": "john"})
    assert result.get("name") == "john"
def test_cyclic_dependency_in_nested_dict():
    arg_defs = dict(person=dict(
        arg_type="dict",
        options=dict(
            name=dict(
                arg_type="str",
                required=True,
                default="testname",
                dependencies=["age"],
            ),
            age=dict(arg_type="int", required=False, dependencies=["name"]),
            address=dict(
                arg_type="dict",
                options=dict(street=dict(arg_type="str"),
                             number=dict(arg_type="str")),
            ),
        ),
    ))
    with pytest.raises(RuntimeError):
        BetterArgParser(arg_defs)
def test_required_top_level_no_default():
    arg_defs = dict(name=dict(arg_type="str", required=True))
    parser = BetterArgParser(arg_defs)
    with pytest.raises(ValueError):
        parser.parse_args({})
def test_default_top_level():
    arg_defs = dict(state=dict(arg_type="str", default="present"))
    parser = BetterArgParser(arg_defs)
    result = parser.parse_args({})
    assert result.get("state") == "present"