From 23e1e07139d1abc3a9ae6338991daba770141a0a Mon Sep 17 00:00:00 2001 From: Adrien Ferrand Date: Sat, 14 Aug 2021 23:06:29 +0200 Subject: [PATCH] Emit deprecation warnings for Zope interfaces (#8970) * Monkeypatch certbot.interfaces module to warn about deprecations * Ignore our own warning * Fix type * Add a changelog entry --- certbot/CHANGELOG.md | 4 +++- certbot/certbot/interfaces.py | 37 +++++++++++++++++++++++++++++++++++ pytest.ini | 3 +++ 3 files changed, 43 insertions(+), 1 deletion(-) diff --git a/certbot/CHANGELOG.md b/certbot/CHANGELOG.md index bd43fe10d..a163b8869 100644 --- a/certbot/CHANGELOG.md +++ b/certbot/CHANGELOG.md @@ -10,7 +10,9 @@ Certbot adheres to [Semantic Versioning](https://semver.org/). ### Changed -* +* `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. ### Fixed diff --git a/certbot/certbot/interfaces.py b/certbot/certbot/interfaces.py index 51b97d2d1..921ba12a7 100644 --- a/certbot/certbot/interfaces.py +++ b/certbot/certbot/interfaces.py @@ -2,9 +2,13 @@ from abc import ABCMeta from abc import abstractmethod from argparse import ArgumentParser +import sys +from types import ModuleType +from typing import cast from typing import Iterable from typing import List from typing import Optional +import warnings import zope.interface @@ -480,3 +484,36 @@ class RenewDeployer(metaclass=ABCMeta): :type lineage: RenewableCert """ + + +# 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 _ZopeInterfacesDeprecationModule: + """ + Internal class delegating to a module, and displaying warnings when + attributes related to Zope interfaces are accessed. + """ + def __init__(self, module): + self.__dict__['_module'] = module + + def __getattr__(self, attr): + if attr in ('IConfig', 'IPlugin', 'IPluginFactory', 'IAuthenticator', + 'IInstaller', 'IDisplay', 'IReporter'): + warnings.warn('{0} attribute in certbot.interfaces 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 Zope interfaces deprecation and planned removal. +sys.modules[__name__] = cast(ModuleType, _ZopeInterfacesDeprecationModule(sys.modules[__name__])) diff --git a/pytest.ini b/pytest.ini index 1eebe5b65..452285429 100644 --- a/pytest.ini +++ b/pytest.ini @@ -16,7 +16,10 @@ # 2) An ImportWarning is raised with older versions of setuptools and # zope.interface. See # 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. filterwarnings = error ignore:The external mock module:PendingDeprecationWarning ignore:.*zope. missing __init__:ImportWarning + ignore:.*attribute in certbot.interfaces module is deprecated:DeprecationWarning