[Utils] Add deprecate function and move testing_utils under utils#659
[Utils] Add deprecate function and move testing_utils under utils#659patrickvonplaten merged 18 commits intomainfrom
Conversation
|
The documentation is not available anymore as the PR was closed or merged. |
| DeprecationWarning, | ||
| " file" | ||
| ) | ||
| deprecate("steps_offset!=1", "1.0.0", deprecation_message, standard_warn=False) |
There was a problem hiding this comment.
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.
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.
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.
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.
This test best describes all the functionality that we need to ensure
patil-suraj
left a comment
There was a problem hiding this comment.
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 |
pcuenca
left a comment
There was a problem hiding this comment.
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.
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 |
| from typing import Union | ||
| from typing import Any, Dict, Optional, Union | ||
|
|
||
| import torch |
There was a problem hiding this comment.
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.
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.
Regarding
import torch, this should be done in another PR - this is unrelated to this PR (import torchwas 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
**kwargsto 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
deprecatefunction (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
deprecateis as follows:=> This forces us to remove this statement when version >= 0.7.0, gives a nice default error message and makes sure that
kwargscan only have deprecated args.Please take a look into the changes here and the tests to better understand all the functionality