-
-
Notifications
You must be signed in to change notification settings - Fork 18.4k
TYP: _config/config.py && core/{apply,construction}.py #30734
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 9 commits
2610ba2
c399d1d
bcf9d76
d1f3fe9
15d6135
0ad85df
27b8e24
8b54e82
3684b30
ce169f5
5d2c111
3db9cb0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -51,7 +51,7 @@ | |||||
from collections import namedtuple | ||||||
from contextlib import contextmanager | ||||||
import re | ||||||
from typing import Any, Dict, Iterable, List | ||||||
from typing import Any, Callable, Dict, Iterable, List, Optional, Tuple, Type, Union | ||||||
import warnings | ||||||
|
||||||
DeprecatedOption = namedtuple("DeprecatedOption", "key msg rkey removal_ver") | ||||||
|
@@ -80,7 +80,7 @@ class OptionError(AttributeError, KeyError): | |||||
# User API | ||||||
|
||||||
|
||||||
def _get_single_key(pat, silent): | ||||||
def _get_single_key(pat: str, silent: bool) -> str: | ||||||
keys = _select_options(pat) | ||||||
if len(keys) == 0: | ||||||
if not silent: | ||||||
|
@@ -98,15 +98,15 @@ def _get_single_key(pat, silent): | |||||
return key | ||||||
|
||||||
|
||||||
def _get_option(pat, silent=False): | ||||||
def _get_option(pat: str, silent: bool = False): | ||||||
key = _get_single_key(pat, silent) | ||||||
|
||||||
# walk the nested dict | ||||||
root, k = _get_root(key) | ||||||
return root[k] | ||||||
|
||||||
|
||||||
def _set_option(*args, **kwargs): | ||||||
def _set_option(*args, **kwargs) -> None: | ||||||
# must at least 1 arg deal with constraints later | ||||||
nargs = len(args) | ||||||
if not nargs or nargs % 2 != 0: | ||||||
|
@@ -138,7 +138,7 @@ def _set_option(*args, **kwargs): | |||||
o.cb(key) | ||||||
|
||||||
|
||||||
def _describe_option(pat="", _print_desc=True): | ||||||
def _describe_option(pat: str = "", _print_desc: bool = True): | ||||||
|
||||||
keys = _select_options(pat) | ||||||
if len(keys) == 0: | ||||||
|
@@ -154,7 +154,7 @@ def _describe_option(pat="", _print_desc=True): | |||||
return s | ||||||
|
||||||
|
||||||
def _reset_option(pat, silent=False): | ||||||
def _reset_option(pat: str, silent: bool = False) -> None: | ||||||
|
||||||
keys = _select_options(pat) | ||||||
|
||||||
|
@@ -173,19 +173,19 @@ def _reset_option(pat, silent=False): | |||||
_set_option(k, _registered_options[k].defval, silent=silent) | ||||||
|
||||||
|
||||||
def get_default_val(pat): | ||||||
def get_default_val(pat: str): | ||||||
key = _get_single_key(pat, silent=True) | ||||||
return _get_registered_option(key).defval | ||||||
|
||||||
|
||||||
class DictWrapper: | ||||||
""" provide attribute-style access to a nested dict""" | ||||||
|
||||||
def __init__(self, d, prefix=""): | ||||||
def __init__(self, d: Dict[str, Any], prefix: str = ""): | ||||||
object.__setattr__(self, "d", d) | ||||||
object.__setattr__(self, "prefix", prefix) | ||||||
|
||||||
def __setattr__(self, key, val): | ||||||
def __setattr__(self, key: str, val: Any) -> None: | ||||||
prefix = object.__getattribute__(self, "prefix") | ||||||
if prefix: | ||||||
prefix += "." | ||||||
|
@@ -211,7 +211,7 @@ def __getattr__(self, key: str): | |||||
else: | ||||||
return _get_option(prefix) | ||||||
|
||||||
def __dir__(self): | ||||||
def __dir__(self) -> Iterable[str]: | ||||||
return list(self.d.keys()) | ||||||
|
||||||
|
||||||
|
@@ -412,23 +412,31 @@ def __exit__(self, *args): | |||||
_set_option(pat, val, silent=True) | ||||||
|
||||||
|
||||||
def register_option(key: str, defval: object, doc="", validator=None, cb=None): | ||||||
"""Register an option in the package-wide pandas config object | ||||||
def register_option( | ||||||
key: str, | ||||||
defval: object, | ||||||
doc: str = "", | ||||||
validator: Optional[Union[Callable[..., None], Type[str]]] = None, | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The Type[str] shouldn't be needed. changing the Callable to allow it to return a value fixes this. Also the validator should accept only a single argument.
Suggested change
|
||||||
cb: Optional[Callable[[str], None]] = None, | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Similar to validator, restricting the return type to None may not be desirable. |
||||||
) -> None: | ||||||
""" | ||||||
Register an option in the package-wide pandas config object | ||||||
|
||||||
Parameters | ||||||
---------- | ||||||
key - a fully-qualified key, e.g. "x.y.option - z". | ||||||
defval - the default value of the option | ||||||
doc - a string description of the option | ||||||
validator - a function of a single argument, should raise `ValueError` if | ||||||
called with a value which is not a legal value for the option. | ||||||
cb - a function of a single argument "key", which is called | ||||||
immediately after an option value is set/reset. key is | ||||||
the full name of the option. | ||||||
|
||||||
Returns | ||||||
------- | ||||||
Nothing. | ||||||
key : str | ||||||
Fully-qualified key, e.g. "x.y.option - z". | ||||||
defval : object | ||||||
Default value of the option. | ||||||
doc : str | ||||||
Description of the option. | ||||||
validator : Callable, optional | ||||||
Function of a single argument, should raise `ValueError` if | ||||||
called with a value which is not a legal value for the option. | ||||||
cb | ||||||
a function of a single argument "key", which is called | ||||||
immediately after an option value is set/reset. key is | ||||||
the full name of the option. | ||||||
|
||||||
Raises | ||||||
------ | ||||||
|
@@ -481,7 +489,9 @@ def register_option(key: str, defval: object, doc="", validator=None, cb=None): | |||||
) | ||||||
|
||||||
|
||||||
def deprecate_option(key, msg=None, rkey=None, removal_ver=None): | ||||||
def deprecate_option( | ||||||
key: str, msg: Optional[str] = None, rkey: Optional[str] = None, removal_ver=None | ||||||
) -> None: | ||||||
""" | ||||||
Mark option `key` as deprecated, if code attempts to access this option, | ||||||
a warning will be produced, using `msg` if given, or a default message | ||||||
|
@@ -494,32 +504,27 @@ def deprecate_option(key, msg=None, rkey=None, removal_ver=None): | |||||
|
||||||
Parameters | ||||||
---------- | ||||||
key - the name of the option to be deprecated. must be a fully-qualified | ||||||
option name (e.g "x.y.z.rkey"). | ||||||
|
||||||
msg - (Optional) a warning message to output when the key is referenced. | ||||||
if no message is given a default message will be emitted. | ||||||
|
||||||
rkey - (Optional) the name of an option to reroute access to. | ||||||
If specified, any referenced `key` will be re-routed to `rkey` | ||||||
including set/get/reset. | ||||||
rkey must be a fully-qualified option name (e.g "x.y.z.rkey"). | ||||||
used by the default message if no `msg` is specified. | ||||||
|
||||||
removal_ver - (Optional) specifies the version in which this option will | ||||||
be removed. used by the default message if no `msg` | ||||||
is specified. | ||||||
|
||||||
Returns | ||||||
------- | ||||||
Nothing | ||||||
key : str | ||||||
Name of the option to be deprecated. | ||||||
must be a fully-qualified option name (e.g "x.y.z.rkey"). | ||||||
msg : str, optional | ||||||
Warning message to output when the key is referenced. | ||||||
if no message is given a default message will be emitted. | ||||||
rkey : str, optional | ||||||
Name of an option to reroute access to. | ||||||
If specified, any referenced `key` will be | ||||||
re-routed to `rkey` including set/get/reset. | ||||||
rkey must be a fully-qualified option name (e.g "x.y.z.rkey"). | ||||||
used by the default message if no `msg` is specified. | ||||||
removal_ver : optional | ||||||
Specifies the version in which this option will | ||||||
be removed. used by the default message if no `msg` is specified. | ||||||
|
||||||
Raises | ||||||
------ | ||||||
OptionError - if key has already been deprecated. | ||||||
|
||||||
OptionError | ||||||
If the specified key has already been deprecated. | ||||||
""" | ||||||
|
||||||
key = key.lower() | ||||||
|
||||||
if key in _deprecated_options: | ||||||
|
@@ -532,7 +537,7 @@ def deprecate_option(key, msg=None, rkey=None, removal_ver=None): | |||||
# functions internal to the module | ||||||
|
||||||
|
||||||
def _select_options(pat): | ||||||
def _select_options(pat: str) -> List[str]: | ||||||
"""returns a list of keys matching `pat` | ||||||
|
||||||
if pat=="all", returns all registered options | ||||||
|
@@ -550,22 +555,22 @@ def _select_options(pat): | |||||
return [k for k in keys if re.search(pat, k, re.I)] | ||||||
|
||||||
|
||||||
def _get_root(key): | ||||||
def _get_root(key: str) -> Tuple[Dict[str, Any], str]: | ||||||
path = key.split(".") | ||||||
cursor = _global_config | ||||||
for p in path[:-1]: | ||||||
cursor = cursor[p] | ||||||
return cursor, path[-1] | ||||||
|
||||||
|
||||||
def _is_deprecated(key): | ||||||
def _is_deprecated(key: str) -> bool: | ||||||
""" Returns True if the given option has been deprecated """ | ||||||
|
||||||
key = key.lower() | ||||||
return key in _deprecated_options | ||||||
|
||||||
|
||||||
def _get_deprecated_option(key): | ||||||
def _get_deprecated_option(key: str): | ||||||
""" | ||||||
Retrieves the metadata for a deprecated option, if `key` is deprecated. | ||||||
|
||||||
|
@@ -582,7 +587,7 @@ def _get_deprecated_option(key): | |||||
return d | ||||||
|
||||||
|
||||||
def _get_registered_option(key): | ||||||
def _get_registered_option(key: str): | ||||||
""" | ||||||
Retrieves the option metadata if `key` is a registered option. | ||||||
|
||||||
|
@@ -593,7 +598,7 @@ def _get_registered_option(key): | |||||
return _registered_options.get(key) | ||||||
|
||||||
|
||||||
def _translate_key(key): | ||||||
def _translate_key(key: str) -> str: | ||||||
""" | ||||||
if key id deprecated and a replacement key defined, will return the | ||||||
replacement key, otherwise returns `key` as - is | ||||||
|
@@ -606,7 +611,7 @@ def _translate_key(key): | |||||
return key | ||||||
|
||||||
|
||||||
def _warn_if_deprecated(key): | ||||||
def _warn_if_deprecated(key: str) -> bool: | ||||||
""" | ||||||
Checks if `key` is a deprecated option and if so, prints a warning. | ||||||
|
||||||
|
@@ -634,7 +639,7 @@ def _warn_if_deprecated(key): | |||||
return False | ||||||
|
||||||
|
||||||
def _build_option_description(k): | ||||||
def _build_option_description(k: str) -> str: | ||||||
""" Builds a formatted description of a registered option and prints it """ | ||||||
|
||||||
o = _get_registered_option(k) | ||||||
|
@@ -659,7 +664,7 @@ def _build_option_description(k): | |||||
return s | ||||||
|
||||||
|
||||||
def pp_options_list(keys, width=80, _print=False): | ||||||
def pp_options_list(keys: Iterable[str], width=80, _print: bool = False): | ||||||
""" Builds a concise listing of available options, grouped by prefix """ | ||||||
|
||||||
from textwrap import wrap | ||||||
|
@@ -729,7 +734,7 @@ def config_prefix(prefix): | |||||
global register_option, get_option, set_option, reset_option | ||||||
|
||||||
def wrap(func): | ||||||
def inner(key, *args, **kwds): | ||||||
def inner(key: str, *args, **kwds) -> Callable[[str], Any]: | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this should be annotated using the pattern for decorators i.e annotate the outer function using a typevar and cast the return type of inner function, see https://mypy.readthedocs.io/en/latest/generics.html#declaring-decorators no need to annotate the inner function |
||||||
pkey = f"{prefix}.{key}" | ||||||
return func(pkey, *args, **kwds) | ||||||
|
||||||
|
@@ -751,7 +756,7 @@ def inner(key, *args, **kwds): | |||||
# arg in register_option | ||||||
|
||||||
|
||||||
def is_type_factory(_type): | ||||||
def is_type_factory(_type) -> Callable[..., None]: | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the returned function accepts exactly one argument
Suggested change
|
||||||
""" | ||||||
|
||||||
Parameters | ||||||
|
@@ -765,14 +770,14 @@ def is_type_factory(_type): | |||||
|
||||||
""" | ||||||
|
||||||
def inner(x): | ||||||
def inner(x) -> None: | ||||||
if type(x) != _type: | ||||||
raise ValueError(f"Value must have type '{_type}'") | ||||||
|
||||||
return inner | ||||||
|
||||||
|
||||||
def is_instance_factory(_type): | ||||||
def is_instance_factory(_type) -> Callable[..., None]: | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the returned function accepts exactly one argument
Suggested change
|
||||||
""" | ||||||
|
||||||
Parameters | ||||||
|
@@ -792,19 +797,19 @@ def is_instance_factory(_type): | |||||
else: | ||||||
type_repr = f"'{_type}'" | ||||||
|
||||||
def inner(x): | ||||||
def inner(x) -> None: | ||||||
if not isinstance(x, _type): | ||||||
raise ValueError(f"Value must be an instance of {type_repr}") | ||||||
|
||||||
return inner | ||||||
|
||||||
|
||||||
def is_one_of_factory(legal_values): | ||||||
def is_one_of_factory(legal_values) -> Callable[..., None]: | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
||||||
callables = [c for c in legal_values if callable(c)] | ||||||
legal_values = [c for c in legal_values if not callable(c)] | ||||||
|
||||||
def inner(x): | ||||||
def inner(x) -> None: | ||||||
if x not in legal_values: | ||||||
|
||||||
if not any(c(x) for c in callables): | ||||||
|
@@ -818,7 +823,7 @@ def inner(x): | |||||
return inner | ||||||
|
||||||
|
||||||
def is_nonnegative_int(value): | ||||||
def is_nonnegative_int(value: Optional[int]) -> None: | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. strange that this returns None. I would expect a function named is_* to return True/False. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think OK to rename this |
||||||
""" | ||||||
Verify that value is None or a positive int. | ||||||
|
||||||
|
@@ -853,7 +858,7 @@ def is_nonnegative_int(value): | |||||
is_text = is_instance_factory((str, bytes)) | ||||||
|
||||||
|
||||||
def is_callable(obj): | ||||||
def is_callable(obj) -> bool: | ||||||
""" | ||||||
|
||||||
Parameters | ||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I vaguely recall this coming up elsewhere. Actually looks like this is inconsistent in typeshed though stdlib matches what's here:
https://github.com/python/typeshed/blob/a1331accbe98ae5f214b824121e5223e52a474f7/stdlib/2and3/builtins.pyi#L67
No strong preference on either, just adding for visibility
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I got the same feeling while annotating this.
So I looked hard in my previous PR until I found it.
#30411 (comment)