Skip to content

Commit

Permalink
Document the deprecation policy and addd the deprecate_parameter deco…
Browse files Browse the repository at this point in the history
…rator to deprecate parameters (#1160)

* Add the deprecate_parameter decorator to deprecate parameters
* Use FutureWarning instead of DeprecationWarning
* Document the deprecation policy

Co-authored-by: Wei Ji <[email protected]>
Co-authored-by: Meghan Jones <[email protected]>
Co-authored-by: Yao Jiayuan <[email protected]>
  • Loading branch information
4 people authored Apr 19, 2021
1 parent 8274dc5 commit 3469dfe
Show file tree
Hide file tree
Showing 3 changed files with 127 additions and 1 deletion.
41 changes: 41 additions & 0 deletions doc/maintenance.md
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,47 @@ supported version of Python. Minimum Python and NumPy version support should be
adjusted upward on every major and minor release, but never on a patch release.


## Backwards compatibility and deprecation policy

PyGMT is still undergoing rapid developement. All of the API is subject to change
until the v1.0.0 release.

Basic policy for backwards compatibility:

- Any incompatible changes should go through the deprecation process below.
- Incompatible changes are only allowed in major and minor releases, not in
patch releases.
- Incompatible changes should be documented in the release notes.

When making incompatible changes, we should follow the process:

- Discuss whether the incompatible changes are necessary on GitHub.
- Make the changes in a backwards compatible way, and raise a `FutureWarning`
warning for old usage. At least one test using the old usage should be added.
- The warning message should clearly explain the changes and include the versions
in which the old usage is deprecated and is expected to be removed.
- The `FutureWarning` warning should appear for 2-4 minor versions, depending on
the impact of the changes. It means the deprecation period usually lasts
3-12 months.
- Remove the old usage and warning when reaching the declared version.

To rename a function parameter, add the `@deprecated_parameter` decorator
before the function definition (but after the `@use_alias` decorator if it exists).
Here is an example:

```
@fmt_docstring
@use_alias(J="projection", R="region", V="verbose")
@kwargs_to_strings(R="sequence")
@deprecate_parameter("sizes", "size", "v0.4.0", remove_version="v0.6.0")
def plot(self, x=None, y=None, data=None, size=None, direction=None, **kwargs):
pass
```

In this case, the old parameter name `sizes` is deprecated since v0.4.0, and will be
fully removed in v0.6.0. The new parameter name is `size`.


## Making a Release

We try to automate the release process as much as possible.
Expand Down
7 changes: 6 additions & 1 deletion pygmt/helpers/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
"""
Functions, classes, decorators, and context managers to help wrap GMT modules.
"""
from pygmt.helpers.decorators import fmt_docstring, kwargs_to_strings, use_alias
from pygmt.helpers.decorators import (
deprecate_parameter,
fmt_docstring,
kwargs_to_strings,
use_alias,
)
from pygmt.helpers.tempfile import GMTTempFile, unique_name
from pygmt.helpers.utils import (
args_in_kwargs,
Expand Down
80 changes: 80 additions & 0 deletions pygmt/helpers/decorators.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"""
import functools
import textwrap
import warnings

import numpy as np
from pygmt.exceptions import GMTInvalidInput
Expand Down Expand Up @@ -439,3 +440,82 @@ def new_module(*args, **kwargs):
return new_module

return converter


def deprecate_parameter(oldname, newname, deprecate_version, remove_version):
"""
Decorator to deprecate a parameter.
The old parameter name will be automatically swapped to the new parameter
name, and users will receive a FutureWarning to inform them of the pending
deprecation.
Use this decorator below the ``use_alias`` decorator.
Parameters
----------
oldname : str
The old, deprecated parameter name.
newname : str
The new parameter name.
deprecate_version : str
The PyGMT version when the old parameter starts to be deprecated.
remove_version : str
The PyGMT version when the old parameter will be fully removed.
Examples
--------
>>> @deprecate_parameter("sizes", "size", "v0.0.0", "v9.9.9")
... @deprecate_parameter("colors", "color", "v0.0.0", "v9.9.9")
... @deprecate_parameter("infile", "data", "v0.0.0", "v9.9.9")
... def module(data, size=0, **kwargs):
... "A module that prints the arguments it received"
... print(f"data={data}, size={size}, color={kwargs['color']}")
>>> # new names are supported
>>> module(data="table.txt", size=5.0, color="red")
data=table.txt, size=5.0, color=red
>>> # old names are supported, FutureWarning warnings are reported
>>> with warnings.catch_warnings(record=True) as w:
... module(infile="table.txt", sizes=5.0, colors="red")
... # check the number of warnings
... assert len(w) == 3
... for i in range(len(w)):
... assert issubclass(w[i].category, FutureWarning)
... assert "deprecated" in str(w[i].message)
...
data=table.txt, size=5.0, color=red
>>> # using both old and new names will raise an GMTInvalidInput exception
>>> import pytest
>>> with pytest.raises(GMTInvalidInput):
... module(data="table.txt", size=5.0, sizes=4.0)
...
"""

def deprecator(module_func):
"""
The decorator that creates the new function to work with both old and
new parameters.
"""

@functools.wraps(module_func)
def new_module(*args, **kwargs):
"""
New module instance that converts old parameters to new parameters.
"""
if oldname in kwargs:
if newname in kwargs:
raise GMTInvalidInput(
f"Can't provide both '{newname}' and '{oldname}'."
)
msg = (
f"The '{oldname}' parameter has been deprecated since {deprecate_version}"
f" and will be removed in {remove_version}."
f" Please use '{newname}' instead."
)
warnings.warn(msg, category=FutureWarning, stacklevel=2)
kwargs[newname] = kwargs.pop(oldname)
return module_func(*args, **kwargs)

return new_module

return deprecator

0 comments on commit 3469dfe

Please sign in to comment.