Skip to content

TYP: some types for pandas/_config/config.py #29897

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

Merged
merged 2 commits into from
Nov 29, 2019
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 27 additions & 32 deletions pandas/_config/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
from collections import namedtuple
from contextlib import contextmanager
import re
from typing import Dict, List
from typing import Any, Dict, Iterable, List
import warnings

DeprecatedOption = namedtuple("DeprecatedOption", "key msg rkey removal_ver")
Expand All @@ -64,7 +64,7 @@
_registered_options: Dict[str, RegisteredOption] = {}

# holds the current values for registered options
_global_config: Dict[str, str] = {}
_global_config: Dict[str, Any] = {}

# keys which have a special meaning
_reserved_keys: List[str] = ["all"]
Expand All @@ -85,7 +85,7 @@ def _get_single_key(pat, silent):
if len(keys) == 0:
if not silent:
_warn_if_deprecated(pat)
raise OptionError("No such keys(s): {pat!r}".format(pat=pat))
raise OptionError(f"No such keys(s): {repr(pat)}")
if len(keys) > 1:
raise OptionError("Pattern matched multiple keys")
key = keys[0]
Expand Down Expand Up @@ -116,8 +116,8 @@ def _set_option(*args, **kwargs):
silent = kwargs.pop("silent", False)

if kwargs:
msg = '_set_option() got an unexpected keyword argument "{kwarg}"'
raise TypeError(msg.format(list(kwargs.keys())[0]))
kwarg = list(kwargs.keys())[0]
raise TypeError(f'_set_option() got an unexpected keyword argument "{kwarg}"')

for k, v in zip(args[::2], args[1::2]):
key = _get_single_key(k, silent)
Expand Down Expand Up @@ -412,7 +412,7 @@ def __exit__(self, *args):
_set_option(pat, val, silent=True)


def register_option(key, defval, doc="", validator=None, cb=None):
def register_option(key: str, defval: object, doc="", validator=None, cb=None):
"""Register an option in the package-wide pandas config object

Parameters
Expand Down Expand Up @@ -441,11 +441,9 @@ def register_option(key, defval, doc="", validator=None, cb=None):
key = key.lower()

if key in _registered_options:
msg = "Option '{key}' has already been registered"
raise OptionError(msg.format(key=key))
raise OptionError(f"Option '{key}' has already been registered")
if key in _reserved_keys:
msg = "Option '{key}' is a reserved key"
raise OptionError(msg.format(key=key))
raise OptionError(f"Option '{key}' is a reserved key")

# the default value should be legal
if validator:
Expand All @@ -455,10 +453,12 @@ def register_option(key, defval, doc="", validator=None, cb=None):
path = key.split(".")

for k in path:
if not bool(re.match("^" + tokenize.Name + "$", k)):
raise ValueError("{k} is not a valid identifier".format(k=k))
# NOTE: tokenize.Name is not a public constant
# error: Module has no attribute "Name" [attr-defined]
if not re.match("^" + tokenize.Name + "$", k): # type: ignore
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe worth considering tokenize.Name to \w+; it hasn't changed in 9 years:

https://github.com/python/cpython/blob/305189ecdc8322c22879a04564cad5989f937462/Lib/tokenize.py#L67

raise ValueError(f"{k} is not a valid identifier")
if keyword.iskeyword(k):
raise ValueError("{k} is a python keyword".format(k=k))
raise ValueError(f"{k} is a python keyword")

cursor = _global_config
msg = "Path prefix to option '{option}' is already an option"
Expand Down Expand Up @@ -522,8 +522,7 @@ def deprecate_option(key, msg=None, rkey=None, removal_ver=None):
key = key.lower()

if key in _deprecated_options:
msg = "Option '{key}' has already been defined as deprecated."
raise OptionError(msg.format(key=key))
raise OptionError(f"Option '{key}' has already been defined as deprecated.")

_deprecated_options[key] = DeprecatedOption(key, msg, rkey, removal_ver)

Expand Down Expand Up @@ -621,11 +620,11 @@ def _warn_if_deprecated(key):
print(d.msg)
warnings.warn(d.msg, FutureWarning)
else:
msg = "'{key}' is deprecated".format(key=key)
msg = f"'{key}' is deprecated"
if d.removal_ver:
msg += " and will be removed in {version}".format(version=d.removal_ver)
msg += f" and will be removed in {d.removal_ver}"
if d.rkey:
msg += ", please use '{rkey}' instead.".format(rkey=d.rkey)
msg += f", please use '{d.rkey}' instead."
else:
msg += ", please refrain from using it."

Expand All @@ -640,17 +639,15 @@ def _build_option_description(k):
o = _get_registered_option(k)
d = _get_deprecated_option(k)

s = "{k} ".format(k=k)
s = f"{k} "

if o.doc:
s += "\n".join(o.doc.strip().split("\n"))
else:
s += "No description available."

if o:
s += "\n [default: {default}] [currently: {current}]".format(
default=o.defval, current=_get_option(k, True)
)
s += f"\n [default: {o.defval}] [currently: {_get_option(k, True)}]"

if d:
s += "\n (Deprecated"
Expand All @@ -666,7 +663,7 @@ def pp_options_list(keys, width=80, _print=False):
from textwrap import wrap
from itertools import groupby

def pp(name, ks):
def pp(name: str, ks: Iterable[str]) -> List[str]:
pfx = "- " + name + ".[" if name else ""
ls = wrap(
", ".join(ks),
Expand All @@ -679,7 +676,7 @@ def pp(name, ks):
ls[-1] = ls[-1] + "]"
return ls

ls = []
ls: List[str] = []
singles = [x for x in sorted(keys) if x.find(".") < 0]
if singles:
ls += pp("", singles)
Expand Down Expand Up @@ -731,7 +728,7 @@ def config_prefix(prefix):

def wrap(func):
def inner(key, *args, **kwds):
pkey = "{prefix}.{key}".format(prefix=prefix, key=key)
pkey = f"{prefix}.{key}"
return func(pkey, *args, **kwds)

return inner
Expand Down Expand Up @@ -768,8 +765,7 @@ def is_type_factory(_type):

def inner(x):
if type(x) != _type:
msg = "Value must have type '{typ!s}'"
raise ValueError(msg.format(typ=_type))
raise ValueError(f"Value must have type '{_type}'")

return inner

Expand All @@ -792,12 +788,11 @@ def is_instance_factory(_type):
_type = tuple(_type)
type_repr = "|".join(map(str, _type))
else:
type_repr = "'{typ}'".format(typ=_type)
type_repr = f"'{_type}'"

def inner(x):
if not isinstance(x, _type):
msg = "Value must be an instance of {type_repr}"
raise ValueError(msg.format(type_repr=type_repr))
raise ValueError(f"Value must be an instance of {type_repr}")

return inner

Expand All @@ -813,10 +808,10 @@ def inner(x):
if not any(c(x) for c in callables):
uvals = [str(lval) for lval in legal_values]
pp_values = "|".join(uvals)
msg = "Value must be one of {pp_values}"
msg = f"Value must be one of {pp_values}"
if len(callables):
msg += " or a callable"
raise ValueError(msg.format(pp_values=pp_values))
raise ValueError(msg)

return inner

Expand Down