Completed
Push — master ( 6fd567...f65269 )
by Daniel
90:27 queued 15s
created

DocumentsListPlugin.__getattr__()   A

Complexity

Conditions 3

Size

Total Lines 12

Duplication

Lines 12
Ratio 100 %

Importance

Changes 2
Bugs 1 Features 1
Metric Value
cc 3
c 2
b 1
f 1
dl 12
loc 12
rs 9.4285

1 Method

Rating   Name   Duplication   Size   Complexity  
A DocumentsListApplication.__init__() 0 5 1
1
"""
2
Groundwork documentation support module.
3
"""
4
5
import logging
6
7
from groundwork.patterns.gw_base_pattern import GwBasePattern
8
9
10
class GwDocumentsPattern(GwBasePattern):
11
    """
12
    Documents can be collected by other Plugins to present their content inside user documentation, online help,
13
    console output or whatever.
14
15
    Please see :ref:`documents` for more details.
16
    """
17
18
    def __init__(self, *args, **kwargs):
19
        super().__init__(*args, **kwargs)
20
21
        if not hasattr(self.app, "documents"):
22
            self.app.documents = DocumentsListApplication(self.app)
23
24
        #: Stores an instance of :class:`~groundwork.patterns.gw_documents_pattern.DocumentsListPlugin`
25
        self.documents = DocumentsListPlugin(self)
26
27
28
class DocumentsListPlugin:
29
    """
30
    Stores and handles documents.
31
32
    These documents are used for real-time and offline documentation of a groundwork application.
33
34
    The content of a document must be string, which is can contain jinja and rst syntax.
35
36
    Plugins, which want to generate a documentation out of all documents, must render this content
37
    (jinja render_template) and transform the rst by the own (e.g. by using rst2html).
38
39
    Please see :ref:`documents` for more details.
40
    """
41
42
    def __init__(self, plugin):
43
        """
44
        :param plugin: The plugin, which wants to use signals
45
        :type plugin: GwBasePattern
46
        """
47
        self._plugin = plugin
48
        self.__app = plugin.app
49
        self.__log = plugin.log
50
51
        # Let's register a receiver, which cares about the deactivation process of documents for this plugin.
52
        # We do it after the original plugin deactivation, so we can be sure that the registered function is the last
53
        # one which cares about documents for this plugin.
54
        self._plugin.signals.connect(receiver="%s_documents_deactivation" % self._plugin.name,
55
                                     signal="plugin_deactivate_post",
56
                                     function=self.__deactivate_documents,
57
                                     description="Deactivate documents for %s" % self._plugin.name,
58
                                     sender=self._plugin)
59
        self.__log.debug("Plugin documents initialised")
60
61
    def __deactivate_documents(self, plugin, *args, **kwargs):
62
        documents = self.get()
63
        for document in documents.keys():
64
            self.unregister(document)
65
66
    def register(self, name, content, description=None):
67
        """
68
        Register a new document.
69
70
        :param content: Content of this document. Jinja and rst are supported.
71
        :type content: str
72
        :param name: Unique name of the document for documentation purposes.
73
        :param description: Short description of this document
74
        """
75
        return self.__app.documents.register(name, content, self._plugin, description)
76
77
    def unregister(self, document):
78
        return self.__app.documents.unregister(document)
79
80
    def get(self, name=None):
81
        return self.__app.documents.get(name, self._plugin)
82
83
84
class DocumentsListApplication:
85
    """
86
87
    """
88
89
    def __init__(self, app):
90
        self.__app = app
91
        self.__log = logging.getLogger(__name__)
92
        self.documents = {}
93
        self.__log.info("Application documents initialised")
94
95
    def register(self, name, content, plugin, description=None):
96
        """
97
        Registers a new document.
98
99
        .. warning: You can not use any relative links inside a given document.
100
                    For instance, sphinx's toctree, image, figure or include statements do not work.
101
102
        :param content: Content of the document
103
        :type content: str
104
        :param name: Unique name of the document for documentation purposes.
105
        :param plugin: Plugin object, under which the signals where registered
106
        :type plugin: GwBasePattern
107
        """
108
        if name in self.documents.keys():
109
            raise DocumentExistsException("Document %s was already registered by %s" %
110
                                          (name, self.documents[name].plugin.name))
111
112
        self.documents[name] = Document(name, content, plugin, description)
113
        self.__log.debug("Document %s registered by %s" % (name, plugin.name))
114
        return self.documents[name]
115
116
    def unregister(self, document):
117
        """
118
        Unregisters an existing document, so that this document is no longer available.
119
120
        This function is mainly used during plugin deactivation.
121
122
        :param document: Name of the document
123
        """
124
        if document not in self.documents.keys():
125
            self.log.warning("Can not unregister document %s" % document)
126
        else:
127
            del (self.documents[document])
128
            self.__log.debug("Document %s got unregistered" % document)
129
130
    def get(self, document=None, plugin=None):
131
        """
132
        Get one or more documents.
133
134
        :param document: Name of the document
135
        :type document: str
136
        :param plugin: Plugin object, under which the document where registered
137
        :type plugin: GwBasePattern
138
        """
139
        if plugin is not None:
140
            if document is None:
141
                documents_list = {}
142
                for key in self.documents.keys():
143 View Code Duplication
                    if self.documents[key].plugin == plugin:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
144
                        documents_list[key] = self.documents[key]
145
                return documents_list
146
            else:
147
                if document in self.documents.keys():
148
                    if self.documents[document].plugin == plugin:
149
                        return self.documents[document]
150
                    else:
151
                        return None
152
                else:
153
                    return None
154
        else:
155
            if document is None:
156
                return self.documents
157
            else:
158
                if document in self.documents.keys():
159
                    return self.documents[document]
160
                else:
161
                    return None
162
163
164
class Document:
165
    """
166
    Groundwork document class. Used to store name, file_path, alias and plugin.
167
168
    This information is mostly used to generated overviews about registered documents.
169
170
    :param name: Name of the document
171
    :type name: str
172
    :param content: Content of the document, which is used for documentation building
173
    :type content: str (jinja + rst)
174
    :param plugin: The plugin, which registered this document
175
    :type plugin: GwBasePattern
176
    :param description: short description of document
177
    """
178
    def __init__(self, name, content, plugin, description=None):
179
        self.name = name
180
        self.content = content
181
        self.plugin = plugin
182
        self.description = description
183
184
185
class NoAbsolutePathException(BaseException):
186
    pass
187
188
189
class DocumentExistsException(BaseException):
190
    pass
191