Skip to content

Commit

Permalink
Fixed the order of Option arguments
Browse files Browse the repository at this point in the history
  • Loading branch information
sg495 committed Jan 23, 2024
1 parent 7b8254a commit 48b4246
Show file tree
Hide file tree
Showing 7 changed files with 57 additions and 61 deletions.
19 changes: 9 additions & 10 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -58,39 +58,38 @@ An option manager object can then be obtained by instantiating the option manage
class MyOptions(OptionManager):
""" Options of some library. """
validate = Option(True, bool)
validate = Option(bool, True)
""" Whether to validate arguments to functions and methods. """
eq_atol = Option(1e-8, float, lambda x: x >= 0)
eq_atol = Option(float, 1e-8, lambda x: x >= 0)
""" Absolute tolerance used for equality comparisons."""
scaling: Option(
{"x": 1.0, "y": 2.0, "z": 1.0},
Mapping[Literal["x", "y", "z"], float],
{"x": 1.0, "y": 2.0, "z": 1.0},
lambda scaling: all(v >= 0 for v in scaling.values())
)
""" Scaling for coordinate axes used in plots. """
options = MyOptions()
Each option takes a default value, a type, and an optional validator function:

.. code-block:: python
validate = Option(True, bool)
# default value ^^^^ ^^^^ option type
validate = Option(bool, True)
# option type ^^^^ ^^^^ default value
eq_atol = Option(1e-8, float, lambda x: x >= 0)
eq_atol = Option(float, 1e-8, lambda x: x >= 0)
# optional validator ^^^^^^^^^^^^^^^^
Any type supported by the `typing-validation <https://github.com/hashberg-io/typing-validation>`_ library can be used for options, including `PEP 484 <https://peps.python.org/pep-0484/>`_ type hints:

.. code-block:: python
scaling: Option(
{"x": 1.0, "y": 2.0, "z": 1.0},
Mapping[Literal["x", "y", "z"], float], # <- type hints supported
{"x": 1.0, "y": 2.0, "z": 1.0},
lambda scaling: all(v >= 0 for v in scaling.values())
)
Expand Down Expand Up @@ -120,7 +119,7 @@ It is also possible to use the options object as a context manager, for temporar
print(options.validate) # True
print(options.eq_atol) # 0.00000001
All options can be reset to their default values by using the `reset <https://optmanage.readthedocs.io/en/latest/api/optmanage.manager.html#optmanage.manager.OptionManager.reset>`_ method of the ``options`` object:
All options can be reset to their default values by using the `OptionManager.reset <https://optmanage.readthedocs.io/en/latest/api/optmanage.manager.html#optmanage.manager.OptionManager.reset>`_ method of the ``options`` object:

.. code-block:: python
Expand All @@ -131,7 +130,7 @@ All options can be reset to their default values by using the `reset <https://op
print(options.validate) # True
print(options.eq_atol) # 0.00000001
An individual option can be reset to its default value by using the `reset <https://optmanage.readthedocs.io/en/latest/api/optmanage.option.html#optmanage.option.Option.reset>`_ method of the `Option <https://optmanage.readthedocs.io/en/latest/api/optmanage.option.html#option>`_ object, accessed from the option manager class:
An individual option can be reset to its default value by using the `Option.reset <https://optmanage.readthedocs.io/en/latest/api/optmanage.option.html#optmanage.option.Option.reset>`_ method of the `Option <https://optmanage.readthedocs.io/en/latest/api/optmanage.option.html#option>`_ object, accessed from the option manager class:

.. code-block:: python
Expand Down
14 changes: 7 additions & 7 deletions docs/getting-started.rst
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,15 @@ An option manager object can then be obtained by instantiating the option manage
class MyOptions(OptionManager):
""" Options of some library. """
validate = Option(True, bool)
validate = Option(bool, True)
""" Whether to validate arguments to functions and methods. """
eq_atol = Option(1e-8, float, lambda x: x >= 0)
eq_atol = Option(float, 1e-8, lambda x: x >= 0)
""" Absolute tolerance used for equality comparisons."""
scaling: Option(
{"x": 1.0, "y": 2.0, "z": 1.0},
Mapping[Literal["x", "y", "z"], float],
{"x": 1.0, "y": 2.0, "z": 1.0},
lambda scaling: all(v >= 0 for v in scaling.values())
)
""" Scaling for coordinate axes used in plots. """
Expand All @@ -39,19 +39,19 @@ Each option takes a default value, a type, and an optional validator function:

.. code-block:: python
validate = Option(True, bool)
# default value ^^^^ ^^^^ option type
validate = Option(bool, True)
# option type ^^^^ ^^^^ default value
eq_atol = Option(1e-8, float, lambda x: x >= 0)
eq_atol = Option(float, 1e-8, lambda x: x >= 0)
# optional validator ^^^^^^^^^^^^^^^^
Any type supported by the `typing-validation <https://github.com/hashberg-io/typing-validation>`_ library can be used for options, including `PEP 484 <https://peps.python.org/pep-0484/>`_ type hints:

.. code-block:: python
scaling: Option(
{"x": 1.0, "y": 2.0, "z": 1.0},
Mapping[Literal["x", "y", "z"], float], # <- type hints supported
{"x": 1.0, "y": 2.0, "z": 1.0},
lambda scaling: all(v >= 0 for v in scaling.values())
)
Expand Down
4 changes: 2 additions & 2 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ You can install the latest release from `PyPI <https://pypi.org/project/optmanag
class MyOptions(OptionManager):
""" Options of some library. """
validate = Option(True, bool)
validate = Option(bool, True)
""" Whether to validate arguments to functions and methods. """
eq_atol = Option(1e-8, float, lambda x: x >= 0)
eq_atol = Option(float, 1e-8, lambda x: x >= 0)
""" Absolute tolerance used for equality comparisons."""
options = MyOptions()
Expand Down
12 changes: 6 additions & 6 deletions optmanage/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,24 +29,24 @@ class OptionManager:
class MyOptions(OptionManager):
''' Options of some library. '''
validate = Option(True, bool)
validate = Option(bool, True)
''' Whether to validate arguments to functions and methods. '''
eq_atol = Option(1e-08, float, lambda x: x >= 0)
eq_atol = Option(float, 1e-08, lambda x: x >= 0)
''' Absolute tolerance used for equality comparisons.'''
print_prec = Option(3, int, lambda x: x >= 0)
print_prec = Option(int, 3, lambda x: x >= 0)
''' Number of decimal digits to be displayed when printing. '''
Each option is defined as a class attribute of type :class:`Option`,
passing a default value, a type, and optionally a validator function:
.. code-block:: python
validate = Option(True, bool)
# default value ^^^^ ^^^^ option type
validate = Option(bool, True)
# option type ^^^^ ^^^^ default value
print_prec = Option(3, int, lambda x: x >= 0)
print_prec = Option(int, 3, lambda x: x >= 0)
# optional validator ^^^^^^^^^^^^^^^^
The option manager can then be instantiated as usual:
Expand Down
9 changes: 3 additions & 6 deletions optmanage/option.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,26 +74,23 @@ class Option(Generic[ValueT]):

def __new__(
cls,
ty: Any,
default: ValueT,
ty: Any = None,
validator: Validator[ValueT] | None = None,
) -> Self:
"""
Creates a new option descriptor.
For usage examples, see :class:`OptionManager`.
:param ty: The type of the option.
:param default: The default value for the option.
:param ty: The type of the option. If not specified, defaults to the
type of the default value.
:param validator: A callable that takes a value and returns whether
it is valid for this option. If not specified,
defaults to :obj:`None` (no validation)
:meta public:
"""
if ty is None:
ty = type(default)
elif not can_validate(ty):
if not can_validate(ty):
raise TypeError(f"Cannot validate type {ty!r}.")
if validator is not None and not callable(validator):
raise TypeError(f"Expected callable validator, got {validator!r}.")
Expand Down
14 changes: 7 additions & 7 deletions test/test_00_option.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from optmanage.option import Option

def test_option_attr_1() -> None:
opt = Option([1.5, 2.], Sequence[float])
opt = Option(Sequence[float], [1.5, 2.])
assert opt.default == [1.5, 2.]
assert opt.type == Sequence[float]
assert opt.validator is None
Expand All @@ -19,28 +19,28 @@ def test_option_attr_1() -> None:
opt.owner # pylint: disable = pointless-statement

def test_option_validation_1() -> None:
opt = Option([1.5, 2.], Sequence[float])
opt = Option(Sequence[float], [1.5, 2.])
opt.validate([1e-8])
with pytest.raises(TypeError):
opt.validate(1e-8) # type: ignore
with pytest.raises(TypeError):
Option(1e-8, Sequence[float])
Option(Sequence[float], 1e-8)

def test_option_attr_2() -> None:
validator = lambda x: x>= 0
opt = Option(1e8, float, validator)
opt = Option(float, 1e8, validator)
assert opt.validator == validator

def test_option_validation_2() -> None:
opt = Option(1e8, float, lambda x: x>= 0)
opt = Option(float, 1e8, lambda x: x>= 0)
with pytest.raises(ValueError):
opt.validate(-1.5)
with pytest.raises(ValueError):
Option(-1.5, float, lambda x: x>= 0)
Option(float, -1.5, lambda x: x>= 0)

def test_option_assignment() -> None:
class MyOptions(OptionManager):
validate = Option(True, bool)
validate = Option(bool, True)
opt = MyOptions.validate
assert opt.name == "validate"
assert opt.owner == MyOptions
46 changes: 23 additions & 23 deletions test/test_01_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@

def test_init() -> None:
class MyOptions(OptionManager):
validate = Option(True, bool)
eq_atol = Option(1e-08, float, lambda x: x >= 0)
validate = Option(bool, True)
eq_atol = Option(float, 1e-08, lambda x: x >= 0)
options = MyOptions()
keys = ["validate", "eq_atol"]
values = [True, 1e-8]
Expand All @@ -24,16 +24,16 @@ class MyOptions(OptionManager):

def test_get_default() -> None:
class MyOptions(OptionManager):
validate = Option(True, bool)
eq_atol = Option(1e-8, float, lambda x: x >= 0)
validate = Option(bool, True)
eq_atol = Option(float, 1e-08, lambda x: x >= 0)
options = MyOptions()
assert options.validate is True
assert options.eq_atol == 1e-8

def test_option_set() -> None:
class MyOptions(OptionManager):
validate = Option(True, bool)
eq_atol = Option(1e-8, float, lambda x: x >= 0)
validate = Option(bool, True)
eq_atol = Option(float, 1e-08, lambda x: x >= 0)
options = MyOptions()
options.validate = False
assert options.validate is False
Expand All @@ -42,8 +42,8 @@ class MyOptions(OptionManager):

def test_option_set_failure() -> None:
class MyOptions(OptionManager):
validate = Option(True, bool)
eq_atol = Option(1e-8, float, lambda x: x >= 0)
validate = Option(bool, True)
eq_atol = Option(float, 1e-08, lambda x: x >= 0)
options = MyOptions()
with pytest.raises(TypeError):
options.validate = 2 # type: ignore
Expand All @@ -52,8 +52,8 @@ class MyOptions(OptionManager):

def test_set() -> None:
class MyOptions(OptionManager):
validate = Option(True, bool)
eq_atol = Option(1e-8, float, lambda x: x >= 0)
validate = Option(bool, True)
eq_atol = Option(float, 1e-08, lambda x: x >= 0)
options = MyOptions()
options.set(validate=False, eq_atol=1.5)
assert options.validate is False
Expand All @@ -71,17 +71,17 @@ class MyOptions(OptionManager):
@pytest.mark.parametrize(["kwargs", "error"], set_failures)
def test_set_failure(kwargs: Mapping[str, Any], error: Type[Exception]) -> None:
class MyOptions(OptionManager):
validate = Option(True, bool)
eq_atol = Option(1e-8, float, lambda x: x >= 0)
validate = Option(bool, True)
eq_atol = Option(float, 1e-08, lambda x: x >= 0)
options = MyOptions()
with pytest.raises(error):
options.set(**kwargs)
assert options.validate is True and options.eq_atol == 1e-8

def test_option_reset() -> None:
class MyOptions(OptionManager):
validate = Option(True, bool)
eq_atol = Option(1e-8, float, lambda x: x >= 0)
validate = Option(bool, True)
eq_atol = Option(float, 1e-08, lambda x: x >= 0)
options = MyOptions()
options.validate = False
MyOptions.validate.reset(options)
Expand All @@ -92,8 +92,8 @@ class MyOptions(OptionManager):

def test_reset() -> None:
class MyOptions(OptionManager):
validate = Option(True, bool)
eq_atol = Option(1e-8, float, lambda x: x >= 0)
validate = Option(bool, True)
eq_atol = Option(float, 1e-08, lambda x: x >= 0)
options = MyOptions()
options.validate = False
options.eq_atol = 1.5
Expand All @@ -103,8 +103,8 @@ class MyOptions(OptionManager):

def test_temp_set() -> None:
class MyOptions(OptionManager):
validate = Option(True, bool)
eq_atol = Option(1e-8, float, lambda x: x >= 0)
validate = Option(bool, True)
eq_atol = Option(float, 1e-08, lambda x: x >= 0)
options = MyOptions()
with options(validate=False, eq_atol=1.5):
assert options.validate is False
Expand All @@ -115,8 +115,8 @@ class MyOptions(OptionManager):
@pytest.mark.parametrize(["kwargs", "error"], set_failures)
def test_temp_set_failure(kwargs: Mapping[str, Any], error: Type[Exception]) -> None:
class MyOptions(OptionManager):
validate = Option(True, bool)
eq_atol = Option(1e-8, float, lambda x: x >= 0)
validate = Option(bool, True)
eq_atol = Option(float, 1e-08, lambda x: x >= 0)
options = MyOptions()
with pytest.raises(error):
with options(**kwargs):
Expand All @@ -128,15 +128,15 @@ def test_getting_started_example() -> None:
class MyOptions(OptionManager):
""" Options of some library. """

validate = Option(True, bool)
validate = Option(bool, True)
""" Whether to validate arguments to functions and methods. """

eq_atol = Option(1e-08, float, lambda x: x >= 0)
eq_atol = Option(float, 1e-08, lambda x: x >= 0)
""" Absolute tolerance used for equality comparisons."""

scaling = Option(
{"x": 1.0, "y": 2.0, "z": 1.0},
Mapping[Literal["x", "y", "z"], float],
{"x": 1.0, "y": 2.0, "z": 1.0},
lambda scaling: all(v >= 0 for v in scaling.values())
)
""" Scaling for coordinate axes used in plots. """
Expand Down

0 comments on commit 48b4246

Please sign in to comment.