From 9d736d5c9c939ef5a47b001ef9cb3ea97122c1c4 Mon Sep 17 00:00:00 2001 From: Adrien Ferrand Date: Wed, 7 Sep 2022 07:09:32 +0200 Subject: [PATCH] Remove zope from Certbot (#9161) * Remove zope and the internal reporter util. * remove zope references from .pylintrc and pytest.ini Co-authored-by: Alex Zorin --- .pylintrc | 9 +- certbot/certbot/_internal/display/obj.py | 15 +-- certbot/certbot/_internal/main.py | 22 +--- certbot/certbot/_internal/plugins/disco.py | 106 +----------------- .../certbot/_internal/plugins/selection.py | 6 +- certbot/certbot/_internal/renewal.py | 5 - certbot/certbot/_internal/reporter.py | 94 ---------------- certbot/certbot/interfaces.py | 69 +----------- certbot/setup.py | 2 - certbot/tests/auth_handler_test.py | 3 +- certbot/tests/cli_test.py | 2 +- certbot/tests/client_test.py | 3 +- certbot/tests/crypto_util_test.py | 2 - certbot/tests/main_test.py | 12 +- certbot/tests/plugins/disco_test.py | 32 ------ certbot/tests/plugins/selection_test.py | 8 +- certbot/tests/reporter_test.py | 89 --------------- pytest.ini | 15 +-- tools/oldest_constraints.txt | 46 ++++---- tools/pinning/oldest/pyproject.toml | 5 - tools/requirements.txt | 6 +- 21 files changed, 49 insertions(+), 502 deletions(-) delete mode 100644 certbot/certbot/_internal/reporter.py delete mode 100644 certbot/tests/reporter_test.py diff --git a/.pylintrc b/.pylintrc index d2730018d..89495c507 100644 --- a/.pylintrc +++ b/.pylintrc @@ -283,10 +283,6 @@ ignored-modules=pkg_resources,confargparse,argparse # (useful for classes with attributes dynamically set). ignored-classes=Field,Header,JWS,closing -# When zope mode is activated, add a predefined set of Zope acquired attributes -# to generated-members. -zope=yes - # List of members which are set dynamically and missed by pylint inference # system, and so shouldn't trigger E0201 when accessed. Python regular # expressions are accepted. @@ -313,9 +309,8 @@ int-import-graph= [CLASSES] -# List of interface methods to ignore, separated by a comma. This is used for -# instance to not check methods defined in Zope's Interface base class. -ignore-iface-methods=isImplementedBy,deferred,extends,names,namesAndDescriptions,queryDescriptionFor,getBases,getDescriptionFor,getDoc,getName,getTaggedValue,getTaggedValueTags,isEqualOrExtendedBy,setTaggedValue,isImplementedByInstancesOf,adaptWith,is_implemented_by,implementedBy,providedBy +# List of interface methods to ignore, separated by a comma. +ignore-iface-methods= # List of method names used to declare (i.e. assign) instance attributes. defining-attr-methods=__init__,__new__,setUp diff --git a/certbot/certbot/_internal/display/obj.py b/certbot/certbot/_internal/display/obj.py index c5c2e388b..54c248b0c 100644 --- a/certbot/certbot/_internal/display/obj.py +++ b/certbot/certbot/_internal/display/obj.py @@ -10,11 +10,7 @@ from typing import Tuple from typing import TypeVar from typing import Union -import zope.component -import zope.interface - from certbot import errors -from certbot import interfaces from certbot._internal import constants from certbot._internal.display import completer from certbot._internal.display import util @@ -34,6 +30,7 @@ SIDE_FRAME = ("- " * 39) + "-" """Display boundary (alternates spaces, so when copy-pasted, markdown doesn't interpret it as a heading)""" + # This class holds the global state of the display service. Using this class # eliminates potential gotchas that exist if self.display was just a global # variable. In particular, in functions `_DISPLAY = ` would create a @@ -50,9 +47,6 @@ _SERVICE = _DisplayService() T = TypeVar("T") -# This use of IDisplay can be removed when this class is no longer accessible -# through the public API in certbot.display.util. -@zope.interface.implementer(interfaces.IDisplay) class FileDisplay: """File-based display.""" # see https://github.com/certbot/certbot/issues/3915 @@ -410,9 +404,6 @@ class FileDisplay: return OK, selection -# This use of IDisplay can be removed when this class is no longer accessible -# through the public API in certbot.display.util. -@zope.interface.implementer(interfaces.IDisplay) class NoninteractiveDisplay: """A display utility implementation that never asks for interactive user input""" @@ -573,8 +564,4 @@ def set_display(display: Union[FileDisplay, NoninteractiveDisplay]) -> None: :param Union[FileDisplay, NoninteractiveDisplay] display: the display service """ - # This call is done only for retro-compatibility purposes. - # TODO: Remove this call once zope dependencies are removed from Certbot. - zope.component.provideUtility(display, interfaces.IDisplay) - _SERVICE.display = display diff --git a/certbot/certbot/_internal/main.py b/certbot/certbot/_internal/main.py index f6d3e02e1..278a67473 100644 --- a/certbot/certbot/_internal/main.py +++ b/certbot/certbot/_internal/main.py @@ -17,8 +17,6 @@ from typing import Union import configobj import josepy as jose -import zope.component -import zope.interface from acme import client as acme_client from acme import errors as acme_errors @@ -38,7 +36,6 @@ from certbot._internal import eff from certbot._internal import hooks from certbot._internal import log from certbot._internal import renewal -from certbot._internal import reporter from certbot._internal import snap_config from certbot._internal import storage from certbot._internal import updater @@ -1165,15 +1162,14 @@ def plugins_cmd(config: configuration.NamespaceConfig, return filtered.init(config) - verified = filtered.verify(ifaces) - logger.debug("Verified plugins: %r", verified) + logger.debug("Filtered plugins: %r", filtered) if not config.prepare: - notify(str(verified)) + notify(str(filtered)) return - verified.prepare() - available = verified.available() + filtered.prepare() + available = filtered.available() logger.debug("Prepared plugins: %s", available) notify(str(available)) @@ -1716,10 +1712,6 @@ def main(cli_args: List[str] = None) -> Optional[Union[str, int]]: args = cli.prepare_and_parse_args(plugins, cli_args) config = configuration.NamespaceConfig(args) - # This call is done only for retro-compatibility purposes. - # TODO: Remove this call once zope dependencies are removed from Certbot. - zope.component.provideUtility(config, interfaces.IConfig) - # On windows, shell without administrative right cannot create symlinks required by certbot. # So we check the rights before continuing. misc.raise_for_non_administrative_windows_rights() @@ -1732,12 +1724,6 @@ def main(cli_args: List[str] = None) -> Optional[Union[str, int]]: if config.func != plugins_cmd: # pylint: disable=comparison-with-callable raise - # These calls are done only for retro-compatibility purposes. - # TODO: Remove these calls once zope dependencies are removed from Certbot. - report = reporter.Reporter(config) - zope.component.provideUtility(report, interfaces.IReporter) - util.atexit_register(report.print_messages) - with make_displayer(config) as displayer: display_obj.set_display(displayer) diff --git a/certbot/certbot/_internal/plugins/disco.py b/certbot/certbot/_internal/plugins/disco.py index 707f5ae9d..027e61838 100644 --- a/certbot/certbot/_internal/plugins/disco.py +++ b/certbot/certbot/_internal/plugins/disco.py @@ -12,11 +12,8 @@ from typing import Mapping from typing import Optional from typing import Type from typing import Union -import warnings import pkg_resources -import zope.interface -import zope.interface.verify from certbot import configuration from certbot import errors @@ -115,7 +112,7 @@ class PluginEntryPoint: def ifaces(self, *ifaces_groups: Iterable[Type]) -> bool: """Does plugin implements specified interface groups?""" return not ifaces_groups or any( - all(_implements(self.plugin_cls, iface) + all(issubclass(self.plugin_cls, iface) for iface in ifaces) for ifaces in ifaces_groups) @@ -133,16 +130,6 @@ class PluginEntryPoint: self._initialized = self.plugin_cls(config, self.name) return self._initialized - def verify(self, ifaces: Iterable[Type]) -> bool: - """Verify that the plugin conforms to the specified interfaces.""" - if not self.initialized: - raise ValueError("Plugin is not initialized.") - for iface in ifaces: # zope.interface.providedBy(plugin) - if not _verify(self.init(), self.plugin_cls, iface): - return False - - return True - @property def prepared(self) -> bool: """Has the plugin been prepared already?""" @@ -264,7 +251,7 @@ class PluginsRegistry(Mapping): plugin2 = other_ep.entry_point.dist.key if other_ep.entry_point.dist else "unknown" raise Exception("Duplicate plugin name {0} from {1} and {2}.".format( plugin_ep.name, plugin1, plugin2)) - if _provides(plugin_ep.plugin_cls, interfaces.Plugin): + if issubclass(plugin_ep.plugin_cls, interfaces.Plugin): plugins[plugin_ep.name] = plugin_ep else: # pragma: no cover logger.warning( @@ -299,10 +286,6 @@ class PluginsRegistry(Mapping): """Filter plugins based on interfaces.""" return self.filter(lambda p_ep: p_ep.ifaces(*ifaces_groups)) - def verify(self, ifaces: Iterable[Type]) -> "PluginsRegistry": - """Filter plugins based on verification.""" - return self.filter(lambda p_ep: p_ep.verify(ifaces)) - def prepare(self) -> List[Union[bool, Error]]: """Prepare all plugins in the registry.""" return [plugin_ep.prepare() for plugin_ep in self._plugins.values()] @@ -341,88 +324,3 @@ class PluginsRegistry(Mapping): if not self._plugins: return "No plugins" return "\n\n".join(str(p_ep) for p_ep in self._plugins.values()) - - -_DEPRECATION_PLUGIN = ("Zope interface certbot.interfaces.IPlugin is deprecated, " - "use ABC certbot.interface.Plugin instead.") - -_DEPRECATION_AUTHENTICATOR = ("Zope interface certbot.interfaces.IAuthenticator is deprecated, " - "use ABC certbot.interface.Authenticator instead.") - -_DEPRECATION_INSTALLER = ("Zope interface certbot.interfaces.IInstaller is deprecated, " - "use ABC certbot.interface.Installer instead.") - -_DEPRECATION_FACTORY = ("Zope interface certbot.interfaces.IPluginFactory is deprecated, " - "use ABC certbot.interface.Plugin instead.") - - -def _provides(target_class: Type[interfaces.Plugin], iface: Type) -> bool: - if issubclass(target_class, iface): - return True - - if iface == interfaces.Plugin and interfaces.IPluginFactory.providedBy(target_class): - logging.warning(_DEPRECATION_FACTORY) - warnings.warn(_DEPRECATION_FACTORY, DeprecationWarning) - return True - - return False - - -def _implements(target_class: Type[interfaces.Plugin], iface: Type) -> bool: - if issubclass(target_class, iface): - return True - - if iface == interfaces.Plugin and interfaces.IPlugin.implementedBy(target_class): - logging.warning(_DEPRECATION_PLUGIN) - warnings.warn(_DEPRECATION_PLUGIN, DeprecationWarning) - return True - - if iface == interfaces.Authenticator and interfaces.IAuthenticator.implementedBy(target_class): - logging.warning(_DEPRECATION_AUTHENTICATOR) - warnings.warn(_DEPRECATION_AUTHENTICATOR, DeprecationWarning) - return True - - if iface == interfaces.Installer and interfaces.IInstaller.implementedBy(target_class): - logging.warning(_DEPRECATION_INSTALLER) - warnings.warn(_DEPRECATION_INSTALLER, DeprecationWarning) - return True - - return False - - -def _verify(target_instance: interfaces.Plugin, target_class: Type[interfaces.Plugin], - iface: Type) -> bool: - if issubclass(target_class, iface): - # No need to trigger some verify logic for ABCs: when the object is instantiated, - # an error would be raised if implementation is not done properly. - # So the checks have been done effectively when the plugin has been initialized. - return True - - zope_iface: Optional[Type[zope.interface.Interface]] = None - message = "" - - if iface == interfaces.Plugin: - zope_iface = interfaces.IPlugin - message = _DEPRECATION_PLUGIN - if iface == interfaces.Authenticator: - zope_iface = interfaces.IAuthenticator - message = _DEPRECATION_AUTHENTICATOR - if iface == interfaces.Installer: - zope_iface = interfaces.IInstaller - message = _DEPRECATION_INSTALLER - - if not zope_iface: - raise ValueError(f"Unexpected type: {iface.__name__}") - - try: - zope.interface.verify.verifyObject(zope_iface, target_instance) - logging.warning(message) - warnings.warn(message, DeprecationWarning) - return True - except zope.interface.exceptions.BrokenImplementation as error: - if zope_iface.implementedBy(target_class): - logger.debug( - "%s implements %s but object does not verify: %s", - target_class, zope_iface.__name__, error, exc_info=True) - - return False diff --git a/certbot/certbot/_internal/plugins/selection.py b/certbot/certbot/_internal/plugins/selection.py index 826e1c932..708877d3e 100644 --- a/certbot/certbot/_internal/plugins/selection.py +++ b/certbot/certbot/_internal/plugins/selection.py @@ -65,7 +65,6 @@ def get_unprepared_installer(config: configuration.NamespaceConfig, return None installers = plugins.filter(lambda p_ep: p_ep.check_name(req_inst)) installers.init(config) - installers = installers.verify((interfaces.Installer,)) if len(installers) > 1: raise errors.PluginSelectionError( "Found multiple installers with the name %s, Certbot is unable to " @@ -116,9 +115,8 @@ def pick_plugin(config: configuration.NamespaceConfig, default: Optional[str], filtered = plugins.visible().ifaces(ifaces) filtered.init(config) - verified = filtered.verify(ifaces) - verified.prepare() - prepared = verified.available() + filtered.prepare() + prepared = filtered.available() if len(prepared) > 1: logger.debug("Multiple candidate plugins: %s", prepared) diff --git a/certbot/certbot/_internal/renewal.py b/certbot/certbot/_internal/renewal.py index 0ba2e8108..bd84901e1 100644 --- a/certbot/certbot/_internal/renewal.py +++ b/certbot/certbot/_internal/renewal.py @@ -19,12 +19,10 @@ from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives.asymmetric import ec from cryptography.hazmat.primitives.asymmetric import rsa from cryptography.hazmat.primitives.serialization import load_pem_private_key -import zope.component from certbot import configuration from certbot import crypto_util from certbot import errors -from certbot import interfaces from certbot import util from certbot._internal import cli from certbot._internal import client @@ -460,9 +458,6 @@ def handle_renewal_request(config: configuration.NamespaceConfig) -> None: if not renewal_candidate: parse_failures.append(renewal_file) else: - # This call is done only for retro-compatibility purposes. - # TODO: Remove this call once zope dependencies are removed from Certbot. - zope.component.provideUtility(lineage_config, interfaces.IConfig) renewal_candidate.ensure_deployed() from certbot._internal import main plugins = plugins_disco.PluginsRegistry.find_all() diff --git a/certbot/certbot/_internal/reporter.py b/certbot/certbot/_internal/reporter.py deleted file mode 100644 index fb09b1f27..000000000 --- a/certbot/certbot/_internal/reporter.py +++ /dev/null @@ -1,94 +0,0 @@ -"""Collects and displays information to the user.""" -import collections -import logging -import queue -import sys -import textwrap - -from certbot import configuration -from certbot import util - -logger = logging.getLogger(__name__) - - -class Reporter: - """Collects and displays information to the user. - - :ivar `queue.PriorityQueue` messages: Messages to be displayed to - the user. - - """ - - HIGH_PRIORITY = 0 - """High priority constant. See `add_message`.""" - MEDIUM_PRIORITY = 1 - """Medium priority constant. See `add_message`.""" - LOW_PRIORITY = 2 - """Low priority constant. See `add_message`.""" - - _msg_type = collections.namedtuple('_msg_type', 'priority text on_crash') - - def __init__(self, config: configuration.NamespaceConfig) -> None: - self.messages: "queue.PriorityQueue[Reporter._msg_type]" = queue.PriorityQueue() - self.config = config - - def add_message(self, msg: str, priority: int, on_crash: bool = True) -> None: - """Adds msg to the list of messages to be printed. - - :param str msg: Message to be displayed to the user. - - :param int priority: One of `HIGH_PRIORITY`, `MEDIUM_PRIORITY`, - or `LOW_PRIORITY`. - - :param bool on_crash: Whether or not the message should be - printed if the program exits abnormally. - - """ - assert self.HIGH_PRIORITY <= priority <= self.LOW_PRIORITY - self.messages.put(self._msg_type(priority, msg, on_crash)) - logger.debug("Reporting to user: %s", msg) - - def print_messages(self) -> None: - """Prints messages to the user and clears the message queue. - - If there is an unhandled exception, only messages for which - ``on_crash`` is ``True`` are printed. - - """ - bold_on = False - if not self.messages.empty(): - no_exception = sys.exc_info()[0] is None - bold_on = sys.stdout.isatty() - if not self.config.quiet: - if bold_on: - print(util.ANSI_SGR_BOLD) - print('IMPORTANT NOTES:') - first_wrapper = textwrap.TextWrapper( - initial_indent=' - ', - subsequent_indent=(' ' * 3), - break_long_words=False, - break_on_hyphens=False) - next_wrapper = textwrap.TextWrapper( - initial_indent=first_wrapper.subsequent_indent, - subsequent_indent=first_wrapper.subsequent_indent, - break_long_words=False, - break_on_hyphens=False) - while not self.messages.empty(): - msg = self.messages.get() - if self.config.quiet: - # In --quiet mode, we only print high priority messages that - # are flagged for crash cases - if not (msg.priority == self.HIGH_PRIORITY and msg.on_crash): - continue - if no_exception or msg.on_crash: - if bold_on and msg.priority > self.HIGH_PRIORITY: - if not self.config.quiet: - sys.stdout.write(util.ANSI_SGR_RESET) - bold_on = False - lines = msg.text.splitlines() - print(first_wrapper.fill(lines[0])) - if len(lines) > 1: - print("\n".join( - next_wrapper.fill(line) for line in lines[1:])) - if bold_on and not self.config.quiet: - sys.stdout.write(util.ANSI_SGR_RESET) diff --git a/certbot/certbot/interfaces.py b/certbot/certbot/interfaces.py index 00c37303a..84223b6c0 100644 --- a/certbot/certbot/interfaces.py +++ b/certbot/certbot/interfaces.py @@ -2,19 +2,13 @@ from abc import ABCMeta from abc import abstractmethod from argparse import ArgumentParser -import sys -from types import ModuleType from typing import Any -from typing import Union -from typing import cast from typing import Iterable from typing import List from typing import Optional from typing import Type from typing import TYPE_CHECKING -import warnings - -import zope.interface +from typing import Union from acme.challenges import Challenge from acme.challenges import ChallengeResponse @@ -62,18 +56,6 @@ class AccountStorage(metaclass=ABCMeta): raise NotImplementedError() -class IConfig(zope.interface.Interface): # pylint: disable=inherit-non-class - """Deprecated, use certbot.configuration.NamespaceConfig instead.""" - - -class IPluginFactory(zope.interface.Interface): # pylint: disable=inherit-non-class - """Deprecated, use certbot.interfaces.Plugin as ABC instead.""" - - -class IPlugin(zope.interface.Interface): # pylint: disable=inherit-non-class - """Deprecated, use certbot.interfaces.Plugin as ABC instead.""" - - class Plugin(metaclass=ABCMeta): """Certbot plugin. @@ -168,10 +150,6 @@ class Plugin(metaclass=ABCMeta): """ -class IAuthenticator(IPlugin): # pylint: disable=inherit-non-class - """Deprecated, use certbot.interfaces.Authenticator as ABC instead.""" - - class Authenticator(Plugin): """Generic Certbot Authenticator. @@ -231,10 +209,6 @@ class Authenticator(Plugin): """ -class IInstaller(IPlugin): # pylint: disable=inherit-non-class - """Deprecated, use certbot.interfaces.Installer as ABC instead.""" - - class Installer(Plugin): """Generic Certbot Installer Interface. @@ -362,14 +336,6 @@ class Installer(Plugin): """ -class IDisplay(zope.interface.Interface): # pylint: disable=inherit-non-class - """Deprecated, use your own Display implementation instead.""" - - -class IReporter(zope.interface.Interface): # pylint: disable=inherit-non-class - """Deprecated, use your own Reporter implementation instead.""" - - class RenewableCert(metaclass=ABCMeta): """Interface to a certificate lineage.""" @@ -499,36 +465,3 @@ 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: ModuleType) -> None: - self.__dict__['_module'] = module - - def __getattr__(self, attr: str) -> None: - 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: str, value: Any) -> None: # pragma: no cover - setattr(self._module, attr, value) - - def __delattr__(self, attr: str) -> None: # pragma: no cover - delattr(self._module, attr) - - def __dir__(self) -> List[str]: # 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/certbot/setup.py b/certbot/setup.py index 8f1de50ca..600087d7f 100644 --- a/certbot/setup.py +++ b/certbot/setup.py @@ -60,8 +60,6 @@ install_requires = [ # installation on Linux. 'pywin32>=300 ; sys_platform == "win32"', f'setuptools>={min_setuptools_version}', - 'zope.component', - 'zope.interface', ] dev_extras = [ diff --git a/certbot/tests/auth_handler_test.py b/certbot/tests/auth_handler_test.py index 9adbcdfbc..ba0323c3e 100644 --- a/certbot/tests/auth_handler_test.py +++ b/certbot/tests/auth_handler_test.py @@ -70,8 +70,7 @@ class HandleAuthorizationsTest(unittest.TestCase): self.mock_display = mock.Mock() self.mock_config = mock.Mock(debug_challenges=False) - with mock.patch("zope.component.provideUtility"): - display_obj.set_display(self.mock_display) + display_obj.set_display(self.mock_display) self.mock_auth = mock.MagicMock(name="Authenticator") diff --git a/certbot/tests/cli_test.py b/certbot/tests/cli_test.py index 514351f32..82138f52d 100644 --- a/certbot/tests/cli_test.py +++ b/certbot/tests/cli_test.py @@ -85,7 +85,7 @@ class ParseTest(unittest.TestCase): @staticmethod def parse(*args, **kwargs): - """Mocks zope.component.getUtility and calls _unmocked_parse.""" + """Mocks certbot._internal.display.obj.get_display and calls _unmocked_parse.""" with test_util.patch_display_util(): return ParseTest._unmocked_parse(*args, **kwargs) diff --git a/certbot/tests/client_test.py b/certbot/tests/client_test.py index e51be7f9b..70f46aee7 100644 --- a/certbot/tests/client_test.py +++ b/certbot/tests/client_test.py @@ -70,8 +70,7 @@ class RegisterTest(test_util.ConfigTestCase): self.config.email = "alias@example.com" self.account_storage = account.AccountMemoryStorage() self.tos_cb = mock.MagicMock() - with mock.patch("zope.component.provideUtility"): - display_obj.set_display(MagicMock()) + display_obj.set_display(MagicMock()) def _call(self): from certbot._internal.client import register diff --git a/certbot/tests/crypto_util_test.py b/certbot/tests/crypto_util_test.py index 0263ff76b..9a111a0eb 100644 --- a/certbot/tests/crypto_util_test.py +++ b/certbot/tests/crypto_util_test.py @@ -2,8 +2,6 @@ import logging import unittest -import certbot.util - try: import mock except ImportError: # pragma: no cover diff --git a/certbot/tests/main_test.py b/certbot/tests/main_test.py index ad443f1ca..e26b19357 100644 --- a/certbot/tests/main_test.py +++ b/certbot/tests/main_test.py @@ -1055,9 +1055,7 @@ class MainTest(test_util.ConfigTestCase): plugins.visible().ifaces.assert_called_once_with(ifaces) filtered = plugins.visible().ifaces() self.assertEqual(filtered.init.call_count, 1) - filtered.verify.assert_called_once_with(ifaces) - verified = filtered.verify() - self.assertEqual(stdout.getvalue().strip(), str(verified)) + self.assertEqual(stdout.getvalue().strip(), str(filtered)) @mock.patch('certbot._internal.main.plugins_disco') @mock.patch('certbot._internal.main.cli.HelpfulArgumentParser.determine_help_topics') @@ -1073,11 +1071,9 @@ class MainTest(test_util.ConfigTestCase): plugins.visible().ifaces.assert_called_once_with(ifaces) filtered = plugins.visible().ifaces() self.assertEqual(filtered.init.call_count, 1) - filtered.verify.assert_called_once_with(ifaces) - verified = filtered.verify() - verified.prepare.assert_called_once_with() - verified.available.assert_called_once_with() - available = verified.available() + filtered.prepare.assert_called_once_with() + filtered.available.assert_called_once_with() + available = filtered.available() self.assertEqual(stdout.getvalue().strip(), str(available)) def test_certonly_abspath(self): diff --git a/certbot/tests/plugins/disco_test.py b/certbot/tests/plugins/disco_test.py index 7c2dda0da..6b599f561 100644 --- a/certbot/tests/plugins/disco_test.py +++ b/certbot/tests/plugins/disco_test.py @@ -5,7 +5,6 @@ from typing import List import unittest import pkg_resources -import zope.interface from certbot import errors from certbot import interfaces @@ -129,29 +128,6 @@ class PluginEntryPointTest(unittest.TestCase): self.assertIs(self.plugin_ep.misconfigured, False) self.assertIs(self.plugin_ep.available, False) - def test_verify(self): - iface1 = mock.MagicMock(__name__="iface1") - iface2 = mock.MagicMock(__name__="iface2") - iface3 = mock.MagicMock(__name__="iface3") - # pylint: disable=protected-access - self.plugin_ep._initialized = plugin = mock.MagicMock() - - exceptions = zope.interface.exceptions - with mock.patch("certbot._internal.plugins.disco._verify") as mock_verify: - mock_verify.exceptions = exceptions - - def verify_object(obj, cls, iface): # pylint: disable=missing-docstring - assert obj is plugin - assert iface is iface1 or iface is iface2 or iface is iface3 - if iface is iface3: - return False - return True - mock_verify.side_effect = verify_object - self.assertTrue(self.plugin_ep.verify((iface1,))) - self.assertTrue(self.plugin_ep.verify((iface1, iface2))) - self.assertFalse(self.plugin_ep.verify((iface3,))) - self.assertFalse(self.plugin_ep.verify((iface1, iface3))) - def test_prepare(self): config = mock.MagicMock() self.plugin_ep.init(config=config) @@ -264,14 +240,6 @@ class PluginsRegistryTest(unittest.TestCase): self.plugin_ep.ifaces.return_value = False self.assertEqual({}, self.reg.ifaces()._plugins) - def test_verify(self): - self.plugin_ep.verify.return_value = True - # pylint: disable=protected-access - self.assertEqual( - self.plugins, self.reg.verify(mock.MagicMock())._plugins) - self.plugin_ep.verify.return_value = False - self.assertEqual({}, self.reg.verify(mock.MagicMock())._plugins) - def test_prepare(self): self.plugin_ep.prepare.return_value = "baz" self.assertEqual(["baz"], self.reg.prepare()) diff --git a/certbot/tests/plugins/selection_test.py b/certbot/tests/plugins/selection_test.py index fb090f05d..b2f387542 100644 --- a/certbot/tests/plugins/selection_test.py +++ b/certbot/tests/plugins/selection_test.py @@ -77,7 +77,7 @@ class PickPluginTest(unittest.TestCase): plugin_ep.init.return_value = "foo" plugin_ep.misconfigured = False - self.reg.visible().ifaces().verify().available.return_value = { + self.reg.visible().ifaces().available.return_value = { "bar": plugin_ep} self.assertEqual("foo", self._call()) @@ -86,14 +86,14 @@ class PickPluginTest(unittest.TestCase): plugin_ep.init.return_value = "foo" plugin_ep.misconfigured = True - self.reg.visible().ifaces().verify().available.return_value = { + self.reg.visible().ifaces().available.return_value = { "bar": plugin_ep} self.assertIsNone(self._call()) def test_multiple(self): plugin_ep = mock.MagicMock() plugin_ep.init.return_value = "foo" - self.reg.visible().ifaces().verify().available.return_value = { + self.reg.visible().ifaces().available.return_value = { "bar": plugin_ep, "baz": plugin_ep, } @@ -104,7 +104,7 @@ class PickPluginTest(unittest.TestCase): [plugin_ep, plugin_ep], self.question) def test_choose_plugin_none(self): - self.reg.visible().ifaces().verify().available.return_value = { + self.reg.visible().ifaces().available.return_value = { "bar": None, "baz": None, } diff --git a/certbot/tests/reporter_test.py b/certbot/tests/reporter_test.py deleted file mode 100644 index 0270ad3f6..000000000 --- a/certbot/tests/reporter_test.py +++ /dev/null @@ -1,89 +0,0 @@ -"""Tests for certbot._internal.reporter.""" -import io -import sys -import unittest - - -try: - import mock -except ImportError: # pragma: no cover - from unittest import mock - - -class ReporterTest(unittest.TestCase): - """Tests for certbot._internal.reporter.Reporter.""" - def setUp(self): - from certbot._internal import reporter - self.reporter = reporter.Reporter(mock.MagicMock(quiet=False)) - - self.old_stdout = sys.stdout - sys.stdout = io.StringIO() - - def tearDown(self): - sys.stdout = self.old_stdout - - def test_multiline_message(self): - self.reporter.add_message("Line 1\nLine 2", self.reporter.LOW_PRIORITY) - self.reporter.print_messages() - output = sys.stdout.getvalue() - self.assertIn("Line 1\n", output) - self.assertIn("Line 2", output) - - def test_tty_print_empty(self): - sys.stdout.isatty = lambda: True - self.test_no_tty_print_empty() - - def test_no_tty_print_empty(self): - self.reporter.print_messages() - self.assertEqual(sys.stdout.getvalue(), "") - try: - raise ValueError - except ValueError: - self.reporter.print_messages() - self.assertEqual(sys.stdout.getvalue(), "") - - def test_tty_successful_exit(self): - sys.stdout.isatty = lambda: True - self._successful_exit_common() - - def test_no_tty_successful_exit(self): - self._successful_exit_common() - - def test_tty_unsuccessful_exit(self): - sys.stdout.isatty = lambda: True - self._unsuccessful_exit_common() - - def test_no_tty_unsuccessful_exit(self): - self._unsuccessful_exit_common() - - def _successful_exit_common(self): - self._add_messages() - self.reporter.print_messages() - output = sys.stdout.getvalue() - self.assertIn("IMPORTANT NOTES:", output) - self.assertIn("High", output) - self.assertIn("Med", output) - self.assertIn("Low", output) - - def _unsuccessful_exit_common(self): - self._add_messages() - try: - raise ValueError - except ValueError: - self.reporter.print_messages() - output = sys.stdout.getvalue() - self.assertIn("IMPORTANT NOTES:", output) - self.assertIn("High", output) - self.assertNotIn("Med", output) - self.assertNotIn("Low", output) - - def _add_messages(self): - self.reporter.add_message("High", self.reporter.HIGH_PRIORITY) - self.reporter.add_message( - "Med", self.reporter.MEDIUM_PRIORITY, on_crash=False) - self.reporter.add_message( - "Low", self.reporter.LOW_PRIORITY, on_crash=False) - - -if __name__ == "__main__": - unittest.main() # pragma: no cover diff --git a/pytest.ini b/pytest.ini index 92a403451..4489792b9 100644 --- a/pytest.ini +++ b/pytest.ini @@ -13,25 +13,18 @@ # The current warnings being ignored are: # 1) The warning raised when importing certbot.tests.util and the external mock # library is installed. -# 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. -# 4) The deprecation warning raised when importing deprecated attributes from +# 2) The deprecation warning raised when importing deprecated attributes from # the certbot.display.util module. -# 5) A deprecation warning is raised in dnspython==1.15.0 in the oldest tests for +# 3) A deprecation warning is raised in dnspython==1.15.0 in the oldest tests for # certbot-dns-rfc2136. -# 6) The vendored version of six in botocore causes ImportWarnings in Python +# 4) The vendored version of six in botocore causes ImportWarnings in Python # 3.10+. See https://github.com/boto/botocore/issues/2548. -# 7) botocore's default TLS settings raise deprecation warnings in Python +# 5) botocore's default TLS settings raise deprecation warnings in Python # 3.10+, but their values are sane from a security perspective. See # https://github.com/boto/botocore/issues/2550. 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 ignore:decodestring\(\) is a deprecated alias:DeprecationWarning:dns ignore:_SixMetaPathImporter.:ImportWarning diff --git a/tools/oldest_constraints.txt b/tools/oldest_constraints.txt index 90ec56a34..9853143fe 100644 --- a/tools/oldest_constraints.txt +++ b/tools/oldest_constraints.txt @@ -2,9 +2,9 @@ # that script. apacheconfig==0.3.2 asn1crypto==0.24.0 -astroid==2.11.6; python_version >= "3.7" -atomicwrites==1.4.0; sys_platform == "win32" and python_version >= "3.7" -attrs==21.4.0; python_version >= "3.7" +astroid==2.11.7; python_version >= "3.7" +atomicwrites==1.4.1; sys_platform == "win32" and python_version >= "3.7" +attrs==22.1.0; python_version >= "3.7" bcrypt==3.2.2; python_version >= "3.7" boto3==1.15.15 botocore==1.18.15 @@ -16,11 +16,11 @@ cloudflare==1.5.1 colorama==0.4.5; sys_platform == "win32" and python_version >= "3.7" configargparse==0.10.0 configobj==5.0.6 -coverage==6.4.1; python_version >= "3.7" +coverage==6.4.2; python_version >= "3.7" cryptography==3.2.1 -cython==0.29.30 +cython==0.29.31 dill==0.3.5.1; python_version >= "3.7" -distlib==0.3.4; python_version >= "3.7" +distlib==0.3.5; python_version >= "3.7" distro==1.0.1 dns-lexicon==3.2.1 dnspython==1.15.0 @@ -35,7 +35,7 @@ future==0.18.2; python_version >= "3.7" google-api-python-client==1.5.5 httplib2==0.9.2 idna==2.6 -importlib-metadata==4.11.4; python_version < "3.8" and python_version >= "3.7" +importlib-metadata==4.12.0; python_version < "3.8" and python_version >= "3.7" iniconfig==1.1.1; python_version >= "3.7" ipaddress==1.0.16 isort==5.10.1; python_version >= "3.7" and python_version < "4.0" @@ -47,14 +47,14 @@ logger==1.4; python_version >= "3.7" mccabe==0.7.0; python_version >= "3.7" mock==1.0.1 mypy-extensions==0.4.3; python_version >= "3.7" -mypy==0.961; python_version >= "3.7" +mypy==0.971; python_version >= "3.7" ndg-httpsclient==0.3.2 oauth2client==4.0.0 packaging==21.3; python_version >= "3.7" paramiko==2.11.0; python_version >= "3.7" parsedatetime==2.4 pbr==1.8.0 -pip==22.1.2; python_version >= "3.7" +pip==22.2.1; python_version >= "3.7" platformdirs==2.5.2; python_version >= "3.7" pluggy==1.0.0; python_version >= "3.7" ply==3.4 @@ -83,35 +83,31 @@ pyyaml==5.4.1; python_version >= "3.7" requests-file==1.5.1; python_version >= "3.7" requests-toolbelt==0.9.1; python_version >= "3.7" requests==2.20.0 -rsa==4.8; python_version >= "3.7" and python_version < "4" +rsa==4.9; python_version >= "3.7" and python_version < "4" s3transfer==0.3.7; python_version >= "3.7" setuptools==41.6.0 six==1.11.0 texttable==1.6.4; python_version >= "3.7" -tldextract==3.3.0; python_version >= "3.7" +tldextract==3.3.1; python_version >= "3.7" tomli==2.0.1; python_version < "3.11" and python_version >= "3.7" or python_full_version <= "3.11.0a6" and python_version >= "3.7" or python_version >= "3.7" tox==1.9.2; python_version >= "3.7" typed-ast==1.5.4; python_version >= "3.7" and python_version < "3.8" or implementation_name == "cpython" and python_version < "3.8" and python_version >= "3.7" types-cryptography==3.3.21; python_version >= "3.7" types-mock==4.0.15; python_version >= "3.7" -types-pyopenssl==22.0.3; python_version >= "3.7" +types-pyopenssl==22.0.9; python_version >= "3.7" types-pyrfc3339==1.1.1; python_version >= "3.7" -types-python-dateutil==2.8.17; python_version >= "3.7" -types-pytz==2022.1.0; python_version >= "3.7" -types-requests==2.27.31; python_version >= "3.7" -types-setuptools==57.4.17; python_version >= "3.7" -types-six==1.16.16; python_version >= "3.7" -types-urllib3==1.26.15; python_version >= "3.7" -typing-extensions==4.2.0; python_version >= "3.7" or python_version < "3.10" and python_version >= "3.7" or python_version < "3.8" and python_version >= "3.7" +types-python-dateutil==2.8.19; python_version >= "3.7" +types-pytz==2022.1.2; python_version >= "3.7" +types-requests==2.28.5; python_version >= "3.7" +types-setuptools==63.2.2; python_version >= "3.7" +types-six==1.16.18; python_version >= "3.7" +types-urllib3==1.26.17; python_version >= "3.7" +typing-extensions==4.3.0; python_version >= "3.7" or python_version < "3.10" and python_version >= "3.7" or python_version < "3.8" and python_version >= "3.7" uritemplate==3.0.1; python_version >= "3.7" urllib3==1.24.2 -virtualenv==20.14.1; python_version >= "3.7" +virtualenv==20.16.2; python_version >= "3.7" websocket-client==0.59.0; python_version >= "3.7" wheel==0.33.6 wheel==0.33.6; python_version >= "3.7" wrapt==1.14.1; python_version >= "3.7" -zipp==3.8.0; python_version < "3.8" and python_version >= "3.7" -zope.component==4.1.0 -zope.event==4.0.3 -zope.hookable==4.0.4 -zope.interface==4.0.5 +zipp==3.8.1; python_version < "3.8" and python_version >= "3.7" diff --git a/tools/pinning/oldest/pyproject.toml b/tools/pinning/oldest/pyproject.toml index 9b76fdbb5..74b899958 100644 --- a/tools/pinning/oldest/pyproject.toml +++ b/tools/pinning/oldest/pyproject.toml @@ -79,11 +79,6 @@ requests = "2.20.0" setuptools = "41.6.0" six = "1.11.0" urllib3 = "1.24.2" -# Package names containing "." need to be quoted. -"zope.component" = "4.1.0" -"zope.event" = "4.0.3" -"zope.hookable" = "4.0.4" -"zope.interface" = "4.0.5" # Build dependencies # Since there doesn't appear to diff --git a/tools/requirements.txt b/tools/requirements.txt index d57f3a600..71ce482b6 100644 --- a/tools/requirements.txt +++ b/tools/requirements.txt @@ -189,8 +189,4 @@ websocket-client==0.59.0; python_version >= "3.7" and python_full_version < "3.0 wheel==0.37.1; python_version >= "3.7" and python_full_version < "3.0.0" or python_version >= "3.7" and python_full_version >= "3.5.0" wrapt==1.13.3; python_version >= "3.7" and python_full_version < "3.0.0" or python_version >= "3.7" and python_full_version >= "3.5.0" or python_version >= "3.7" and python_full_version >= "3.6.2" yarg==0.1.9; python_version >= "3.7" -zipp==3.7.0; python_version >= "3.7" and python_full_version < "3.0.0" and python_version < "3.8" or python_version >= "3.7" and python_version < "3.8" and python_full_version >= "3.5.0" -zope.component==5.0.1; python_version >= "3.7" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.7" -zope.event==4.5.0; python_version >= "3.7" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.7" -zope.hookable==5.1.0; python_version >= "3.7" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.7" -zope.interface==5.4.0; python_version >= "3.7" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.7" +zipp==3.8.1; python_version >= "3.7" and python_version < "3.8"