From 8be27e07a7dec0c62696652aa7d18fe719af33be Mon Sep 17 00:00:00 2001 From: Kyle Bowman Date: Thu, 21 Mar 2024 22:12:14 -0400 Subject: [PATCH] Add Path type for argspecs. --- src/proto/utils.py | 11 ++++++++++- tests/dummy.py | 4 ++++ tests/test_utils.py | 19 ++++++++++--------- 3 files changed, 24 insertions(+), 10 deletions(-) diff --git a/src/proto/utils.py b/src/proto/utils.py index 5622c13..98ff1be 100644 --- a/src/proto/utils.py +++ b/src/proto/utils.py @@ -2,6 +2,7 @@ import argparse from collections.abc import Callable from functools import singledispatch import inspect +from pathlib import Path from typing import Union @@ -87,10 +88,18 @@ def get_parser(fn: Callable)->argparse.ArgumentParser: @singledispatch def get_argspecs(annotation: type)->dict: """ Creates a partial argspec dictionary from a parameter annotation. """ + return {'type': type(annotation)} + +@get_argspecs.register +def empty_argspecs(annotation: inspect._empty)->dict: + """ Implements argspecs for unannotated parameters. """ return {} @get_argspecs.register def scalar_argspecs(annotation: Union[int, float, str])->dict: """ Implements get_argspecs for integers, floats, and strings. """ return {'type': type(annotation)} - \ No newline at end of file + +@get_argspecs.register +def path_argspecs(annotation: Path): + return {'type': type(annotation)} diff --git a/tests/dummy.py b/tests/dummy.py index 0905623..b1bf40a 100644 --- a/tests/dummy.py +++ b/tests/dummy.py @@ -2,6 +2,7 @@ This module contains dummy functions that are used by the test suite. """ +from pathlib import Path from typing import Optional class DummyCallable: @@ -30,3 +31,6 @@ def dummy_fn_optional(string: Optional[str] = None, num: Optional[int] = 42)->st # NOTE: The dummy_fn_full function is the prototypical "happy path" for signagures. def dummy_fn_full(string: str="default", num: int = 42)->str: return f"String: {string} \n Integer: {num} \n" + +def dummy_fn_path(path: Path): + return str(path) \ No newline at end of file diff --git a/tests/test_utils.py b/tests/test_utils.py index 41f0b03..e1b8af0 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -65,9 +65,8 @@ def test_get_parser_defaults(): """ If a fn default is specified, use keyword syntax (optional). """ string="not default" num=42 - sys.argv[1:] = [f"--string={string}", "--num", str(num)] parser=get_parser(dummy_fn_full) - args = parser.parse_args() + args = parser.parse_args(args=[f"--string={string}", "--num", str(num)]) assert args.string == string assert int(args.num) == num @@ -75,33 +74,35 @@ def test_get_parser_no_defaults(): """ If no function default is specified, use postional syntax (required). """ string="not default" num=42 - sys.argv[1:] = [string, str(num)] parser=get_parser(dummy_fn_no_signature) - args = parser.parse_args() + args = parser.parse_args(args=[string, str(num)]) assert args.string == string def test_get_parser_method(): """ Ensures that 'self' and 'cls' are ignored. """ string="not default" num=42 - sys.argv[1:] = [f"--string={string}", "--num", str(num)] parser=get_parser(DummyClass().dummy_method) - args = parser.parse_args() + args = parser.parse_args(args=[f"--string={string}", "--num", str(num)]) assert args.string == string parser2=get_parser(DummyClass.dummy_classmethod) - args2 = parser2.parse_args() + args2 = parser2.parse_args([f"--string={string}", "--num", str(num)]) assert args2.string == string def test_get_parser_types_scalar(): """ Asserts ints, strings, and floats, are parsed from CLI as types. """ string="not default" num="42" - sys.argv[1:] = [f"--string={string}", "--num", str(num)] parser=get_parser(dummy_fn_full) - args = parser.parse_args() + args = parser.parse_args(args=[f"--string={string}", "--num", str(num)]) assert args.string == string assert args.num == int(num) +def test_get_parser_types_path(): + parser=get_parser(dummy_fn_path) + args = parser.parse_args(args=['.']) + assert isinstance(args.path, Path) + def test_get_parser_types_union(): parser=get_parser(dummy_fn_optional) args=parser.parse_args(args=['--string','yay']) -- 2.39.5