|
73 | 73 | # |
74 | 74 |
|
75 | 75 | # stdlib |
76 | | -import functools |
77 | 76 | import inspect |
78 | 77 | import sys |
79 | | -import textwrap |
80 | 78 | import typing |
81 | | -import warnings |
82 | | -from datetime import date |
83 | 79 | from math import log10 |
84 | 80 | from pprint import pformat |
85 | 81 | from typing import Any, Callable, Dict, Iterable, List, Optional, Tuple, Union |
86 | 82 |
|
87 | 83 | # 3rd party |
88 | | -import deprecation # type: ignore |
89 | | -from packaging import version |
| 84 | +from deprecation_alias import deprecated # type: ignore # TODO |
90 | 85 |
|
91 | 86 | # this package |
92 | 87 | import domdf_python_tools.words |
| 88 | +from domdf_python_tools import __version__ |
93 | 89 | from domdf_python_tools.typing import HasHead, String |
94 | 90 |
|
95 | 91 | if typing.TYPE_CHECKING or domdf_python_tools.__docs: # pragma: no cover |
@@ -358,174 +354,12 @@ def head(obj: Union[Tuple, List, "DataFrame", "Series", String, HasHead], n: int |
358 | 354 | return str(obj[:n]) + etc # type: ignore |
359 | 355 |
|
360 | 356 |
|
361 | | -def deprecated( |
362 | | - deprecated_in: Optional[str] = None, |
363 | | - removed_in: Optional[str] = None, |
364 | | - current_version: Optional[str] = None, |
365 | | - details: str = '', |
366 | | - name: Optional[str] = None |
367 | | - ): |
368 | | - r"""Decorate a function to signify its deprecation. |
369 | | -
|
370 | | - This function wraps a method that will soon be removed and does two things: |
371 | | -
|
372 | | - * The docstring of the method will be modified to include a notice |
373 | | - about deprecation, e.g., "Deprecated since 0.9.11. Use foo instead." |
374 | | - * Raises a :class:`~deprecation.DeprecatedWarning` |
375 | | - via the :mod:`warnings` module, which is a subclass of the built-in |
376 | | - :class:`DeprecationWarning`. Note that built-in |
377 | | - :class:`DeprecationWarning`\s are ignored by default, so for users |
378 | | - to be informed of said warnings they will need to enable them -- see |
379 | | - the :mod:`warnings` module documentation for more details. |
380 | | -
|
381 | | - :param deprecated_in: The version at which the decorated method is considered |
382 | | - deprecated. This will usually be the next version to be released when |
383 | | - the decorator is added. The default is :py:obj:`None`, which effectively |
384 | | - means immediate deprecation. If this is not specified, then the |
385 | | - ``removed_in`` and ``current_version`` arguments are ignored. |
386 | | - :no-default deprecated_in: |
387 | | -
|
388 | | - :param removed_in: The version or :class:`datetime.date` when the decorated |
389 | | - method will be removed. The default is :py:obj:`None`, specifying that |
390 | | - the function is not currently planned to be removed. |
391 | | -
|
392 | | - .. note:: |
393 | | -
|
394 | | - This parameter cannot be set to a value if ``deprecated_in=None``. |
395 | | -
|
396 | | - :no-default removed_in: |
397 | | -
|
398 | | - :param current_version: The source of version information for the currently |
399 | | - running code. This will usually be a ``__version__`` attribute in your |
400 | | - library. The default is :py:obj:`None`. When ``current_version=None`` |
401 | | - the automation to determine if the wrapped function is actually in |
402 | | - a period of deprecation or time for removal does not work, causing a |
403 | | - :class:`~deprecation.DeprecatedWarning` to be raised in all cases. |
404 | | - :no-default current_version: |
405 | | -
|
406 | | - :param details: Extra details to be added to the method docstring and |
407 | | - warning. For example, the details may point users to a replacement |
408 | | - method, such as "Use the foo_bar method instead". |
409 | | -
|
410 | | - :param name: The name of the deprecated function, if an alias is being |
411 | | - deprecated. Default is to the name of the decorated function. |
412 | | - :no-default name: |
413 | | - """ |
414 | | - |
415 | | - # You can't just jump to removal. It's weird, unfair, and also makes |
416 | | - # building up the docstring weird. |
417 | | - if deprecated_in is None and removed_in is not None: |
418 | | - raise TypeError("Cannot set removed_in to a value without also setting deprecated_in") |
419 | | - |
420 | | - # Only warn when it's appropriate. There may be cases when it makes sense |
421 | | - # to add this decorator before a formal deprecation period begins. |
422 | | - # In CPython, PendingDeprecatedWarning gets used in that period, |
423 | | - # so perhaps mimick that at some point. |
424 | | - is_deprecated = False |
425 | | - is_unsupported = False |
426 | | - |
427 | | - # StrictVersion won't take a None or a "", so make whatever goes to it |
428 | | - # is at least *something*. Compare versions only if removed_in is not |
429 | | - # of type datetime.date |
430 | | - if isinstance(removed_in, date): |
431 | | - if date.today() >= removed_in: |
432 | | - is_unsupported = True |
433 | | - else: |
434 | | - is_deprecated = True |
435 | | - elif current_version: |
436 | | - current_version = version.parse(current_version) # type: ignore |
437 | | - |
438 | | - if removed_in is not None and current_version >= version.parse(removed_in): # type: ignore |
439 | | - is_unsupported = True |
440 | | - elif deprecated_in is not None and current_version >= version.parse(deprecated_in): # type: ignore |
441 | | - is_deprecated = True |
442 | | - else: |
443 | | - # If we can't actually calculate that we're in a period of |
444 | | - # deprecation...well, they used the decorator, so it's deprecated. |
445 | | - # This will cover the case of someone just using |
446 | | - # @deprecated("1.0") without the other advantages. |
447 | | - is_deprecated = True |
448 | | - |
449 | | - should_warn = any([is_deprecated, is_unsupported]) |
450 | | - |
451 | | - def _function_wrapper(function): |
452 | | - # Everything *should* have a docstring, but just in case... |
453 | | - existing_docstring = function.__doc__ or '' |
454 | | - |
455 | | - # split docstring at first occurrence of newline |
456 | | - string_list = existing_docstring.split('\n', 1) |
457 | | - |
458 | | - if should_warn: |
459 | | - # The various parts of this decorator being optional makes for |
460 | | - # a number of ways the deprecation notice could go. The following |
461 | | - # makes for a nicely constructed sentence with or without any |
462 | | - # of the parts. |
463 | | - |
464 | | - parts = {"deprecated_in": '', "removed_in": '', "details": ''} |
465 | | - |
466 | | - if deprecated_in: |
467 | | - parts["deprecated_in"] = f" {deprecated_in}" |
468 | | - if removed_in: |
469 | | - # If removed_in is a date, use "removed on" |
470 | | - # If removed_in is a version, use "removed in" |
471 | | - if isinstance(removed_in, date): |
472 | | - parts["removed_in"] = f"\n This will be removed on {removed_in}." |
473 | | - else: |
474 | | - parts["removed_in"] = f"\n This will be removed in {removed_in}." |
475 | | - if details: |
476 | | - parts["details"] = f" {details}" |
477 | | - |
478 | | - deprecation_note = (".. deprecated::{deprecated_in}{removed_in}{details}".format_map(parts)) |
479 | | - |
480 | | - # default location for insertion of deprecation note |
481 | | - loc = 1 |
482 | | - |
483 | | - if len(string_list) > 1: |
484 | | - # With a multi-line docstring, when we modify |
485 | | - # existing_docstring to add our deprecation_note, |
486 | | - # if we're not careful we'll interfere with the |
487 | | - # indentation levels of the contents below the |
488 | | - # first line, or as PEP 257 calls it, the summary |
489 | | - # line. Since the summary line can start on the |
490 | | - # same line as the """, dedenting the whole thing |
491 | | - # won't help. Split the summary and contents up, |
492 | | - # dedent the contents independently, then join |
493 | | - # summary, dedent'ed contents, and our |
494 | | - # deprecation_note. |
495 | | - |
496 | | - # in-place dedent docstring content |
497 | | - string_list[1] = textwrap.dedent(string_list[1]) |
498 | | - |
499 | | - # we need another newline |
500 | | - string_list.insert(loc, '\n') |
501 | | - |
502 | | - # change the message_location if we add to end of docstring |
503 | | - # do this always if not "top" |
504 | | - if deprecation.message_location != "top": |
505 | | - loc = 3 |
506 | | - |
507 | | - # insert deprecation note and dual newline |
508 | | - string_list.insert(loc, deprecation_note) |
509 | | - string_list.insert(loc, "\n\n") |
510 | | - |
511 | | - @functools.wraps(function) |
512 | | - def _inner(*args, **kwargs): |
513 | | - if should_warn: |
514 | | - if is_unsupported: |
515 | | - cls = deprecation.UnsupportedWarning |
516 | | - else: |
517 | | - cls = deprecation.DeprecatedWarning |
518 | | - |
519 | | - the_warning = cls(name or function.__name__, deprecated_in, removed_in, details) |
520 | | - warnings.warn(the_warning, category=DeprecationWarning, stacklevel=2) |
521 | | - |
522 | | - return function(*args, **kwargs) |
523 | | - |
524 | | - _inner.__doc__ = ''.join(string_list) |
525 | | - |
526 | | - return _inner |
527 | | - |
528 | | - return _function_wrapper |
| 357 | +deprecated = deprecated( |
| 358 | + deprecated_in="2.0.0", |
| 359 | + removed_in="2.3.0", |
| 360 | + current_version=__version__, |
| 361 | + details="Use the new 'deprecation-alias' package instead." |
| 362 | + )(deprecated) # yapf: disable |
529 | 363 |
|
530 | 364 |
|
531 | 365 | def magnitude(x: float) -> int: |
|
0 commit comments