Total Complexity | 138 |
Total Lines | 600 |
Duplicated Lines | 6 % |
Changes | 10 | ||
Bugs | 0 | Features | 0 |
Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
Complex classes like Actions often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
1 | # |
||
36 | class Actions(object): |
||
37 | """An Actions instance represents an action event |
||
38 | """ |
||
39 | |||
40 | def __init__(self, args): |
||
41 | """Initialize Actions class |
||
42 | |||
43 | :param argparse.Namespace args: result from argparse.parse_args |
||
44 | """ |
||
45 | logmgr_flog() |
||
46 | |||
47 | # set default variables |
||
48 | self.__files = args.files |
||
49 | self.__args = args |
||
50 | self.__xml = OrderedDict() |
||
51 | |||
52 | # set the default output format for 'alias' sub cmd to 'table' |
||
53 | if args.action == "alias": |
||
54 | args.format = "table" |
||
55 | |||
56 | if self.__files: |
||
57 | # temporary xml handler list |
||
58 | xml = list() |
||
59 | |||
60 | # start multiple processes for initialize all XML files |
||
61 | with ThreadPool(processes=self.__args.jobs) as pool: |
||
62 | for i in pool.map(self.init_xml_handlers, self.__files): |
||
63 | xml.append(i) |
||
64 | |||
65 | # build the self.__xml dict |
||
66 | for i in xml: |
||
67 | name = i["file"] |
||
68 | self.__xml[name] = dict() |
||
69 | |||
70 | for x in i: |
||
71 | if x is not "file": |
||
72 | self.__xml[name][x] = i[x] |
||
73 | |||
74 | # stop if we found an error and --stop-on-error is set |
||
75 | if self.__args.stop_on_error and "error" in self.__xml[name]: |
||
76 | log.error("{}: {}".format(name, self.__xml[name]["errorstr"])) |
||
77 | sys.exit(self.__xml[name]["error"]) |
||
78 | |||
79 | def init_xml_handlers(self, fname): |
||
80 | """ |
||
81 | Initializes an XmlHandler for a file. |
||
82 | |||
83 | :param string fname: The file name |
||
84 | """ |
||
85 | handler = None |
||
86 | |||
87 | try: |
||
88 | handler = { "file": fname, "handler": XmlHandler(fname, True) } |
||
89 | except (DMXmlParseError, DMInvalidXMLRootElement, DMFileNotFoundError, DMNotDocBook5File) as err: |
||
90 | handler = { "file": fname, "errorstr": err.errorstr, "error": err.error } |
||
91 | |||
92 | return handler |
||
93 | |||
94 | def parse(self): |
||
95 | logmgr_flog() |
||
96 | |||
97 | action = self.__args.action |
||
98 | if hasattr(self, action) and getattr(self, action) is not None: |
||
99 | log.debug("Action.__init__: %s", self.__args) |
||
100 | return getattr(self, action)(self.__args.properties) |
||
101 | else: |
||
102 | log.error("Method \"%s\" is not implemented.", action) |
||
103 | sys.exit(ReturnCodes.E_METHOD_NOT_IMPLEMENTED) |
||
104 | |||
105 | |||
106 | def init(self, arguments): |
||
107 | logmgr_flog() |
||
108 | |||
109 | _set = dict() |
||
110 | props = list(DEFAULT_DM_PROPERTIES) |
||
111 | |||
112 | # count all valid and invalid xml files |
||
113 | validfiles, invalidfiles = self.get_files_status(self.__xml) |
||
114 | |||
115 | # append bugtracker properties if needed |
||
116 | if self.__args.with_bugtracker: |
||
117 | for item in BT_ELEMENTLIST: |
||
118 | props.append(item) |
||
119 | |||
120 | # set default properties |
||
121 | for item in props: |
||
122 | rprop = item.replace("/", "_") |
||
123 | |||
124 | if hasattr(self.__args, rprop) and \ |
||
125 | getattr(self.__args, rprop) is not None: |
||
126 | _set[item] = getattr(self.__args, rprop) |
||
127 | |||
128 | # iter through all xml handlers and init its properties |
||
129 | for f in self.__files: |
||
130 | if "error" not in self.__xml[f]: |
||
131 | xh = self.__xml[f]["handler"] |
||
132 | |||
133 | log.info("Trying to initialize the predefined DocManager " |
||
134 | "properties for %r.", xh.filename) |
||
135 | |||
136 | if xh.init_default_props(self.__args.force, |
||
137 | self.__args.with_bugtracker) == 0: |
||
138 | print("[{}] Initialized default " |
||
139 | "properties for {!r}.".format(green(" ok "), |
||
140 | xh.filename)) |
||
141 | else: |
||
142 | log.warning("Could not initialize all properties for %r because " |
||
143 | "there are already some properties in the XML file " |
||
144 | "which would be overwritten after this operation has been " |
||
145 | "finished. If you want to perform this operation and " |
||
146 | "overwrite the existing properties, you can add the " |
||
147 | "'--force' option to your command.", xh.filename) |
||
148 | |||
149 | # set default values for the given properties |
||
150 | for i in _set: |
||
151 | ret = xh.get(i) |
||
152 | if len(ret[i]) == 0 or self.__args.force: |
||
153 | xh.set({ i: str(_set[i]) }) |
||
154 | |||
155 | # if bugtracker options are provided, set default values |
||
156 | for i in BT_ELEMENTLIST: |
||
157 | rprop = i.replace("/", "_") |
||
158 | |||
159 | if hasattr(self.__args, rprop) and \ |
||
160 | getattr(self.__args, rprop) is not None and \ |
||
161 | len(getattr(self.__args, rprop)) >= 1: |
||
162 | xh.set({ i: getattr(self.__args, rprop) }) |
||
163 | else: |
||
164 | print("[{}] Initialized default properties for {!r}: {}. ".format(\ |
||
165 | red(" error "), |
||
166 | f, |
||
167 | red(self.__xml[f]["errorstr"]))) |
||
168 | |||
169 | # save the changes |
||
170 | if validfiles: |
||
171 | for f in self.__files: |
||
172 | if "error" not in self.__xml[f]: |
||
173 | self.__xml[f]["handler"].write() |
||
174 | |||
175 | # print the statistics |
||
176 | print("\nInitialized successfully {} files. {} files failed.".format(\ |
||
177 | green(validfiles), red(invalidfiles))) |
||
178 | |||
179 | def set(self, arguments): |
||
180 | """Set key/value pairs from arguments |
||
181 | |||
182 | :param list arguments: List of arguments with key=value pairs |
||
183 | """ |
||
184 | logmgr_flog() |
||
185 | |||
186 | # count all valid and invalid xml files |
||
187 | validfiles, invalidfiles = self.get_files_status(self.__xml) |
||
188 | |||
189 | # split key and value |
||
190 | args = [i.split("=") for i in arguments] |
||
191 | |||
192 | # iter through all key and values |
||
193 | for f in self.__files: |
||
194 | if "error" in self.__xml[f]: |
||
195 | print("[ {} ] {} -> {}".format(red("error"), f, red(self.__xml[f]['errorstr']))) |
||
196 | else: |
||
197 | for arg in args: |
||
198 | try: |
||
199 | key, value = arg |
||
200 | |||
201 | if key == "languages": |
||
202 | value = value.split(",") |
||
203 | value = ",".join(self.remove_duplicate_langcodes(value)) |
||
204 | |||
205 | log.debug("[%s] Trying to set value for property " |
||
206 | "%r to %r.", f, key, value) |
||
207 | |||
208 | if self.__args.bugtracker: |
||
209 | self.__xml[f]["handler"].set({"bugtracker/" + key: value}) |
||
210 | else: |
||
211 | self.__xml[f]["handler"].set({key: value}) |
||
212 | except ValueError: |
||
213 | log.error('Invalid usage. ' |
||
214 | 'Set values with the following format: ' |
||
215 | 'property=value') |
||
216 | sys.exit(ReturnCodes.E_INVALID_USAGE_KEYVAL) |
||
217 | |||
218 | print("[ {} ] Set data for file {}.".format(green("ok"), f)) |
||
219 | |||
220 | # save the changes |
||
221 | for f in self.__files: |
||
222 | if "error" not in self.__xml[f]: |
||
223 | log.debug("[%s] Trying to save the changes.", f) |
||
224 | self.__xml[f]["handler"].write() |
||
225 | |||
226 | print_stats(validfiles, invalidfiles) |
||
227 | |||
228 | |||
229 | def set_attr(self, arguments): |
||
230 | prop = self.__args.property |
||
231 | attrs = self.__args.attributes |
||
232 | |||
233 | if not prop: |
||
234 | log.error("You must specify a property with -p!") |
||
235 | sys.exit(ReturnCodes.E_INVALID_ARGUMENTS) |
||
236 | |||
237 | if not attrs: |
||
238 | log.error("You must specify at least one attribute with -a!") |
||
239 | sys.exit(ReturnCodes.E_INVALID_ARGUMENTS) |
||
240 | |||
241 | # count all valid and invalid xml files |
||
242 | validfiles, invalidfiles = self.get_files_status(self.__xml) |
||
243 | |||
244 | data = OrderedDict() |
||
245 | for i in attrs: |
||
246 | try: |
||
247 | key, val = i.split("=") |
||
248 | data[key] = val |
||
249 | except ValueError: |
||
250 | log.error("The values of -a must have a key and a value, like: key=value or key=") |
||
251 | sys.exit(ReturnCodes.E_INVALID_USAGE_KEYVAL) |
||
252 | |||
253 | for f in self.__files: |
||
254 | if "error" in self.__xml[f]: |
||
255 | print("[{}] {} -> {}".format(red(" error "), f, red(self.__xml[f]["errorstr"]))) |
||
256 | else: |
||
257 | try: |
||
258 | self.__xml[f]["handler"].set_attr(prop, data) |
||
259 | self.__xml[f]["handler"].write() |
||
260 | |||
261 | print("[{}] Set attributes for file {}.".format(green(" ok "), f)) |
||
262 | View Code Duplication | except DMPropertyNotFound: |
|
|
|||
263 | print("[{}] Property {} was not found in {}.".format(red(" error "), yellow(prop), f)) |
||
264 | |||
265 | # we must substract 1 of "validfiles" since XML files are valid even |
||
266 | # if they don't have the given property. |
||
267 | validfiles -= 1 |
||
268 | invalidfiles += 1 |
||
269 | |||
270 | print_stats(validfiles, invalidfiles) |
||
271 | |||
272 | |||
273 | def del_attr(self, arguments): |
||
274 | prop = self.__args.property |
||
275 | attrs = self.__args.attributes |
||
276 | |||
277 | if not prop: |
||
278 | log.error("You must specify a property with -p!") |
||
279 | sys.exit(ReturnCodes.E_INVALID_ARGUMENTS) |
||
280 | |||
281 | if not attrs: |
||
282 | log.error("You must specify at least one attribute with -a!") |
||
283 | sys.exit(ReturnCodes.E_INVALID_ARGUMENTS) |
||
284 | |||
285 | # count all valid and invalid xml files |
||
286 | validfiles, invalidfiles = self.get_files_status(self.__xml) |
||
287 | |||
288 | for f in self.__files: |
||
289 | if "error" in self.__xml[f]: |
||
290 | print("[{}] {} -> {}".format(red(" error "), f, red(self.__xml[f]["errorstr"]))) |
||
291 | else: |
||
292 | try: |
||
293 | errors = self.__xml[f]["handler"].del_attr(prop, attrs) |
||
294 | self.__xml[f]["handler"].write() |
||
295 | |||
296 | if errors: |
||
297 | print("[{}] These attributes couldn't be deleted for {}: {}".format( |
||
298 | yellow(" notice "), f, ", ".join(errors) |
||
299 | )) |
||
300 | else: |
||
301 | print("[{}] Deleted attributes for file {}.".format(green(" ok "), f)) |
||
302 | |||
303 | except DMPropertyNotFound: |
||
304 | print("[{}] Property {} was not found in {}.".format(red(" error "), yellow(prop), f)) |
||
305 | |||
306 | View Code Duplication | # we must substract 1 of "validfiles" since XML files are valid even |
|
307 | # if they don't have the given property. |
||
308 | validfiles -= 1 |
||
309 | invalidfiles += 1 |
||
310 | |||
311 | print_stats(validfiles,invalidfiles) |
||
312 | |||
313 | |||
314 | def get_attr(self, arguments): |
||
315 | props = self.__args.properties |
||
316 | attrs = self.__args.attributes |
||
317 | |||
318 | data = dict(data=OrderedDict(),errors=None) |
||
319 | |||
320 | for f in self.__files: |
||
321 | data['data'][f] = self.__xml[f]["handler"].get_attr(props, attrs) |
||
322 | |||
323 | return data |
||
324 | |||
325 | def get(self, arguments): |
||
326 | """Lists all properties |
||
327 | |||
328 | :param list arguments: |
||
329 | :return: [(FILENAME, {PROPERTIES}), ...] |
||
330 | :rtype: list |
||
331 | """ |
||
332 | logmgr_flog() |
||
333 | |||
334 | output = list() |
||
335 | errors = list() |
||
336 | |||
337 | for f in self.__files: |
||
338 | if "error" in self.__xml[f]: |
||
339 | errors.append([f, self.__xml[f]['errorstr']]) |
||
340 | else: |
||
341 | output.append((f, self.__xml[f]["handler"].get(arguments))) |
||
342 | |||
343 | return {'data': output, 'errors': errors} |
||
344 | |||
345 | |||
346 | def delete(self, arguments): |
||
347 | """Delete a property |
||
348 | |||
349 | :param list arguments: |
||
350 | """ |
||
351 | logmgr_flog() |
||
352 | |||
353 | # statistics variables |
||
354 | file_errors = 0 |
||
355 | props_failed = 0 |
||
356 | props_deleted = 0 |
||
357 | |||
358 | # delete the properties |
||
359 | for f in self.__files: |
||
360 | if "error" in self.__xml[f]: |
||
361 | print("[{}] {} -> {}".format(red(" error "), f, red(self.__xml[f]["errorstr"]))) |
||
362 | file_errors += 1 |
||
363 | else: |
||
364 | failed_properties = list() |
||
365 | |||
366 | for arg in arguments: |
||
367 | cond = None |
||
368 | prop = arg |
||
369 | pos = arg.find("=") |
||
370 | |||
371 | # look if there is condition |
||
372 | if pos != -1: |
||
373 | prop = arg[:pos] |
||
374 | cond = arg[pos+1:] |
||
375 | |||
376 | if not self.__xml[f]["handler"].delete(prop, cond): |
||
377 | failed_properties.append(arg) |
||
378 | props_failed += 1 |
||
379 | else: |
||
380 | props_deleted += 1 |
||
381 | |||
382 | if not failed_properties: |
||
383 | print("[{}] {}".format(green(" ok "), f)) |
||
384 | else: |
||
385 | print("[{}] {} -> Couldn't delete these properties: {}".format( |
||
386 | yellow(" info "), f, ", ".join(failed_properties) |
||
387 | )) |
||
388 | |||
389 | # save changes |
||
390 | for f in self.__files: |
||
391 | if "error" not in self.__xml[f]: |
||
392 | self.__xml[f]["handler"].write() |
||
393 | |||
394 | # print statistics |
||
395 | print("") |
||
396 | print("Deleted successfully {} propert{}, {} propert{} couldn't be deleted, and {} {} invalid.".format( |
||
397 | green(props_deleted), 'ies' if props_deleted != 1 else 'y', |
||
398 | yellow(props_failed), 'ies' if props_failed != 1 else 'y', red(file_errors), |
||
399 | 'files were' if file_errors != 1 else 'file was' |
||
400 | )) |
||
401 | |||
402 | def analyze(self, arguments): # pylint:disable=unused-argument |
||
403 | handlers = dict() |
||
404 | |||
405 | # Set default query format |
||
406 | try: |
||
407 | qformat = self.args.config['analzye']['queryformat'] |
||
408 | except KeyError: |
||
409 | pass |
||
410 | |||
411 | if self.args.queryformat: |
||
412 | qformat = self.args.queryformat |
||
413 | |||
414 | file_data = list() |
||
415 | errors = list() |
||
416 | ntfiledata = namedtuple("FileData", "file,out_formatted,data") |
||
417 | validfiles, invalidfiles = self.get_files_status(self.__xml) |
||
418 | |||
419 | for f in self.__files: |
||
420 | if "error" in self.__xml[f]: |
||
421 | errors.append("Error in '{}': {}".format(f, red(self.__xml[f]["errorstr"]))) |
||
422 | else: |
||
423 | try: |
||
424 | analyzer = Analyzer(self.__xml[f]["handler"]) |
||
425 | except DMInvalidXMLHandlerObject: |
||
426 | log.critical("XML Handler object is None.") |
||
427 | |||
428 | out = qformat[:] |
||
429 | out = analyzer.replace_constants(out) |
||
430 | fields = analyzer.extract_fields(out) |
||
431 | data = analyzer.fetch_data(self.__args.filter, self.__args.sort, self.__args.default_output) |
||
432 | |||
433 | if not self.__args.sort: |
||
434 | # we can print all caught data here. If we have no data, we assume that the user |
||
435 | # didn't want to see any data from the XML files and he just want to see the |
||
436 | # output of the constants like {os.file} - https://github.com/openSUSE/docmanager/issues/93 |
||
437 | if data: |
||
438 | print(analyzer.format_output(out, data)) |
||
439 | elif analyzer.filters_matched: |
||
440 | print(analyzer.format_output(out, data)) |
||
441 | else: |
||
442 | file_data.append(ntfiledata(file=f, out_formatted=out, data=data)) |
||
443 | |||
444 | if self.__args.sort: |
||
445 | values = None |
||
446 | |||
447 | if self.__args.sort == 'filename': |
||
448 | values = sorted(file_data, key=lambda x: x.file) |
||
449 | else: |
||
450 | try: |
||
451 | values = sorted(file_data, key=lambda x: int(x.data[self.__args.sort]) \ |
||
452 | if x.data[self.__args.sort].isnumeric() \ |
||
453 | else \ |
||
454 | x.data[self.__args.sort]) |
||
455 | except KeyError: |
||
456 | log.error("Could not find key '{}' in -qf for sort.") |
||
457 | |||
458 | if values: |
||
459 | for i in values: |
||
460 | print(analyzer.format_output(i.out_formatted, i.data)) |
||
461 | |||
462 | if not self.__args.quiet: |
||
463 | print("\nSuccessfully analyzed {} XML files.".format(green(validfiles))) |
||
464 | |||
465 | if errors and not self.__args.quiet: |
||
466 | print("Got {} errors in the analyzed files:\n".format(red(len(errors)))) |
||
467 | for i in errors: |
||
468 | print(i) |
||
469 | |||
470 | def _readconfig(self, confname): |
||
471 | """Read the configuration file |
||
472 | |||
473 | :param str confname: name of configuration file |
||
474 | :return: ConfigParser object |
||
475 | """ |
||
476 | |||
477 | # exit if the config file is a directory |
||
478 | if os.path.isdir(confname): |
||
479 | log.error("File '{}' is a directory. Cannot write " |
||
480 | "into directories!".format(confname)) |
||
481 | sys.exit(ReturnCodes.E_FILE_IS_DIRECTORY) |
||
482 | |||
483 | # open the config file with the ConfigParser |
||
484 | conf = ConfigParser() |
||
485 | if not conf.read(confname): |
||
486 | if os.path.exists(confname): |
||
487 | log.error("Permission denied for file '{}'! " |
||
488 | "Maybe you need sudo rights?".format(confname)) |
||
489 | sys.exit(ReturnCodes.E_PERMISSION_DENIED) |
||
490 | return conf |
||
491 | |||
492 | def config(self, values): # pylint:disable=unused-argument |
||
493 | if not self.__args.system and not self.__args.user and not self.__args.repo and not self.__args.own: |
||
494 | log.error("No config file specified. Please choice between either '--system', '--user', '--repo', or '--own'.") |
||
495 | sys.exit(ReturnCodes.E_CONFIGCMD_NO_METHOD_SPECIFIED) |
||
496 | |||
497 | prop = self.__args.property |
||
498 | value = self.__args.value |
||
499 | |||
500 | # search for the section, the property and the value |
||
501 | pos = prop.find(".") |
||
502 | if pos == -1: |
||
503 | log.error("Invalid property syntax. Use: section.property") |
||
504 | sys.exit(ReturnCodes.E_INVALID_CONFIG_PROPERTY_SYNTAX) |
||
505 | |||
506 | section = prop[:pos] |
||
507 | prop = prop[pos+1:] |
||
508 | |||
509 | confname = None |
||
510 | |||
511 | # determine config file |
||
512 | if self.__args.system: |
||
513 | confname = GLOBAL_CONFIG[0] |
||
514 | elif self.__args.user: |
||
515 | confname = USER_CONFIG |
||
516 | elif self.__args.repo: |
||
517 | confname = GIT_CONFIG |
||
518 | elif self.__args.own: |
||
519 | confname = self.__args.own |
||
520 | |||
521 | # open the config file with the ConfigParser |
||
522 | conf = self._readconfig(confname) |
||
523 | |||
524 | # handle the 'get' method |
||
525 | if value is None: |
||
526 | if conf.has_section(section): |
||
527 | try: |
||
528 | print(conf.get(section, prop)) |
||
529 | except NoOptionError: |
||
530 | pass |
||
531 | |||
532 | sys.exit(ReturnCodes.E_OK) |
||
533 | |||
534 | # add the section if its not available |
||
535 | if not conf.has_section(section): |
||
536 | conf.add_section(section) |
||
537 | |||
538 | # set the property |
||
539 | conf.set(section, prop, value) |
||
540 | |||
541 | # save the changes |
||
542 | try: |
||
543 | if not os.path.exists(confname): |
||
544 | # 'x' for creating and writing to a new file |
||
545 | conf.write(open(confname, 'x')) # pylint:disable=bad-open-mode |
||
546 | else: |
||
547 | conf.write(open(confname, 'w')) |
||
548 | except PermissionError: # pylint:disable=undefined-variable |
||
549 | log.error("Permission denied for file '{}'! " |
||
550 | "Maybe you need sudo rights?".format(confname)) |
||
551 | sys.exit(ReturnCodes.E_PERMISSION_DENIED) |
||
552 | |||
553 | def alias(self, values): |
||
554 | action = self.__args.alias_action |
||
555 | alias = self.__args.alias |
||
556 | value = self.__args.command |
||
557 | m = { 0: None, 1: GLOBAL_CONFIG[0], 2: USER_CONFIG, 3: GIT_CONFIG } |
||
558 | configname = m.get(self.__args.method, self.__args.own) |
||
559 | save = False |
||
560 | |||
561 | if action != 'list': |
||
562 | if alias is None and value is None: |
||
563 | log.error("You have to provide an alias name for method '{}'.".format(action)) |
||
564 | sys.exit(ReturnCodes.E_INVALID_ARGUMENTS) |
||
565 | |||
566 | if not value: |
||
567 | value = "" |
||
568 | |||
569 | # parse the config file |
||
570 | conf = self._readconfig(configname) |
||
571 | |||
572 | # add alias section if it's not found |
||
573 | if not conf.has_section("alias"): |
||
574 | conf.add_section("alias") |
||
575 | |||
576 | # handle actions |
||
577 | if action == "set": |
||
578 | conf.set("alias", alias, value) |
||
579 | save = True |
||
580 | elif action == "get": |
||
581 | try: |
||
582 | print(conf.get("alias", alias)) |
||
583 | except NoOptionError: |
||
584 | pass |
||
585 | elif action == "del": |
||
586 | save = True |
||
587 | conf.remove_option("alias", alias) |
||
588 | elif action == "list": |
||
589 | data = dict() |
||
590 | data["configfile"] = configname |
||
591 | data["aliases"] = conf['alias'] |
||
592 | |||
593 | return data |
||
594 | |||
595 | # save the changes |
||
596 | if save: |
||
597 | try: |
||
598 | if not os.path.exists(configname): |
||
599 | log.error("The config file does not exists.") |
||
600 | sys.exit(ReturnCodes.E_FILE_NOT_FOUND) |
||
601 | |||
602 | conf.write(open(configname, 'w')) |
||
603 | except PermissionError: |
||
604 | log.error("Permission denied for file '{}'! " |
||
605 | "Maybe you need sudo rights?".format(configname)) |
||
606 | sys.exit(ReturnCodes.E_PERMISSION_DENIED) |
||
607 | |||
608 | def remove_duplicate_langcodes(self, values): |
||
609 | new_list = [] |
||
610 | for i in values: |
||
611 | if i not in new_list: |
||
612 | new_list.append(i) |
||
613 | |||
614 | return new_list |
||
615 | |||
616 | |||
617 | def get_files_status(self, handlers): |
||
618 | """Count all valid and invalid XML files |
||
619 | |||
620 | :param dict handlers: The self.__xml object with all XML handlers |
||
621 | """ |
||
622 | validfiles = 0 |
||
623 | invalidfiles = 0 |
||
624 | |||
625 | for i in self.__files: |
||
626 | if "error" in handlers[i]: |
||
627 | invalidfiles += 1 |
||
628 | else: |
||
629 | validfiles += 1 |
||
630 | |||
631 | return [validfiles, invalidfiles] |
||
632 | |||
633 | @property |
||
634 | def args(self): |
||
635 | return self.__args |
||
636 |