Completed
Push — master ( 793cf7...172351 )
by P.R.
04:33
created

SDoc.run_format()   A

Complexity

Conditions 1

Size

Total Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 1
CRAP Score 1.512

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 10
ccs 1
cts 5
cp 0.2
rs 9.4285
cc 1
crap 1.512
1
"""
2
SDoc
3
4
Copyright 2016 Set Based IT Consultancy
5
6
Licence MIT
7
"""
8
# ----------------------------------------------------------------------------------------------------------------------
9 1
import configparser
10 1
import os
11
12 1
from sdoc import sdoc2
13 1
from sdoc.error import SDocError
14 1
from sdoc.sdoc1.SDoc1Interpreter import SDoc1Interpreter
15 1
from sdoc.sdoc2.NodeStore import NodeStore
16 1
from sdoc.sdoc2.SDoc2Interpreter import SDoc2Interpreter
17
18
19 1
class SDoc:
20
    """
21
    The SDoc program.
22
    """
23
    # ------------------------------------------------------------------------------------------------------------------
24 1
    def __init__(self):
25
        """
26
        Object contructor.
27
        """
28 1
        self._io = None
29
        """
30
        The IO object.
31
32
        :type: None|sdoc.style.SdocStyle.SdocStyle
33
        """
34
35 1
        self._format = None
36
        """
37
        The class for generation the document in the target format.
38
39
        :type: sdoc.format.Format.Format
40
        """
41
42 1
        self._target_dir = '.'
43
        """
44
        The directory where the document in the target format must be created.
45
46
        :type: str
47
        """
48
49 1
        self._temp_dir = '.'
50
        """
51
        The directory where temporary files are stored.
52
53
        :type: str
54
        """
55
56 1
        self._config_path = ''
57
        """
58
        The path of the config file.
59
60
        :type: str
61
        """
62
63 1
        self._nodes_paths = []
64
        """
65
        A list with path names from with node modules must be imported.
66
67
        :type: [str]
68
        """
69
70 1
        self._formatter_paths = []
71
        """
72
        A list with path names from with node modules must be imported.
73
74
        :type: [str]
75
        """
76
77 1
        self._errors = 0
78 1
        """
79
        The total number of errors encountered at SDoc level 1 and level 2.
80
81
        :type: int
82
        """
83
84
    # ------------------------------------------------------------------------------------------------------------------
85 1
    @property
86
    def io(self):
0 ignored issues
show
Coding Style Naming introduced by
The name io does not conform to the attribute naming conventions ([a-z_][a-z0-9_]{2,30}$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
87
        """
88
        Getter for io.
89
90
        :rtype: cleo.styles.output_style.OutputStyle
91
        """
92
        return self._io
93
94
    # ------------------------------------------------------------------------------------------------------------------
95 1
    @io.setter
96
    def io(self, io):
0 ignored issues
show
Coding Style Naming introduced by
The name io does not conform to the attribute naming conventions ([a-z_][a-z0-9_]{2,30}$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
Coding Style Naming introduced by
The name io does not conform to the argument naming conventions ([a-z_][a-z0-9_]{2,30}$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
97
        """
98
        Setter for io.
99
100
        :param cleo.styles.output_style.OutputStyle io: The IO object.
101
        """
102 1
        self._io = io
103
104
    # ------------------------------------------------------------------------------------------------------------------
105 1
    @property
106
    def config_path(self):
107
        """
108
        Getter for config_path.
109
110
        :rtype: str
111
        """
112
        return self._config_path
113
114
    # ------------------------------------------------------------------------------------------------------------------
115 1
    @config_path.setter
116
    def config_path(self, config_path):
117
        """
118
        Setter for config_path.
119
120
        :param cleo.styles.output_style.OutputStyle config_path: The path of the config file.
121
        """
122 1
        self._config_path = config_path
123
124
    # ------------------------------------------------------------------------------------------------------------------
125 1
    @property
126
    def target_dir(self):
127
        """
128
        Getter for target_dir.
129
130
        :rtype: str
131
        """
132
        return self.target_dir
133
134
    # ------------------------------------------------------------------------------------------------------------------
135 1
    @property
136
    def temp_dir(self):
137
        """
138
        Getter for temp_dir.
139
140
        :rtype: str
141
        """
142
        return self.temp_dir
143
144
    # ------------------------------------------------------------------------------------------------------------------
145 1
    def _config_create_formatter(self, config):
146
        """
147
        Creates the formatter for generating the document in the target format.
148
149
        :param configparser.ConfigParser config: The config parser.
150
        """
151 1
        available_formats = ['html']
152
153
        # Read the target format of the document.
154 1
        target_format = config.get('sdoc', 'format', fallback=None)
155 1
        if target_format not in available_formats:
156
            raise SDocError("The format '{0!s}' is not available in SDoc. Set another in config file '{1!s}'"
157
                            .format(target_format, self._config_path))
158
159 1
        if not target_format:
160
            raise SDocError("Option 'format' in section 'sdoc' not set in config file '{0!s}'"
161
                            .format(self._config_path))
162
163
        # Read the class name for formatting the SDoc2 nodes into the target format.
164 1
        section = 'format_' + target_format
165 1
        class_name = config.get(section, 'class', fallback=None)
166 1
        if not class_name:
167
            raise SDocError("Option 'class' in section '{0!s}' not set in config file '{1!s}'".
168
                            format(section, self._config_path))
169
170
        # Import the class.
171 1
        try:
172 1
            parts = class_name.split('.')
173 1
            module = ".".join(parts[:-1])
174 1
            __import__(module)
175 1
            m = __import__(module)
176 1
            for comp in parts[1:]:
177 1
                m = getattr(m, comp)
178
        except AttributeError:
179
            raise SDocError("There is no module named '{0!s}'! Set name correctly in config file '{1!s}'"
180
                            .format(class_name, self._config_path))
181
182
        # Create the formatter.
183 1
        self._format = m(self._io, config[section])
184
185
    # ------------------------------------------------------------------------------------------------------------------
186 1
    def _config_set_temp_dir(self, config):
187
        """
188
        Reads the directory for storing temporary files.
189
190
        :param configparser.ConfigParser config: The config parser.
191
        """
192 1
        self._temp_dir = config.get('sdoc', 'temp_dir', fallback=self._temp_dir)
193
194 1
        if not self._temp_dir:
195
            raise SDocError("Option 'temp_dir' in section 'sdoc' not set correctly in config file '{0!s}'".
196
                            format(self._config_path))
197
198 1
        if not os.access(self._temp_dir, os.W_OK):
199
            raise SDocError("Directory '{0!s}' is not writable".format(self._temp_dir))
200
201
    # ------------------------------------------------------------------------------------------------------------------
202 1
    def _config_set_target_dir(self, config):
203
        """
204
        Reads the directory where the document in the target format must be created.
205
206
        :param configparser.ConfigParser config: The config parser.
207
        """
208 1
        self._target_dir = config.get('sdoc', 'target_dir', fallback=self._target_dir)
209
210 1
        if not self._target_dir:
211
            raise SDocError("Option 'target_dir' in section 'sdoc' not set correctly in config file '{0!s}'".
212
                            format(self._config_path))
213
214 1
        if not os.access(self._target_dir, os.W_OK):
215
            raise SDocError("Directory '{0!s}' is not writable".format(self._target_dir))
216
217
    # ------------------------------------------------------------------------------------------------------------------
218 1
    def _read_config_file(self):
219
        """
220
        Reads the configuration file.
221
        """
222 1
        config = configparser.ConfigParser()
223 1
        config.read(self._config_path)
224
225
        # Get the temp and target directory.
226 1
        self._config_set_temp_dir(config)
227 1
        self._config_set_target_dir(config)
228
229
        # Create the formatter for generating the document in the target format.
230 1
        self._config_create_formatter(config)
231
232 1
        self._formatter_paths.append(os.path.dirname(__file__) + '/sdoc2/formatter')
233 1
        self._nodes_paths.append(os.path.dirname(__file__) + '/sdoc2/node')
234
235
    # ------------------------------------------------------------------------------------------------------------------
236 1
    def _create_node_store(self):
237
        """
238
        Creates the node store (for storing nodes).
239
        """
240 1
        sdoc2.node_store = NodeStore(self._io)
241
242
    # ------------------------------------------------------------------------------------------------------------------
243 1
    @staticmethod
244
    def importing(path):
245
        """
246
        Imports modules from specific path.
247
248
        :param str path: The specific path.
249
        """
250 1
        modules = os.listdir(os.path.dirname(__file__) + path)
251
252 1
        path = path.replace('/', '.')
253
254 1
        for module in modules:
255 1
            if module != '__init__.py' and module[-3:] == '.py':
256 1
                __import__('sdoc' + path + module[:-3], locals(), globals())
257
258
    # ------------------------------------------------------------------------------------------------------------------
259 1
    def _import_nodes(self):
260
        """
261
        Imports nodes from path which is declared below.
262
        """
263
        # @todo improve
264 1
        self.importing('/sdoc2/node/')
265
266
    # ------------------------------------------------------------------------------------------------------------------
267 1
    def _import_formatters(self):
268
        """
269
        Imports formatters from path which is declared below.
270
        """
271
        # @todo improve
272 1
        self.importing('/sdoc2/formatter/html/')
273
274
    # ------------------------------------------------------------------------------------------------------------------
275 1
    def init(self):
0 ignored issues
show
Coding Style introduced by
This method should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
276 1
        self._read_config_file()
277 1
        self._create_node_store()
278 1
        self._import_nodes()
279 1
        self._import_formatters()
280
281
    # ------------------------------------------------------------------------------------------------------------------
282 1
    def run_sdoc1(self, sdoc1_path, sdoc2_path):
283
        """
284
        Run the SDoc1 parser.
285
286
        :param str sdoc1_path: The path of the SDoc1 document.
287
        :param str sdoc2_path: The path were the the SDoc2 document mut be stored.
288
        """
289 1
        self._io.title('SDoc1')
290
291 1
        interpreter1 = SDoc1Interpreter(self._io)
292 1
        self._errors += interpreter1.process(sdoc1_path, sdoc2_path)
293
294 1
        return self._errors
295
296
    # ------------------------------------------------------------------------------------------------------------------
297 1
    def run_sdoc2(self, sdoc2_path):
298
        """
299
        Run the SDoc2 parser.
300
301
        :param str sdoc2_path: The path of the SDoc2 document.
302
        """
303 1
        self._io.writeln('')
304 1
        self._io.title('SDoc2')
305
306 1
        interpreter2 = SDoc2Interpreter(self._io)
307 1
        self._errors += interpreter2.process(sdoc2_path)
308
309 1
        return self._errors
310
311
    # ------------------------------------------------------------------------------------------------------------------
312 1
    def run_format(self):
313
        """
314
        Generates the target document in the specific format.
315
        """
316
        self._io.writeln('')
317
        self._io.title('Format')
318
319
        self._errors += sdoc2.node_store.generate(self._format)
320
321
        return self._errors
322
323
    # ------------------------------------------------------------------------------------------------------------------
324 1
    def run_sdoc(self, main_filename):
325
        """
326
        Runs the SDoc1 and SDoc2 parser.
327
328
        :param str main_filename: The path of the SDoc1 document.
329
        """
330
        self.init()
331
332
        temp_filename = self._temp_dir + '/' + os.path.basename(main_filename) + '.sdoc2'
333
        self.run_sdoc1(main_filename, temp_filename)
334
        self.run_sdoc2(temp_filename)
335
        self.run_format()
336
337
        if self._errors:
338
            self._io.writeln(" ")
339
            self._io.title('Errors')
340
            self._io.writeln('There were <err>{0} errors</err> in total'.format(self._errors))
341
342
        return self._errors
343
344
# ----------------------------------------------------------------------------------------------------------------------
345