mirror of
				https://salsa.debian.org/freeipa-team/freeipa.git
				synced 2025-02-25 18:55:28 -06:00 
			
		
		
		
	plugable: turn Plugin attributes into properties
Implement the `name`, `doc` and `summary` Plugin attributes as properties to allow them to be overriden in sub-classes. Always use .doc rather than .__doc__ to access plugin documentation. Remove the mostly unused `module`, `fullname`, `bases` and `label` attributes. https://fedorahosted.org/freeipa/ticket/4739 Reviewed-By: David Kupka <dkupka@redhat.com>
This commit is contained in:
		@@ -39,7 +39,6 @@ import six
 | 
			
		||||
 | 
			
		||||
from ipalib import errors
 | 
			
		||||
from ipalib.config import Env
 | 
			
		||||
from ipalib import text
 | 
			
		||||
from ipalib.text import _
 | 
			
		||||
from ipalib.base import ReadOnly, NameSpace, lock, islocked
 | 
			
		||||
from ipalib.constants import DEFAULT_CONFIG
 | 
			
		||||
@@ -127,38 +126,30 @@ class Plugin(ReadOnly):
 | 
			
		||||
 | 
			
		||||
    finalize_early = True
 | 
			
		||||
 | 
			
		||||
    label = None
 | 
			
		||||
 | 
			
		||||
    def __init__(self, api):
 | 
			
		||||
        assert api is not None
 | 
			
		||||
        self.__api = api
 | 
			
		||||
        self.__finalize_called = False
 | 
			
		||||
        self.__finalized = False
 | 
			
		||||
        self.__finalize_lock = threading.RLock()
 | 
			
		||||
        cls = self.__class__
 | 
			
		||||
        self.name = cls.__name__
 | 
			
		||||
        self.module = cls.__module__
 | 
			
		||||
        self.fullname = '%s.%s' % (self.module, self.name)
 | 
			
		||||
        self.bases = tuple(
 | 
			
		||||
            '%s.%s' % (b.__module__, b.__name__) for b in cls.__bases__
 | 
			
		||||
        )
 | 
			
		||||
        self.doc = _(cls.__doc__)
 | 
			
		||||
        if not self.doc.msg:
 | 
			
		||||
            self.summary = '<%s>' % self.fullname
 | 
			
		||||
        else:
 | 
			
		||||
            self.summary = unicode(self.doc).split('\n\n', 1)[0].strip()
 | 
			
		||||
        log_mgr.get_logger(self, True)
 | 
			
		||||
        if self.label is None:
 | 
			
		||||
            self.label = text.FixMe(self.name + '.label')
 | 
			
		||||
        if not isinstance(self.label, text.LazyText):
 | 
			
		||||
            raise TypeError(
 | 
			
		||||
                TYPE_ERROR % (
 | 
			
		||||
                    self.fullname + '.label',
 | 
			
		||||
                    text.LazyText,
 | 
			
		||||
                    type(self.label),
 | 
			
		||||
                    self.label
 | 
			
		||||
                )
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def name(self):
 | 
			
		||||
        return type(self).__name__
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def doc(self):
 | 
			
		||||
        return type(self).__doc__
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def summary(self):
 | 
			
		||||
        doc = self.doc
 | 
			
		||||
        if not _(doc).msg:
 | 
			
		||||
            cls = type(self)
 | 
			
		||||
            return u'<%s.%s>' % (cls.__module__, cls.__name__)
 | 
			
		||||
        else:
 | 
			
		||||
            return unicode(doc).split('\n\n', 1)[0].strip()
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def api(self):
 | 
			
		||||
 
 | 
			
		||||
@@ -1328,7 +1328,7 @@ class ra(rabase.rabase):
 | 
			
		||||
        if detail is not None:
 | 
			
		||||
            err_msg = u'%s (%s)' % (err_msg, detail)
 | 
			
		||||
 | 
			
		||||
        self.error('%s.%s(): %s', self.fullname, func_name, err_msg)
 | 
			
		||||
        self.error('%s.%s(): %s', type(self).__name__, func_name, err_msg)
 | 
			
		||||
        raise errors.CertificateOperationError(error=err_msg)
 | 
			
		||||
 | 
			
		||||
    @cachedproperty
 | 
			
		||||
@@ -1428,7 +1428,7 @@ class ra(rabase.rabase):
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        """
 | 
			
		||||
        self.debug('%s.check_request_status()', self.fullname)
 | 
			
		||||
        self.debug('%s.check_request_status()', type(self).__name__)
 | 
			
		||||
 | 
			
		||||
        # Call CMS
 | 
			
		||||
        http_status, http_headers, http_body = \
 | 
			
		||||
@@ -1508,7 +1508,7 @@ class ra(rabase.rabase):
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        """
 | 
			
		||||
        self.debug('%s.get_certificate()', self.fullname)
 | 
			
		||||
        self.debug('%s.get_certificate()', type(self).__name__)
 | 
			
		||||
 | 
			
		||||
        # Convert serial number to integral type from string to properly handle
 | 
			
		||||
        # radix issues. Note: the int object constructor will properly handle large
 | 
			
		||||
@@ -1581,7 +1581,7 @@ class ra(rabase.rabase):
 | 
			
		||||
        .. [2] Base64 encoded
 | 
			
		||||
 | 
			
		||||
        """
 | 
			
		||||
        self.debug('%s.request_certificate()', self.fullname)
 | 
			
		||||
        self.debug('%s.request_certificate()', type(self).__name__)
 | 
			
		||||
 | 
			
		||||
        # Call CMS
 | 
			
		||||
        http_status, http_headers, http_body = \
 | 
			
		||||
@@ -1653,7 +1653,7 @@ class ra(rabase.rabase):
 | 
			
		||||
        +---------------+---------------+---------------+
 | 
			
		||||
 | 
			
		||||
        """
 | 
			
		||||
        self.debug('%s.revoke_certificate()', self.fullname)
 | 
			
		||||
        self.debug('%s.revoke_certificate()', type(self).__name__)
 | 
			
		||||
        if type(revocation_reason) is not int:
 | 
			
		||||
            raise TypeError(TYPE_ERROR % ('revocation_reason', int, revocation_reason, type(revocation_reason)))
 | 
			
		||||
 | 
			
		||||
@@ -1718,7 +1718,7 @@ class ra(rabase.rabase):
 | 
			
		||||
        +---------------+---------------+---------------+
 | 
			
		||||
        """
 | 
			
		||||
 | 
			
		||||
        self.debug('%s.take_certificate_off_hold()', self.fullname)
 | 
			
		||||
        self.debug('%s.take_certificate_off_hold()', type(self).__name__)
 | 
			
		||||
 | 
			
		||||
        # Convert serial number to integral type from string to properly handle
 | 
			
		||||
        # radix issues. Note: the int object constructor will properly handle large
 | 
			
		||||
@@ -1772,7 +1772,7 @@ class ra(rabase.rabase):
 | 
			
		||||
            ts = time.strptime(value, '%Y-%m-%d')
 | 
			
		||||
            return int(time.mktime(ts) * 1000)
 | 
			
		||||
 | 
			
		||||
        self.debug('%s.find()', self.fullname)
 | 
			
		||||
        self.debug('%s.find()', type(self).__name__)
 | 
			
		||||
 | 
			
		||||
        # Create the root element
 | 
			
		||||
        page = etree.Element('CertSearchRequest')
 | 
			
		||||
@@ -1844,7 +1844,7 @@ class ra(rabase.rabase):
 | 
			
		||||
            e.text = str(booloptions[opt]).lower()
 | 
			
		||||
 | 
			
		||||
        payload = etree.tostring(doc, pretty_print=False, xml_declaration=True, encoding='UTF-8')
 | 
			
		||||
        self.debug('%s.find(): request: %s', self.fullname, payload)
 | 
			
		||||
        self.debug('%s.find(): request: %s', type(self).__name__, payload)
 | 
			
		||||
 | 
			
		||||
        url = 'http://%s/ca/rest/certs/search?size=%d' % (
 | 
			
		||||
            ipautil.format_netloc(self.ca_host, 8080),
 | 
			
		||||
@@ -1869,7 +1869,7 @@ class ra(rabase.rabase):
 | 
			
		||||
                                                   detail=e.reason)
 | 
			
		||||
 | 
			
		||||
        data = response.readlines()
 | 
			
		||||
        self.debug('%s.find(): response: %s', self.fullname, data)
 | 
			
		||||
        self.debug('%s.find(): response: %s', type(self).__name__, data)
 | 
			
		||||
        parser = etree.XMLParser()
 | 
			
		||||
        try:
 | 
			
		||||
            doc = etree.fromstring(data[0], parser)
 | 
			
		||||
 
 | 
			
		||||
@@ -423,11 +423,11 @@ class WSGIExecutioner(Executioner):
 | 
			
		||||
        return [response]
 | 
			
		||||
 | 
			
		||||
    def unmarshal(self, data):
 | 
			
		||||
        raise NotImplementedError('%s.unmarshal()' % self.fullname)
 | 
			
		||||
        raise NotImplementedError('%s.unmarshal()' % type(self).__name__)
 | 
			
		||||
 | 
			
		||||
    def marshal(self, result, error, _id=None,
 | 
			
		||||
                version=VERSION_WITHOUT_CAPABILITIES):
 | 
			
		||||
        raise NotImplementedError('%s.marshal()' % self.fullname)
 | 
			
		||||
        raise NotImplementedError('%s.marshal()' % type(self).__name__)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class jsonserver(WSGIExecutioner, HTTP_Status):
 | 
			
		||||
@@ -705,7 +705,7 @@ class xmlserver(KerberosWSGIExecutioner):
 | 
			
		||||
        if method_name in self._system_commands:
 | 
			
		||||
            return u''
 | 
			
		||||
        elif method_name in self.Command:
 | 
			
		||||
            return unicode(self.Command[method_name].__doc__ or '')
 | 
			
		||||
            return unicode(self.Command[method_name].doc or '')
 | 
			
		||||
        else:
 | 
			
		||||
            raise errors.CommandError(name=method_name)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -114,7 +114,7 @@ def test_command_help():
 | 
			
		||||
    assert h_ctx.stderr == ''
 | 
			
		||||
 | 
			
		||||
    assert h_ctx.stdout == help_ctx.stdout
 | 
			
		||||
    assert unicode(user_add.__doc__) in help_ctx.stdout
 | 
			
		||||
    assert unicode(user_add.doc) in help_ctx.stdout
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_ambiguous_command_or_topic():
 | 
			
		||||
 
 | 
			
		||||
@@ -52,8 +52,6 @@ class test_Plugin(ClassChecker):
 | 
			
		||||
        api = 'the api instance'
 | 
			
		||||
        o = self.cls(api)
 | 
			
		||||
        assert o.name == 'Plugin'
 | 
			
		||||
        assert o.module == 'ipalib.plugable'
 | 
			
		||||
        assert o.fullname == 'ipalib.plugable.Plugin'
 | 
			
		||||
        assert isinstance(o.doc, text.Gettext)
 | 
			
		||||
        class some_subclass(self.cls):
 | 
			
		||||
            """
 | 
			
		||||
@@ -67,8 +65,6 @@ class test_Plugin(ClassChecker):
 | 
			
		||||
            """
 | 
			
		||||
        o = some_subclass(api)
 | 
			
		||||
        assert o.name == 'some_subclass'
 | 
			
		||||
        assert o.module == __name__
 | 
			
		||||
        assert o.fullname == '%s.some_subclass' % __name__
 | 
			
		||||
        assert o.summary == 'Do sub-classy things.'
 | 
			
		||||
        assert isinstance(o.doc, text.Gettext)
 | 
			
		||||
        class another_subclass(self.cls):
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										4
									
								
								makeapi
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								makeapi
									
									
									
									
									
								
							@@ -214,13 +214,13 @@ def validate_doc():
 | 
			
		||||
            topic = next_topic
 | 
			
		||||
 | 
			
		||||
        # Does the command have documentation?
 | 
			
		||||
        if cmd.__doc__ is None:
 | 
			
		||||
        if cmd.doc is None:
 | 
			
		||||
            src_file = inspect.getsourcefile(cmd_class)
 | 
			
		||||
            line_num = inspect.getsourcelines(cmd_class)[1]
 | 
			
		||||
            n_missing_cmd_doc += 1
 | 
			
		||||
            print("%s:%d command \"%s\" has no doc" % (src_file, line_num, cmd.name))
 | 
			
		||||
        # Yes the command has doc, but is it internationalized?
 | 
			
		||||
        elif not is_i18n(cmd.__doc__):
 | 
			
		||||
        elif not is_i18n(cmd.doc):
 | 
			
		||||
            src_file = inspect.getsourcefile(cmd_class)
 | 
			
		||||
            line_num = inspect.getsourcelines(cmd_class)[1]
 | 
			
		||||
            n_missing_cmd_i18n += 1
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user