|
7 | 7 | """
|
8 | 8 | import functools
|
9 | 9 | import textwrap
|
| 10 | +import warnings |
10 | 11 |
|
11 | 12 | import numpy as np
|
12 | 13 | from pygmt.exceptions import GMTInvalidInput
|
@@ -439,3 +440,82 @@ def new_module(*args, **kwargs):
|
439 | 440 | return new_module
|
440 | 441 |
|
441 | 442 | return converter
|
| 443 | + |
| 444 | + |
| 445 | +def deprecate_parameter(oldname, newname, deprecate_version, remove_version): |
| 446 | + """ |
| 447 | + Decorator to deprecate a parameter. |
| 448 | +
|
| 449 | + The old parameter name will be automatically swapped to the new parameter |
| 450 | + name, and users will receive a FutureWarning to inform them of the pending |
| 451 | + deprecation. |
| 452 | +
|
| 453 | + Use this decorator below the ``use_alias`` decorator. |
| 454 | +
|
| 455 | + Parameters |
| 456 | + ---------- |
| 457 | + oldname : str |
| 458 | + The old, deprecated parameter name. |
| 459 | + newname : str |
| 460 | + The new parameter name. |
| 461 | + deprecate_version : str |
| 462 | + The PyGMT version when the old parameter starts to be deprecated. |
| 463 | + remove_version : str |
| 464 | + The PyGMT version when the old parameter will be fully removed. |
| 465 | +
|
| 466 | + Examples |
| 467 | + -------- |
| 468 | + >>> @deprecate_parameter("sizes", "size", "v0.0.0", "v9.9.9") |
| 469 | + ... @deprecate_parameter("colors", "color", "v0.0.0", "v9.9.9") |
| 470 | + ... @deprecate_parameter("infile", "data", "v0.0.0", "v9.9.9") |
| 471 | + ... def module(data, size=0, **kwargs): |
| 472 | + ... "A module that prints the arguments it received" |
| 473 | + ... print(f"data={data}, size={size}, color={kwargs['color']}") |
| 474 | + >>> # new names are supported |
| 475 | + >>> module(data="table.txt", size=5.0, color="red") |
| 476 | + data=table.txt, size=5.0, color=red |
| 477 | + >>> # old names are supported, FutureWarning warnings are reported |
| 478 | + >>> with warnings.catch_warnings(record=True) as w: |
| 479 | + ... module(infile="table.txt", sizes=5.0, colors="red") |
| 480 | + ... # check the number of warnings |
| 481 | + ... assert len(w) == 3 |
| 482 | + ... for i in range(len(w)): |
| 483 | + ... assert issubclass(w[i].category, FutureWarning) |
| 484 | + ... assert "deprecated" in str(w[i].message) |
| 485 | + ... |
| 486 | + data=table.txt, size=5.0, color=red |
| 487 | + >>> # using both old and new names will raise an GMTInvalidInput exception |
| 488 | + >>> import pytest |
| 489 | + >>> with pytest.raises(GMTInvalidInput): |
| 490 | + ... module(data="table.txt", size=5.0, sizes=4.0) |
| 491 | + ... |
| 492 | + """ |
| 493 | + |
| 494 | + def deprecator(module_func): |
| 495 | + """ |
| 496 | + The decorator that creates the new function to work with both old and |
| 497 | + new parameters. |
| 498 | + """ |
| 499 | + |
| 500 | + @functools.wraps(module_func) |
| 501 | + def new_module(*args, **kwargs): |
| 502 | + """ |
| 503 | + New module instance that converts old parameters to new parameters. |
| 504 | + """ |
| 505 | + if oldname in kwargs: |
| 506 | + if newname in kwargs: |
| 507 | + raise GMTInvalidInput( |
| 508 | + f"Can't provide both '{newname}' and '{oldname}'." |
| 509 | + ) |
| 510 | + msg = ( |
| 511 | + f"The '{oldname}' parameter has been deprecated since {deprecate_version}" |
| 512 | + f" and will be removed in {remove_version}." |
| 513 | + f" Please use '{newname}' instead." |
| 514 | + ) |
| 515 | + warnings.warn(msg, category=FutureWarning, stacklevel=2) |
| 516 | + kwargs[newname] = kwargs.pop(oldname) |
| 517 | + return module_func(*args, **kwargs) |
| 518 | + |
| 519 | + return new_module |
| 520 | + |
| 521 | + return deprecator |
0 commit comments