forked from rapidsai/cudf
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This PR adds `cudf.options`, a global dictionary to store configurations. A set of helper functions to manage the registries are also included. See documentation included in the PR for detail. See demonstration use in: rapidsai#11272 Closes rapidsai#5311 Authors: - Michael Wang (https://github.com/isVoid) Approvers: - Lawrence Mitchell (https://github.com/wence-) - Matthew Roeschke (https://github.com/mroeschke) - Bradley Dice (https://github.com/bdice) URL: rapidsai#11193
- Loading branch information
Showing
9 changed files
with
251 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
.. _api.options: | ||
|
||
============ | ||
cudf Options | ||
============ | ||
|
||
.. autosummary:: | ||
:toctree: api/ | ||
|
||
cudf.get_option | ||
cudf.set_option | ||
cudf.describe_option |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,3 +5,4 @@ | |
library_design | ||
documentation | ||
options |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
# Options | ||
|
||
The usage of options is explained in the [user guide](options_user_guide). | ||
This document provides more explanations on how developers work with options internally. | ||
|
||
Options are stored as a dictionary in the `cudf.options` module. | ||
Each option name is its key in the dictionary. | ||
The value of the option is an instance of an `Options` object. | ||
|
||
An `Options` object has the following attributes: | ||
- `value`: the current value of the option | ||
- `description`: a text description of the option | ||
- `validator`: a boolean function that returns `True` if `value` is valid, | ||
`False` otherwise. | ||
|
||
Developers can use `cudf.options._register_option` to add options to the dictionary. | ||
{py:func}`cudf.get_option` is provided to get option values from the dictionary. | ||
|
||
When testing the behavior of a certain option, | ||
it is advised to use [`yield` fixture](https://docs.pytest.org/en/7.1.x/how-to/fixtures.html#yield-fixtures-recommended) to set up and clean up the option. | ||
|
||
See the [API reference](api.options) for more details. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,5 +12,6 @@ groupby | |
guide-to-udfs | ||
cupy-interop | ||
dask-cudf | ||
options | ||
PandasCompat | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
(options_user_guide)= | ||
|
||
# Options | ||
|
||
cuDF has an options API to configure and customize global behavior. | ||
This API complements the [pandas.options](https://pandas.pydata.org/docs/user_guide/options.html) API with features specific to cuDF. | ||
|
||
{py:func}`cudf.describe_option` will print the option's description, | ||
the current value, and the default value. | ||
When no argument is provided, | ||
all options are printed. | ||
To set value to a option, use {py:func}`cudf.set_option`. | ||
|
||
See the [API reference](api.options) for more details. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
# Copyright (c) 2022, NVIDIA CORPORATION. | ||
|
||
from dataclasses import dataclass | ||
from typing import Any, Callable, Dict, Optional | ||
|
||
|
||
@dataclass | ||
class Option: | ||
default: Any | ||
value: Any | ||
description: str | ||
validator: Callable | ||
|
||
|
||
_OPTIONS: Dict[str, Option] = {} | ||
|
||
|
||
def _register_option( | ||
name: str, default_value: Any, description: str, validator: Callable | ||
): | ||
"""Register an option. | ||
Parameters | ||
---------- | ||
name : str | ||
The name of the option. | ||
default_value : Any | ||
The default value of the option. | ||
description : str | ||
A text description of the option. | ||
validator : Callable | ||
Called on the option value to check its validity. Should raise an | ||
error if the value is invalid. | ||
Raises | ||
------ | ||
BaseException | ||
Raised by validator if the value is invalid. | ||
""" | ||
validator(default_value) | ||
_OPTIONS[name] = Option( | ||
default_value, default_value, description, validator | ||
) | ||
|
||
|
||
def get_option(name: str) -> Any: | ||
"""Get the value of option. | ||
Parameters | ||
---------- | ||
key : str | ||
The name of the option. | ||
Returns | ||
------- | ||
The value of the option. | ||
Raises | ||
------ | ||
KeyError | ||
If option ``name`` does not exist. | ||
""" | ||
try: | ||
return _OPTIONS[name].value | ||
except KeyError: | ||
raise KeyError(f'"{name}" does not exist.') | ||
|
||
|
||
def set_option(name: str, val: Any): | ||
"""Set the value of option. | ||
Parameters | ||
---------- | ||
name : str | ||
The name of the option. | ||
val : Any | ||
The value to set. | ||
Raises | ||
------ | ||
KeyError | ||
If option ``name`` does not exist. | ||
BaseException | ||
Raised by validator if the value is invalid. | ||
""" | ||
try: | ||
option = _OPTIONS[name] | ||
except KeyError: | ||
raise KeyError(f'"{name}" does not exist.') | ||
option.validator(val) | ||
option.value = val | ||
|
||
|
||
def _build_option_description(name, opt): | ||
return ( | ||
f"{name}:\n" | ||
f"\t{opt.description}\n" | ||
f"\t[Default: {opt.default}] [Current: {opt.value}]" | ||
) | ||
|
||
|
||
def describe_option(name: Optional[str] = None): | ||
"""Prints the description of an option. | ||
If `name` is unspecified, prints the description of all available options. | ||
Parameters | ||
---------- | ||
name : Optional[str] | ||
The name of the option. | ||
""" | ||
names = _OPTIONS.keys() if name is None else [name] | ||
for name in names: | ||
print(_build_option_description(name, _OPTIONS[name])) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
# Copyright (c) 2022, NVIDIA CORPORATION. | ||
|
||
from contextlib import redirect_stdout | ||
from io import StringIO | ||
|
||
import pytest | ||
|
||
import cudf | ||
|
||
|
||
@pytest.fixture(scope="module", autouse=True) | ||
def empty_option_environment(): | ||
old_option_environment = cudf.options._OPTIONS | ||
cudf.options._OPTIONS = {} | ||
yield | ||
cudf.options._OPTIONS = old_option_environment | ||
|
||
|
||
@pytest.fixture | ||
def odd_option(empty_option_environment): | ||
def validator(x): | ||
if not x % 2 == 1: | ||
raise ValueError(f"Invalid option value {x}") | ||
|
||
cudf.options._register_option( | ||
"odd_option", | ||
1, | ||
"An odd option.", | ||
validator, | ||
) | ||
yield | ||
del cudf.options._OPTIONS["odd_option"] | ||
|
||
|
||
@pytest.fixture | ||
def even_option(empty_option_environment): | ||
def validator(x): | ||
if not x % 2 == 0: | ||
raise ValueError(f"Invalid option value {x}") | ||
|
||
cudf.options._register_option( | ||
"even_option", 0, "An even option.", validator | ||
) | ||
yield | ||
del cudf.options._OPTIONS["even_option"] | ||
|
||
|
||
def test_option_get_set(odd_option): | ||
assert cudf.get_option("odd_option") == 1 | ||
cudf.set_option("odd_option", 101) | ||
assert cudf.get_option("odd_option") == 101 | ||
|
||
|
||
def test_option_set_invalid(odd_option): | ||
with pytest.raises(ValueError, match="Invalid option value 0"): | ||
cudf.set_option("odd_option", 0) | ||
|
||
|
||
def test_option_description(odd_option): | ||
s = StringIO() | ||
with redirect_stdout(s): | ||
cudf.describe_option("odd_option") | ||
s.seek(0) | ||
expected = "odd_option:\n\tAn odd option.\n\t[Default: 1] [Current: 1]\n" | ||
assert expected == s.read() | ||
|
||
|
||
def test_option_description_all(odd_option, even_option): | ||
s = StringIO() | ||
with redirect_stdout(s): | ||
cudf.describe_option() | ||
s.seek(0) | ||
expected = ( | ||
"odd_option:\n\tAn odd option.\n\t[Default: 1] [Current: 1]\n" | ||
"even_option:\n\tAn even option.\n\t[Default: 0] [Current: 0]\n" | ||
) | ||
assert expected == s.read() |