Repository: pypa/setuptools
Pull request #1545 (2018-10-27 20:37:52)

Custom Deprecation Warning classes.
Added custom deprecation warning classes because DeprecationWarning is not visible unless the user opts in.

Closes Issue #159

robinjhuang: Added unit tests, so the previous code coverage issue should be resolved now. Let us know if you want anything else changed :)

@martonp and I are interested in Python events in New York. Please let us know about future events. We had a lot of fun at this hackathon.

Our emails: 
marci93@gmail.com
robin.j.huang@gmail.com

Patch:
diff --git a/changelog.d/1545.feature.rst b/changelog.d/1545.feature.rst
new file mode 100644
index 000000000..70591d56d
--- /dev/null
+++ b/changelog.d/1545.feature.rst
@@ -0,0 +1,1 @@
+Changed the warning class of all deprecation warnings; deprecation warning classes are no longer derived from ``DeprecationWarning`` and are thus visible by default.
diff --git a/pkg_resources/__init__.py b/pkg_resources/__init__.py
index 741347013..d8e4c26b4 100644
--- a/pkg_resources/__init__.py
+++ b/pkg_resources/__init__.py
@@ -238,6 +238,9 @@ __all__ = [
     'register_finder', 'register_namespace_handler', 'register_loader_type',
     'fixup_namespace_packages', 'get_importer',
 
+    # Warnings
+    'PkgResourcesDeprecationWarning',
+
     # Deprecated/backward compatibility only
     'run_main', 'AvailableDistributions',
 ]
@@ -2335,7 +2338,7 @@ class EntryPoint:
             warnings.warn(
                 "Parameters to load are deprecated.  Call .resolve and "
                 ".require separately.",
-                DeprecationWarning,
+                PkgResourcesDeprecationWarning,
                 stacklevel=2,
             )
         if require:
@@ -3158,3 +3161,11 @@ def _initialize_master_working_set():
     # match order
     list(map(working_set.add_entry, sys.path))
     globals().update(locals())
+
+class PkgResourcesDeprecationWarning(Warning):
+    """
+    Base class for warning about deprecations in ``pkg_resources``
+
+    This class is not derived from ``DeprecationWarning``, and as such is
+    visible by default.
+    """
diff --git a/setuptools/__init__.py b/setuptools/__init__.py
index 54309b57f..e438036a8 100644
--- a/setuptools/__init__.py
+++ b/setuptools/__init__.py
@@ -8,6 +8,8 @@ import distutils.filelist
 from distutils.util import convert_path
 from fnmatch import fnmatchcase
 
+from ._deprecation_warning import SetuptoolsDeprecationWarning
+
 from setuptools.extern.six import PY3
 from setuptools.extern.six.moves import filter, map
 
@@ -22,6 +24,7 @@ __metaclass__ = type
 
 __all__ = [
     'setup', 'Distribution', 'Feature', 'Command', 'Extension', 'Require',
+    'SetuptoolsDeprecationWarning',
     'find_packages'
 ]
 
@@ -188,4 +191,5 @@ def findall(dir=os.curdir):
     return list(files)
 
 
+# Apply monkey patches
 monkey.patch_all()
diff --git a/setuptools/_deprecation_warning.py b/setuptools/_deprecation_warning.py
new file mode 100644
index 000000000..086b64dd3
--- /dev/null
+++ b/setuptools/_deprecation_warning.py
@@ -0,0 +1,7 @@
+class SetuptoolsDeprecationWarning(Warning):
+    """
+    Base class for warning deprecations in ``setuptools``
+
+    This class is not derived from ``DeprecationWarning``, and as such is
+    visible by default.
+    """
diff --git a/setuptools/command/easy_install.py b/setuptools/command/easy_install.py
index c670a16e6..06c98271b 100644
--- a/setuptools/command/easy_install.py
+++ b/setuptools/command/easy_install.py
@@ -40,8 +40,11 @@ import subprocess
 import shlex
 import io
 
+
 from sysconfig import get_config_vars, get_path
 
+from setuptools import SetuptoolsDeprecationWarning
+
 from setuptools.extern import six
 from setuptools.extern.six.moves import configparser, map
 
@@ -2077,7 +2080,7 @@ class ScriptWriter:
     @classmethod
     def get_script_args(cls, dist, executable=None, wininst=False):
         # for backward compatibility
-        warnings.warn("Use get_args", DeprecationWarning)
+        warnings.warn("Use get_args", EasyInstallDeprecationWarning)
         writer = (WindowsScriptWriter if wininst else ScriptWriter).best()
         header = cls.get_script_header("", executable, wininst)
         return writer.get_args(dist, header)
@@ -2085,7 +2088,7 @@ class ScriptWriter:
     @classmethod
     def get_script_header(cls, script_text, executable=None, wininst=False):
         # for backward compatibility
-        warnings.warn("Use get_header", DeprecationWarning, stacklevel=2)
+        warnings.warn("Use get_header", EasyInstallDeprecationWarning, stacklevel=2)
         if wininst:
             executable = "python.exe"
         return cls.get_header(script_text, executable)
@@ -2120,7 +2123,7 @@ class ScriptWriter:
     @classmethod
     def get_writer(cls, force_windows):
         # for backward compatibility
-        warnings.warn("Use best", DeprecationWarning)
+        warnings.warn("Use best", EasyInstallDeprecationWarning)
         return WindowsScriptWriter.best() if force_windows else cls.best()
 
     @classmethod
@@ -2152,7 +2155,7 @@ class WindowsScriptWriter(ScriptWriter):
     @classmethod
     def get_writer(cls):
         # for backward compatibility
-        warnings.warn("Use best", DeprecationWarning)
+        warnings.warn("Use best", EasyInstallDeprecationWarning)
         return cls.best()
 
     @classmethod
@@ -2333,3 +2336,7 @@ def _patch_usage():
         yield
     finally:
         distutils.core.gen_usage = saved
+
+class EasyInstallDeprecationWarning(SetuptoolsDeprecationWarning):
+    """Class for warning about deprecations in EasyInstall in SetupTools. Not ignored by default, unlike DeprecationWarning."""
+    
diff --git a/setuptools/command/egg_info.py b/setuptools/command/egg_info.py
index bd116e1f6..e1022d31f 100644
--- a/setuptools/command/egg_info.py
+++ b/setuptools/command/egg_info.py
@@ -31,7 +31,7 @@ import setuptools.unicode_utils as unicode_utils
 from setuptools.glob import glob
 
 from setuptools.extern import packaging
-
+from setuptools import SetuptoolsDeprecationWarning
 
 def translate_pattern(glob):
     """
@@ -696,7 +696,7 @@ def get_pkg_info_revision():
     Get a -r### off of PKG-INFO Version in case this is an sdist of
     a subversion revision.
     """
-    warnings.warn("get_pkg_info_revision is deprecated.", DeprecationWarning)
+    warnings.warn("get_pkg_info_revision is deprecated.", EggInfoDeprecationWarning)
     if os.path.exists('PKG-INFO'):
         with io.open('PKG-INFO') as f:
             for line in f:
@@ -704,3 +704,7 @@ def get_pkg_info_revision():
                 if match:
                     return int(match.group(1))
     return 0
+
+
+class EggInfoDeprecationWarning(SetuptoolsDeprecationWarning):
+    """Class for warning about deprecations in eggInfo in setupTools. Not ignored by default, unlike DeprecationWarning."""
diff --git a/setuptools/dist.py b/setuptools/dist.py
index 6ee4a97f3..f6078dbe0 100644
--- a/setuptools/dist.py
+++ b/setuptools/dist.py
@@ -21,6 +21,8 @@ from setuptools.extern import six
 from setuptools.extern import packaging
 from setuptools.extern.six.moves import map, filter, filterfalse
 
+from . import SetuptoolsDeprecationWarning
+
 from setuptools.depends import Require
 from setuptools import windows_support
 from setuptools.monkey import get_unpatched
@@ -33,7 +35,7 @@ __import__('setuptools.extern.packaging.version')
 
 
 def _get_unpatched(cls):
-    warnings.warn("Do not call this function", DeprecationWarning)
+    warnings.warn("Do not call this function", DistDeprecationWarning)
     return get_unpatched(cls)
 
 
@@ -980,7 +982,7 @@ class Feature:
             "Features are deprecated and will be removed in a future "
             "version. See https://github.com/pypa/setuptools/issues/65."
         )
-        warnings.warn(msg, DeprecationWarning, stacklevel=3)
+        warnings.warn(msg, DistDeprecationWarning, stacklevel=3)
 
     def __init__(
             self, description, standard=False, available=True,
@@ -1069,3 +1071,7 @@ class Feature:
                     " doesn't contain any packages or modules under %s"
                     % (self.description, item, item)
                 )
+
+
+class DistDeprecationWarning(SetuptoolsDeprecationWarning):
+    """Class for warning about deprecations in dist in setuptools. Not ignored by default, unlike DeprecationWarning."""


Test patch:
diff --git a/pkg_resources/tests/test_resources.py b/pkg_resources/tests/test_resources.py
index 171ba2f96..86afcf741 100644
--- a/pkg_resources/tests/test_resources.py
+++ b/pkg_resources/tests/test_resources.py
@@ -15,7 +15,7 @@ import pkg_resources
 from pkg_resources import (
     parse_requirements, VersionConflict, parse_version,
     Distribution, EntryPoint, Requirement, safe_version, safe_name,
-    WorkingSet)
+    WorkingSet, PkgResourcesDeprecationWarning)
 
 
 # from Python 3.6 docs.
@@ -492,6 +492,15 @@ class TestEntryPoints:
         with pytest.raises(ValueError):
             EntryPoint.parse_map(self.submap_str)
 
+    def testDeprecationWarnings(self):
+        ep = EntryPoint(
+            "foo", "pkg_resources.tests.test_resources", ["TestEntryPoints"],
+            ["x"]
+        )
+        with pytest.warns(pkg_resources.PkgResourcesDeprecationWarning):
+            ep.load(require=False)
+
+
 
 class TestRequirements:
     def testBasics(self):
diff --git a/setuptools/tests/test_dist.py b/setuptools/tests/test_dist.py
index 5162e1c98..223ad90c9 100644
--- a/setuptools/tests/test_dist.py
+++ b/setuptools/tests/test_dist.py
@@ -3,7 +3,7 @@
 from __future__ import unicode_literals
 
 import io
-
+from setuptools.dist import DistDeprecationWarning, _get_unpatched
 from setuptools import Distribution
 from setuptools.extern.six.moves.urllib.request import pathname2url
 from setuptools.extern.six.moves.urllib_parse import urljoin
@@ -56,6 +56,9 @@ def test_dist_fetch_build_egg(tmpdir):
     assert [dist.key for dist in resolved_dists if dist] == reqs
 
 
+def test_dist__get_unpatched_deprecated():
+    pytest.warns(DistDeprecationWarning, _get_unpatched, [""])
+
 def __maintainer_test_cases():
     attrs = {"name": "package",
              "version": "1.0",
diff --git a/setuptools/tests/test_easy_install.py b/setuptools/tests/test_easy_install.py
index b0cc4c9fb..2cf65ae7e 100644
--- a/setuptools/tests/test_easy_install.py
+++ b/setuptools/tests/test_easy_install.py
@@ -15,7 +15,7 @@ import distutils.errors
 import io
 import zipfile
 import mock
-
+from setuptools.command.easy_install import EasyInstallDeprecationWarning, ScriptWriter, WindowsScriptWriter
 import time
 from setuptools.extern import six
 from setuptools.extern.six.moves import urllib
@@ -288,6 +288,22 @@ class TestEasyInstallTest:
         assert (target / 'mypkg_script').exists()
 
 
+    def test_dist_get_script_args_deprecated(self):
+        with pytest.warns(EasyInstallDeprecationWarning):
+            ScriptWriter.get_script_args(None, None)
+
+    def test_dist_get_script_header_deprecated(self):
+        with pytest.warns(EasyInstallDeprecationWarning):
+            ScriptWriter.get_script_header("")
+
+    def test_dist_get_writer_deprecated(self):
+        with pytest.warns(EasyInstallDeprecationWarning):
+            ScriptWriter.get_writer(None)
+
+    def test_dist_WindowsScriptWriter_get_writer_deprecated(self):
+        with pytest.warns(EasyInstallDeprecationWarning):
+            WindowsScriptWriter.get_writer()
+
 @pytest.mark.filterwarnings('ignore:Unbuilt egg')
 class TestPTHFileWriter:
     def test_add_from_cwd_site_sets_dirty(self):
diff --git a/setuptools/tests/test_egg_info.py b/setuptools/tests/test_egg_info.py
index 59ffb16d1..46fb884f2 100644
--- a/setuptools/tests/test_egg_info.py
+++ b/setuptools/tests/test_egg_info.py
@@ -7,7 +7,7 @@ import re
 import stat
 import time
 
-from setuptools.command.egg_info import egg_info, manifest_maker
+from setuptools.command.egg_info import egg_info, manifest_maker, EggInfoDeprecationWarning, get_pkg_info_revision
 from setuptools.dist import Distribution
 from setuptools.extern.six.moves import map
 
@@ -603,3 +603,6 @@ class TestEggInfo:
         with open(os.path.join(egg_info_dir, 'PKG-INFO')) as pkginfo_file:
             pkg_info_lines = pkginfo_file.read().split('\n')
         assert 'Version: 0.0.0.dev0' in pkg_info_lines
+
+    def test_get_pkg_info_revision_deprecated(self):
+        pytest.warns(EggInfoDeprecationWarning, get_pkg_info_revision)
\ No newline at end of file