Completed
Push — master ( 4563ee...0442a2 )
by P.R.
02:07
created

SDoc.__init__()   A

Complexity

Conditions 1

Size

Total Lines 52

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 52
rs 9.4929
cc 1

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
"""
2
SDoc
3
4
Copyright 2016 Set Based IT Consultancy
5
6
Licence MIT
7
"""
8
# ----------------------------------------------------------------------------------------------------------------------
9
import argparse
10
import configparser
11
import os
12
13
import sys
14
from io import StringIO
15
16
import sdoc
17
from sdoc.error import SDocError
18
from sdoc.sdoc1.SDoc1Interpreter import SDoc1Interpreter
19
from sdoc.sdoc2.NodeStore import NodeStore
20
from sdoc.sdoc2.SDoc2Interpreter import SDoc2Interpreter
21
22
23
class SDoc:
24
    """
25
    The SDoc program.
26
    """
27
28
    # ------------------------------------------------------------------------------------------------------------------
29
    def __init__(self):
30
        """
31
        Object contructor.
32
        """
33
        self._args = None
34
        """
35
        The parsed arguments of this program.
36
37
        :type: Namespace
38
        """
39
40
        self._formatter = None
41
        """
42
        The class for generation the document in the target format.
43
44
        :type: sdoc.format.Format.Format
45
        """
46
47
        self._target_dir = '.'
48
        """
49
        The directory where the document in the target format must be created.
50
51
        :type: str
52
        """
53
54
        self._temp_dir = '.'
55
        """
56
        The directory where temporary files are stored.
57
58
        :type: str
59
        """
60
61
        self._nodes_paths = []
62
        """
63
        A list with path names from with node modules must be imported.
64
65
        :type: [str]
66
        """
67
68
        self._formatter_paths = []
69
        """
70
        A list with path names from with node modules must be imported.
71
72
        :type: [str]
73
        """
74
75
        self._errors = 0
76
        """
77
        The total number of errors encountered at SDoc level 1 and level 2.
78
79
        :type: int
80
        """
81
82
    # ------------------------------------------------------------------------------------------------------------------
83
    @property
84
    def target_dir(self):
85
        """
86
        Getter for target_dir.
87
88
        :rtype: str
89
        """
90
        return self.target_dir
91
92
    # ------------------------------------------------------------------------------------------------------------------
93
    @property
94
    def temp_dir(self):
95
        """
96
        Getter for temp_dir.
97
98
        :rtype: str
99
        """
100
        return self.temp_dir
101
102
    # ------------------------------------------------------------------------------------------------------------------
103
    def _parse_arguments(self):
104
        """
105
        Parses the arguments for SDoc program.
106
        """
107
        parser = argparse.ArgumentParser(description='Description')
108
109
        parser.add_argument(metavar='[main.sdoc]',
110
                            nargs=1,
111
                            dest='main',
112
                            help='path to main SDoc document')
113
114
        parser.add_argument('-c',
115
                            '--config',
116
                            metavar='<config.cfg>',
117
                            required=True,
118
                            dest='config_filename',
119
                            help='path to configuration file')
120
121
        parser.add_argument('-1',
122
                            '--sdoc1-only',
123
                            action='store_true',
124
                            dest='sdoc1-only',
125
                            default=False,
126
                            help='runs only the SDoc1 parser')
127
128
        self._args = parser.parse_args()
129
130
    # ------------------------------------------------------------------------------------------------------------------
131
    def _config_create_formatter(self, config):
132
        """
133
        Creates the formatter for generating the document in the target format.
134
135
        :param configparser.ConfigParser config: The config parser.
136
        """
137
        available_formats = ['html']
138
139
        # Read the target format of the document.
140
        target_format = config.get('sdoc', 'format', fallback=None)
141
        if target_format not in available_formats:
142
            raise SDocError("The format '{0!s}' is not available in SDoc. Set another in config file '{1!s}'"
143
                            .format(target_format, self._args.config_filename))
144
145
        if not target_format:
146
            raise SDocError("Option 'format' in section 'sdoc' not set in config file '{0!s}'"
147
                            .format(self._args.config_filename))
148
149
        # Read the class name for formatting the SDoc2 nodes into the target format.
150
        section = 'format_' + target_format
151
        class_name = config.get(section, 'class', fallback=None)
152
        if not class_name:
153
            raise SDocError("Option 'class' in section '{0!s}' not set in config file '{1!s}'".
154
                            format(section, self._args.config_filename))
155
156
        # Import the class.
157
        try:
158
            parts = class_name.split('.')
159
            module = ".".join(parts[:-1])
160
            __import__(module)
161
            m = __import__(module)
162
            for comp in parts[1:]:
163
                m = getattr(m, comp)
164
        except AttributeError:
165
            raise SDocError("There is no module named '{0!s}'! Set name correctly in config file '{1!s}'"
166
                            .format(class_name, self._args.config_filename))
167
168
        # Create the formatter.
169
        self._formatter = m(config[section])
170
171
    # ------------------------------------------------------------------------------------------------------------------
172
    def _config_set_temp_dir(self, config):
173
        """
174
        Reads the directory for storing temporary files.
175
176
        :param configparser.ConfigParser config: The config parser.
177
        """
178
        self._temp_dir = config.get('sdoc', 'temp_dir', fallback=self._temp_dir)
179
180
        if not self._temp_dir:
181
            raise SDocError("Option 'temp_dir' in section 'sdoc' not set correctly in config file '{0!s}'".
182
                            format(self._args.config_filename))
183
184
        if not os.access(self._temp_dir, os.W_OK):
185
            raise SDocError("Directory '{0!s}' is not writable".format(self._temp_dir))
186
187
    # ------------------------------------------------------------------------------------------------------------------
188
    def _config_set_target_dir(self, config):
189
        """
190
        Reads the directory where the document in the target format must be created.
191
192
        :param configparser.ConfigParser config: The config parser.
193
        """
194
        self._target_dir = config.get('sdoc', 'target_dir', fallback=self._target_dir)
195
196
        if not self._target_dir:
197
            raise SDocError("Option 'target_dir' in section 'sdoc' not set correctly in config file '{0!s}'".
198
                            format(self._args.config_filename))
199
200
        if not os.access(self._target_dir, os.W_OK):
201
            raise SDocError("Directory '{0!s}' is not writable".format(self._target_dir))
202
203
    # ------------------------------------------------------------------------------------------------------------------
204
    def _read_config_file(self):
205
        """
206
        Reads the configuration file.
207
        """
208
        config = configparser.ConfigParser()
209
        config.read(self._args.config_filename)
210
211
        # Get the temp and target directory.
212
        self._config_set_temp_dir(config)
213
        self._config_set_target_dir(config)
214
215
        # Create the formatter for generating the document in the target format.
216
        self._config_create_formatter(config)
217
218
        self._formatter_paths.append(os.path.dirname(__file__) + '/sdoc2/formatter')
219
        self._nodes_paths.append(os.path.dirname(__file__) + '/sdoc2/node')
220
221
    # ------------------------------------------------------------------------------------------------------------------
222
    @staticmethod
223
    def _create_node_store():
224
        """
225
        Creates the node store (for storing nodes).
226
        """
227
        sdoc.sdoc2.node_store = NodeStore()
228
229
    # ------------------------------------------------------------------------------------------------------------------
230
    @staticmethod
231
    def importing(path):
232
        """
233
        Imports modules from specific path.
234
235
        :param str path: The specific path.
236
        """
237
        modules = os.listdir(os.path.dirname(__file__) + path)
238
239
        path = path.replace('/', '.')
240
241
        for module in modules:
242
            if module != '__init__.py' and module[-3:] == '.py':
243
                __import__('sdoc' + path + module[:-3], locals(), globals())
244
245
    # ------------------------------------------------------------------------------------------------------------------
246
    def _import_nodes(self):
247
        """
248
        Imports nodes from path which is declared below.
249
        """
250
        # @todo improve
251
        self.importing('/sdoc2/node/')
252
253
    # ------------------------------------------------------------------------------------------------------------------
254
    def _import_formatters(self):
255
        """
256
        Imports formatters from path which is declared below.
257
        """
258
        # @todo improve
259
        self.importing('/sdoc2/formatter/html/')
260
261
    # ------------------------------------------------------------------------------------------------------------------
262
    def run_sdoc1(self, main_filename, temp_filename):
263
        """
264
        Run the SDoc1 parser.
265
266
        :param str main_filename: The name of the file with then main SDoc1 document.
267
        :param str temp_filename: The name of the temporary file where the SDoc2 document must be stored.
268
        """
269
        interpreter1 = SDoc1Interpreter()
270
        self._errors += interpreter1.process(main_filename, temp_filename)
271
272
    # ------------------------------------------------------------------------------------------------------------------
273
    def run_sdoc2(self, temp_filename):
274
        """
275
        Run the SDoc2 parser.
276
277
        :param str temp_filename: The name of the temporary file where the SDoc2 document is stored.
278
        """
279
        interpreter2 = SDoc2Interpreter()
280
        self._errors += interpreter2.process(temp_filename)
281
282
    # ------------------------------------------------------------------------------------------------------------------
283
    def _run_sdoc(self):
284
        """
285
        Runs the SDoc1 and SDoc2 parser.
286
        """
287
        main_filename = self._args.main[0]
288
        temp_filename = self._temp_dir + '/' + os.path.basename(main_filename) + '.sdoc2'
289
290
        self.run_sdoc1(main_filename, temp_filename)
291
292
        self.run_sdoc2(temp_filename)
293
294
        # Start generating file with specific format.
295
        sdoc.sdoc2.node_store.generate(self._formatter)
296
297
    # ------------------------------------------------------------------------------------------------------------------
298 View Code Duplication
    def test_sdoc1(self, main_filename):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
299
        """
300
        Parses a SDoc document and returns a tuple with the stdout and the resulting SDoc2 document.
301
302
        :param str main_filename: The name of the file with then main SDoc1 document.
303
304
        :rtype: (str,str)
305
        """
306
        self._create_node_store()
307
        self._import_nodes()
308
        self._import_formatters()
309
310
        old_stdout, sys.stdout = sys.stdout, StringIO()
311
312
        temp_filename = main_filename + '.sdoc2'
313
        interpreter1 = SDoc1Interpreter()
314
        interpreter1.process(main_filename, temp_filename)
315
316
        output = sys.stdout.getvalue().strip()
317
        sys.stdout = old_stdout
318
319
        with open(temp_filename, 'rt') as fd:
320
            sdoc2 = fd.read()
321
322
        os.unlink(temp_filename)
323
324
        return output, sdoc2
325
326
    # ------------------------------------------------------------------------------------------------------------------
327 View Code Duplication
    def test_sdoc2(self, main_filename):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
328
        """
329
        Parses a SDoc document and returns a tuple with the stdout and the resulting SDoc2 document.
330
331
        :param str main_filename: The name of the file with then main SDoc1 document.
332
333
        :rtype: (str,str)
334
        """
335
        self._create_node_store()
336
        self._import_nodes()
337
        self._import_formatters()
338
339
        old_stdout, sys.stdout = sys.stdout, StringIO()
340
341
        temp_filename = main_filename + '.sdoc2'
342
        interpreter1 = SDoc1Interpreter()
343
        interpreter1.process(main_filename, temp_filename)
344
345
        interpreter2 = SDoc2Interpreter()
346
        interpreter2.process(temp_filename)
347
348
        sdoc.sdoc2.node_store.number_numerable()
349
350
        output = sys.stdout.getvalue().strip()
351
        sys.stdout = old_stdout
352
353
        with open(temp_filename, 'rt') as fd:
354
            sdoc2 = fd.read()
355
356
        os.unlink(temp_filename)
357
358
        return output, sdoc2
359
360
    # ------------------------------------------------------------------------------------------------------------------
361
    def main(self):
362
        """
363
        The main function the SDoc program.
364
        """
365
        self._parse_arguments()
366
367
        self._read_config_file()
368
369
        self._create_node_store()
370
371
        self._import_nodes()
372
373
        self._import_formatters()
374
375
        self._run_sdoc()
376
377
        if self._errors:
378
            print()
379
            print('The were {0:d} errors in total'.format(self._errors))
380
381
        exit(self._errors)
382
383
# ----------------------------------------------------------------------------------------------------------------------
384