|
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