Merge pull request #5542 from pradyunsg/dev-ops/deprecation-utilities

Introduce a helper function for deprecation
This commit is contained in:
Pradyun Gedam 2018-07-20 00:37:53 +05:30 committed by GitHub
commit 169ca95666
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 88 additions and 62 deletions

View File

@ -211,6 +211,12 @@ document existing behavior with the intention of covering that behavior with
the above deprecation process are always acceptable, and will be considered on
their merits.
.. note::
pip has a helper function for making deprecation easier for pip maintainers.
The supporting documentation can be found in the source code of
``pip._internal.utils.deprecation.deprecated``. The function is not a part of
pip's public API.
Release Process
===============

View File

@ -9,7 +9,6 @@ import os
import posixpath
import re
import sys
import warnings
from collections import namedtuple
from pip._vendor import html5lib, requests, six
@ -29,7 +28,7 @@ from pip._internal.exceptions import (
)
from pip._internal.models.index import PyPI
from pip._internal.pep425tags import get_supported
from pip._internal.utils.deprecation import RemovedInPip12Warning
from pip._internal.utils.deprecation import deprecated
from pip._internal.utils.logging import indent_log
from pip._internal.utils.misc import (
ARCHIVE_EXTENSIONS, SUPPORTED_EXTENSIONS, cached_property, normalize_path,
@ -212,10 +211,12 @@ class PackageFinder(object):
# # dependency_links value
# # FIXME: also, we should track comes_from (i.e., use Link)
if self.process_dependency_links:
warnings.warn(
deprecated(
"Dependency Links processing has been deprecated and will be "
"removed in a future release.",
RemovedInPip12Warning,
replacement=None,
gone_in="18.2",
issue=4187,
)
self.dependency_links.extend(links)

View File

@ -4,7 +4,6 @@ import collections
import logging
import os
import re
import warnings
from pip._vendor import pkg_resources, six
from pip._vendor.packaging.utils import canonicalize_name
@ -13,7 +12,7 @@ from pip._vendor.pkg_resources import RequirementParseError
from pip._internal.exceptions import InstallationError
from pip._internal.req import InstallRequirement
from pip._internal.req.req_file import COMMENT_RE
from pip._internal.utils.deprecation import RemovedInPip12Warning
from pip._internal.utils.deprecation import deprecated
from pip._internal.utils.misc import (
dist_is_editable, get_installed_distributions,
)
@ -216,10 +215,12 @@ class FrozenRequirement(object):
'for this package:'
)
else:
warnings.warn(
deprecated(
"SVN editable detection based on dependency links "
"will be dropped in the future.",
RemovedInPip12Warning,
replacement=None,
gone_in="18.2",
issue=4187,
)
comments.append(
'# Installing as editable to satisfy requirement %s:' %

View File

@ -8,7 +8,6 @@ import shutil
import sys
import sysconfig
import traceback
import warnings
import zipfile
from distutils.util import change_root
from email.parser import FeedParser # type: ignore
@ -33,7 +32,7 @@ from pip._internal.locations import (
PIP_DELETE_MARKER_FILENAME, running_under_virtualenv,
)
from pip._internal.req.req_uninstall import UninstallPathSet
from pip._internal.utils.deprecation import RemovedInPip12Warning
from pip._internal.utils.deprecation import deprecated
from pip._internal.utils.hashes import Hashes
from pip._internal.utils.logging import indent_log
from pip._internal.utils.misc import (
@ -582,11 +581,13 @@ class InstallRequirement(object):
if requires is None:
logging.warn(template, self, "it is missing.")
warnings.warn(
deprecated(
"Future versions of pip may reject packages with "
"pyproject.toml files that do not contain the [build-system]"
"table and the requires key, as specified in PEP 518.",
RemovedInPip12Warning,
replacement=None,
gone_in="18.2",
issue=5416,
)
# Currently, we're isolating the build based on the presence of the

View File

@ -6,68 +6,84 @@ from __future__ import absolute_import
import logging
import warnings
from pip._vendor.packaging.version import parse
from pip import __version__ as current_version
from pip._internal.utils.typing import MYPY_CHECK_RUNNING
if MYPY_CHECK_RUNNING:
from typing import Any # noqa: F401
from typing import Any, Optional # noqa: F401
class PipDeprecationWarning(Warning):
pass
class Pending(object):
pass
class RemovedInPip12Warning(PipDeprecationWarning, Pending):
pass
_original_showwarning = None # type: Any
# Warnings <-> Logging Integration
_warnings_showwarning = None # type: Any
def _showwarning(message, category, filename, lineno, file=None, line=None):
if file is not None:
if _warnings_showwarning is not None:
_warnings_showwarning(
if _original_showwarning is not None:
_original_showwarning(
message, category, filename, lineno, file, line,
)
elif issubclass(category, PipDeprecationWarning):
# We use a specially named logger which will handle all of the
# deprecation messages for pip.
logger = logging.getLogger("pip._internal.deprecations")
logger.warning(message)
else:
if issubclass(category, PipDeprecationWarning):
# We use a specially named logger which will handle all of the
# deprecation messages for pip.
logger = logging.getLogger("pip._internal.deprecations")
# This is purposely using the % formatter here instead of letting
# the logging module handle the interpolation. This is because we
# want it to appear as if someone typed this entire message out.
log_message = "DEPRECATION: %s" % message
# PipDeprecationWarnings that are Pending still have at least 2
# versions to go until they are removed so they can just be
# warnings. Otherwise, they will be removed in the very next
# version of pip. We want these to be more obvious so we use the
# ERROR logging level.
if issubclass(category, Pending):
logger.warning(log_message)
else:
logger.error(log_message)
else:
_warnings_showwarning(
message, category, filename, lineno, file, line,
)
_original_showwarning(
message, category, filename, lineno, file, line,
)
def install_warning_logger():
# Enable our Deprecation Warnings
warnings.simplefilter("default", PipDeprecationWarning, append=True)
global _warnings_showwarning
global _original_showwarning
if _warnings_showwarning is None:
_warnings_showwarning = warnings.showwarning
if _original_showwarning is None:
_original_showwarning = warnings.showwarning
warnings.showwarning = _showwarning
def deprecated(reason, replacement, gone_in, issue=None):
# type: (str, Optional[str], Optional[str], Optional[int]) -> None
"""Helper to deprecate existing functionality.
reason:
Textual reason shown to the user about why this functionality has
been deprecated.
replacement:
Textual suggestion shown to the user about what alternative
functionality they can use.
gone_in:
The version of pip does this functionality should get removed in.
Raises errors if pip's current version is greater than or equal to
this.
issue:
Issue number on the tracker that would serve as a useful place for
users to find related discussion and provide feedback.
Always pass replacement, gone_in and issue as keyword arguments for clarity
at the call site.
"""
# Construct a nice message.
# This is purposely eagerly formatted as we want it to appear as if someone
# typed this entire message out.
message = "DEPRECATION: " + reason
if replacement is not None:
message += " A possible replacement is {}.".format(replacement)
if issue is not None:
url = "https://github.com/pypa/pip/issues/" + str(issue)
message += " You can find discussion regarding this at {}.".format(url)
# Raise as an error if it has to be removed.
if gone_in is not None and parse(current_version) >= parse(gone_in):
raise PipDeprecationWarning(message)
warnings.warn(message, category=PipDeprecationWarning, stacklevel=2)

View File

@ -1,21 +1,22 @@
import textwrap
def test_environ(script, tmpdir):
"""$PYTHONWARNINGS was added in python2.7"""
demo = tmpdir.join('warnings_demo.py')
demo.write('''
from pip._internal.utils import deprecation
deprecation.install_warning_logger()
demo.write(textwrap.dedent('''
from logging import basicConfig
from pip._internal.utils import deprecation
from logging import basicConfig
basicConfig()
deprecation.install_warning_logger()
basicConfig()
from warnings import warn
warn("deprecated!", deprecation.PipDeprecationWarning)
''')
deprecation.deprecated("deprecated!", replacement=None, gone_in=None)
'''))
result = script.run('python', demo, expect_stderr=True)
assert result.stderr == \
'ERROR:pip._internal.deprecations:DEPRECATION: deprecated!\n'
expected = 'WARNING:pip._internal.deprecations:DEPRECATION: deprecated!\n'
assert result.stderr == expected
script.environ['PYTHONWARNINGS'] = 'ignore'
result = script.run('python', demo)