-
Notifications
You must be signed in to change notification settings - Fork 6.1k
[Utils] Add deprecate function and move testing_utils under utils #659
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
Conversation
The documentation is not available anymore as the PR was closed or merged. |
) | ||
deprecate("steps_offset!=1", "1.0.0", deprecation_message, standard_warn=False) |
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.
This is a big change and I like to keep it for a bit until we force people to not pass steps_offset
anymore.
|
||
offset = kwargs["offset"] | ||
deprecated_offset = deprecate( | ||
"offset", "0.5.0", "Please pass `steps_offset` to `__init__` instead.", take_from=kwargs |
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.
bump as we would have already missed this version
|
||
offset = kwargs["offset"] | ||
deprecated_offset = deprecate( | ||
"offset", "0.5.0", "Please pass `steps_offset` to `__init__` instead.", take_from=kwargs |
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.
bump as we would have already missed this version
" `'images'` instead.", | ||
DeprecationWarning, | ||
) | ||
deprecate("samples", "0.6.0", "Please use `.images` or `'images'` instead.") |
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.
bump twice as we would have already missed this version and it's important
from diffusers.utils import deprecate | ||
|
||
|
||
class DeprecateTester(unittest.TestCase): |
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.
This test best describes all the functionality that we need to ensure
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.
Thanks a lot for working on this, this will be very useful!
And really nice tests 😍 ! Love this way of explaining new features with tests.
src/diffusers/utils/testing_utils.py
Outdated
def deprecate(*args, take_from: Optional[Union[Dict, Any]] = None, standard_warn=True): | ||
from .. import __version__ | ||
|
||
deprecated_kwargs = take_from | ||
values = () | ||
if not isinstance(args[0], tuple): | ||
args = (args,) | ||
|
||
for attribute, version_name, message in args: | ||
if version.parse(version.parse(__version__).base_version) >= version.parse(version_name): | ||
raise ValueError( | ||
f"The deprecation tuple {(attribute, version_name, message)} should be removed since diffusers'" | ||
f" version {__version__} is >= {version_name}" | ||
) | ||
|
||
warning = None | ||
if isinstance(deprecated_kwargs, dict) and attribute in deprecated_kwargs: | ||
values += (deprecated_kwargs.pop(attribute),) | ||
warning = f"The `{attribute}` argument is deprecated and will be removed in version {version_name}." | ||
elif hasattr(deprecated_kwargs, attribute): | ||
values += (getattr(deprecated_kwargs, attribute),) | ||
warning = f"The `{attribute}` attribute is deprecated and will be removed in version {version_name}." | ||
elif deprecated_kwargs is None: | ||
warning = f"`{attribute}` is deprecated and will be removed in version {version_name}." | ||
|
||
if warning is not None: | ||
warning = warning + " " if standard_warn else "" | ||
warnings.warn(warning + message, DeprecationWarning) | ||
|
||
if isinstance(deprecated_kwargs, dict) and len(deprecated_kwargs) > 0: | ||
call_frame = inspect.getouterframes(inspect.currentframe())[1] | ||
filename = call_frame.filename | ||
line_number = call_frame.lineno | ||
function = call_frame.function | ||
key, value = next(iter(deprecated_kwargs.items())) | ||
raise TypeError(f"{function} in {filename} line {line_number-1} got an unexpected keyword argument `{key}`") | ||
|
||
if len(values) == 0: | ||
return |
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.
Very cool!
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.
Big +1
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.
This is extremely cool, and so useful! It was very helpful to start by reading the tests.
Seeing that deprecate
was inside testing_utils.py
sounded a bit off, so I looked more closely to see what was there and realized that we would be breaking import diffusers
when PyTorch is not installed. In any case, I believe that the semantics of the function call for moving it to another place.
deprecated_offset = deprecate( | ||
"offset", "0.5.0", "Please pass `steps_offset` to `__init__` instead.", take_from=kwargs | ||
) | ||
offset = deprecated_offset or self.config.steps_offset |
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.
Great naming here, the intention is very clear!
src/diffusers/utils/testing_utils.py
Outdated
def deprecate(*args, take_from: Optional[Union[Dict, Any]] = None, standard_warn=True): | ||
from .. import __version__ | ||
|
||
deprecated_kwargs = take_from | ||
values = () | ||
if not isinstance(args[0], tuple): | ||
args = (args,) | ||
|
||
for attribute, version_name, message in args: | ||
if version.parse(version.parse(__version__).base_version) >= version.parse(version_name): | ||
raise ValueError( | ||
f"The deprecation tuple {(attribute, version_name, message)} should be removed since diffusers'" | ||
f" version {__version__} is >= {version_name}" | ||
) | ||
|
||
warning = None | ||
if isinstance(deprecated_kwargs, dict) and attribute in deprecated_kwargs: | ||
values += (deprecated_kwargs.pop(attribute),) | ||
warning = f"The `{attribute}` argument is deprecated and will be removed in version {version_name}." | ||
elif hasattr(deprecated_kwargs, attribute): | ||
values += (getattr(deprecated_kwargs, attribute),) | ||
warning = f"The `{attribute}` attribute is deprecated and will be removed in version {version_name}." | ||
elif deprecated_kwargs is None: | ||
warning = f"`{attribute}` is deprecated and will be removed in version {version_name}." | ||
|
||
if warning is not None: | ||
warning = warning + " " if standard_warn else "" | ||
warnings.warn(warning + message, DeprecationWarning) | ||
|
||
if isinstance(deprecated_kwargs, dict) and len(deprecated_kwargs) > 0: | ||
call_frame = inspect.getouterframes(inspect.currentframe())[1] | ||
filename = call_frame.filename | ||
line_number = call_frame.lineno | ||
function = call_frame.function | ||
key, value = next(iter(deprecated_kwargs.items())) | ||
raise TypeError(f"{function} in {filename} line {line_number-1} got an unexpected keyword argument `{key}`") | ||
|
||
if len(values) == 0: | ||
return |
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.
Big +1
src/diffusers/utils/testing_utils.py
Outdated
from distutils.util import strtobool | ||
from pathlib import Path | ||
from typing import Union | ||
from typing import Any, Dict, Optional, Union | ||
|
||
import torch |
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 think this breaks import diffusers
if PyTorch is not installed.
We should move deprecate
to its own file. Not sure whether we should call it deprecate.py
, deprecation_utils.py
or something more general in case we need more functionality in the future.
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.
Sounds good! I'll add it to deprecation_utils.py
Regarding import torch
, this should be done in another PR - this is unrelated to this PR (import torch
was there before). We should definitely make sure though that the library doesn't break when torch
is not installed.
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.
Regarding
import torch
, this should be done in another PR - this is unrelated to this PR (import torch
was there before).
Yes, but testing_utils
was only imported when testing, that's really the difference (not the import
). I should have made it clearer in my comment :)
…ggingface#659) * [Utils] Add deprecate function * up * up * uP * up * up * up * up * uP * up * fix * up * move to deprecation utils file * fix * fix * fix more
…ace#659) (This goes on to produce compilation errors, but one step at a time)
…ggingface#659) * [Utils] Add deprecate function * up * up * uP * up * up * up * up * uP * up * fix * up * move to deprecation utils file * fix * fix * fix more
Improved deprecation functionality
We are introducing multiple deprecation cycles already and currently are missing structure on how to handle this exactly and by adding
**kwargs
to the scheduler config init we have lost functionality. More specifically:PNDMScheduler(num_inference_steps=5)
nothing happens because it's swallowed by **kwargs. However we should, just as before [Pytorch] add dep. warning for pytorch schedulers #651 throw a TypeError in this case.=> This PR solves this by introducing a
deprecate
function (which should be mainly used by maintainers) that automatically forces us to remove deprecated functionality correctly + solves 2. by throwing a type error. In addition it removes boiler plate code and should make it more efficient for us to deprecate things.The API of
deprecate
is as follows:=> This forces us to remove this statement when version >= 0.7.0, gives a nice default error message and makes sure that
kwargs
can only have deprecated args.Please take a look into the changes here and the tests to better understand all the functionality