From 2712558d05eb7cb8ecf2a7df50591098c453aabd Mon Sep 17 00:00:00 2001 From: Frank Brehm Date: Wed, 7 Sep 2022 15:41:04 +0200 Subject: [PATCH] Creating and useing a base application class for all application classes. --- lib/pp_admintools/app/__init__.py | 167 +++++++++++++++++++++++++++++- lib/pp_admintools/app/ldap.py | 56 ++-------- lib/pp_admintools/app/mail.py | 14 +-- lib/pp_admintools/app/pdns.py | 4 +- 4 files changed, 178 insertions(+), 63 deletions(-) diff --git a/lib/pp_admintools/app/__init__.py b/lib/pp_admintools/app/__init__.py index 892def3..3177b65 100644 --- a/lib/pp_admintools/app/__init__.py +++ b/lib/pp_admintools/app/__init__.py @@ -1,6 +1,169 @@ -#!/bin/env python3 # -*- coding: utf-8 -*- +""" +@author: Frank Brehm +@contact: frank.brehm@pixelpark.com +@copyright: © 2022 by Frank Brehm, Berlin +@summary: A base module for all DPX application classes +""" +from __future__ import absolute_import + +# Standard modules +import logging +import argparse + +# Third party modules +from fb_tools.common import to_bool +from fb_tools.cfg_app import FbConfigApplication +from fb_tools.errors import FbAppError +from fb_tools.multi_config import BaseMultiConfig + +# Own modules +from .. import __version__ as GLOBAL_VERSION +from .. import DEFAULT_CONFIG_DIR + +from ..config.ldap import MAX_TIMEOUT + +from ..xlate import XLATOR + +LOG = logging.getLogger(__name__) + +_ = XLATOR.gettext +ngettext = XLATOR.ngettext + +__version__ = '0.2.0' + + +# ============================================================================= +class DPXAppError(FbAppError): + """ Base exception class for all exceptions in all LDAP using application classes.""" + pass + + +# ============================================================================= +class TimeoutOptionAction(argparse.Action): + + # ------------------------------------------------------------------------- + def __init__(self, option_strings, *args, **kwargs): + + super(TimeoutOptionAction, self).__init__( + option_strings=option_strings, *args, **kwargs) + + # ------------------------------------------------------------------------- + def __call__(self, parser, namespace, given_timeout, option_string=None): + + try: + timeout = int(given_timeout) + if timeout <= 0 or timeout > MAX_TIMEOUT: + msg = _( + "a timeout must be greater than zero and less " + "or equal to {}.").format(MAX_TIMEOUT) + raise ValueError(msg) + except (ValueError, TypeError) as e: + msg = _("Wrong timeout {!r}:").format(given_timeout) + msg += ' ' + str(e) + raise argparse.ArgumentError(self, msg) + + setattr(namespace, self.dest, timeout) + +# ============================================================================= +class BaseDPXApplication(FbConfigApplication): + """ + Base class for all DPX application classes. + """ + + default_prompt_timeout = 10 + max_prompt_timeout = 600 + + # ------------------------------------------------------------------------- + def __init__( + self, appname=None, verbose=0, version=GLOBAL_VERSION, base_dir=None, + cfg_class=BaseMultiConfig, initialized=False, usage=None, description=None, + argparse_epilog=None, argparse_prefix_chars='-', env_prefix=None, + config_dir=DEFAULT_CONFIG_DIR): + + self._yes = False + self._prompt_timeout = self.default_prompt_timeout + + super(BaseDPXApplication, self).__init__( + appname=appname, verbose=verbose, version=version, base_dir=base_dir, + description=description, cfg_class=cfg_class, initialized=False, + argparse_epilog=argparse_epilog, argparse_prefix_chars=argparse_prefix_chars, + env_prefix=env_prefix, config_dir=config_dir + ) + + # ----------------------------------------------------------- + @property + def yes(self): + """Assume 'yes' as an answer to all questions.""" + return self._yes + + @yes.setter + def yes(self, value): + self._yes = to_bool(value) + + # ----------------------------------------------------------- + @property + def prompt_timeout(self): + """The timeout in seconds for waiting for an answer on a prompt.""" + return getattr(self, '_prompt_timeout', self.default_prompt_timeout) + + @prompt_timeout.setter + def prompt_timeout(self, value): + v = int(value) + if v < 0 or v > self.max_prompt_timeout: + LOG.warning(_("Wrong prompt timeout {v!r}, must be 0 >= 0 and <= {max}.").format( + v=value, max=self.max_prompt_timeout)) + else: + self._prompt_timeout = v + + # ------------------------------------------------------------------------- + def as_dict(self, short=True): + """ + Transforms the elements of the object into a dict + + @param short: don't include local properties in resulting dict. + @type short: bool + + @return: structure as dict + @rtype: dict + """ + + res = super(BaseDPXApplication, self).as_dict(short=short) + + res['prompt_timeout'] = self.prompt_timeout + res['yes'] = self.yes + + return res + + # ------------------------------------------------------------------------- + def init_arg_parser(self): + """ + Public available method to initiate the argument parser. + """ + + super(BaseDPXApplication, self).init_arg_parser() + + self.arg_parser.add_argument( + '-Y', '--yes', '--assume-yes', action="store_true", dest="yes", help=argparse.SUPPRESS) + + # ------------------------------------------------------------------------- + def post_init(self): + """ + Method to execute before calling run(). Here could be done some + finishing actions after reading in commandline parameters, + configuration a.s.o. + + This method could be overwritten by descendant classes, these + methhods should allways include a call to post_init() of the + parent class. + + """ + + self.initialized = False + + super(BaseDPXApplication, self).post_init() + + self.yes = self.args.yes -__version__ = '0.1.0' # vim: ts=4 et list diff --git a/lib/pp_admintools/app/ldap.py b/lib/pp_admintools/app/ldap.py index 9490690..9f08a9a 100644 --- a/lib/pp_admintools/app/ldap.py +++ b/lib/pp_admintools/app/ldap.py @@ -29,9 +29,7 @@ from ldap3 import ALL_ATTRIBUTES # from ldap3.core.exceptions import LDAPInvalidDnError, LDAPInvalidValueError # from ldap3.core.exceptions import LDAPException, LDAPBindError -from fb_tools.common import pp, to_bool, is_sequence -from fb_tools.cfg_app import FbConfigApplication -from fb_tools.errors import FbAppError +from fb_tools.common import pp, is_sequence from fb_tools.mailaddress import MailAddress from fb_tools.collections import FrozenCIStringSet, CIStringSet @@ -44,10 +42,12 @@ from .. import MAX_PORT_NUMBER, DEFAULT_CONFIG_DIR # from ..argparse_actions import PortOptionAction +from . import DPXAppError, TimeoutOptionAction, BaseDPXApplication + # from ..config.ldap import LdapConfigError from ..config.ldap import LdapConnectionInfo, LdapConfiguration # rom ..config.ldap import DEFAULT_PORT_LDAP, DEFAULT_PORT_LDAPS -from ..config.ldap import DEFAULT_TIMEOUT, MAX_TIMEOUT +from ..config.ldap import DEFAULT_TIMEOUT __version__ = '0.4.2' LOG = logging.getLogger(__name__) @@ -57,7 +57,7 @@ ngettext = XLATOR.ngettext # ============================================================================= -class LdapAppError(FbAppError): +class LdapAppError(DPXAppError): """ Base exception class for all exceptions in all LDAP using application classes.""" pass @@ -126,34 +126,7 @@ class LdapPortOptionAction(argparse.Action): # ============================================================================= -class TimeoutOptionAction(argparse.Action): - - # ------------------------------------------------------------------------- - def __init__(self, option_strings, *args, **kwargs): - - super(TimeoutOptionAction, self).__init__( - option_strings=option_strings, *args, **kwargs) - - # ------------------------------------------------------------------------- - def __call__(self, parser, namespace, given_timeout, option_string=None): - - try: - timeout = int(given_timeout) - if timeout <= 0 or timeout > MAX_TIMEOUT: - msg = _( - "a timeout must be greater than zero and less " - "or equal to {}.").format(MAX_TIMEOUT) - raise ValueError(msg) - except (ValueError, TypeError) as e: - msg = _("Wrong timeout {!r}:").format(given_timeout) - msg += ' ' + str(e) - raise argparse.ArgumentError(self, msg) - - setattr(namespace, self.dest, timeout) - - -# ============================================================================= -class BaseLdapApplication(FbConfigApplication): +class BaseLdapApplication(BaseDPXApplication): """ Base class for all application classes using LDAP. """ @@ -187,7 +160,6 @@ class BaseLdapApplication(FbConfigApplication): self._password_file = None self.ldap_instances = [] - self._yes = False self.ldap_server = {} self.ldap_connection = {} @@ -226,16 +198,6 @@ class BaseLdapApplication(FbConfigApplication): self._password_file = path - # ----------------------------------------------------------- - @property - def yes(self): - """Assume 'yes' as an answer to all questions.""" - return self._yes - - @yes.setter - def yes(self, value): - self._yes = to_bool(value) - # ------------------------------------------------------------------------- def as_dict(self, short=True): """ @@ -255,7 +217,6 @@ class BaseLdapApplication(FbConfigApplication): res['show_cmdline_ldap_timeout'] = self.show_cmdline_ldap_timeout res['use_default_ldap_connection'] = self.use_default_ldap_connection res['use_multiple_ldap_connections'] = self.use_multiple_ldap_connections - res['yes'] = self.yes return res @@ -274,9 +235,6 @@ class BaseLdapApplication(FbConfigApplication): group_title = _('Options fo LDAP connections') ldap_group = self.arg_parser.add_argument_group(group_title) - ldap_group.add_argument( - '-y', '--yes', '--assume-yes', action="store_true", dest="yes", help=argparse.SUPPRESS) - if self.use_default_ldap_connection: ldap_host = LdapConfiguration.default_ldap_server @@ -402,8 +360,6 @@ class BaseLdapApplication(FbConfigApplication): self._init_default_connection() - self.yes = self.args.yes - if self.use_default_ldap_connection: self.ldap_instances = ['default'] return diff --git a/lib/pp_admintools/app/mail.py b/lib/pp_admintools/app/mail.py index 46ae306..3a63083 100644 --- a/lib/pp_admintools/app/mail.py +++ b/lib/pp_admintools/app/mail.py @@ -22,13 +22,7 @@ import smtplib # Third party modules from fb_tools.common import pp - -from fb_tools.cfg_app import FbConfigApplication - -from fb_tools.errors import FbAppError - from fb_tools.xlate import format_list - from fb_tools import MailAddress # Own modules @@ -41,7 +35,9 @@ from ..argparse_actions import PortOptionAction from ..config.mail import MailConfiguration -__version__ = '0.2.9' +from . import DPXAppError, BaseDPXApplication + +__version__ = '0.3.1' LOG = logging.getLogger(__name__) _ = XLATOR.gettext @@ -49,13 +45,13 @@ ngettext = XLATOR.ngettext # ============================================================================= -class MailAppError(FbAppError): +class MailAppError(DPXAppError): """ Base exception class for all exceptions in all mail sending application classes.""" pass # ============================================================================= -class BaseMailApplication(FbConfigApplication): +class BaseMailApplication(BaseDPXApplication): """ Base class for all mail sending application classes. """ diff --git a/lib/pp_admintools/app/pdns.py b/lib/pp_admintools/app/pdns.py index 76118dc..2c5a68a 100644 --- a/lib/pp_admintools/app/pdns.py +++ b/lib/pp_admintools/app/pdns.py @@ -33,14 +33,14 @@ from .. import __version__ as GLOBAL_VERSION from ..argparse_actions import PortOptionAction, TimeoutOptionAction -from ..app.mail import MailAppError, BaseMailApplication +from .mail import MailAppError, BaseMailApplication from ..config.pdns import PdnsConfiguration # from ..config.pdns import PdnsConfigError, PdnsConfiguration from ..xlate import XLATOR -__version__ = '0.9.2' +__version__ = '0.9.3' LOG = logging.getLogger(__name__) _ = XLATOR.gettext -- 2.39.5