Repository: jupyter/jupyter_client
Pull request #672 (2021-08-04 21:11:41)

Rename trait to allowed_kernelspecs
Partially addresses jupyter/jupyter_client#642 by deprecating `KernelSpecManager.whitelist` in favor of the more descriptive and inclusive `KernelSpecManager.allowed_kernelspecs`.


Patch:
diff --git a/jupyter_client/kernelspec.py b/jupyter_client/kernelspec.py
index 99b3544..ab62f54 100644
--- a/jupyter_client/kernelspec.py
+++ b/jupyter_client/kernelspec.py
@@ -16,6 +16,7 @@ from traitlets import CaselessStrEnum
 from traitlets import Dict
 from traitlets import HasTraits
 from traitlets import List
+from traitlets import observe
 from traitlets import Set
 from traitlets import Type
 from traitlets import Unicode
@@ -148,7 +149,12 @@ class KernelSpecManager(LoggingConfigurable):
 
     whitelist = Set(
         config=True,
-        help="""Whitelist of allowed kernel names.
+        help="""Deprecated, use `KernelSpecManager.allowed_kernelspecs`
+        """,
+    )
+    allowed_kernelspecs = Set(
+        config=True,
+        help="""List of allowed kernel names.
 
         By default, all installed kernels are allowed.
         """,
@@ -157,6 +163,32 @@ class KernelSpecManager(LoggingConfigurable):
         help="List of kernel directories to search. Later ones take priority over earlier."
     )
 
+    _deprecated_aliases = {
+        "whitelist": ("allowed_kernelspecs", "7.0"),
+    }
+
+    # Method copied from
+    # https://github.com/jupyterhub/jupyterhub/blob/d1a85e53dccfc7b1dd81b0c1985d158cc6b61820/jupyterhub/auth.py#L143-L161
+    @observe(*list(_deprecated_aliases))
+    def _deprecated_trait(self, change):
+        """observer for deprecated traits"""
+        old_attr = change.name
+        new_attr, version = self._deprecated_aliases.get(old_attr)
+        new_value = getattr(self, new_attr)
+        if new_value != change.new:
+            # only warn if different
+            # protects backward-compatible config from warnings
+            # if they set the same value under both names
+            self.log.warning(
+                "{cls}.{old} is deprecated in JupyterLab {version}, use {cls}.{new} instead".format(
+                    cls=self.__class__.__name__,
+                    old=old_attr,
+                    new=new_attr,
+                    version=version,
+                )
+            )
+            setattr(self, new_attr, change.new)
+
     def _kernel_dirs_default(self):
         dirs = jupyter_path("kernels")
         # At some point, we should stop adding .ipython/kernels to the path,
@@ -196,9 +228,9 @@ class KernelSpecManager(LoggingConfigurable):
             except ImportError:
                 self.log.warning("Native kernel (%s) is not available", NATIVE_KERNEL_NAME)
 
-        if self.whitelist:
-            # filter if there's a whitelist
-            d = {name: spec for name, spec in d.items() if name in self.whitelist}
+        if self.allowed_kernelspecs:
+            # filter if there's an allow list
+            d = {name: spec for name, spec in d.items() if name in self.allowed_kernelspecs}
         return d
         # TODO: Caching?
 


Test patch:
diff --git a/jupyter_client/tests/test_kernelspec.py b/jupyter_client/tests/test_kernelspec.py
index 19436e3..6953d4b 100644
--- a/jupyter_client/tests/test_kernelspec.py
+++ b/jupyter_client/tests/test_kernelspec.py
@@ -59,6 +59,18 @@ class KernelSpecTests(unittest.TestCase):
         kernels = self.ksm.find_kernel_specs()
         self.assertEqual(kernels["sample"], self.sample_kernel_dir)
 
+    def test_allowed_kernel_names(self):
+        ksm = kernelspec.KernelSpecManager()
+        ksm.allowed_kernelspecs = ["foo"]
+        kernels = ksm.find_kernel_specs()
+        assert not len(kernels)
+
+    def test_deprecated_whitelist(self):
+        ksm = kernelspec.KernelSpecManager()
+        ksm.whitelist = ["bar"]
+        kernels = ksm.find_kernel_specs()
+        assert not len(kernels)
+
     def test_get_kernel_spec(self):
         ks = self.ksm.get_kernel_spec("SAMPLE")  # Case insensitive
         self.assertEqual(ks.resource_dir, self.sample_kernel_dir)