diff --git a/tensorboard/BUILD b/tensorboard/BUILD index 3e4440e560..ffbbc39893 100644 --- a/tensorboard/BUILD +++ b/tensorboard/BUILD @@ -309,7 +309,6 @@ py_library( srcs = ["default.py"], srcs_version = "PY3", deps = [ - "//tensorboard:expect_pkg_resources_installed", "//tensorboard/backend:experimental_plugin", "//tensorboard/plugins/audio:audio_plugin", "//tensorboard/plugins/core:core_plugin", @@ -347,7 +346,6 @@ py_test( deps = [ ":default", ":test", - "//tensorboard:expect_pkg_resources_installed", "//tensorboard/plugins:base_plugin", ], ) @@ -367,7 +365,7 @@ py_test( deps = [ ":test", ":version", - "//tensorboard:expect_pkg_resources_installed", + "//tensorboard:expect_packaging_installed", ], ) @@ -466,6 +464,11 @@ py_library(name = "expect_absl_testing_absltest_installed") # `pip install setuptools`. py_library(name = "expect_pkg_resources_installed") +# This is a dummy rule used as a packaging dependency in open-source. +# We expect packaging to already be installed on the system, e.g. via +# `pip install packaging`. +py_library(name = "expect_packaging_installed") + # This is a dummy rule used as a pandas dependency in open-source. # We expect pandas to already be installed on the system, e.g. via # `pip install pandas`. diff --git a/tensorboard/data/BUILD b/tensorboard/data/BUILD index 0a3337af1a..6946466d02 100644 --- a/tensorboard/data/BUILD +++ b/tensorboard/data/BUILD @@ -62,7 +62,7 @@ py_library( ":grpc_provider", ":ingester", "//tensorboard:expect_grpc_installed", - "//tensorboard:expect_pkg_resources_installed", + "//tensorboard:expect_packaging_installed", "//tensorboard/data/proto:protos_all_py_pb2", "//tensorboard/util:tb_logging", ], diff --git a/tensorboard/data/server_ingester.py b/tensorboard/data/server_ingester.py index fb0d2fc59c..ca721a82b2 100644 --- a/tensorboard/data/server_ingester.py +++ b/tensorboard/data/server_ingester.py @@ -22,7 +22,7 @@ import time import grpc -import pkg_resources +from packaging import version as packaging_version from tensorboard.data import grpc_provider from tensorboard.data import ingester @@ -231,7 +231,7 @@ def __init__(self, path, version): """ self._path = path self._version = ( - pkg_resources.parse_version(version) + packaging_version.parse(version) if version is not None else version ) @@ -260,7 +260,7 @@ def at_least_version(self, required_version): """ if self._version is None: return True - return self._version >= pkg_resources.parse_version(required_version) + return self._version >= packaging_version.parse(required_version) def get_server_binary(): diff --git a/tensorboard/default.py b/tensorboard/default.py index 7e6711337a..84595036be 100644 --- a/tensorboard/default.py +++ b/tensorboard/default.py @@ -26,8 +26,7 @@ import logging - -import pkg_resources +from importlib import metadata from tensorboard.plugins.audio import audio_plugin from tensorboard.plugins.core import core_plugin @@ -119,8 +118,14 @@ def get_dynamic_plugins(): [1]: https://packaging.python.org/specifications/entry-points/ """ return [ - entry_point.resolve() - for entry_point in pkg_resources.iter_entry_points( - "tensorboard_plugins" - ) + entry_point.load() + for entry_point in _iter_entry_points("tensorboard_plugins") ] + + +def _iter_entry_points(group): + """Returns entry points for a given group across Python versions.""" + entry_points = metadata.entry_points() + if hasattr(entry_points, "select"): + return entry_points.select(group=group) + return entry_points.get(group, ()) diff --git a/tensorboard/default_test.py b/tensorboard/default_test.py index e131be9ea6..41438e8951 100644 --- a/tensorboard/default_test.py +++ b/tensorboard/default_test.py @@ -17,49 +17,28 @@ from unittest import mock -import pkg_resources - from tensorboard import default -from tensorboard.plugins import base_plugin from tensorboard import test -class FakePlugin(base_plugin.TBPlugin): - """FakePlugin for testing.""" - - plugin_name = "fake" - - -class FakeEntryPoint(pkg_resources.EntryPoint): - """EntryPoint class that fake loads FakePlugin.""" - - @classmethod - def create(cls): - """Creates an instance of FakeEntryPoint. - - Returns: - instance of FakeEntryPoint - """ - return cls("foo", "bar") - - def resolve(self): - """Returns FakePlugin instead of resolving module. +class FakeEntryPoint: + def __init__(self, value): + self._value = value - Returns: - FakePlugin - """ - return FakePlugin + def load(self): + return self._value class DefaultTest(test.TestCase): - @mock.patch.object(pkg_resources, "iter_entry_points") + @mock.patch.object(default, "_iter_entry_points") def test_get_dynamic_plugin(self, mock_iter_entry_points): - mock_iter_entry_points.return_value = [FakeEntryPoint.create()] + fake_plugin = object() + mock_iter_entry_points.return_value = [FakeEntryPoint(fake_plugin)] actual_plugins = default.get_dynamic_plugins() mock_iter_entry_points.assert_called_with("tensorboard_plugins") - self.assertEqual(actual_plugins, [FakePlugin]) + self.assertEqual(actual_plugins, [fake_plugin]) if __name__ == "__main__": diff --git a/tensorboard/version_test.py b/tensorboard/version_test.py index dbfd59b0f0..f4a99e671d 100644 --- a/tensorboard/version_test.py +++ b/tensorboard/version_test.py @@ -13,7 +13,7 @@ # limitations under the License. -import pkg_resources +from packaging import version as packaging_version from tensorboard import test as tb_test from tensorboard import version @@ -22,22 +22,11 @@ class VersionTest(tb_test.TestCase): def test_valid_pep440_version(self): """Ensure that our version is PEP 440-compliant.""" - # pkg_resources.parse_version() doesn't have a public return type, - # so we get a handle to it by parsing known good and bad versions. - # - # Note: depending on the version of the module (which is bundled - # with setuptools), when called with a non-compliant version, it - # either returns a `LegacyVersion` (setuptools < 66) or raises an - # `InvalidVersion` exception (setuptools >= 66). Handle both cases. - compliant_version = pkg_resources.parse_version("1.0.0") - try: - legacy_version = pkg_resources.parse_version("arbitrary string") - except Exception: - legacy_version = None - self.assertNotEqual(type(compliant_version), type(legacy_version)) - - tensorboard_version = pkg_resources.parse_version(version.VERSION) - self.assertIsInstance(tensorboard_version, type(compliant_version)) + with self.assertRaises(packaging_version.InvalidVersion): + packaging_version.parse("arbitrary string") + + tensorboard_version = packaging_version.parse(version.VERSION) + self.assertIsInstance(tensorboard_version, packaging_version.Version) if __name__ == "__main__":