Completed
Push — master ( 5e06db...2f8739 )
by P.R.
30s
created

SDoc.set_arguments()   A

Complexity

Conditions 1

Size

Total Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

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