Repository: certbot/certbot (language: python)

Issue:
Add deprecation warnings for legacy certbot.display.util code
As a followup from https://github.com/certbot/certbot/pull/8967, I think we should generate deprecation warnings using an approach like https://github.com/certbot/certbot/pull/6859/files#diff-e5eaf744409c293203b898ba9896da75689fd04ff5f1566c035940a5b195c257 for any code in `certbot.display.util` that is unused and/or we don't want to be part of our public API.


Discussion / hints:

Fix patch:
diff --git a/certbot/CHANGELOG.md b/certbot/CHANGELOG.md
index a163b886958..cdbe12fb587 100644
--- a/certbot/CHANGELOG.md
+++ b/certbot/CHANGELOG.md
@@ -10,6 +10,9 @@ Certbot adheres to [Semantic Versioning](https://semver.org/).
 
 ### Changed
 
+* Several attributes in `certbot.display.util` module are deprecated and will
+  be removed in a future release of Certbot. Any import of these attributes will
+  emit a warning to prepare the transition for developers.
 * `zope` based interfaces in `certbot.interfaces` module are deprecated and will
   be removed in a future release of Certbot. Any import of these interfaces will
   emit a warning to prepare the transition for developers.
diff --git a/certbot/certbot/display/util.py b/certbot/certbot/display/util.py
index d1a955e48e0..3cd38db0fe3 100644
--- a/certbot/certbot/display/util.py
+++ b/certbot/certbot/display/util.py
@@ -9,10 +9,14 @@
 Other messages can use the `logging` module. See `log.py`.
 
 """
+import sys
+from types import ModuleType
+from typing import cast
 from typing import List
 from typing import Optional
 from typing import Tuple
 from typing import Union
+import warnings
 
 
 # These specific imports from certbot._internal.display.obj and
@@ -202,3 +206,36 @@ def assert_valid_call(prompt, default, cli_flag, force_interactive):
         msg += ("\nYou can set an answer to "
                 "this prompt with the {0} flag".format(cli_flag))
     assert default is not None or force_interactive, msg
+
+
+# This class takes a similar approach to the cryptography project to deprecate attributes
+# in public modules. See the _ModuleWithDeprecation class here:
+# https://github.com/pyca/cryptography/blob/91105952739442a74582d3e62b3d2111365b0dc7/src/cryptography/utils.py#L129
+class _DisplayUtilDeprecationModule:
+    """
+    Internal class delegating to a module, and displaying warnings when attributes
+    related to deprecated attributes in the certbot.display.util module.
+    """
+    def __init__(self, module):
+        self.__dict__['_module'] = module
+
+    def __getattr__(self, attr):
+        if attr in ('FileDisplay', 'NoninteractiveDisplay', 'SIDE_FRAME', 'input_with_timeout',
+                    'separate_list_input', 'summarize_domain_list', 'WIDTH', 'HELP', 'ESC'):
+            warnings.warn('{0} attribute in certbot.display.util module is deprecated '
+                          'and will be removed soon.'.format(attr),
+                          DeprecationWarning, stacklevel=2)
+        return getattr(self._module, attr)
+
+    def __setattr__(self, attr, value):  # pragma: no cover
+        setattr(self._module, attr, value)
+
+    def __delattr__(self, attr):  # pragma: no cover
+        delattr(self._module, attr)
+
+    def __dir__(self):  # pragma: no cover
+        return ['_module'] + dir(self._module)
+
+
+# Patching ourselves to warn about deprecation and planned removal of some elements in the module.
+sys.modules[__name__] = cast(ModuleType, _DisplayUtilDeprecationModule(sys.modules[__name__]))


Test patch:
diff --git a/pytest.ini b/pytest.ini
index 45228542977..a3ec1ce174d 100644
--- a/pytest.ini
+++ b/pytest.ini
@@ -18,8 +18,11 @@
 #    https://github.com/zopefoundation/zope.interface/issues/68 for more info.
 # 3) The deprecation warning raised when importing old Zope interfaces from
 #    the certbot.interfaces module.
+# 4) The deprecation warning raised when importing deprecated attributes from
+#    the certbot.display.util module.
 filterwarnings =
     error
     ignore:The external mock module:PendingDeprecationWarning
     ignore:.*zope. missing __init__:ImportWarning
     ignore:.*attribute in certbot.interfaces module is deprecated:DeprecationWarning
+    ignore:.*attribute in certbot.display.util module is deprecated:DeprecationWarning
\ No newline at end of file