268 @param outputQueue output queue (multiprocessing.Queue) |
269 @param outputQueue output queue (multiprocessing.Queue) |
269 """ |
270 """ |
270 for filename, source, args in iter(inputQueue.get, 'STOP'): |
271 for filename, source, args in iter(inputQueue.get, 'STOP'): |
271 result = __checkCodeStyle(filename, source, args) |
272 result = __checkCodeStyle(filename, source, args) |
272 outputQueue.put((filename, result)) |
273 outputQueue.put((filename, result)) |
|
274 |
|
275 |
|
276 def __checkSyntax(filename, source): |
|
277 """ |
|
278 Private module function to perform a syntax check. |
|
279 |
|
280 @param filename source filename |
|
281 @type str |
|
282 @param source string containing the code to check |
|
283 @type str |
|
284 @return tuple containing the error dictionary with syntax error details |
|
285 and a statistics dictionary or a tuple containing two None |
|
286 @rtype tuple of (dict, dict) or tuple of (None, None) |
|
287 """ |
|
288 src = "".join(source) |
|
289 # Check type for py2: if not str it's unicode |
|
290 if sys.version_info[0] == 2: |
|
291 try: |
|
292 src = src.encode('utf-8') |
|
293 except UnicodeError: |
|
294 pass |
|
295 |
|
296 try: |
|
297 ast.parse(src, filename, 'exec') |
|
298 return None, None |
|
299 except (SyntaxError, TypeError): |
|
300 exc_type, exc = sys.exc_info()[:2] |
|
301 if len(exc.args) > 1: |
|
302 offset = exc.args[1] |
|
303 if len(offset) > 2: |
|
304 offset = offset[1:3] |
|
305 else: |
|
306 offset = (1, 0) |
|
307 return ({ |
|
308 "file": filename, |
|
309 "line": offset[0], |
|
310 "offset": offset[1], |
|
311 "code": "E901", |
|
312 "args": [exc_type.__name__, exc.args[0]], |
|
313 }, { |
|
314 "E901": 1, |
|
315 }) |
273 |
316 |
274 |
317 |
275 def __checkCodeStyle(filename, source, args): |
318 def __checkCodeStyle(filename, source, args): |
276 """ |
319 """ |
277 Private module function to perform the code style check and/or fix |
320 Private module function to perform the code style check and/or fix |
338 ignore = [i.strip() for i in |
381 ignore = [i.strip() for i in |
339 excludeMessages.split(',') if i.strip()] |
382 excludeMessages.split(',') if i.strip()] |
340 else: |
383 else: |
341 ignore = [] |
384 ignore = [] |
342 |
385 |
343 # TODO: perform syntax check and report invalid syntax once for all |
386 syntaxError, syntaxStats = __checkSyntax(filename, source) |
344 |
387 if syntaxError: |
345 # check coding style |
388 errors = [syntaxError] |
346 pycodestyle.BLANK_LINES_CONFIG = { |
389 stats.update(syntaxStats) |
347 # Top level class and function. |
390 |
348 'top_level': blankLines[0], |
391 # perform the checks only, if syntax is ok |
349 # Methods and nested class and function. |
392 else: |
350 'method': blankLines[1], |
393 # check coding style |
351 } |
394 pycodestyle.BLANK_LINES_CONFIG = { |
352 styleGuide = pycodestyle.StyleGuide( |
395 # Top level class and function. |
353 reporter=CodeStyleCheckerReport, |
396 'top_level': blankLines[0], |
354 repeat=repeatMessages, |
397 # Methods and nested class and function. |
355 select=select, |
398 'method': blankLines[1], |
356 ignore=ignore, |
399 } |
357 max_line_length=maxLineLength, |
400 styleGuide = pycodestyle.StyleGuide( |
358 max_doc_length=maxDocLineLength, |
401 reporter=CodeStyleCheckerReport, |
359 hang_closing=hangClosing, |
402 repeat=repeatMessages, |
360 ) |
403 select=select, |
361 report = styleGuide.check_files([filename]) |
404 ignore=ignore, |
362 stats.update(report.counters) |
405 max_line_length=maxLineLength, |
363 errors = report.errors |
406 max_doc_length=maxDocLineLength, |
364 |
407 hang_closing=hangClosing, |
365 # check documentation style |
408 ) |
366 docStyleChecker = DocStyleChecker( |
409 report = styleGuide.check_files([filename]) |
367 source, filename, select, ignore, [], repeatMessages, |
410 stats.update(report.counters) |
368 maxLineLength=maxDocLineLength, docType=docType) |
411 errors = report.errors |
369 docStyleChecker.run() |
412 |
370 stats.update(docStyleChecker.counters) |
413 # check documentation style |
371 errors += docStyleChecker.errors |
414 docStyleChecker = DocStyleChecker( |
372 |
|
373 # miscellaneous additional checks |
|
374 miscellaneousChecker = MiscellaneousChecker( |
|
375 source, filename, select, ignore, [], repeatMessages, |
|
376 miscellaneousArgs) |
|
377 miscellaneousChecker.run() |
|
378 stats.update(miscellaneousChecker.counters) |
|
379 errors += miscellaneousChecker.errors |
|
380 |
|
381 # check code complexity |
|
382 complexityChecker = ComplexityChecker( |
|
383 source, filename, select, ignore, codeComplexityArgs) |
|
384 complexityChecker.run() |
|
385 stats.update(complexityChecker.counters) |
|
386 errors += complexityChecker.errors |
|
387 |
|
388 # check function annotations |
|
389 if sys.version_info >= (3, 5, 0): |
|
390 # annotations are supported from Python 3.5 on |
|
391 from AnnotationsChecker import AnnotationsChecker |
|
392 annotationsChecker = AnnotationsChecker( |
|
393 source, filename, select, ignore, [], repeatMessages, |
415 source, filename, select, ignore, [], repeatMessages, |
394 annotationArgs) |
416 maxLineLength=maxDocLineLength, docType=docType) |
395 annotationsChecker.run() |
417 docStyleChecker.run() |
396 stats.update(annotationsChecker.counters) |
418 stats.update(docStyleChecker.counters) |
397 errors += annotationsChecker.errors |
419 errors += docStyleChecker.errors |
398 |
420 |
399 securityChecker = SecurityChecker( |
421 # miscellaneous additional checks |
400 source, filename, select, ignore, [], repeatMessages, |
422 miscellaneousChecker = MiscellaneousChecker( |
401 securityArgs) |
423 source, filename, select, ignore, [], repeatMessages, |
402 securityChecker.run() |
424 miscellaneousArgs) |
403 stats.update(securityChecker.counters) |
425 miscellaneousChecker.run() |
404 errors += securityChecker.errors |
426 stats.update(miscellaneousChecker.counters) |
|
427 errors += miscellaneousChecker.errors |
|
428 |
|
429 # check code complexity |
|
430 complexityChecker = ComplexityChecker( |
|
431 source, filename, select, ignore, codeComplexityArgs) |
|
432 complexityChecker.run() |
|
433 stats.update(complexityChecker.counters) |
|
434 errors += complexityChecker.errors |
|
435 |
|
436 # check function annotations |
|
437 if sys.version_info >= (3, 5, 0): |
|
438 # annotations are supported from Python 3.5 on |
|
439 from AnnotationsChecker import AnnotationsChecker |
|
440 annotationsChecker = AnnotationsChecker( |
|
441 source, filename, select, ignore, [], repeatMessages, |
|
442 annotationArgs) |
|
443 annotationsChecker.run() |
|
444 stats.update(annotationsChecker.counters) |
|
445 errors += annotationsChecker.errors |
|
446 |
|
447 securityChecker = SecurityChecker( |
|
448 source, filename, select, ignore, [], repeatMessages, |
|
449 securityArgs) |
|
450 securityChecker.run() |
|
451 stats.update(securityChecker.counters) |
|
452 errors += securityChecker.errors |
405 |
453 |
406 errorsDict = {} |
454 errorsDict = {} |
407 for error in errors: |
455 for error in errors: |
408 if error["line"] > len(source): |
456 if error["line"] > len(source): |
409 error["line"] = len(source) |
457 error["line"] = len(source) |