提交 936554c1 authored 作者: Michael Osthege's avatar Michael Osthege 提交者: Brandon T. Willard

Deprecate change_flags and _config_print in theano.configparser

上级 9b2ad15f
...@@ -9,6 +9,25 @@ from theano.configdefaults import default_blas_ldflags ...@@ -9,6 +9,25 @@ from theano.configdefaults import default_blas_ldflags
from theano.configparser import ConfigParam from theano.configparser import ConfigParam
def test_api_deprecation_warning():
# accessing through configdefaults.config is the new best practice
with pytest.warns(None):
root = configdefaults.config
assert isinstance(str(root), str)
# accessing through configparser.config is discouraged
root = configparser.config
with pytest.warns(DeprecationWarning, match="instead"):
root.add(
"test_deprecationwarning",
"A config var from a test case.",
configparser.StrParam("test_default"),
)
with pytest.warns(DeprecationWarning, match="instead"):
with root.change_flags(test_deprecationwarning="new_value"):
pass
def test_invalid_default(): def test_invalid_default():
# Ensure an invalid default value found in the Theano code only causes # Ensure an invalid default value found in the Theano code only causes
# a crash if it is not overridden by the user. # a crash if it is not overridden by the user.
......
...@@ -64,7 +64,12 @@ for p in sys.path: ...@@ -64,7 +64,12 @@ for p in sys.path:
raise RuntimeError("You have the theano directory in your Python path.") raise RuntimeError("You have the theano directory in your Python path.")
from theano.configdefaults import config from theano.configdefaults import config
from theano.configparser import change_flags from theano.utils import deprecated
change_flags = deprecated("Use theano.config.change_flags instead!")(
config.change_flags
)
# This is the api version for ops that generate C code. External ops # This is the api version for ops that generate C code. External ops
......
...@@ -2232,10 +2232,15 @@ SUPPORTED_DNN_CONV_PRECISION = ( ...@@ -2232,10 +2232,15 @@ SUPPORTED_DNN_CONV_PRECISION = (
"float64", "float64",
) )
# TODO: we should add the configs explicitly to an instance of the TheanoConfigParser # Eventually, the instance of `TheanoConfigParser` should be created right here,
# Even if we treat it as a singleton, we should implement as if it wasn't, so we can # where it is also populated with settings. But for a transition period, it
# test it independently. # remains as `configparser._config`, while everybody accessing it through
config = theano.configparser.config # `configparser.config` is flooded with deprecation warnings. These warnings
# instruct one to use `theano.config`, which is an alias for
# `theano.configdefaults.config`.
config = theano.configparser._config
# The functions below register config variables into the config instance above.
add_basic_configvars() add_basic_configvars()
add_dnn_configvars() add_dnn_configvars()
add_magma_configvars() add_magma_configvars()
......
...@@ -15,6 +15,8 @@ from configparser import ( ...@@ -15,6 +15,8 @@ from configparser import (
from functools import wraps from functools import wraps
from io import StringIO from io import StringIO
from theano.utils import deprecated
_logger = logging.getLogger("theano.configparser") _logger = logging.getLogger("theano.configparser")
...@@ -161,8 +163,11 @@ class TheanoConfigParser: ...@@ -161,8 +163,11 @@ class TheanoConfigParser:
# The user provided a value, filter it now. # The user provided a value, filter it now.
configparam.__get__(self, type(self), delete_key=True) configparam.__get__(self, type(self), delete_key=True)
except KeyError: except KeyError:
_logger.error( # This is raised because the underlying `ConfigParser` in
f"Suppressed KeyError in AddConfigVar for parameter '{name}'!" # `self._theano_cfg` does not contain an entry for the given
# section and/or value.
_logger.info(
f"Suppressed KeyError in TheanoConfigParser.add for parameter '{name}'!"
) )
# the ConfigParam implements __get__/__set__, enabling us to create a property: # the ConfigParam implements __get__/__set__, enabling us to create a property:
...@@ -263,7 +268,7 @@ class ConfigParam: ...@@ -263,7 +268,7 @@ class ConfigParam:
self.in_c_key = None self.in_c_key = None
# Note that we do not call `self.filter` on the default value: this # Note that we do not call `self.filter` on the default value: this
# will be done automatically in AddConfigVar, potentially with a # will be done automatically in TheanoConfigParser.add, potentially with a
# more appropriate user-provided default value. # more appropriate user-provided default value.
# Calling `filter` here may actually be harmful if the default value is # Calling `filter` here may actually be harmful if the default value is
# invalid and causes a crash or has unwanted side effects. # invalid and causes a crash or has unwanted side effects.
...@@ -527,8 +532,48 @@ def _create_default_config(): ...@@ -527,8 +532,48 @@ def _create_default_config():
return config return config
config = _create_default_config() # will be overwritten by configdefaults
# aliasing for old API class ConfigProxy:
AddConfigVar = config.add def __init__(self, actual):
change_flags = config.change_flags ConfigProxy._actual = actual
_config_print = config.config_print
def __getattr__(self, attr):
if attr == "_actual":
return ConfigProxy._actual
warnings.warn(
"Accessing config through `theano.configparser.config` is deprecated. "
"Use `theano.config` instead.",
DeprecationWarning,
stacklevel=2,
)
return getattr(self._actual, attr)
def __setattr__(self, attr, value):
if attr == "_actual":
return setattr(ConfigProxy._actual, attr, value)
warnings.warn(
"Accessing config through `theano.configparser.config` is deprecated. "
"Use `theano.config` instead.",
DeprecationWarning,
stacklevel=2,
)
return setattr(self._actual, attr, value)
# Create the actual instance of the config. This one should eventually move to
# `configdefaults`:
_config = _create_default_config()
# The old API often imported the default config object from `configparser`.
# These imports/accesses should be replaced with `theano.config`, so this wraps
# it with warnings:
config = ConfigProxy(_config)
# We can't alias the methods of the `config` variable above without already
# triggering the warning. Instead, we wrap the methods of the actual instance
# with warnings:
change_flags = deprecated("Use theano.config.change_flags instead!")(
_config.change_flags
)
_config_print = deprecated("Use theano.config.config_print instead!")(
_config.config_print
)
"""Utility functions for Theano.""" """Utility functions for Theano."""
import inspect
import traceback
import warnings
from collections import OrderedDict from collections import OrderedDict
from collections.abc import Callable from collections.abc import Callable
from functools import wraps
__all__ = [ __all__ = [
...@@ -110,3 +114,35 @@ def maybe_add_to_os_environ_pathlist(var, newpath): ...@@ -110,3 +114,35 @@ def maybe_add_to_os_environ_pathlist(var, newpath):
os.environ[var] = newpaths os.environ[var] = newpaths
except Exception: except Exception:
pass pass
def deprecated(message: str = ""):
"""
This is a decorator which can be used to mark functions
as deprecated. It will result in a warning being emitted
when the function is used first time and filter is set for show DeprecationWarning.
Taken from https://stackoverflow.com/a/40899499/4473230
"""
def decorator_wrapper(func):
@wraps(func)
def function_wrapper(*args, **kwargs):
current_call_source = "|".join(
traceback.format_stack(inspect.currentframe())
)
if current_call_source not in function_wrapper.last_call_source:
warnings.warn(
"Function {} is now deprecated! {}".format(func.__name__, message),
category=DeprecationWarning,
stacklevel=2,
)
function_wrapper.last_call_source.add(current_call_source)
return func(*args, **kwargs)
function_wrapper.last_call_source = set()
return function_wrapper
return decorator_wrapper
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论