diff --git a/README.md b/README.md index 3fc6b63..4953e85 100644 --- a/README.md +++ b/README.md @@ -29,9 +29,9 @@ oneFace is an easy way to create interfaces in Python, just decorate your functi from oneface import one, Arg @one -def bmi(name: Arg(str), - height: Arg(float, [100, 250]) = 160, - weight: Arg(float, [0, 300]) = 50.0): +def bmi(name: str, + height: Arg[float, [100, 250]] = 160, + weight: Arg[float, [0, 300]] = 50.0): BMI = weight / (height / 100) ** 2 print(f"Hi {name}. Your BMI is: {BMI}") return BMI diff --git a/docs/basic_usage.md b/docs/basic_usage.md index 6bb6233..6c60509 100644 --- a/docs/basic_usage.md +++ b/docs/basic_usage.md @@ -7,7 +7,16 @@ Using `one` decorate the function, and use `Arg` mark type and range of the argu from oneface import one, Arg @one -def print_person(name: Arg(str), age: Arg(int, [0, 120])): +def print_person(name: str, age: Arg[int, [0, 120]]): + return f"{name} is {age} years old." +``` + +**Note**: `Arg(type, range)` is same to `Arg[type, range]`. + +```Python +# This is same to the previous defination +@one +def print_person(name: str, age: Arg(int, [0, 120])): return f"{name} is {age} years old." ``` @@ -51,7 +60,7 @@ By default, oneface will pretty print the input arguments with a table. It can b ```Python @one(print_args=False) -def print_person(name: Arg(str), age: Arg(int, [0, 120])): +def print_person(name: str, age: Arg[int, [0, 120]]): return f"{name} is {age} years old." >>> print_person("Tom", 20) @@ -66,7 +75,7 @@ Create a python module `print_person.py`: from oneface import one, Arg @one -def print_person(name: Arg(str), age: Arg(int, [0, 120])): +def print_person(name: str, age: Arg[int, [0, 120]]): return f"{name} is {age} years old." print_person.cli() diff --git a/docs/builtin_types.md b/docs/builtin_types.md index 0a5fd74..55c891a 100644 --- a/docs/builtin_types.md +++ b/docs/builtin_types.md @@ -20,14 +20,14 @@ from oneface.core import one, Arg from oneface.types import (Selection, SubSet, InputPath, OutputPath) @one -def func(in_path: Arg(InputPath), - out_path: Arg(OutputPath) = "./test", - a: Arg(int, [0, 10], text="parameter (a)") = 10, - b: Arg(float, [0, 1]) = 0.1, - c: Arg(str) = "aaaa", - d: Arg(bool) = False, - e: Arg(Selection, ["a", "b", "c"]) = "a", - f: Arg(SubSet, ["a", "b", "c"]) = ["a"]): +def func(in_path: InputPath, + out_path: OutputPath = "./test", + a: Arg[int, [0, 10], text="parameter (a)"] = 10, + b: Arg[float, [0, 1]] = 0.1, + c: Arg[str] = "aaaa", + d: Arg[bool] = False, + e: Arg[Selection, ["a", "b", "c"]] = "a", + f: Arg[SubSet, ["a", "b", "c"]] = ["a"]): print(in_path, out_path) print(a, b, c, d, e, f) return a + b diff --git a/docs/dash_confs.md b/docs/dash_confs.md index 7f387d1..ab6553a 100644 --- a/docs/dash_confs.md +++ b/docs/dash_confs.md @@ -9,9 +9,9 @@ The `show_console` parameter is used to control whether it is displayed. from oneface import one, Arg @one -def bmi(name: Arg(str) = "Tom", - height: Arg(float, [100, 250]) = 160, - weight: Arg(float, [0, 300]) = 50.0): +def bmi(name: str = "Tom", + height: Arg[float, [100, 250]] = 160, + weight: Arg[float, [0, 300]] = 50.0): BMI = weight / (height / 100) ** 2 print(f"Hi {name}. Your BMI is: {BMI}") return BMI diff --git a/docs/index.md b/docs/index.md index 3f828fc..3461b31 100644 --- a/docs/index.md +++ b/docs/index.md @@ -33,15 +33,16 @@ $ pip install "oneface[pyside2]" # for example ## Example -oneFace is an easy way to create interfaces in Python, just decorate your function and mark the type and range of the arguments: +oneFace is an easy way to create interfaces in Python, +just decorate your function and mark the **type** and **range** of the arguments: ```Python from oneface import one, Arg @one -def bmi(name: Arg(str), - height: Arg(float, [100, 250]) = 160, - weight: Arg(float, [0, 300]) = 50.0): +def bmi(name: str, + height: Arg[float, [100, 250]] = 160, + weight: Arg[float, [0, 300]] = 50.0): BMI = weight / (height / 100) ** 2 print(f"Hi {name}. Your BMI is: {BMI}") return BMI diff --git a/docs/qt_confs.md b/docs/qt_confs.md index 83653bb..14c4049 100644 --- a/docs/qt_confs.md +++ b/docs/qt_confs.md @@ -8,9 +8,9 @@ By default the window name is the name of the function, but it can be changed by from oneface import one, Arg @one -def bmi(name: Arg(str), - height: Arg(float, [100, 250]) = 160, - weight: Arg(float, [0, 300]) = 50.0): +def bmi(name: str, + height: Arg[float, [100, 250]] = 160, + weight: Arg[float, [0, 300]] = 50.0): BMI = weight / (height / 100) ** 2 print(f"Hi {name}. Your BMI is: {BMI}") return BMI @@ -27,8 +27,8 @@ By default, argument label is the variable name. But it can be explicitly set by ```Python @one def bmi(name: Arg(str, text="NAME"), # explicitly label setting - height: Arg(float, [100, 250]) = 160, - weight: Arg(float, [0, 300]) = 50.0): + height: Arg[float, [100, 250]] = 160, + weight: Arg[float, [0, 300]] = 50.0): BMI = weight / (height / 100) ** 2 print(f"Hi {name}. Your BMI is: {BMI}") return BMI diff --git a/docs/type_extension.md b/docs/type_extension.md index dc56a49..e7d3efa 100644 --- a/docs/type_extension.md +++ b/docs/type_extension.md @@ -23,7 +23,7 @@ This will allow oneface to check the type of the input parameter to make sure it ```Python @one -def print_person(person: Arg(Person)): +def print_person(person: Person): print(f"{person.name} is {person.age} years old.") >>> print_person(["Tom", 10]) # Incorrect input type @@ -83,7 +83,7 @@ Mark the range in argument annotation: ```Python @one -def print_person(person: Arg(Person, [0, 100])): +def print_person(person: Arg[Person, [0, 100]]): print(f"{person.name} is {person.age} years old.") ``` diff --git a/oneface/__init__.py b/oneface/__init__.py index c5058f9..a2d3837 100644 --- a/oneface/__init__.py +++ b/oneface/__init__.py @@ -1,5 +1,5 @@ from .core import one, Arg -__version__ = '0.0.2' +__version__ = '0.1.0' __all__ = [one, Arg] diff --git a/oneface/arg.py b/oneface/arg.py index f95cf62..4766ba5 100644 --- a/oneface/arg.py +++ b/oneface/arg.py @@ -7,8 +7,15 @@ class Empty: pass -class Arg(): +class ArgMeta(type): + def __getitem__(self, args): + if isinstance(args, tuple): + return Arg(*args) + else: + return Arg(args) + +class Arg(metaclass=ArgMeta): type_to_range_checker = {} type_to_type_checker = {} @@ -34,7 +41,7 @@ def check(self, val): if not self.type_checker(val, self.type): raise TypeError( f"Input value {val} is not in valid type({self.type})") - if self.range_checker is not None: + if (self.range is not None) and (self.range_checker is not None): if (not self.range_checker(val, self.range)): raise ValueError(f"Input value {val} is not in a valid range.") @@ -75,4 +82,3 @@ def get_func_argobjs(func: T.Callable) -> T.OrderedDict[str, Arg]: arg.default = p.default args[n] = arg return args - diff --git a/oneface/dash_app.py b/oneface/dash_app.py index 690161b..fdab5fc 100644 --- a/oneface/dash_app.py +++ b/oneface/dash_app.py @@ -285,7 +285,7 @@ class DropdownInputItem(InputItem): def get_input(self): return dcc.Dropdown( self.range, - value=(self.default or range[0]) + value=(self.default or self.range[0]) ) @@ -293,7 +293,7 @@ class MultiDropdownInputItem(InputItem): def get_input(self): return dcc.Dropdown( self.range, - value=(self.default or range[0]), multi=True + value=(self.default or self.range[0]), multi=True ) diff --git a/tests/test_core.py b/tests/test_core.py index 4e9d3f2..db88b89 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -30,6 +30,11 @@ def func(a: Arg(bool)): pass with pytest.raises(ArgsCheckError) as e: func(1) + @one(print_args=False) + def func(a: Arg(int)): + return a + with pytest.raises(ArgsCheckError) as e: + func(1.0) assert isinstance(e.value.args[0][0], TypeError) @@ -62,7 +67,7 @@ class A(): def __init__(self, a): self.a = a - @one + @one(print_args=False) def mth1(self, b: Arg(float, [0, 1])): return self.a + b @@ -99,8 +104,22 @@ def func1(): assert func1.__doc__ == "test" +def test_implicit(): + @one(print_args=False) + def func(a: int): + return a + 1 + assert func(1) == 2 + with pytest.raises(ArgsCheckError): + func(1.0) + @one(print_args=False) + def func(a: Arg[int, [0, 10]], b: Arg[int, [0, 10]]): + return a + b + assert func(10, 10) == 20 + + if __name__ == "__main__": - test_arg_check() + #test_arg_check() #test_arg_register() #test_print_args() #test_class_method_arg_check() + test_implicit()